“Time cannot be bought. But time can be saved.”
This quote may be too deep for a web development post, but it exemplifies well what performance means to User Experience (UX). The most important performance metrics revolve around the first fractions of second between the request of your application and the user interacting with it.
People have built profitable businesses shaving off those little milliseconds. Others have spent considerable amount of time studying the correlation between that loading interval and direct conversions.
It’s not a rumor the position your website shows in Google’s (and other search engines as well) Search Results Page (SERP) is influenced by performance.
Performance not only determines a big portion of how pleasant the UX will be, but also if you’ll even get to pitch your product to that specific user. It also intertwines with accessibility, allowing limited connections to have a seamless experience is as much a business as it is an ethical concern.
Besides optimizing our own code for performance, there are a couple of low hanging fruits which allow browsers to help us on the endeavor of providing fast and smooth navigation.
Prefetching the DNS means advising your browser a connection to that server will be sought. Therefore, the browser can antecipate the DNS lookup. This decreases the latency between server connections, which are often cause of poor perceived performance in websites.
<link rel="dns-prefetch" href="https://fonts.gstatic.com/" />
⚠️ Needless to say it should only be used for third-party requests. Your own domain will have already been resolved by the time this hint is read.
rel="preconnect" to your
<link> will advise the browser you intend to make request towards the domain in its
href and you would like the browser to establish a connection with that server as soon as possible. While
prefetch only accelerates the DNS lookup,
preconnect has a more significant impact:
- DNS lookup (just like
- TCP connection establishment
- TLS handshake (for
It’s worth noting that establishing multiple preconnections may and will cause a bottleneck, degrading performance instead of improving it. Therefore preconnect is only recommended to use on the most important resource. Prefetch, on the other hand, can be used more freely and combining the two can only help.
<link rel="dns-prefetch" href="https://fonts.gstatic.com/" /> <link rel="preconnect" href="https://fonts.gstatic.com/" />
Starting connections early on can only go so far. Some resources depend on others to be useful, like a font depends on a stylesheet. In the above example (
fonts.gstatic domain), connection starts as early as possible. But it still can present a considerable risk and bottleneck to performance.
Most fonts are imported through passing a source in
@fontface rule, inside your CSS stylesheet. See the problem? If your CSS is an external resource, it needs to be requested, loaded, and parsed in order to even start fetching your font.
And the issue goes on!
To save users from poorly implemented interfaces where resources are fetched recklessly, the browser does not fetch the font as soon as it finds the
@fontface rule (which is usually on top). No, the browser waits until at least one element in the DOM requires that font. And then, it blocks the entire rendering. Fetches the font, loads the font, parses the font, applies the styles. Now the browser can continue to build the rest of the DOM.
Luckily, there is a way of telling the browser beforehand such a disruptive resource will be required.
This hint declares a fetch request within the HTML. In the Web font example above, the font resource could be linked to directly to the HTML. Eliminating the request chain.
⚠️ Limit the resources to be preloaded to a bare minimum to avoid performance bottlenecks.
<link rel="preload" href="fonts/webfont.woff2" as="font" type="font/woff2" crossorigin />
Preload requires a little bit more configuration than
dns-prefetch. For a resource to be properly loaded, it needs to have a
MIME/TYPE, and the
link tag accepts another attribute for indicating a request will be cross-origin.
Two important things to remember:
- Font requests are always cross-origin, regardless where they’re hosted
- For a cross-origin request to work, you also need to have CORS already configured
It is also possible to pass a
media attribute for responsive preloading.
<link rel="preload" href="small.png" as="image" media="(max-width: 600px)" /> <link rel="preload" href="big.png" as="image" media="(min-width: 601px)" />
You can pass these and other
<link> attributes as value of a HTTP Response Header as well. The
Link field exists precisely for this and can be passed multiple values separated by a semi-colon.
Link: <https://one.example.com>; rel="dns-prefetch", <https://two.example.com>; rel="dns-prefetch", <https://three.example.com>; rel="preconnect"
Which other low hanging fruits are there in web performance that you would also recommend?