{"id":253223,"date":"2017-03-30T04:52:29","date_gmt":"2017-03-30T11:52:29","guid":{"rendered":"http:\/\/css-tricks.com\/?p=253223"},"modified":"2017-04-06T16:02:28","modified_gmt":"2017-04-06T23:02:28","slug":"making-animations-wait","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/making-animations-wait\/","title":{"rendered":"Making Animations Wait"},"content":{"rendered":"

I recently launched a CSS animation course<\/a> for designers and developers wanting to improve their web animation skills. While building the course, I ran into the issue where content would animate before assets had downloaded. This article covers the approach I put together to fix the problem and ensure all animations played when expected.<\/p>\n

<\/p>\n

We’ve all been there. For example, we want to fade in a hero header on load, so we add the fade-in keyframes, setting up the animation, but then the animations starts before the background image is downloaded. We get a half-loaded image fading in, and even worse, our logo or headline appear before the background is ready.<\/p>\n

load<\/code> events and animation-play-state<\/code><\/h3>\n

Browsers give us a handy JavaScript load<\/code> event when content has finished loading. That event will fire for elements such as images and scripts. We can use this to control when our animations play.<\/p>\n

We’re going to make use of some JavaScript to listen for a load event, and make use animation-play-state<\/code> to pause our animations until the event.<\/p>\n

The following JavaScript should do the trick.<\/p>\n

document.body.classList.add('js-loading');\r\n\r\nwindow.addEventListener(\"load\", showPage);\r\n\r\nfunction showPage() {\r\n  document.body.classList.remove('js-loading');\r\n}<\/code><\/pre>\n

Here’s what the code does. The first line adds a js-loading<\/code> class to the body<\/code> element. Then it sets up an event listener.<\/p>\n

The event listener waits until the load<\/code> event occurs, and then run the function removeLoadingClass<\/code>. At this point, all the images and other assets have downloaded.<\/p>\n

Lastly the removeLoadingClass<\/code> removes the class from the body<\/code> tag.<\/p>\n

This code should be added to the HTML of your page, such as the head<\/code>. If loaded in from an external file, the CSS could load and be parsed before this code executes, which would give the animations a chance to start before we’re ready.<\/p>\n

Let’s use this class to make any on-page animations wait until the content is ready.<\/p>\n

Waiting for one image<\/h3>\n

This approach waits for all assets on a page to load. You might want to only wait for one image, in your header for example. Thankfully there are load events for each image. The approach set out in Measuring Image Widths in JavaScript<\/a> can help.<\/p>\n

We can adjust the JavaScript to focus on one specific image.<\/p>\n

\/\/ Adjust the \"querySelector\" value to target your image\r\nvar img = document.querySelector(\"img\");\r\ndocument.body.classList.add('js-loading');\r\nimg.addEventListener(\"load\", removeLoadingClass);\r\nfunction removeLoadingClass() {\r\n  document.body.classList.remove('js-loading');\r\n}<\/code><\/pre>\n

The animation-play-state<\/code> Property<\/h3>\n

The animation-play-state<\/a> property is well supported by modern browsers. It tells the browser whether the current animation is running or paused. By default animations are “running”.<\/p>\n

We can use this property to make any animations on the page “pause” while we’re loading the content. We add this to our CSS.<\/p>\n

.js-loading *,\r\n.js-loading *:before,\r\n.js-loading *:after {\r\n  animation-play-state: paused !important;\r\n}<\/code><\/pre>\n

This code sets the play state of everything on the page to “paused”, whenever the body<\/code> has the class js-loading<\/code>.<\/p>\n

It will make sure it applies to all of the :before<\/code> and :after<\/code> pseudo-elements also.<\/p>\n

When JavaScript removes the js-loading<\/code> class from the body<\/code> tag, the rule no longer applies and all animations will be in their expected running state.<\/p>\n

A nice benefit of this approach is that we don’t have to change anything else in our stylesheet!<\/p>\n

What if JavaScript fails?<\/h3>\n

This is always a question worth asking if we rely on JavaScript to handle displaying content on screen. Sometimes JavaScript fails. It can be disabled. Plugins can do unpredictable things. While in most cases this will work, JavaScript is always a little outside our control so it’s good to think about what would happen if the JavaScript didn’t work as expected.<\/p>\n

In this case, I think we’re good. If the JavaScript doesn’t run, it won’t apply the js-loading<\/code> class. The animations will play straight away. This might result in a little strangeness with the background image loading as it animates, but that’s a worst case scenario and a reasonable fallback.<\/p>\n

See it in action<\/h3>\n

Let’s test this to see it working. We need a large image. I found this rather gorgeous Nasa photo on Unsplash<\/a>. It’s over 2MB in size.<\/p>\n

When the page loads we should see the blank screen initially. To really see it in action we can use Chrome’s built-in throttling feature. Opening the inspector, select the “Network” tab, then open the dropdown containing speed presets. From this, we select “Good 3G”, which should be slow enough to see this in action.<\/p>\n

\"\"
A preset Network speed in Chrome<\/figcaption><\/figure>\n

Press “Rerun” on this demo and no animations should play until the image has fully loaded.<\/p>\n

See the Pen Using load and animation-play-state to wait till image has loaded #2<\/a> by Donovan Hutchinson (@donovanh<\/a>) on CodePen<\/a>.<\/p>\n

Try removing the JavaScript (and clear the cache before reloading) to see the difference! <\/p>\n

Loading Spinner<\/h3>\n

If you want to avoid a blank page at this point, you ought to have some loading text or animation that lets people know. It depends on how long you think the delay might be. If you have an enormously large image and the page tends to wait for more than a second or two, then a spinner might be a good idea.<\/p>\n

On the other hand, it might be worth compressing the image more or scaling it down so that it loads more quickly. Experiment and see what works best for you.<\/p>\n


\n

I hope this technique helps you keep your animations working together.<\/p>\n

If you’d like to know more about animating your web sites, you might enjoy the tutorials over on CSSAnimation.rocks<\/a>. Follow along on Twitter at @cssanimation<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"

I recently launched a CSS animation course for designers and developers wanting to improve their web animation skills. While building the course, I ran into the issue where content would animate before assets had downloaded. This article covers the approach I put together to fix the problem and ensure all animations played when expected.<\/p>\n","protected":false},"author":248196,"featured_media":0,"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":false,"jetpack_social_options":[]},"categories":[4],"tags":[612],"jetpack_publicize_connections":[],"acf":[],"jetpack_featured_media_url":"","jetpack-related-posts":[{"id":179204,"url":"https:\/\/css-tricks.com\/add-page-transitions-css-smoothstate-js\/","url_meta":{"origin":253223,"position":0},"title":"How To Add Page Transitions with CSS and smoothState.js","date":"August 15, 2014","format":false,"excerpt":"CSS animations (and a little JavaScript trickery) can let us add page transitions and move away from the hard-cut of page loads. My jQuery plugin smoothState.js helps polish those transitions and improve UI response times. Page transitions benefit the user experience Imagine, for a second, how disorienting it would be\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":253223,"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":358975,"url":"https:\/\/css-tricks.com\/empathetic-animation\/","url_meta":{"origin":253223,"position":2},"title":"Empathetic Animation","date":"December 29, 2021","format":false,"excerpt":"Animation on the web is often a contentious topic. I think, in part, it\u2019s because bad animation is blindingly obvious, whereas well-executed animation fades seamlessly into the background. When handled well, animation can really elevate a website, whether it\u2019s just adding a bit of personality or providing visual hints and\u2026","rel":"","context":"In "2021 End-of-Year Thoughts"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2021\/12\/Screen-Shot-2021-12-29-at-8.07.40-AM.png?fit=1200%2C761&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":363057,"url":"https:\/\/css-tricks.com\/nuking-motion-with-prefers-reduced-motion\/","url_meta":{"origin":253223,"position":3},"title":"No Motion Isn’t Always prefers-reduced-motion","date":"February 8, 2022","format":false,"excerpt":"There is a code snippet that I see all the time when the media query prefers-reduced-motion is talked about. Here it is: @media (prefers-reduced-motion: reduce) { * { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; } } This is CSS that attempts to obliterate any\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2020\/09\/macos-preference-motion.png?fit=1200%2C905&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":160266,"url":"https:\/\/css-tricks.com\/myth-busting-css-animations-vs-javascript\/","url_meta":{"origin":253223,"position":4},"title":"Myth Busting: CSS Animations vs. JavaScript","date":"January 13, 2014","format":false,"excerpt":"The following is a guest post by Jack Doyle, author of the GreenSock Animation Platform (GSAP). Jack does a lot of work with animations in the browser and has discovered that the generic opinion that \"CSS is faster\" just isn't true. It's more than that, as well. I'll let him\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":304130,"url":"https:\/\/css-tricks.com\/playing-with-particles-using-the-web-animations-api\/","url_meta":{"origin":253223,"position":5},"title":"Playing With Particles Using the Web Animations API","date":"March 18, 2020","format":false,"excerpt":"When it comes to motion and animations, there is probably nothing I love more than particles. This is why every time I explore new technologies I always end up creating demos with as many particles as I can. In this post, we'll make even more particle magic using the Web\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2020\/03\/sparkles.png?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]}],"featured_media_src_url":null,"_links":{"self":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/253223"}],"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\/248196"}],"replies":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/comments?post=253223"}],"version-history":[{"count":9,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/253223\/revisions"}],"predecessor-version":[{"id":253482,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/253223\/revisions\/253482"}],"wp:attachment":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/media?parent=253223"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/categories?post=253223"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/tags?post=253223"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}