Fun with animated gradients
This post is an adaptation of a presentation I gave at the first PNW Web Codepen Meetup. Disclaimer: I work on the Microsoft Edge browser platform team but represent my own opinions, yadda yadda.
I find it kind of funny that, now that we no longer need to 9-slice images to get a button with a gradient on it, CSS gradients are possibly somewhat underutilized. I am thankful we are no longer in an era of web design where everything needs to be mega glossed, but gradients are a little more versatile than you might think—especially when we add animation into the equation.
Let’s have fun with gradients!
But first, let’s be responsible >:[
Some considerations to keep in mind when it comes to animating gradients:
Code generators can spit out some nasty stuff; Ana Tudor explained some key problems with using gradient generators. If you choose to use pre- or post-processing tools, be sure to vet those for efficiency and accuracy—both prefixes and property values.
Note: for simplicity’s sake, my demos will be shown unprefixed.
This is a complicated space because there are so many different factors that can differ page to page, but a good place to start is by consulting CSS triggers. The site shows what CSS properties will cause the browser to do more rendering work on first load (the “change from default” column) and on subsequent changes to elements’ properties. “Layout” is when the browser calculates how elements are positioned and sized on the screen. “Paint” is when it draws pixels to the screen. Sometimes repaints are done in layers; “composite” refers to the step in the rendering process where the browser combines these layers.
This is all to say: test your code for performance, especially if you are making changes to properties that would change the dimensions or placement of an element within a page.
Animation should be used to enhance an experience, not hinder it. The Web Content Accessibility Guidelines (WCAG) 2.0 document says that if an animation starts automatically, lasts more than 5 seconds, and is “presented in parallel” with other content, the user should be provided with the means to pause or stop that animation. Elements also should not flash more than 3 times per second; in Level AA compliance (legal compliance ranges between levels A–AAA), those flashes can be below “general flash and red flash guidelines”.
Thsese guidelines can help improve experiences for those with seizures, cognitive disabilities, and motion sensitives, but can be beneficial to anyone trying to focus on a task or read some content. I’ve paraphrased WCAG here, so I would suggest checking out the official document in order to correctly follow compliance guidelines (see guidelines 2.2 and 2.3 in the link).
The experiments below make use of most of these properties related to background images, transitions, and animations:
background-image background-size background-position transition-property transition-duration transition-timing-function transition-delay animation-name animation-duration animation-timing-function animation-iteration-count animation-direction animation-play-state animation-delay animation-fill-mode
There are shorthands for these properties (
animation), but for clarity, I’ll be using the non-shorthand versions.
The experiments focus more on different effects you can achieve using these properties. For more in-depth information and available property values, you can refer to these CSS specifications: CSS images (gradients), backgrounds and borders, transitions, animations.
Now, onto the experiments!
Experiment #1: Instagram link
What prompted me to explore animated/transitioned gradients is a little quirk I ran into while trying to style an instagram link on my personal site. Basically, I wanted to fade the background of the link from the Instagram brand gradient to the main color on my site.
The result is that the background gradient just flips to the solid color, rather than fading. I thought this might be because a linear gradient and a background color are two different property types, namely, a CSS image and a color. Sidenote: the
background shorthand property is not actually animatable, per the CSS transitions specification.
So next I tried faking a solid color with a gradient:
The fake solid color is a little messy, but the transitions spec requires an equal number of stops:
gradient: interpolated via the positions and colors of each stop. They must have the same type (radial or linear) and same number of stops in order to be animated.
Woo hoo! That works…in Microsoft Edge. No transitions in Chrome, Firefox, or Safari. I didn’t want this to be the only social media icon in the batch without a transition, so I had to do some pseudo element trickery:
The gradient is applied to the
::before pseudo element, whose opacity is changed on hover. One bonus from this approach is that
opacity is a less costly CSS change, perf-wise, per the CSS Triggers site.
Experiment #2: Ripple button
A pseudo element on the button has a repeating radial gradient backround. When the
submitted class is added to the button via click, a CSS animation changes the padding on the button, thereby revealing more rings and creating a “ripple”. The animation of
padding here is one we would have to pay attention to, perf-wise, as we are redrawing the padding box throughout the animation. I initially considered changing the
background-size property to achieve this effect, but that has undesirable effects cross-browser, such as tiling the ellipses, or stretching them.
Experiment #3: gradient-as-marketing
Animated gradients can appeal to emotions in more obvious ways. An AC company could speak to frazzled, overheated customers by transitioning a splash area from a hot red to a cool blue:
In this example, the gradient background is divided into thirds: the first third is red, the middle transitions from red to blue, and the last third is blue. The background size is set to 300%, and its position is animated vertically. This way, we end on a completely “cool” background.
transition-fill-mode property tells the browser how to apply the styles from the animation; by setting
forwards as the property value, we are saying that we want the browser to keep/apply the styles from the last frame of the animation (otherwise, the background would jump back to red).
Experiment #4: shiny callout
Motion draws the eye. If you have a callout that you want to draw the user’s attention to that is outside the flow of the main content, you could do a “shiny” effect:
This effect employs the same general principles as #4, except this time we’re animating at a 135deg angle, and the background is scaled to 400% so that the last quarter of the gradient covers the box when the animation ends.
Experiment #5: “plaid” loading spinner
Sometimes accidents can create interesting effects. This gradient is displayed at 200% background-size, and its position is set to 150%. This glitches out to create a somewhat “plaid” effect:
The spinner only runs 4 times to account for accessibility benchmarks (if it were longer than 5s we’d need to provide a way to turn the animation off). I do hope your content loads in less than 5 seconds.
Experiment #6: animated intrinsic placeholder
This experiment builds on the intrinsic placeholder approach to prevent page jumping when images load. A
picture element has a top padding equal to the image ratio of the asset inside it, which will be positioned absolutely when it loads. You may need to throttle your connection to see this one.
We can use some background sizing trickery on a radial gradient to produce a “breathing dots” effect. Sadly, this one doesn’t perform super well in Chrome; the dots feel a bit shaky as the background size animates. This might be one where we choose to drop animation and just use gradients for their ability to provide a little repeat pattern without having to load an image asset.
Those are my micro-experiments with animating gradients! Feel free to share your own in the comments.