2

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?

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
bigmadwolf
  • 3,419
  • 3
  • 30
  • 44

3 Answers3

6

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).

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
4

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.

SW4
  • 69,876
  • 20
  • 132
  • 137
  • I suppose my question is two fold really, should you simply pass them into the already prefixed keyframe declarations, and if so which ones? – bigmadwolf Feb 16 '15 at 16:11
  • IE9 is the only version that requires the -ms- prefix for transforms, but it doesn't support animations at all so having the prefix for transforms for versions that do support animations is quite pointless. – BoltClock Feb 16 '15 at 16:13
  • yeah it seems unintuitive to me to prefix the properties in the already prefixed keyframe declarations, I'm not doubting you specifically, and thank you for the quick answer but is there anything to back this up? – bigmadwolf Feb 16 '15 at 16:14
  • @pushplaybang - note that you have prefixed just that, the keyframe declaration, not the actual underlying transform. That said, as Boltclock notes, the IE9 declaration will not accomplish much, it is above for indicative purposes – SW4 Feb 16 '15 at 16:16
  • sweet that makes sense, are the -ms-prefixes not necessary for IE versions later than 9 though? – bigmadwolf Feb 16 '15 at 16:18
  • @pushplaybang: Like I said, no. Absolutely not. – BoltClock Feb 16 '15 at 16:20
  • awesome. One day maybe we'll be free of the prefixing malarky – bigmadwolf Feb 16 '15 at 16:22
  • @pushplaybang: As a matter of fact, prefixes are mostly going away for good. Only a few stragglers remain, and most new features won't even ship with prefixes anymore. – BoltClock Feb 16 '15 at 16:23
  • I can't wait. Except I still live in a world where progressive enhancement is our mantra (not a bad thing at all) and we serve at the pleasure of many corporate clients wielding IE8 and similar old bits and pieces run by maniacal change resistant IT departments. So I try and do everything defensively to support the maximum range of old sh@#$. – bigmadwolf Feb 16 '15 at 16:27
4

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.

Community
  • 1
  • 1
cimmanon
  • 67,211
  • 17
  • 165
  • 171