11  HTML and CSS

For good old web basics that I somehow didn’t know about, or just learned a fancy new way of dealing with.

11.1 How to use :not() with CSS selectors

In CSS, :not() is a negation pseudo class1. It’s used with a selector or list of selectors as arguments to target elements that do not match those arguments.

The basic syntax shown in the :not entry of the CSS Almanac (Cope 2021) is as follows:

CSS
/* the X argument can be replaced with any simple selectors */
:not(X) {
  property: value;
}

The X argument from the code above accepts a comma-separated list of one or more selectors, but can not contain another negation selector (i.e. you can’t nest your not:()s) or any other pseudo elements.

Other “unusual effects and outcomes” of not:() are detailed in the Description section of the not:() entry of the MDN Web Docs (MDN Contributors 2023), which is well worth giving a gander.

Example/my use case

I put :not() to use in this very document (a Quarto book). I like to style my links (<a> elements) in a way that’s slightly different to the Quarto defaults (the details of which are irrelevant). I wanted to target links that are in lists (<li>s). Initially, when I used li a as a CSS selector, this was too broad (applying properties I didn’t want to be used in places like the table of contents and breadcrumbs).

So, I refined my selection by passing in the selectors to :not() where I didn’t want my styling applied:

CSS
li a:not(header *, nav *) {
  property: value;
}
Caution

If I had been able to identify a positive selector (e.g. if there was a div with an id that applied just to the document content below the title-block-header), I would have used it.

As mentioned, :not() can have surprising behavior. Also, the selector list argument of :not() does not have universal browser support (as of this writing, it works for 96.1% of global users).

Learn more

11.2 The font-display descriptor

font-display is a descriptor2 of the @font-face CSS at rule. As defined on its MDN reference page:

The font-display descriptor determines how a font face is displayed based on whether and when it is downloaded and ready to use.

It has five possible values (auto, block, swap, fallback, and optional), which determine how the browser will handle text while a font is being loaded/is unavailable. Monica Dinculescu’s font-display playground3 is an excellent, concise explainer which, among other things, includes the following diagram showing the difference in how the four values determine how a browser will (or will not) display text while a webfont is being loaded:

Duration of invisible versus fallback font display for the four values of font-display: block, swap, fallback, and optional. Block is invisible for up to three seconds, then uses the fallback font until the webfont is downloaded. Swap will appear unstyled/fallback until the webfont is loaded. Fallback will be invisible for up to 100ms, fallback font will be shown for up to 3s when the webfont is downloaded. Optional will be invisible for up to 100ms, then use either fallback or webfont depending on the user's connection speed.
Figure 11.1: Duration of invisible vs. fallback font display with each font-display value, by Monica Dinculescu.

You can also expand the table below to see the duration of block and swap periods for each font-display value from Best practices for fonts (Hempenius and Pollard 2022).

View table
Block and swap periods for five possible font-display values.
Value Block period Swap period
Auto Varies by browser Varies by browser
Block 2-3 seconds Infinite
Swap 0ms Infinite
Fallback 100ms 3 seconds
Optional 100ms None

For even more detail, I recommend reading 5 steps to faster web fonts by Iain Bean (2021).


  1. You can learn more about functional pseudo-classes (a group that includes :not()) or pseudo-classes in general from their linked MDN reference pages.↩︎

  2. A CSS descriptor is pretty much like a CSS property that belongs to an at rule (as opposed to a selector).↩︎

  3. If Monica’s project isn’t running, I made a Glitch remix of it with an updated Node version you can try. All credit for the content is Monica’s.↩︎