Use new and upcoming CSS features today, thanks to PostCSS

In this video, Kevin J Powell, shows how to use new and upcoming CSS features today, thanks to PostCSS and its postcss-preset-env plugin.

The video covers Custom Media Queries, Media Query Ranges, CSS Nesting, and Custom Selectors.

Media Queries Level 4: Media Query Range Contexts (Media Query Ranges)

A media feature like width can take its value from a range. When used, we prefix these with min- or max- to express “minimum condition” or “maximum condition” constraints.

@media (min-width: 300px) and (max-width: 750px) {
	…
}

In CSS Media Queries Level 4 these type of Media Features can now be written as a “range context”, which uses ordinary mathematical comparison operators.

@media (300px <= width <= 750px) {
	…
}

The syntax might seem a little bit odd at first, but for me the trick is to read it as “the width sits in between the two values”

Also works with single values. This example will most likely be more readable to anyone who has (basic) programming knowledge:

/* Old Way */
@media (max-width: 750px) {
	…
}
/* New Way */
@media (width <= 750px) {
	…
}

~

At the time for writing, only Gecko/Firefox supports Range Contexts (ever since Firefox 63). There was some (minor) movement in the Blink/Chromium issue in September, but progress seems to have stalled. No word on WebKit/Safari.

The pen embedded below will indicate if your browser supports Media Query Range Contexts or not:

~

If you’re using PostCSS, you can use the postcss-media-minmax processor to already write Range Contexts:

npm install postcss-media-minmax
var fs = require('fs')
var postcss = require('postcss')
var minmax = require('postcss-media-minmax')

var css = fs.readFileSync('input.css', 'utf8')

var output = postcss()
  .use(minmax())
  .process(css)
  .css
  
console.log('\n====>Output CSS:\n', output)  

~

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

Conditional border-radius and three future CSS features

Stefan Judis has reworked Ahmad Shadeed‘s Conditional border-radius, using these three (future) CSS additions:

  1. Media query ranges
  2. Container Queries
  3. CSS @when + @else

Unlike the original code, the result definitely is a very nice and readable piece of code that doesn’t feel hacky at all — I like where CSS is headed 😊

Conditional border-radius and three future CSS features →

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 →

Detecting Hover-Capable Devices

Using Level 5 Media Queries, Michelle writes how to distinguish hover from touch devices.

@media (hover: hover) {
  .some-component {
    /* Styles for hover-able devices */
  }
}

Detecting Hover-Capable Devices →

The new responsive: Web design in a component-driven world

In this session from Google I/O 2021, Una Kravets talks about “the new responsive”, short for being responsive to the user, container, and form-factor (text-version available via link below):

The web community is entering into a new era of responsive design and shifting our perspectives on what it means. With user preference queries, container queries, and other form-factor queries on the horizon, we’ll soon have the tools to create responsive designs far beyond what querying the global viewport allows.

To me, this post is the perfect successor to A List Apart’s A Dao of Web Design and Responsive Web Design. The timing is only off by one year …

The new responsive: Web design in a component-driven world →

The complete guide to CSS media queries

Last summer Kilian Valkhof did a wonderful write-up on the Polypane blog covering CSS Media Queries.

Media queries are what make modern responsive design possible. With them you can set different styling based on things like a users screen size, device capabilities or user preferences. But how do they work, which ones are there and which ones should you use?

Good for beginners, but seasoned developers might also want to take a look at the “New notations in Media query levels 4 and 5” section, especially the part about Media Query Ranges:

/* old notation */
@media (min-width: 300px) and (max-width: 750px) {
}

/* new notation */
@media (300px <= width <= 750px) {
}

This is gonna be awesome! 😎

The complete guide to CSS media queries →

Nested Media Queries

I can’t seem to find any mention of this in the Media Queries Module specification, but apparently it’s allowed to nest media queries, as shared by Šime Vidas:

That’s … awesome! 🤯

Fiddling with it a bit more, turns out this snippet also works as expected:

@media not print {
  @media (min-width: 0) {
    p {
      font-weight: bold;
    }
    @media (max-width: 750px) {
      p {
        background: yellow;
      }
    }
  }
}

You can play with this CodePen demo to try it yourself.

💁‍♂️ Don’t confuse Nested Media Queries with CSS Nesting, an upcoming feature of CSS, which allows you to nest selectors.

UPDATE: Thanks to reader Vadim Makeev for pointing out that support for nested @media blocks was added to Opera 12.50 back in 2012! Its syntax is defined in the CSS Conditional Rules Module specification.

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

Creating websites with prefers-reduced-data

Part of CSS Media Queries Level 5 is the User Preference Media Feature prefers-reduced-data:

The prefers-reduced-data CSS media feature is used to detect if the user has requested the web content that consumes less internet traffic.

There currently is no browser support at all, but that doesn’t stop Kilian Valkhof from taking a peek under the hood.

/* Serve a smaller image by default */
body {
  background-image: url(/images/small-fast-image.webp);
}

/* But replace it with a large image when applicable */
@media (prefers-reduced-data: no-preference) {
  body {
    background-image: url(/image/large-pretty-image.png);
  }
}

Like prefers-reduced-motion, it’s good to think of the prefers-reduced-data: reduce option as the default option: people get the lean, fast experience, and only when they indicate no-preference, we send them more data. That way, older browser[s] that don’t support the media query get the lean experience by default.

I especially like the example where the Infinite Scroll paradigm is replaced with a “load more” button when the user has prefers-reduced-data: reduce set. Clever!

Creating websites with prefers-reduced-data

🔥 Another great User Preference Media Feature is prefers-reduced-motion, which can easily be taken into account by using CSS Custom Properties. And you most likely will have heard about prefers-color-scheme too, which allows you to implement Dark Mode.

Container Queries are coming to Chromium!

  • Update 2021-02-12: 🎉 Thanks to the hard work by Miriam Suzanne and others this proposal is now officially part of the CSS Specification Process (ref) and set to be part of css-contain-3 … it’s happening, people!

  • Update 2021-03-28: 👀 A first iteration of this implementation has landed in Chrome 91 … let’s take a closer look and build a demo!

  • Update 2021-05-02: ♻️ Creating a Containment Context / Container Root also requires style containment. The code examples have been updated to include this change.

  • Update 2021.06.11: 🚨 To create a container you no longer need to set the contain property, but instead use the container property. This post does not include these changes, but the first look post does.

Just announced on the Chromium mailing list is an “Intent to Prototype” Container Queries, which is quite exciting news I must say!

🤔 Container Queries?

Container Queries allow authors to style elements according to the size of a container. This is similar to a @media query, except that it evaluates against a container instead of the viewport.

The experimental implementation will follow Miriam Suzanne’s proposal, which looks like this:

/* (1) Create an implicit "container root" */
main,
aside {
  contain: layout style inline-size;
}

.media-object {
  display: grid;
  gap: 1em;
}

/* (2) Container Query targeting the nearest 
   "container root" ancestor. The rules nested
   inside will only be applied if the "container
   root" has a max-width of 45em */
@container (max-width: 45em) {
  .media-object {
    grid-template: 'img content' auto / auto 1fr;
  }
}

Applying contain: inline-size; (1) onto an element will make it an implicit “container root” or “containment context”. For this to work you also need to apply layout and style containment on the container, so the full code becomes contain: layout style inline-size;.

Elements contained inside a “container root” can then have container queries applied onto them, by use of a new at-rule @container (<container-media-query>) (2). The target selector and CSS rules to apply in that case are — similar to what we do with “regular” media queries — nested within the @container at-rule.

In the example above extra rules will be applied to .media-object whenever its nearest “container root” ancestor — such as <main> or <aside> — has a max-width of 45em.

🧑‍🔬 This proposal is experimental and has not been approved by the CSSWG yet. The expressed “intent to prototype” is meant as an experiment to see whether this idea would be worth pursuing or not. In the end, it could be that the final syntax can differ from the one listed here, if the proposal is workable in the first place.

~

A previous version of this proposal by L. David Baron required a context selector to be set, but that has been dropped here. The @container rule from Miriam’s version will work in any containment context (read: the nearest parent element that has contain: size set). The syntax might still change, but that’s irrelevant to the prototype which is to be implemented:

This is not at all finalized, but the underlying problems we need to solve in Blink are (mostly) the same regardless of how the feature is accessed, so we’ll for now use this proposal as the temporary syntax.

~

Intent to Prototype: Container Queries →
Chrome Tracking Bug →

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