“For developers, Apple’s Safari is crap and outdated”

Perry Sun:

Safari is very good web browser, delivering fast performance and solid privacy features.

But at the same time, the lack of support for key web technologies and APIs has been both perplexing and annoying at the same time.

The enormous popularity of iOS makes it all the more annoying that Apple continues to hold back developers from being able to create great experiences over the web that work across all platforms.

Well, can’t say I disagree there …

Thankfully there’s now people like Jen Simmons working at Apple, actively asking what should change (you can find my response here). Let’s hope she can have an impact there.

For developers, Apple’s Safari is crap and outdated →

useUnmountSignal() — A React Hook to cancel promises when a component is unmounted

A React Hook that wraps around the almighty AbortController. It will automatically call abort() on the created AbortSignal instance when the component unmounts.

import useUnmountSignal from 'use-unmount-signal';

function Example() {
  const unmountSignal = useUnmountSignal();
  return (
      onClick={() =>
        fetch('https://ping.example.com', { signal: unmountSignal })

Installation per NPM:

npm i use-unmount-signal

use-unmount-signal (GitHub) →

Prevent Layout Shifts between Web Fonts and Fallback Fonts with the size-adjust @font-face descriptor

You know something good’s landed when two out of the three great Web/CSS resources — here Smashing Magazine and web.dev (*) — write about the same topic: the size-adjust descriptor for @font-face.

To improve font rendering, a great technique is font swapping. The problem however, is that sometimes when the web font loads, it shifts the entire page around since it presents at a slightly different box height size.

By putting size-adjust in the @font-face rule, it sets a global glyph adjustment for the font face. Timing this right will lead to minimal visual change, a seamless swap.

Available in Chromium 92 and (flagged) Firefox 89 at the time of writing. Up-to-date list on “Can I Use …”.

The posts contain links to tools to help you define the perfect size-adjust value.

(*) The third one of the bunch being CSS-Tricks

Execute ES Modules on the CLI

Jonathan Neal shared this little snippet on Twitter:

Here’s the code:

":" //#;exec /usr/bin/env node --input-type=module - "$@" > "$0"

import process from 'process';
const { argv } = process

Save your file as command.js and you can run bash command.js on the shell.


What intrigued me here was this special shebang at the very top. I did expect #!/usr/bin/env node in there, but not the fact that the script itself is fed into node as an argument.

Going down the rabbit hole, I found this post from 2014 that explains the funky version. There’s two commands in there, split by a ;

  1. ":" //#
  2. exec /usr/bin/env node --input-type=module - "$@" > "$0"

The first part does nothing beyond expanding arguments (//) and a no-op. The # indicates the start of a comment, but the comment itself remains empty.

The second part feeds the scriptname ($0) and the rest of the arguments ($@) into the node binary. Via the --input-type=module flag, node is configured to treat the file itself as an ES Module.


Digging at bit deeper I learned that there are three ways to configure node to treat your file as an ES Module:

  1. Use the --input-type=module

  2. Give your file the .mjs extension

  3. Place a package.json with the follow contents near the file

      "type": "module"

I like the --input-type=module version with the shebang trick Jonathan shared there, as it requires no extra files (package.json) and allows you to keep the .js extension (or even drop it entirely).


🔥 Like what you see? Want to stay in the loop? Here's how:

Image Cut-Out Effects using CSS or SVG

Ahmad Shadeed shows us how to do image cut-out effects, using either CSS or SVG.

Handy to — for example — show a group of avatars.

See the Pen Seen Avatars – SVG Mask by Ahmad Shadeed (@shadeed) on CodePen.

Looking at the CSS variant: I was familiar with -webkit-mask-image and that you could combine multiple masks, but didn’t know that that there’s this wonderful mask-composite property that you can use along with that! Cool!

Thinking About The Cut-Out Effect: CSS or SVG? →


RenderingNG — Ready for the next generation of web content

In the post on TablesNG, we looked at some of the features this under-the-hood rewrite for tables in Chromium provides us. But that’s only the tip of the iceberg, as the Chromium team have also been working on a whole new rendering engine architecture, named RenderingNG.

In 2021, we will largely complete the process of designing, building and shipping a new cutting-edge Chromium rendering engine architecture. Let’s call it RenderingNG, since it is truly a next-generation rendering architecture that greatly outperforms what came before. RenderingNG has been in progress for at least eight years, and unlocks a huge amount of potential for the next generation of fast, fluid, reliable, responsive and interactive web content.

There are two posts up on web.dev covering RenderingNG, with some very in-depth detail. It’s packed with tons of information. Take this visualization of the Rendering Pipeline structure — which is explained in the articles — for example:

Illustrations by the hand of Una.

  1. RenderingNG: Goals and Key Properties →
  2. RenderingNG: Architecture Components and Rendering Pipeline →

It’s this rewrite that keeps wonderful new things such as Scroll-Linked Animations with CSS @scroll-timeline very performant. Thanks to RenderingNG, the scroll- and animation-part run on the compositor (e.g. “off main thread”).

Prevent unwanted Layout Shifts caused by Scrollbars with the scrollbar-gutter CSS property

A side-effect when showing scrollbars on the web is that the layout of the content might change depending on the type of scrollbar. The scrollbar-gutter CSS property —which will soon ship with Chromium — aims to give us developers more control over that.

Let’s take a look.


👨‍🔬 The CSS features described in this post are currently only supported in Chromium 88+ with the #experimental-web-platform-features flag enabled through chrome://flags.

💥 To keep your primary Chromium install clean, I recommend you do not set this flag in Chromium Stable, but resort to Beta / Canary builds.


Table of Contents

  1. Classic vs. Overlay Scrollbars
  2. The Problem
  3. The Solution: scrollbar-gutter: stable;
  4. Keeping things symmetric with both-edges
  5. Caveats
  6. Browser Support
  7. In Summary


# Classic vs. Overlay Scrollbars

Before we jump in, there’s a distinction between two types of scrollbars that we need to make.

# Overlay Scrollbars

Overlay Scrollbars are those iOS/macOS-style scrollbars which are placed over the content. They are not shown by default, but only while the user is scrolling. To keep the content underneath visible they are semi-transparent, but that’s totally up to the user-agent (browser) to determine. While interacting with them, their size may also vary.

Figure: An Overlay Scrollbar is placed over the content.

# Classic Scrollbars

Classic Scrollbars are scrollbars that are placed in the so-called “Scrollbar Gutter”. The Scrollbar Gutter is the space between the inner border edge and the outer padding edge. With classic scrollbars, the size of the Scrollbar Gutter is the same as the width of the scrollbar. These scrollbars are usually opaque (not transparent) and take away some space from the adjacent content.

Figure: A Classic Scrollbar takes away some space from the adjacent content.

🍏 macOS User? You can switch from Overlay to Classic Scrollbars via System Preferences!

If you’re a macOS user you can switch from Overlay to Classic Scrollbars via System Preferences → General. Set “Show scroll bars” to “Always”:

Using defaults you can also enable it:

defaults write NSGlobalDomain AppleShowScrollBars -string "Always"

Some applications — such as Chrome — need to be restarted after changing the setting.


# The Problem

When the content of a box becomes too big (e.g. when it is overflowing), the browser will — by default — show a scrollbar. In case of a classic scrollbar this has a nasty side-effect: as the scrollbar needs some space, the available width for the content shrinks — thus the layout shifts.

Figure: As the scrollbar gets shown, the content shifts.

☝️ In case of Overlay Scrollbars there’s no layout shift, as those scrollbars get rendered over the content.


# The Solution: scrollbar-gutter: stable;

The scrollbar-gutter property aims to solve the problem described above.

By setting scrollbar-gutter to stable we can have the UA always show the Scrollbar Gutter, even if the box is not overflowing and no scrollbar is shown. This way we have a visually stable layout: when the box starts to overflow the scrollbar will be rendered but no layout shift will happen as space for it was already reserved.

Figure: As the scrollbar gets shown, the content does not shift as the browser had already reserved space for the scrollbar gutter.

When the scrollbar gutter is present but the scrollbar is not, the background of the scrollbar gutter is painted as an extension of the padding.

Note that this scrollbar-gutter property has no effect on the rendering of the scrollbar itself — it only affects the rendering of the gutter. The rendering of the scrollbar is controlled by the overflow property.

The default value for scrollbar-gutter is auto. With this value set, the behavior is unchanged from the one described in The Problem


# Keeping things symmetric with both-edges

A scrollbar-gutter value of stable can be extended with both-edges. By setting scrollbar-gutter: stable both-edges; you can achieve symmetry. As per spec:

If a scrollbar gutter would be present on one of the inline start edge or the inline end edge of the box, another scrollbar gutter must be present on the opposite edge as well.

Figure: As the scrollbar gets shown, the content does not shift. Above that the same gutter space was reserved on the opposite edge.

In a previous version of the spec both-edges was named mirror. The experimental implementation in Chromium still uses this old name.


# Caveats

There are only two small caveats with this one:

  1. As for the overflow property, a scrollbar-gutter set on the root element is applied to the viewport instead.
  2. Unlike the overflow property, the browser will not propagate scrollbar-gutter from the HTML body element.


# Browser Support

scrollbar-gutter is not supported in any browser at the time of writing. Chromium has released an “Intent To Ship” just last week, so I expect it to land in Chromium unflagged pretty soon. Other browser vendors are sending positive signals towards this addition, so they’ll follow too.

To follow along, here are the relevant Tracking Bugs:


# In Summary

With the scrollbar-gutter we can prevent some unwanted layout changes caused by scrollbars. The graphic below summarizes the scenarios covered in this post:

If your browser supports scrollbar-gutter, you can also check out this CodePen demo:

See the Pen CSS scrollbar-gutter demo by Bramus (@bramus) on CodePen.


To help spread the contents of this post, feel free to retweet the announcement tweet:


🔥 Like what you see? Want to stay in the loop? Here's how:

Dev Roulette Live — Conversations with Frontend Developers

I don’t know exactly how she does it, but apart from all the work on her side projects, newsletter, family, etc. Stephanie Eckles also hosts a show named “Dev Roulette Live”

Dev Roulette is a conversation between Stephanie Eckles and up to two mystery guests about topics that are particularly important to front-end developers including: CSS, JS, and Accessibility.

For the second episode (mid June) I had the honor to join the conversation together with Michelle Barker.

It was great to finally “meet” both Stephanie and Michelle, two persons who definitely are on my “you should follow them on Twitter”-list. In the hour we had we talked about Layout in CSS, Creative CSS, Progressive Enhancement, etc.

I very much like the spontaneous atmosphere that lives during these conversations. Take the topics for example: although they are a pre-defined set of topics, they are not fixed — a spin of the wheel decides what topic will be talked about.

If you can’t join live (on Twitch), you can always watch the recordings afterwards, on YouTube.

Dev Roulette Live →
Dev Roulette Live on YouTube →

Detecting media query support in CSS and JavaScript

Kilian Valkhof recently needed to check if prefers-reduced-data was supported by the browser or not

For this, I couldn’t use just @media (prefers-reduced-data: no-preference) because that would be false if either there was no support (since the browser wouldn’t understand the media query) or if it was supported but the user wanted to preserve data.

What I needed was a test for the media feature regardless of its value. It turns out we can do that by using the or notation in media queries.

The result is a pretty mind-bending at-rule:

@media not all and (prefers-reduced-data), (prefers-reduced-data) {

I don’t fully grasp it but if Kilian says it works, I trust him on that.With a few extra pointers by Kilian on Twitter I get it now. Thankfully the JS version is a bit easier (and that one I do understand entirely).

Detecting media query support in CSS and JavaScript →

“Inline Parameters” extension for VSCode

Inspired by JetBrains’ “Inline Parameter Name Hints” feature, Liam Hammett created an extension for VSCode with the same functionality:

This feature can give you additional context when reading your code, making it easier to understand what different function parameters refer to by showing the parameter’s name inline.

No longer do you have to be confused about whether the needle or haystack comes first, or have to slow down your workflow by going to a function’s source to figure out what it does!

Supported languages are JavaScript, TypeScript, PHP, and LUA.

Inline Parameters for VSCode →