Ricky_Ruiz Ricky_Ruiz - 1 month ago 5
CSS Question

Is it safe to remove a property from the `0%` keyframe of a CSS animation if it is already declared in the class the animation is applied to?

Context:



According to the Animation Spec:


If a ‘0%’ or ‘from’ keyframe is not specified, then the user agent
constructs a ‘0%’ keyframe using the computed values of the properties
being animated. If a ‘100%’ or ‘to’ keyframe is not specified, then
the user agent constructs a ‘100%’ keyframe using the computed values
of the properties being animated.


This can lead to two different interpretations:


  • A) Declare the property in the class and not in the
    0%
    or
    from
    keyframe.

  • B) Declare the property in the class and in the
    0%
    or
    from
    keyframe.






Simplified Example:





p:first-of-type {
opacity: 0;
animation: a 3s linear infinite alternate;
}
@keyframes a {
100% {
opacity: 1;
}
}
p:last-of-type {
opacity: 0;
animation: b 3s linear infinite alternate;
}
@keyframes b {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}

<p>
A) Declare the property in the class <strong>and not</strong> in the `0%` or `from` keyframe.
</p>
<p>
B) Declare the property in the class <strong>and </strong> in the `0%` or `from` keyframe.
</p>








While both have the same end result, following the Don't Repeat Yourself (DRY) principle, A) could vastly reduce code for all the animations that use more than one property.




Complex Example:





/*
Layout
*/

* {
box-sizing: border-box;
}
body {
margin: 0;
}
ul {
margin: 0;
padding: 0;
list-style: none;
}
.container {
height: 100vh;
display: flex;
flex-direction: column;
justify-content: space-around;
counter-reset: list-item;
}
.container > li {
position: relative;
counter-increment: list-item;
}
.container > li::before {
content: counter(list-item, upper-alpha);
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: flex-end;
align-items: flex-end;
font-size: 1.5em;
background-color: moccasin;
}
.container > li::after {
content: '';
position: absolute;
top: 50%;
left: 0;
width: 100%;
transform: translateY(-50%);
height: 2px;
background-color: gold;
}
/*
SVG
*/

.svg-spritesheet {
display: none;
}
.svg__icon {
display: inline-block;
vertical-align: middle;
width: 1em;
height: 1em;
}
.svg__icon--square {
font-size: 5em;
color: dodgerblue;
}
/*
Question Related
*/

.container > li:first-of-type .svg__icon--square {
opacity: 0;
transform: scale(.5) rotate(45deg);
animation: animationA 5s linear infinite alternate;
}
.container > li:nth-child(2) .svg__icon--square {
opacity: 0;
transform: scale(.5) rotate(45deg);
animation: animationB 5s linear infinite alternate;
}
@keyframes animationA {
to {
opacity: 1;
transform: translateX(500px) scale(1) rotate(90deg);
}
}
@keyframes animationB {
from {
opacity: 0;
transform: scale(.5) rotate(45deg);
}
to {
opacity: 1;
transform: translateX(500px) scale(1) rotate(90deg);
}
}

<ul class="container">
<li>
<svg class="svg__icon svg__icon--square">
<use xlink:href="#svg-icon-square"></use>
</svg>
</li>
<li>
<svg class="svg__icon svg__icon--square">
<use xlink:href="#svg-icon-square"></use>
</svg>
</li>
</ul>

<svg class="svg-spritesheet">
<symbol id="svg-icon-square" viewBox="0 0 32 32">
<title>Demo Square</title>
<rect width="32" height="32" fill="currentColor" />
</symbol>
</svg>








Question:



Is it safe to remove a property from the
0%
keyframe of a CSS animation if it is already declared in the class the animation is applied to?

Is doing this:

.el {
opacity: 0;
animation: example 1s;
}

@keyframes example {
100% {
opacity: 1;
}
}


considered safe across browsers? Or is it to be expected that user agents render different results or performance?




TESTS:



Rendering the same result:

Windows 10 / 64-bit


  • Chrome 54.0.2840.71 m (64-bit)

  • FireFox 49.0.2

  • Edge 25.10586.0.0


Answer

The computed value of a property can vary depending on what CSS rules are applying to a given element, the specificity of these rules, whether the element has an inline style declaration for that property, whether a script is modifying the value of that property at runtime, etc.

If you want an animation to start from a predictable, and fixed, value, you will need to specify this value in the 0% keyframe so that it doesn't start animating from what the computed value happens to be at the time the animation starts instead.

You can leave out the 0% keyframe if you can guarantee that the computed value for that element at the time the animation is started is always a constant value. You must leave out the 0% keyframe if you want the animation to always start from whatever the computed value happens to be at the time, if it can change.

Comments