Too Many SVGs Clogging Up Your Markup? Try use

Good reminder by Georgi Nikoloff to have one (visually hidden) SVG that contains several layers, which you can then include further down in your code.

SVG has a <defs> tag that lets us declare something like our graph footer just once and then simply reference it — using <use> — from anywhere on the page to render it as many times as we want.

That way you end up with less DOM nodes, less bytes transferred, and less memory consumed.

Too Many SVGs Clogging Up Your Markup? Try use

Debugging Layout Shifts

Over at web.dev, Katie Hempenius learns us how to identify and fix layout shifts using the Layout Instability API and the DevTools.

What I take away from this is that you can easily spot them using DevTools: In the Rendering Panel you can enable an option to highlight areas of Layout Shift:

To enable Layout Shift Regions in DevTools, go to Settings → More Tools → Rendering → Layout Shift Regions then refresh the page that you wish to debug. Areas of layout shift will be briefly highlighted in purple.

Debugging layout shifts →

JavaScript performance beyond bundle size

Nolan Lawson, on how we might focus too much on JavaScript bundle size:

Performance is a multi-faceted thing. It would be great if we could reduce it down to a single metric such as bundle size, but if you really want to cover all the bases, there are a lot of different angles to consider.

He digs into other factors that have an influence:

  • Parse/compile time
  • Execution time
  • Power usage
  • Memory usage
  • Disk usage

JavaScript performance beyond bundle size →

Before You React.memo()

Dan Abramov shares 2 techniques to try before resorting to optimize with React.memo()

In this post, I want to share two different techniques. They’re surprisingly basic, which is why people rarely realize they improve rendering performance.

These techniques are complementary to what you already know! They don’t replace memo or useMemo, but they’re often good to try first.

Covered Solutions:

  1. Move State Down
  2. Lift Content Up

Before You memo() →

Debugging layout repaint issues triggered by CSS Transition

Dzhavat ran into an interesting performance issue where practically his whole site would repaint when a transition in the header was triggered.

The element being animated is a span wrapping some text placed inside an h1. The h1 itself is in the upper left corner on the page and contains my name. Initially, only the letter “D” is shows. The remaining part fades-in on hover.

I was quite surprised to see the whole page flashing green given the transition was scoped to a very isolated element. I didn’t really see any connection between animating a span and causing repaint on the whole page.

The culprit: Stacking Contexts

Debugging layout repaint issues triggered by CSS Transition →

How to avoid layout shifts caused by web fonts

Simon Hearne, who has been keeping a closer eye on unexpected layout shifts ever since Core Web Vitals came into play:

One common cause of layout shift is surprisingly difficult to resolve though: flashes of unstyled text (FOUT). In this post we will explore the surprisingly complex world of text rendering on the web and some techniques to remove FOUT while not incurring a CLS penalty.

How to avoid layout shifts caused by web fonts →

How We Improved SmashingMag Performance

Interesting real-world case-study over at Smashing Magazine:

In this article, we’ll take a close look at some of the changes we made on this very site — running on JAMStack with React — to optimize the web performance and improve the Core Web Vitals metrics. With some of the mistakes we’ve made, and some of the unexpected changes that helped boost all the metrics across the board.

Be sure to check out the linked diagnostics.css by Tim Kaldec. It can be used to indicate clear (or potential) problems with the markup.

How We Improved SmashingMag Performance →

content-visiblity: auto; vs. jumpy scrollbars, a solution

As warned in content-visibility: the new CSS property that boosts your rendering performance you need to be careful with applying content-visibility: auto; on each and every element as the scrollbar might get jumpy.

This is because elements will be rendered as they scroll into the viewport and will be hidden as they scroll out of the viewport, thereby affecting the height of the rendered page, and thus also affecting the scrollbar.

ℹ️ Apart from a jumpy scrollbar it can also negatively affect accessibility when you include headings and landmark elements inside of regions styled with content-visibility: auto;. See Content-visibility and Accessible Semantics for details.

Now, thanks to infinite scroll we are — or at least I am — kind of used to the thumb part of the scrollbar shrinking and jumping back up a bit on the scrollbar track as you scroll down. What we’re not used to is the thumb part jump forwards on the scroll track as you scroll down. This is because elements that slide out of the viewport will no long be rendered — as that’s what content-visibility: auto; does — and the scrollbar is (by default) only calculated against the rendered elements.


Elements can become non-rendered elements as they scroll out of the viewport,
thanks to content-visibility: auto; doing its thing.

To cater for this jumpy behavior you should use contain-intrinsic-size so space for an element is reserved when it’s not being rendered. However, it is not always possible to know a box its dimensions in advance. Looking for a way to automatically reserve space for previously rendered elements, Alex Russel created a little script for it.

One challenge with naive application of content-visibility, though, is the way that it removes elements from the rendered tree once they leave the viewport — particularly as you scroll downward. If the scroll position depends on elements above the currently viewable content “accordion scrollbars” can dance gleefully as content-visibility: auto does its thing.

In a first version of the script he applied content-visibility: visible on each element from the moment it had appeared on screen. To detect this an IntersectionObserver is used. While this does prevent the scrollbar thumb from jumping forwards as you scroll down, it will make the page slow again as that content remains rendered (even though it’s off-screen).

A second version of the script takes a different approach and calculates the contain-intrinsic-size to apply based on the element’s dimensions. That way elements that passed by once now have a correct contain-intrinsic-size set, and can safely be hidden again as content-visibility: auto does its job.

let spaced = new WeakMap();
let reserveSpace = (el, rect) => {
    let old = spaced.get(el);
    // Set intrinsic size to prevent jumping.
    if (!old || rectNotEQ(old, rect)) {
        spaced.set(el, rect);
        el.attributeStyleMap.set(
        "contain-intrinsic-size",
        `${rect.width}px ${rect.height}px`
        );
    }
};

Additionally he also added a ResizeObserver to cater for resize events.

Resize-Resilient `content-visiblity` Fixes →

🤔 Clever script indeed, yet I cannot help but think: this should be possible without the needs for this extra script. What if a value like contain-intrinsic-size: auto; would be allowed, and do exactly as the script Alex built does?

UPDATE 2020.12.21: I’ve created an issue on GitHub that proposes contain-intrinsic-size: auto;. Let’s see where this goes …

UPDATE 2021.01.13: Looks like support for contain-intrinsic-size: auto; will land in the spec!

How to useRef to Fix React Performance Issues

Sidney Alcantara who works on Firetable, a product which features a data grid and an adjacent side drawer. When clicking a cell in the table, the side drawer opens with info about the current cell. Initially they lifted up the state, but that caused performance issues:

The problem was whenever the user selected a cell or opened the side drawer, the update to this global context would cause the entire app to re-render. This included the main table component, which could have dozens of cells displayed at a time, each with its own editor component. This would result in a render time of around 650 ms(!), long enough to see a visible delay in the side drawer’s open animation.

After exploring to split the context, or resort to useMemo/React.memo they settled on useRef to solve this.

Good use-case and detailed write-up!

How to useRef to Fix React Performance Issues →

Beyond Fast: Features to Improve the Performance of your Web Pages

Few tips by Jake Archibald — as presented at #ChromeDevSummit — on how you can use some of the new and upcoming web features to improve the performance of your page.

Covered are the aforementioned content-visibility, Font metric override descriptors, the Back/Forward Cache, Portals, and Preloading