My new course, Setting up DevTools for Performance Testing, is live! Twelve videos demonstrating power features, secret experiments, and workflow tips (and lots more). Get it now: https://csswizardry.gumroad.com/l/perfect-devtools/…
. So many takeaways!
If you care about #webperf and #ux (and I hope you do!) then you should care about optimizing your hero images. Tracking and fixing your Largest Contentful Paint (LCP) time is a good place to start.
Being fast is more important than ever. But despite being the easiest metric to monitor, debug, and optimise, LCP is still the one that most websites struggle with. Get ready to ask for a pay rise, after @csswizardry's #perfnow talk: https://youtube.com/watch?v=JhTR2fz68ec…
Being fast is more important than ever. But despite being the easiest metric to monitor, debug, and optimise, LCP is still the one that most websites struggle with. Get ready to ask for a pay rise, after
I whipped these out of my site last night for absolutely no good reason. That said, I would always recommend adding <html lang=xx> in your server-generated HTML.
Silly little micro-optimisation, but this is a fully valid, functional HTML document—html/head/body tags are all optional, saving 39 bytes!
<!DOCTYPE html>
<title>Hello, world!</title>
<h1>Hello, world!</h1>
<script>
document.body.classList.add('foobar')
</script>
I first wrote about this SEVEN years ago, but I’m currently helping a client refactor a huge, huge CSS project: @extend in Sass is almost always an anti-pattern. The simple way around is 5× smaller.
I first wrote about this SEVEN years ago, but I’m currently helping a client refactor a huge, huge CSS project: @extend in Sass is almost always an anti-pattern. The simple way around is 5× smaller.
To anyone who says that selector performance is never important, here we have an example of it adding approx. 0.25s of latency to user input. That’s bad.
If we look at the kinds of selectors we’re dealing with, they’re all pretty gross: incredibly broad Key Selectors (e.g. * or :not([hidden])); substring selectors (e.g. [class*="icss-"]); counters (e.g. div:nth-child(3)); complex combinators (e.g. ~); and descendants.
This leads to a half-second Recalc Style! Roughly half of Recalc Style is spent on selector matching, so about 250ms is spent just working over selectors. We spent almost 1.4ms just matching ::before!
This page has 5,000 DOM nodes, but the Recalc Style event is only scoped to 1,984 of them. When a user opens the hamburger nav, a class is added to the BODY. This causes a style invalidation, and the whole CSS is reapplied against the page (well, in our case, 1,984 DOM nodes).
<🧵> CSS Selector Performance. It’s something that most people tell you not to worry about. But sufficiently bad selectors on a sufficiently large DOM can have a real impact on the user experience, and even on INP.
One of my favourite outcomes from workshops is when an attendee asks a question so good that I end up writing a whole article to answer it. Today: document.write() – why IS it so bad?
It’s the same for DOMContentLoaded (blog post incoming…). Internal browser events exist for a reason, and although they might not represent the user experience, neither does e.g. TTFB, yet we still happily track that. Internal events; internal significance.
While Load isn’t a useful user-centric metric, there’s nothing to say that we shouldn’t be capturing non-user-facing data, especially if it marks an important milestone for our own application logic.