{"id":271227,"date":"2018-06-01T07:30:40","date_gmt":"2018-06-01T14:30:40","guid":{"rendered":"http:\/\/css-tricks.com\/?p=271227"},"modified":"2021-03-26T16:02:45","modified_gmt":"2021-03-26T23:02:45","slug":"the-state-of-changing-gradients-with-css-transitions-and-animations","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/the-state-of-changing-gradients-with-css-transitions-and-animations\/","title":{"rendered":"The State of Changing Gradients with CSS Transitions and Animations"},"content":{"rendered":"\n

Back in 2012, Internet Explorer 10 came out and, among other things, it finally supported CSS gradients and, in addition to that, the ability to animate them with just CSS! No other browser supported this at the time, but I was hopeful for the future.<\/p>\n\n\n\n

Sadly, six years have passed and nothing has changed in this department. Edge supports animating gradients with CSS, just like IE 10 did back then, but no other browser has added support for this. And while animating background-size<\/code> or background-position<\/code> or the opacity<\/code> or rotation of a pseudo element layered on top can take us a long way<\/a> in terms of achieving cool effects, these workarounds are still limited.<\/p>\n\n\n\n\n\n\n\n

There are effects we cannot reproduce without adding lots of extra elements or lots of extra gradients, such as “the blinds effect” seen below.<\/p>\n\n\n\n

\"Animated
The blinds effect (live demo<\/a>, Edge\/ IE 10+ only).<\/figcaption><\/figure>\n\n\n\n

In Edge, getting the above effect is achieved with a keyframe animation<\/code><\/a>:<\/p>\n\n\n\n

html {\n  background: linear-gradient(90deg, #f90 0%, #444 0) 50%\/ 5em;\n  animation: blinds 1s ease-in-out infinite alternate;\n}\n\n@keyframes blinds {\n  to {\n    background-image: linear-gradient(90deg, #f90 100%, #444 0);\n  }\n}<\/code><\/pre>\n\n\n\n

If that seems WET<\/a>, we can DRY<\/a> it up with a touch of Sass<\/a>:<\/p>\n\n\n\n

@function blinds($open: 0) {\n  @return linear-gradient(90deg, #f90 $open*100%, #444 0);\n}\n\nhtml {\n  background: blinds() 50%\/ 5em;\n  animation: blinds 1s ease-in-out infinite alternate;\n}\n\n@keyframes blinds { to { background-image: blinds(1) } }<\/code><\/pre>\n\n\n\n

While we’ve made the code we write and what we’ll need to edit later a lot more maintainable, we still have repetition in the compiled CSS and we’re limited by the fact that we can only animate between stops with the same unit \u2014 while animating from 0%<\/code> to 100%<\/code> works just fine, trying to use 0<\/code> or 0px<\/code> instead of 0%<\/code> results in no animation happening anymore. Not to mention that Chrome and Firefox just flip from orange to grey with no stop position animation<\/code> at all!<\/p>\n\n\n\n

Fortunately, these days we have an even better option: CSS variables!<\/p>\n\n\n\n

Right out of the box, CSS variables are not animatable, though we can get transition<\/code> (but not animation<\/code>!) effects if the property we use them for is animatable<\/em>. For example, when used inside a transform<\/code> function, we can transition<\/code> the transform<\/code> the property.<\/p>\n\n\n\n

Let’s consider the example of a box that gets shifted and squished when a checkbox is checked. On this box, we set a transform<\/code> that depends on a factor --f<\/code> which is initially 1<\/code>:<\/p>\n\n\n\n

.box {\n  \/* basic styles like dimensions and background *\/\n  --f: 1;\n  transform: translate(calc((1 - var(--f))*100vw)) scalex(var(--f));\n}<\/code><\/pre>\n\n\n\n

When the checkbox is :checked<\/code>, we change the value of the CSS variable --f<\/code> to .5<\/code>:<\/p>\n\n\n\n

:checked ~ .box { --f: .5 }<\/code><\/pre>\n\n\n\n

Setting a transition<\/code> on the .box<\/code> makes it go smoothly from one state to the other:<\/p>\n\n\n\n

.box {\n  \/* same styles as before *\/\n  transition: transform .3s ease-in;\n}<\/code><\/pre>\n\n\n\n

Note that this doesn’t really work in the current version of Edge due to this bug<\/a>.<\/p>\n\n\n\n