Tagged “performance”
My new syntax for modern, responsive blog images
I’ve started trialling different HTML and technologies for the “simple” responsive images (i.e. not art-directed per breakpoint) used in blog articles on this site. I’m continuing to lean on Cloudinary as my free image host, CDN and format-conversion service. But at the HTML level I’ve moved from a complicated <img srcset>
based approach which included many resized versions of the same image. I now use a simpler <picture>
and <source>
based pattern that keeps the number of images and breakpoints low, leaning instead into the performance gains offered by the newer image formats avif
and webp
.
Avoiding img layout shifts: aspect-ratio vs width & height attributes (on Jake Archibald's blog)
Recently I’ve noticed some developers recommending using the CSS aspect-ratio
property directly on images. My understanding of aspect-ratio
was that it’s not so much intended for elements like img
which already have an intrinsic aspect ratio, but rather for the likes of div
which do not. Furthermore, when the goal is to prevent the layout shift that can occur after an image loads we should supply our images with width
and height
HTML attributes rather than using CSS.
In this timely post, Jake helpfully explains how width
and height
attributes are used by CSS as presentation hints to automatically set an aspect-ratio
that will also, in cases where the attributes were set wrongly, fall back to the image’s intrinsic aspect ratio. Therefore, concentrating on HTML alone is ideal for our content images. My previous approach seems sound but I now know a little more about why.
Learn Responsive Design (on web.dev)
Jeremy Keith’s new course for Google’s web.dev learning platform is fantastic and covers a variety of aspects of responsive design including layout (macro and micro), images, icons and typography.
Harry Roberts says “Get Your Head Straight”
Harry Roberts (who created ITCSS for organising CSS at scale but these days focuses on performance) has just given a presentation about the importance of getting the content, order and optimisation of the <head>
element right, including lots of measurement data to back up his claims. Check out the slides: Get your Head Straight
Practical front-end performance tips
I’ve been really interested in the subject of Web Performance since I read Steve Souders’ book High Performance Websites back in 2007. Although some of the principles in that book are still relevant, it’s also fair to say that a lot has changed since then so I decided to pull together some current tips. Disclaimer: This is a living document which I’ll expand over time. Also: I’m a performance enthusiast but not an expert. If I have anything wrong, please let me know.
Astro
Astro looks very interesting. It’s in part a static site builder (a bit like Eleventy) but it also comes with a modern (revolutionary?) developer experience which lets you author components as web components or in a JS framework of your choice but then renders those to static HTML for optimal performance. Oh, and as far as I can tell theres no build pipeline!
Astro lets you use any framework you want (or none at all). And if most sites only have islands of interactivity, shouldn’t our tools optimize for that?
Ruthlessly eliminating layout shift on netlify.com, by Zach Leatherman
I love hearing about clever front-end solutions which combine technologies and achieve multiple goals. In Zach’s post we hear how Netlify’s website suffered from layout shift when conditionally rendering dismissible promo banners, and how he addressed this by rethinking the problem and shifting responsibilities around the stack.
Here’s my summary of the smart ideas covered in the post:
- decide on the appropriate server-rendered content… in this case showing rather than hiding the banner, making the most common use case faster to load
- have the banner “dismiss” button’s event handling script store the banner’s
href
in the user’s localStorage as an identifier accessible on return visits - process lightweight but critical JavaScript logic early in the
<head>
… in this case a check for this banner’s identifier existing in localStorage - under certain conditions – in this case when the banner was previously seen and dismissed – set a “state” class (
banner--hide
) on the<html>
element, leading to the component being hidden seamlessly by CSS - build the banner as a web component, the first layer of which being a custom element
<announcement-banner>
and the second a JavaScript class to enhance it - delegate responsibility for presenting the banner’s “dismiss” button to the same script responsible for the component’s enhancements, meaning that a broken button won’t be presented if that script were to break.
So much to like in there!
Here are some further thoughts the article provoked.
Web components FTW
It feels like creating a component such as this one as a web component leads to a real convergence of benefits:
- tool-free, async loading of the component JS as an ES module
- fast, native element discovery (no need for a
document.querySelector
) - enforces using a nice, idiomatic class providing encapsulation and high-performing native callbacks
- resilience and progressive enhancement by putting all your JS-dependent stuff into the JS class and having that enhance your basic custom element. If that JS breaks, you still have the basic element and won’t present any broken elements.
Even better, you end up with framework-independent, standards-based component that you could share with others for reuse elsewhere, just like Zach did.
Multiple banners
I could see there being a case where there are multiple banners during the same time period. I guess in that situation the localStorage banner
value could be a stringified object rather than a simple, single-URL string.
Setting context on the root
It’s really handy to have a way to exert just-in-time control over the display of a server-rendered element in a way that avoids flashes of content… and adding a class to the <html>
element offers that. In this approach, we run the small amount of JavaScript required to test a local condition (e.g. checking for a value in localStorage) really early. That lets us process our conditional logic before the element is rendered… although this also means that it’s not yet available in the DOM for direct manipulation. But adding a class to the HTML element means that we can pre-prepare CSS to use that class as a contextual selector for hiding the element.
We’re already familiar with the technique of placing classes on the root element from libraries like modernizr and some font-loading approaches, but this article serves as a reminder that we can employ it whenever we need it.
Handling the close button
Zach’s approach to handling the banner’s dismiss button was interesting. He makes sure that it’s not shown unless the web component’s JavaScript runs successfully which is great, but rather than inject it with JavaScript he includes it in the initial HTML but hidden with CSS, and his method of hiding is opacity
.
We use opacity to toggle the close button so that it doesn’t reflow the component when it’s enabled via JavaScript.
I think what Zach’s saying is that the alternatives – inserting the button with JS, or toggling the hidden
attribute or its CSS counterpart display:none
– would affect geometry causing the browser to perform layout… whereas modifying opacity does not.
I love that level of diligence! Typically I prefer to delegate responsibility for inserting JS-dependent buttons to JavaScript because in comparison to including a button in the server-rendered HTML then hiding it, it feels more resilient and a more maintainable separation of concerns. However as always the best solution depends on the situation.
If I were going down Zach’s route I think I’d replace opacity
with visibility
since the latter hiding method removes the hidden element from the document which feels more accessible, while still avoiding triggering the reflow that display
would.
Side-thoughts
In a server-side scripted application – one using Rails or PHP, for example – you could alternatively handle persisting state with cookies rather than localStorage… allowing you to test for the presence of the cookie on the server then handle conditional rendering of the banner on the server too, rather than needing classes which trigger hiding. I can see an argument for that. Thing is though, not everyone’s working in that environment. Zach has provided a standalone solution.
References
- Zach’s Herald of the dog web component
- CSS Triggers of reflow and repaint
- Minimising layout thrashing
Big picture performance analysis using Lighthouse Parade (on Cloud Four)
I like the sound of this performance analysis tool from the clever folks at Cloud Four, especially because it covers your entire site rather than just a single page.
Lighthouse Parade is a Node.js command line tool that crawls a domain and gathers lighthouse performance data for every page. With a single command, the tool will crawl an entire site, run a Lighthouse report for each page, and then output a spreadsheet with the aggregated data.
Creating websites with prefers-reduced-data (on polypane.app)
Even though more and more people get access to the internet every day, not all of them have fast gigabit connections or unlimited data. Using the media query prefers-reduced-data we can keep our sites accessible to everyone.
Daniel Post shared a really cool performance-optimisation trick for Eleventy on Twitter the other day. When statically generating your site you can loop through your pages and, for each, use PurgeCSS to find the required CSS, then inline that into the <head>
. This way, each page contains only the CSS it needs and no more!
I’ve just installed this on my personal site. I was already inlining my CSS into the <head>
but the promise of only including the minimum CSS that each specific page needs was too good to resist.
Turned out it was a breeze to get working, a nice introduction to Eleventy transforms, and so far it’s working great!
Thoughts on inline JavaScript event handlers in the <head>
I’ve been thinking about Scott Jehl’s “simplest way to load external CSS asynchronously” technique. I’m interested in its use of an inline (onload
) event handler for running JavaScript-based enhancements in the <head>
, in the context of some broader ruminations on how best to progressively enhance UI elements with JavaScript (for example adding toggle show/hide) without causing layout jank.
The Simplest Way to Load CSS Asynchronously (Filament Group)
Scott Jehl of Filament Group demonstrates a one-liner technique for loading external CSS files without them delaying page rendering.
How to optimise performance when using Google-hosted fonts (on CSS Wizardry)
A combination of asynchronously loading CSS, asynchronously loading font files, opting into FOFT, fast-fetching asynchronous CSS files, and warming up external domains makes for an experience several seconds faster than the baseline.
We’ve ruined the Web. Here’s how we fix it. (This is HCD podcast)
During the COVID situation, people have an urgent need to access critical information online. But in 2020, the average webpage is rammed full of large JavaScript files, huge images etc, and as a result is slow to load. This problem is likely to be most keenly felt by those who don’t have the luxury of fast internet – potentially the same people who need access to that critical information the most.
Here’s a brilliant discussion between Gerry McGovern and Jeremy Keith on that problem, suggesting tactics to help fix things such as performance budgets, introducing tactics at the design stage to mimic slow connections and other access constraints, optimising for return visits, progressive enhancement and more.
Emergency Website Kit (Max Böck)
In cases of emergency, many organizations need a quick way to publish critical information. But existing (CMS) websites are often unable to handle sudden spikes in traffic.
CSS Triggers
Check whether or not a CSS property is a good candidate for smooth animation based on whether updates to its value trigger expensive changes (to, for example, “element geometry”) causing layout updates and repaints.
When should you add the defer attribute to the script element? (on Go Make Things)
For many years I’ve placed script elements just before the closing body
tag rather than in the <head>
. Since a standard <script>
element is render-blocking, the theory is that by putting it at the end of the document – after the main content of the page has loaded – it’s no longer blocking anything, and there’s no need to wrap it in a DOMContentLoaded
event listener.
It turns out that my time-honoured default is OK, but there is a better approach.
Lazy load embedded YouTube videos (CSS-Tricks)
This is a very clever idea via Arthur Corenzan. Rather than use the default YouTube embed, which adds a crapload of resources to a page whether the user plays the video or not, use the little tiny placeholder webpage that is just an image you can click that is linked to the YouTube embed.
Webfont loading strategies
When it comes to webfonts, if you want to serve an accessible and high performance experience across device types it’s not as straightforward as just specifying your fonts in CSS then hoping for the best.
Native lazy-loading for the web
Now that we have the HTML attribute loading
we can set loading="lazy"
on our website’s media, and the loading of non-critical, below-the-fold media will be deferred until the user scrolls to them.
Stuffing the front end
Here’s Bridget Stewart, a developer from Ohio, with some thoroughly enjoyable “curmudgeonly” thoughts on why your website doesn’t necessarily need a Javascript framework.
See all tags.