I have the following snippet of Sass that works like a charm, but I wonder if I need to prefix my transform properties, and, if so, how? (if not, why not?)
@mixin expand-o-band() {
0% { opacity: 1; transform: scale(1); }
100% { opacity: 0; transform: scale(2); }
}
@-webkit-keyframes expand-o-band { @include expand-o-band(); }
@-moz-keyframes expand-o-band { @include expand-o-band(); }
@-o-keyframes expand-o-band { @include expand-o-band(); }
@keyframes expand-o-band { @include expand-o-band(); }
.circle-thing {
-webkit-animation: expand-o-band 1.5s infinite; /* Safari 4+ */
-moz-animation: expand-o-band 1.5s infinite; /* Fx 5+ */
-o-animation: expand-o-band 1.5s infinite; /* Opera 12+ */
animation: expand-o-band 1.5s infinite; /* IE 10+, Fx 29+ */
}
Please note I'm not asking about using something like autoprefixer, etc., to do this for me, but what I would need to add to my mix-in to make this compatible with the widest range of browsers?
Given that:
Im not asking about using something like autoprefixer
It depends on which browsers and which versions you want to support:
-ms-
can be used for IE9 (below IE9 is not supported at all) however, animations are only supported in IE10+, as such, if you are animating a transform including the ms
prefix is redundant
-webkit-
can be used for Chrome 35, 31, Safari and android browsers
@mixin expand-o-band() {
0% {
opacity: 1;
-ms-transform: scale(1); /* <--- not necessary */
-webkit-transform: scale(1);
transform: scale(1);
}
100% {
opacity: 0;
-ms-transform: scale(2); /* <--- not necessary */
-webkit-transform: scale(2);
transform: scale(2);
}
}
Generally solutions like autoprefixer are highly recommended because they allow you to write clean CSS then to clearly define which browsers and (legacy) versions thereof you wish to support. The advantage of this is that your source is then less likely to include items which may at a later date become irrelevant to you (and your end user base), and the worry of correctly including the right implementations is abstracted away.
This is one of those cases where vendor prefixes for standardized features become extremely problematic, because you need to account for all the different prefixed and/or unprefixed implementations of different features in different versions of different browsers.
What a mouthful. And then you have to combine various permutations of these. What a handful.
In short, you need to figure out which versions of each browser requires a prefix for each of the individual properties, and unless you don't mind the bloat, you will need to apply the prefixes differently for individual browsers. Fortunately, this part is made extremely easy by the fantastic and up-to-date resource, caniuse.com; here are the compatibility tables for 2D transforms and animations.
The good news is that browsers are generally very consistent in terms of reaching stable (i.e. unprefixed) implementations of both transforms and animations:
IE9 implemented -ms-transform
, and only began implementing animations in IE10 with stable unprefixed syntax by RTM as well as unprefixing transforms. IE is notably the only browser where prefixing transforms in animations is pointless, because on top of being the only browser to require prefixes for transforms, IE9 simply isn't going to recognize CSS animations anyway.
That doesn't stop you from using -ms-transform
elsewhere and having animations as a form of progressive enhancement, of course, but including it within animations is pointless. Also, you may have read about an @-ms-keyframes
prefix, but that is only used in pre-release versions of IE10 which have since long expired and will no longer run anyway.
Firefox shipped -moz-transform
as early as version 3.5, with animations coming in much later at version 5, then removed prefixes from both features simultaneously in version 16.
WebKit-based browsers (including Opera 15 and later) still require the -webkit-
prefix for animations today, and transforms are only unprefixed in recent versions of Chrome. You will need the prefix for both features.
Opera 12.00 was the only version to use @-o-keyframes
. -o-transform
was used up to that version as well. 12.10 dropped prefixes for both, and then it went straight on to regress into requiring both prefixes again by moving to WebKit in version 15 as mentioned above.
Unfortunately, since you have all these prefixes in your CSS animations and you're using the same mixin for all of them, you will need just as many prefixes for your CSS transforms for your prefixed animations to actually be of any use:
@mixin expand-o-band() {
0% {
opacity: 1;
-webkit-transform: scale(1);
-moz-transform: scale(1);
-o-transform: scale(1);
transform: scale(1);
}
100% {
opacity: 0;
-webkit-transform: scale(2);
-moz-transform: scale(2);
-o-transform: scale(2);
transform: scale(2);
}
}
You can greatly reduce the bloat if you use a mixin that takes a prefix argument, and pass the appropriate prefix to the mixin in each of your @keyframes
rules, but that's probably outside the scope of this question (but it's mostly because I don't really know Sass).
The short answer is: Don't roll your own. BoltClock already did an excellent job of explaining why your implementation won't be good enough for all scenarios (prefixed properties vs prefixed values).
The good news is that the fine people at Compass have already solved this problem for you.
@include keyframes(expand-o-band) {
0% {
/* prefixed property */
@include border-radius(0);
}
100% {
@include border-radius(1em);
/* prefixed value */
@include background(linear-gradient(to bottom, black, white));
}
}
.circle-thing {
@include animation(expand-o-band 1.5s infinite);
background: yellow;
padding: 5em;
border: 1px solid;
}
Output:
@-moz-keyframes expand-o-band {
0% {
/* prefixed property */
-moz-border-radius: 0;
border-radius: 0;
}
100% {
-moz-border-radius: 1em;
border-radius: 1em;
/* prefixed value */
background: -moz-linear-gradient(top, #000000, #ffffff);
background: linear-gradient(to bottom, #000000, #ffffff);
}
}
@-webkit-keyframes expand-o-band {
0% {
/* prefixed property */
-webkit-border-radius: 0;
border-radius: 0;
}
100% {
-webkit-border-radius: 1em;
border-radius: 1em;
/* prefixed value */
background: -webkit-linear-gradient(top, #000000, #ffffff);
background: linear-gradient(to bottom, #000000, #ffffff);
}
}
@keyframes expand-o-band {
0% {
/* prefixed property */
-moz-border-radius: 0;
-webkit-border-radius: 0;
border-radius: 0;
}
100% {
-moz-border-radius: 1em;
-webkit-border-radius: 1em;
border-radius: 1em;
/* prefixed value */
background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #000000), color-stop(100%, #ffffff));
background: -moz-linear-gradient(top, #000000, #ffffff);
background: -webkit-linear-gradient(top, #000000, #ffffff);
background: linear-gradient(to bottom, #000000, #ffffff);
}
}
.circle-thing {
-moz-animation: expand-o-band 1.5s infinite;
-webkit-animation: expand-o-band 1.5s infinite;
animation: expand-o-band 1.5s infinite;
background: yellow;
padding: 5em;
border: 1px solid;
}
http://sassmeister.com/gist/2413d0894bf609e80b5d
By default, Compass will maximize browser compatibility (and is fully configurable). All of their mixins that emit prefixes are compatible with their keyframes mixin. I can't even paste the relevant code to recreate the magic that goes into this because there is so much of it.