content-visibility: the new CSS property that boosts your rendering performance

Coming to Chromium 85 is content-visibility (part of Display Locking):

content-visibility enables the user agent to skip an element’s rendering work, including layout and painting, until it is needed. Because rendering is skipped, if a large portion of your content is off-screen, leveraging the content-visibility property makes the initial user load much faster. It also allows for faster interactions with the on-screen content. Pretty neat.

You see that correct in the image above: rendering went from 232ms down to 30ms … that’s a 7x improvement!

Now don’t go plastering this all over your site, but use it carefully. As Una noted:

Combined with contain-intrinsic-size it’d look like this:

.story {
  content-visibility: auto;
  contain-intrinsic-size: 1000px;
}

content-visibility: the new CSS property that boosts your rendering performance →

Chrome vs. BlinkMacSystemFont: A Workaround

UPDATE 2020-04-28: Good news everyone! A workaround for this bug has landed in Canary (Chromium 84) and will be merged into the M83 release! The workaround described here still applies for Chromium 81.

The problem

As detailed before there’s this bug that shipped with Chromium 81 which somehow prevents the font-weight CSS property from being applied on the BlinkMacSystemFont font. Quite annoying, as that font is part of the widespread system font stack and affects all modern versions of macOS.

The Chromium bug itself is marked as a blocker for Chromium M83 – the next Chromium version – but as far as I can tell there’s no real progress being made on it. Above that the M83-based build of Google Chrome won’t start shipping until May 19, so we’re stuck for at least another month with this issue. Other browsers (such as Edge, Brave, etc.) might ship their M83-based build even later.

~

The Fix

As a workaround, some users have suggested to simply not use SF Pro (which is the outcome of using BlinkMacSystemFont) but that’s quite a hard measure I must say. Thankfully there’s a better solution. Thanks to Twitter I’ve come to known that the Inter font family is practically a drop-in replacement for SF Pro.

Here on bram.us I’ve adjusted my font stack to no longer use BlinkMacSystemFont and load Inter – served by Google Fonts – instead. To preserve other platforms to load their own system font, I’ve added Inter somewhere at the back of the line.

Here’s a diff of my CSS:

+ @import url('https://fonts.googleapis.com/css2?family=Inter&display=swap');

…

- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", 'Inter', "Helvetica Neue", sans-serif;
+ font-family: -apple-system, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", 'Inter', "Helvetica Neue", sans-serif;

💡 Note that in the snippet above I’m loading all available font-weight Inter supports. It’s recommended to limit this and only load the font-weights you actually need. You can do this via the Google Fonts website

~

With this adjustment in place my website looks quite decent again. Let’s hope the Chromium team can fix this issue soon. In the mean time we can use Inter as workaround.

Did this help you out? Like what you see?
Thank me with a coffee.

I don't do this for profit but a small one-time donation would surely put a smile on my face. Thanks!

☕️ Buy me a Coffee (€3)

To stay in the loop you can follow @bramus or follow @bramusblog on Twitter.

Chrome vs. BlinkMacSystemFont: when bold is not bold

UPDATE 2020-04-28: Good news everyone! A workaround for this bug has landed in Canary (Chromium 84) and will be merged into the M83 release!

Today I noticed here on bram.us that the titles suddenly have gotten thinner in Chrome on macOS. Was this due to a recent WordPress Theme Update? Was it caused by a recent macOS update? Or was it the update to Chrome version 81 that broke my site?

~

I’m running WordPress here with (a slightly modified version of) the default Twenty Nineteen theme. The theme uses a so called system font stack for its titles:

h1, h2, h3, h4, h5, h6 {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
  font-weight: 700;
}

While the font stack itself was applied correctly – the font eventually used is BlinkMacSystemFont here on my Mac – the font-weight seems to be ignored by Chrome.

~

After some experimenting I’ve narrowed down the problem to its core, and have come to conclude that the issue is:

  1. Not WordPress-related. The issue is present on any site with elements that use the BlinkMacSystemFont font (which is only available on recent macOS installs).
  2. Only occurs when larger font-sizes (> 20px) are used.
  3. Chromium related: Latest Firefox and Safari still show the bold titles. Google Chrome and Edge Beta show the thin versions.
  4. Chromium 81+ related: Edge (based on Chromium version 80) works fine, Edge Beta (based on Chromium version 81) doesn’t. Chrome Canary (based on Chromium version 84) also has this issue.

Here’s a pen with a standalone test case. No matter what you set the font-weight to, the title always remains thin (on macOS, in a Chromium 81+ browser).

To be complete: I’m running the latest macOS Catalina, version 10.15.4 (19E266).

~

I’ve created a bug on the Chromium Bug Tracker for this, which by now has been confirmed. The problem indeed got introduced in Chrome 81 and is reproducible. If I understand things correctly, work is being done to have it fixed by Chrome 83, which is the next version of Chrome (there is no Chrome 82 as the release schedule got thrown around due to #coronavirus).

Currently there’s no workaround that you as a developer can implement, other than simply not using BlinkMacSystemFont. As a developer you can work around this issue by dropping BlinkMacSystemFont from your font stack and using the Inter Font Family instead. See https://www.bram.us/2020/04/24/chrome-vs-blinkmacsystemfont-a-workaround/ for details.

💁‍♂️ It’s not the first time Chrome is having font issues. In Chrome 79 there was this weird issue that some people saw the font Hoefler Text being rendered as Hoefler Text Ornaments. The issue was never really fixed but seemed to have disappeared for most with the release of Chrome 80.

Optimize Rendering with CSS Containment

The folks at Igalia has been recently working on the implementation of CSS Containment in Chromium – which already shipped in Chrome 52, back in 2016 – by providing some fixes and optimizations based on the standard.

Their post forms a nice intro on the subject:

The main goal of CSS Containment standard is to improve the rendering performance of web pages, allowing the isolation of a subtree from the rest of the document. This specification only introduces one new CSS property called contain with different possible values.

  • layout: The internal layout of the element is totally isolated from the rest of the page, it’s not affected by anything outside and its contents cannot have any effect on the ancestors.
  • paint: Descendants of the element cannot be displayed outside its bounds, nothing will overflow this element (or if it does it won’t be visible).
  • size: The size of the element can be computed without checking its children, the element dimensions are independent of its contents.
  • style: The effects of counters and quotes cannot escape this element, so they are isolated from the rest of the page.

Browser engines can use that information to implement optimizations and avoid doing extra work when they know which subtrees are independent of the rest of the page.

An introduction to CSS Containment →

How CSS works: Parsing and painting CSS in the critical rendering path

Insightful post by the folks over at LogRocket on the rendering pipeline:

If your site takes forever to load, chances are your users aren’t gonna wait for it to finish, even if there’s valuable content to be found there. Some studies have shown that up to 50% of users leave a page after 3 seconds of waiting.

With users expecting those types of load times, it’s our responsibility as web developers to not bloat the amount of stuff we’re sending to the user. Sadly, CSS is often the culprit of increased load times, so having a nuanced understanding of how the CSS you send is transformed into beautiful pixels will help you optimize that crucial seconds where users are most likely to bounce.

How CSS works: Parsing & painting CSS in the critical rendering path →

Jake Archibald: “In The Loop” — Taking a close look into the browser’s Event Loop

Talk by Jake Archibald, as brought at JSConf.Asia 2018, taking a close look into the browser’s Event Loop:

This talk looks at the browser’s event loop, the thing that orchestrates the main thread of the browser, which includes JavaScript, events, and rendering. We’ll look at the difference between tasks, microtasks, requestAnimationFrame, requestIdleCallback, and where events land.
Hopefully you’ll never have to use setTimeout hacks again!”

And yeah, I’ve also used getComputedStyle() in the middle of some JS code before, in order to force layout/re-rendering 😬

~

Additionally you might also want to read How JavaScript works: Event loop and the rise of Async programming by Alexander Zlatkov, which also has a nice visualisation of what’s going on.

Once saw an interactie version of the visuals as shown in Alexander Zlatkov’s post. I think it was in a talk, yet can’t seem to find it back anywhere … if someone could point me to it, feel free to comment 😉

UPDATE: Found it! The tool is named Loupe, and I saw it in this talk by Philip Roberts:

Inside a super fast CSS Engine: Quantum CSS (aka Stylo)

Great writeup on how Firefox’s new CSS Engine “Quantum CSS” works. Also sports a clear and in-depth explanation of the rendering pipeline, with some nice illustrations to go along.

You may have heard of Project Quantum… it’s a major rewrite of Firefox’s internals to make Firefox fast. We’re swapping in parts from our experimental browser, Servo, and making massive improvements to other parts of the engine.

The first major component from Servo – a new CSS engine called Quantum CSS (previously known as Stylo) – is now available for testing in our Nightly version.

Inside a super fast CSS Engine: Quantum CSS (aka Stylo) →

Understanding the Critical Rendering Path

When a browser receives the HTML response for a page from the server, there are a lot of steps to be taken before pixels are drawn on the screen. This sequence the browsers needs to run through for the initial paint of the page is called the “Critical Rendering Path”.

Good and short writeup on how the pixel/rendering pipeline works – something that every developer should now – perfect for those new to the subject.

Do note that next to the DOM and CSSOM another object model also gets generated: the accessibility tree / object model.

Understanding the Critical Rendering Path →

If you like videos more, Paul Lewis has covered this quite some time ago.

Is Houdini ready yet‽

css-houdini

“Is Houdini ready yet‽” is a dedicated page to tracking the status of Houdini.

But what is Houdini? Here’s a snippet from Smashing Magazine:

Imagine how much nicer your development life would be if you could use any CSS property and know for sure it was going to work, exactly the same, in every browser. And think about all of the new features you read of in blog posts or hear about at conferences and meetups — things like CSS grids, CSS snap points and sticky positioning. Imagine if you could use all of them today and in a way that was as performant as native CSS features. And all you’d need to do is grab the code from GitHub.

This is the dream of Houdini.

But how?

The Houdini task force has introduced several new specifications that will give developers access to all parts – instead of just the DOM/CSSOM part – of the rendering pipeline. The chart below shows the pipeline and which new specifications can be used to modify which steps.

05-spec-coverage-opt

With Houdini’s APIs one could – for example – implement the Masonry or Grid Layouts, running them at native speed instead of as a script/polyfill:

body {
  display: layout('masonry');
}

Is Houdini ready yet‽ →
Houdini: Maybe The Most Exciting Development In CSS You’ve Never Heard Of →