{"id":5380,"date":"2018-11-13T09:47:07","date_gmt":"2018-11-13T09:47:07","guid":{"rendered":"https:\/\/www.bronco.co.uk\/our-ideas\/?p=5380"},"modified":"2018-11-13T09:47:51","modified_gmt":"2018-11-13T09:47:51","slug":"page-loading-effects-with-progressive-enhancement","status":"publish","type":"post","link":"https:\/\/www.bronco.co.uk\/our-ideas\/page-loading-effects-with-progressive-enhancement\/","title":{"rendered":"Page loading effects with progressive enhancement"},"content":{"rendered":"<p>With growing support for CSS transitions and keyframe animations it\u2019s become more common to see websites adopt a variety of effects, such as fades or motion, on page load to create a more visually dynamic website.<\/p>\n<p>It\u2019s hard to argue that done right these effects don\u2019t delight new users, at least while such effects aren\u2019t ubiquitous throughout the web. But many examples rely on JavaScript to make these elements appear with default CSS setting the opacity of some or all elements to zero. The result being a blank page if the JavaScript doesn\u2019t load properly.<\/p>\n<p><small><strong>Further Reading<\/strong>: <a href=\"https:\/\/www.smashingmagazine.com\/2018\/05\/using-the-web-with-javascript-turned-off\/\">I Used The Web For A Day With JavaScript Turned Off<\/a><\/small><\/p>\n<h2>Is progressive enhancement worth it?<\/h2>\n<p>If you look at the direction of the web currently you\u2019d think that as an industry the decision has been made that the web can no longer evolve whilst still accommodating <code>&lt;noscript&gt;<\/code> users. Not only is the problem at the centre of this post indicative of this but the popularity of JavaScript frameworks like React and Vue.js suggest an increasing reliance on JavaScript.<\/p>\n<p><strong style=\"font-size: 1.5em;\">The <a href=\"https:\/\/blockmetry.com\/blog\/javascript-disabled\">0.2% of UK &lt;noscript&gt; web users<\/a> is too small a percentage to invest the time and money to provide even the most basic experience to.<\/strong><\/p>\n<p>Though this statement may make business sense it doesn\u2019t account for those instances where people have JavaScript enabled but where it fails to load for some reason. Not to mention, as we\u2019ll discover, the number of users with browsers that do not support CSS transitions or keyframe animations that are frequently required by these techniques.<\/p>\n<div class=\"aligncenter\" style=\"max-width: 500px;\">\n<blockquote class=\"twitter-tweet\" data-lang=\"en-gb\">\n<p dir=\"ltr\" lang=\"en\">I know everyone loves a website that fades in on load but if it means a blank page when JS is disabled is it really worth it?<\/p>\n<p>\u2014 Kean Richmond (@keanrichmond) <a href=\"https:\/\/twitter.com\/keanrichmond\/status\/1060488092770025472?ref_src=twsrc%5Etfw\">8 November 2018<\/a><\/p><\/blockquote>\n<p><script async src=\"https:\/\/platform.twitter.com\/widgets.js\" charset=\"utf-8\"><\/script><\/p>\n<\/div>\n<p>For web applications using React et al the conversations required are far more complex, however for websites that are built more simply it\u2019s a genuine question as to whether the benefits of these visual flourishes outweigh the disadvantages, especially when the greatest of these is a completely blank website.<\/p>\n<p><small><strong>Disclaimer<\/strong>: Without understanding the requirements, limitations and a whole host of other factors I can&#8217;t say that a website\/agencies decision to not provide a fallback for <code>&lt;noscript&gt;<\/code> users is justified or not. Only that this decision, or lack of same, will negatively affect some users critically.<\/small><\/p>\n<h2>Can it be done?<\/h2>\n<p>The crux of the problem is that to avoid a flash of content, which disappears and then reappears when the JavaScript loads, developers will implement <code>opacity:0<\/code> throughout their CSS. This removes this flash of content but also means if you deactivate JavaScript these elements will never become visible.<\/p>\n<p>This problem has been swirling around my head for a while, but I never seemed to nail down a possible solution&#8230; until now.<\/p>\n<h3>Step 1 \u2013 opacity:1 on load<\/h3>\n<p>For some years I\u2019ve adopted a non-js\/js class switcher in order to style elements based on whether JavaScript has loaded or not. This seems like a good starting point for our solution. Traditionally I\u2019ve implemented this as part of an external file, so let\u2019s start here.<\/p>\n<p class=\"codepen\" data-height=\"400\" data-theme-id=\"0\" data-slug-hash=\"jQrVdz\" data-default-tab=\"js,result\" data-user=\"keanr\" data-pen-title=\"Animation - Step 1\">See the Pen <a href=\"https:\/\/codepen.io\/keanr\/pen\/jQrVdz\/\">Animation &#8211; Step 1<\/a> by Kean Richmond (<a href=\"https:\/\/codepen.io\/keanr\">@keanr<\/a>) on <a href=\"https:\/\/codepen.io\">CodePen<\/a>.<\/p>\n<p><script async src=\"https:\/\/static.codepen.io\/assets\/embed\/ei.js\"><\/script><\/p>\n<p><small><strong>Disclaimer<\/strong>: With codepen you\u2019ll have to assume the HTML is requesing an external JavaScript file<\/small><\/p>\n<p>We&#8217;re then using <code>opacity:0<\/code> in conjunction with our .js class so only users with JavaScript enabled would see the content fade and move into position.<\/p>\n<p>So far so good. But throw in a defer attribute and we\u2018re back to getting the flash of text we need to avoid.<\/p>\n<p><small><strong>Note<\/strong>: Using a throttled connection, and adding a number of images into your test page, is the best way to test if you\u2019re getting this flash.<\/small><\/p>\n<h3>Step 2 \u2013 inline JavaScript<\/h3>\n<p>So our class switcher needs moving, in this instance to the top of our <code>&lt;head&gt;<\/code> to ensure it runs first and without delay. An external render-blocking file could be used but at a few lines of code, inline seems like the way to go.<\/p>\n<p class=\"codepen\" data-height=\"400\" data-theme-id=\"0\" data-slug-hash=\"VVjPLj\" data-default-tab=\"html,result\" data-user=\"keanr\" data-pen-title=\"Animation - Step 2\">See the Pen <a href=\"https:\/\/codepen.io\/keanr\/pen\/VVjPLj\/\">Animation &#8211; Step 2<\/a> by Kean Richmond (<a href=\"https:\/\/codepen.io\/keanr\">@keanr<\/a>) on <a href=\"https:\/\/codepen.io\">CodePen<\/a>.<\/p>\n<p>This works great. <code>&lt;noscript&gt;<\/code> users get the website acting as if there were no animation and our JavaScript users get the animation on load.<\/p>\n<p><small><strong>Note<\/strong>: There\u2019s two points in the loading sequence we can enact our animation. This is either when all assets of the website are loaded, or when the DOM Tree has been loaded (and before external assets, including images, have). Which of these you chose will depend on if having external assets not loaded at the point you start your animation is going to cause problems.<\/small><\/p>\n<h3>Step 3 \u2013 more inline JavaScript<\/h3>\n<p>I believe we have a solution for <code>&lt;noscript&gt;<\/code> users, but what about those users where the JavaScript file fails to load or contains an error that stops our code from running. Again, we need to look at taking the external file out of the equation.<\/p>\n<p>Initially placing this at the bottom of the website makes sense as a way to collate similar code in one place. But as we\u2019re trying to find a solution that is fault tolerant there\u2019s always a risk that the code could break at any point between our rendered element and the bottom of the file. While these are the kinds of errors usually caught and fixed in development, let\u2019s run with this.<\/p>\n<p class=\"codepen\" data-height=\"400\" data-theme-id=\"0\" data-slug-hash=\"rQLjOg\" data-default-tab=\"html,result\" data-user=\"keanr\" data-pen-title=\"Animation - Step 3\">See the Pen <a href=\"https:\/\/codepen.io\/keanr\/pen\/rQLjOg\/\">Animation &#8211; Step 3<\/a> by Kean Richmond (<a href=\"https:\/\/codepen.io\/keanr\">@keanr<\/a>) on <a href=\"https:\/\/codepen.io\">CodePen<\/a>.<\/p>\n<p>Rather than have our function that adds a .loading class into our content in an external file, we have created a short function in the <code>&lt;head&gt;<\/code> of our file which we call directly after our element has rendered almost guaranteeing this to run.We now have a solution that covers <code>&lt;noscript&gt;<\/code> users, external JS file failures and server side errors that may cut our page in half.<\/p>\n<h3>Step 4 \u2013 old browsers<\/h3>\n<p>Remember that I mentioned some browsers will not support CSS transitions or Keyframe animations? In our examples we\u2019re using keyframe animations to make our elements appear, and when a browser does not support these we\u2019re left once again with a blank page.<\/p>\n<p>The main browsers that <a href=\"https:\/\/caniuse.com\/#search=animation\">don\u2019t support these<\/a> are Internet Explorer 9 and below and Opera Mini, the latter of which has a 2.1% global share. But they do support JavaScript.<\/p>\n<p class=\"codepen\" data-height=\"400\" data-theme-id=\"0\" data-slug-hash=\"rQLjLE\" data-default-tab=\"html,result\" data-user=\"keanr\" data-pen-title=\"Animation - Step 4\">See the Pen <a href=\"https:\/\/codepen.io\/keanr\/pen\/rQLjLE\/\">Animation &#8211; Step 4<\/a> by Kean Richmond (<a href=\"https:\/\/codepen.io\/keanr\">@keanr<\/a>) on <a href=\"https:\/\/codepen.io\">CodePen<\/a>.<\/p>\n<p>Our solution, up till now, is to add a .loaded class to our element which triggers the animation in our CSS that makes the element visible. To cover for these old browsers which lack CSS support but support JavaScript is to use the .loaded class to make the element appear and then within our keyframe animation to have it instantly disappear, and appear through the course of the animation.<\/p>\n<p>Yes, we\u2019re really playing some hard core hide and seek with this element over its lifetime.<\/p>\n<p>The impact of working this way is that we can no longer use <code>animation-delay<\/code> as this will create a noticeable flash of the content appearing. But with keyframe animations we can repeat the initial hidden state, in this example that\u2019s at 10%, which works out at 0.15 seconds.<\/p>\n<h2>Did I do it?<\/h2>\n<p>The code you\u2019ll have seen above is a very simple example, written and tested in no more than a couple of hours and won\u2019t necessarily work in all use cases. It certainly doesn\u2019t take into account user scrolling, though the Interaction Observer API may offer a suitable solution that integrates with the above code rather easily.<\/p>\n<p>What I\u2019m getting at is this is just an experiment, not yet used in a rich and fully functioning website and certainly not some ground breaking solution. So far it certainly seems like a workable and better solution than ignoring progressive enhancement altogether. But it&#8217;s simplicity has me thinking there&#8217;s either a gremlin I&#8217;ve yet to spot, or I&#8217;m observing a problem that isn&#8217;t as widespread as it appears to me.<\/p>\n<p>Those who dig deeper into how browsers load and render pages may take issue and find fault with this game of hide and seek being played or know of instances where the content may still flash into view when we\u2019d worked to avoid this. But for now it seems like a pretty solid solution, relatively simple to implement at small scales.<\/p>\n<p>If you do have anything to add to the conversation, such as a better or more tested solution, leave a comment below.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>With growing support for CSS transitions and keyframe animations it\u2019s become more common to see websites adopt a variety of effects, such as fades or motion, on page load to create a more visually dynamic website. It\u2019s hard to argue that done right these effects don\u2019t delight new users, at least while such effects aren\u2019t [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":5381,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[2],"class_list":["post-5380","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-web-and-ux"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.bronco.co.uk\/our-ideas\/wp-json\/wp\/v2\/posts\/5380","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.bronco.co.uk\/our-ideas\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.bronco.co.uk\/our-ideas\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.bronco.co.uk\/our-ideas\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.bronco.co.uk\/our-ideas\/wp-json\/wp\/v2\/comments?post=5380"}],"version-history":[{"count":0,"href":"https:\/\/www.bronco.co.uk\/our-ideas\/wp-json\/wp\/v2\/posts\/5380\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.bronco.co.uk\/our-ideas\/wp-json\/wp\/v2\/media\/5381"}],"wp:attachment":[{"href":"https:\/\/www.bronco.co.uk\/our-ideas\/wp-json\/wp\/v2\/media?parent=5380"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.bronco.co.uk\/our-ideas\/wp-json\/wp\/v2\/categories?post=5380"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}