{"id":291730,"date":"2019-06-27T08:00:14","date_gmt":"2019-06-27T15:00:14","guid":{"rendered":"http:\/\/css-tricks.com\/?p=291730"},"modified":"2019-06-27T08:00:14","modified_gmt":"2019-06-27T15:00:14","slug":"different-approaches-for-creating-a-staggered-animation","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/different-approaches-for-creating-a-staggered-animation\/","title":{"rendered":"Different Approaches for Creating a Staggered Animation"},"content":{"rendered":"

Animating elements, at its most basic, is fairly straightforward. Define the keyframes. Name the animation. Call it on an element.<\/p>\n

But sometimes we need something a little<\/em> more complex to get the right \u201cfeel” for the way things move. For example, a sound equalizer might use the same animation on each bar, but they are staggered to give the illusion of being animated independently.<\/p>\n

<\/p>\n

\nSee the Pen
\nApple Music Sound Equilizer in SVG<\/a> by Geoff Graham (
@geoffgraham<\/a>)
\non
CodePen<\/a>.<\/span>\n<\/p>\n

I was recently building a dashboard and wanted the items in one of the widgets to flow into view with a staggered animation.<\/p>\n

\n
.my-list li {\r\n  animation: my-animation 300ms ease-out;\r\n}\r\n\r\n.my-list li:nth-child(1) {\r\n  animation-delay: 100ms;\r\n}\r\n\r\n.my-list li:nth-child(2) {\r\n  animation-delay: 200ms;\r\n}\r\n\r\n.my-list li:nth-child(3) {\r\n  animation-delay: 300ms;\r\n}\r\n\r\n\/* and so on *\/<\/code><\/pre>\n

This technique does indeed stagger items well, particularly if you know how many items are going to be in the list at any given time. Where things fall apart, however, is when the number of items is unpredictable, which was the case for the widget I was building for the dashboard. I really didn\u2019t want to come back to this piece of code every time the number of items in the list changed, so I knocked out a quick Sass loop that accounts for up to 50 items and increments the animation delay with each item:<\/p>\n

.my-list {\r\n  li {\r\n    animation: my-animation 300ms ease-out;\r\n      \r\n    @for $i from 1 through 50 {\r\n      &:nth-child(#{$i}) {\r\n        animation-delay: 100ms * $i;\r\n      }\r\n    }\r\n  }\r\n}<\/code><\/pre>\n

That should do it! Yet, it feels way too hacky. Sure, it doesn\u2019t add that much weight to the file, but you know the compiled CSS will include a bunch of unused selectors, like nth-child(45)<\/code>.<\/p>\n

There must be a better way. This is where I would normally reach for JavaScript to find all of the items and add a delay but\u2026 this time I spent a little time exploring to see if there is a way to do it with CSS alone.<\/p>\n

How about CSS counters?<\/h3>\n

The first thing I thought of was using a CSS counter in combination with the calc()<\/code> function:<\/p>\n

.my-list {\r\n  counter-reset: my-counter;\r\n}\r\n\r\n.my-list li {\r\n  counter-increment: my-counter;\r\n  animation-delay: calc(counter(my-counter) * 100ms);\r\n}<\/code><\/pre>\n

Unfortunately, that won\u2019t work because the spec says counters cannot be used in calc()<\/code><\/a>):<\/p>\n

Components of a calc()<\/code> expression can be literal values or attr()<\/code> or calc()<\/code> expressions.<\/p><\/blockquote>\n

Turns out a few people like this idea, but it hasn\u2019t gone further than the draft stage<\/a>.<\/p>\n

How about a data attribute?<\/h3>\n

Having read that excerpt from the spec, I learned that calc()<\/code> can use attr()<\/code>. And, according to the CSS Values and Units specification<\/a>): <\/p>\n

In CSS3, the attr()<\/code> expression can return many different types<\/p><\/blockquote>\n

This made me think; perhaps a data attribute could do the trick.<\/p>\n

<ul class=\"my-list\">\r\n  <li data-count=\"1\"><\/li>\r\n  <li data-count=\"2\"><\/li>\r\n  <li data-count=\"3\"><\/li>\r\n  <li data-count=\"4\"><\/li>\r\n<\/ul><\/code><\/pre>\n
.my-list li {\r\n  animation-delay: calc(attr(data-count) * 150ms);\r\n}<\/code><\/pre>\n

But my hopes were dashed as the browser support for this is diabolical!<\/p>\n

This browser support data is from Caniuse<\/a>, which has more detail. A number indicates that browser supports the feature at that version and up.<\/p><\/div>

Desktop<\/h4>
Chrome<\/span><\/th>Firefox<\/span><\/th>IE<\/span><\/th>Edge<\/span><\/th>Safari<\/span><\/th><\/tr><\/thead>
No<\/span><\/td>No<\/span><\/td>No<\/span><\/td>No<\/span><\/td>No<\/span><\/td><\/tr><\/table><\/div>

Mobile \/ Tablet<\/h4>
Android Chrome<\/span><\/th>Android Firefox<\/span><\/th>Android<\/span><\/th>iOS Safari<\/span><\/th><\/tr><\/thead>
No<\/span><\/td>No<\/span><\/td>No<\/span><\/td>No<\/span><\/td><\/tr><\/table><\/div><\/div>\n

So, back to the drawing board.<\/p>\n

How about custom properties?<\/h3>\n

The next idea I had was using CSS custom properties. It\u2019s not pretty, but it worked 🙂 <\/p>\n

\n See the Pen
\n CSS variables animation order<\/a> by Dan Benmore (
@dbenmore<\/a>)
\n on
CodePen<\/a>.<\/span>\n<\/p>\n

Turns out it\u2019s pretty flexible too. For example, the animation can be reversed:<\/p>\n

\n See the Pen
\n CSS variables reverse animation order<\/a> by Dan Benmore (
@dbenmore<\/a>)
\n on
CodePen<\/a>.<\/span>\n<\/p>\n

It can also do something completely random and<\/em> animate elements at the same time:<\/p>\n

\n See the Pen
\n CSS variables random animation order<\/a> by Dan Benmore (
@dbenmore<\/a>)
\n on
CodePen<\/a>.<\/span>\n<\/p>\n

We can even push it a bit further and do a diagonal swoosh:<\/p>\n

\n See the Pen
\n Set animation stagger with CSS properties \/ variables<\/a> by Dan Benmore (
@dbenmore<\/a>)
\n on
CodePen<\/a>.<\/span>\n<\/p>\n

The browser support isn\u2019t all that bad (pokes stick at Internet Explorer<\/em>).<\/p>\n

This browser support data is from Caniuse<\/a>, which has more detail. A number indicates that browser supports the feature at that version and up.<\/p><\/div>

Desktop<\/h4>
Chrome<\/span><\/th>Firefox<\/span><\/th>IE<\/span><\/th>Edge<\/span><\/th>Safari<\/span><\/th><\/tr><\/thead>
49<\/span><\/td>31<\/span><\/td>No<\/span><\/td>16<\/span><\/td>10<\/span><\/td><\/tr><\/table><\/div>

Mobile \/ Tablet<\/h4>
Android Chrome<\/span><\/th>Android Firefox<\/span><\/th>Android<\/span><\/th>iOS Safari<\/span><\/th><\/tr><\/thead>
123<\/span><\/td>124<\/span><\/td>123<\/span><\/td>10.0-10.2<\/span><\/td><\/tr><\/table><\/div><\/div>\n

One of the great features of CSS is that it will ignore things it doesn\u2019t understand<\/a>, thanks to the cascade<\/a>. That means everything will animate in into view together. If that\u2019s not your bag, you can add a feature query to override a default animation:<\/p>\n

.my-list li {\r\n  animation: fallback-animation;\r\n}\r\n\r\n@supports (--variables) {\r\n  .my-list li {\r\n    animation: fancy-animation;\r\n    animation-delay: calc(var(--animation-order) * 100ms);\r\n  }\r\n}<\/code><\/pre>\n

Vanilla CSS FTW<\/abbr><\/h3>\n

The more I stop and ask myself whether I need JavaScript, the more I\u2019m amazed what CSS can do on its own. Sure, it would be nice if CSS counters could be used in a calc()<\/code> function and it would be a pretty elegant solution. But for now, inline custom properties provide both a powerful and flexible way to solve this problem.<\/p>\n","protected":false},"excerpt":{"rendered":"

Animating elements, at its most basic, is fairly straightforward. Define the keyframes. Name the animation. Call it on an element. But sometimes we need something a little more complex to get the right \u201cfeel” for the way things move. For example, a sound equalizer might use the same animation on each bar, but they are […]<\/p>\n","protected":false},"author":261843,"featured_media":291737,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_bbp_topic_count":0,"_bbp_reply_count":0,"_bbp_total_topic_count":0,"_bbp_total_reply_count":0,"_bbp_voice_count":0,"_bbp_anonymous_reply_count":0,"_bbp_topic_count_hidden":0,"_bbp_reply_count_hidden":0,"_bbp_forum_subforum_count":0,"sig_custom_text":"","sig_image_type":"featured-image","sig_custom_image":0,"sig_is_disabled":false,"inline_featured_image":false,"c2c_always_allow_admin_comments":false,"footnotes":"","jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":[]},"categories":[4],"tags":[708,1036],"jetpack_publicize_connections":[],"acf":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2019\/06\/staggered-items.png?fit=1200%2C600&ssl=1","jetpack-related-posts":[{"id":255880,"url":"https:\/\/css-tricks.com\/repeatable-staggered-animation-three-ways-sass-gsap-web-animations-api\/","url_meta":{"origin":291730,"position":0},"title":"Repeatable, Staggered Animation Three Ways: Sass, GSAP and Web Animations API","date":"July 4, 2017","format":false,"excerpt":"Staggered animation, also known as \"follow through\" or \"overlapping action\" is one of the twelve Disney principles of animation as defined by Ollie Johnston and Frank Thomas in their 1981 book \"The Illusion of Life\". At its core, the concept deals with animating objects in delayed succession to produce fluid\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":357239,"url":"https:\/\/css-tricks.com\/a-handy-little-system-for-animated-entrances-in-css\/","url_meta":{"origin":291730,"position":1},"title":"A Handy Little System for Animated Entrances in CSS","date":"November 26, 2021","format":false,"excerpt":"I love little touches that make a website feel like more than just a static document. What if web content wouldn\u2019t just \u201cappear\u201d when a page loaded, but instead popped, slid, faded, or spun into place? It might be a stretch to say that movements like this are always useful,\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2021\/11\/pop-in.gif?fit=900%2C450&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":244442,"url":"https:\/\/css-tricks.com\/staggering-animations\/","url_meta":{"origin":291730,"position":2},"title":"Staggering Animations","date":"August 16, 2016","format":false,"excerpt":"The following is a guest post by David DeSandro. David wanted to offer a new feature in Isotope: staggered animations. Like so many things web, there are lots of ways he could have approached it. Here he looks at some of the possibilities, the advantages and disadvantages of each, and\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":366509,"url":"https:\/\/css-tricks.com\/choosing-an-animation-library-for-solitaire\/","url_meta":{"origin":291730,"position":3},"title":"How I Chose an Animation Library for My Solitaire Game","date":"June 29, 2022","format":false,"excerpt":"There is an abundance of both CSS and JavaScript libraries for animation libraries out there. So many, in fact, that choosing the right one for your project can seem impossible. That's the situation I faced when I decided to build an online Solitaire game. I knew I'd need an animation\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2022\/06\/solitaire-anime-gsap.png?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":177678,"url":"https:\/\/css-tricks.com\/clever-uses-step-easing\/","url_meta":{"origin":291730,"position":4},"title":"Clever Uses for Step Easing","date":"August 5, 2014","format":false,"excerpt":"The following is a guest post by Julian Shapiro. Julian has been working on Velocity.js recently, which he has written about here on CSS-Tricks before. Julian lives in a world of animation, so it's no surprise he's collected together some interesting examples of exotic animation techniques. Here he shares all\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":20803,"url":"https:\/\/css-tricks.com\/slide-in-as-you-scroll-down-boxes\/","url_meta":{"origin":291730,"position":5},"title":"Slide In (as you scroll down) Boxes","date":"March 27, 2013","format":false,"excerpt":"I was playing with my new Nexus 7 (I really wanted to own a real Android device) and I noticed a neat little effect in the Google+ app that comes with it. As you swipe down, new modules of content slide up into place. Video is best here: We can\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"featured_media_src_url":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2019\/06\/staggered-items.png?fit=1024%2C512&ssl=1","_links":{"self":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/291730"}],"collection":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/users\/261843"}],"replies":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/comments?post=291730"}],"version-history":[{"count":5,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/291730\/revisions"}],"predecessor-version":[{"id":291884,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/291730\/revisions\/291884"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/media\/291737"}],"wp:attachment":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/media?parent=291730"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/categories?post=291730"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/tags?post=291730"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}