Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Named media queries with @custom-media

Breakpoints — the widths where the layout changes — repeat across the whole project. A named media query, @custom-media, lets you write a condition once and refer to it by name afterwards. It is a draft CSS standard that browsers do not understand yet, so postcss-preset-env replaces the names with the conditions themselves.

Declaring and using

The plugin is already enabled in postcss.config.js. Declare the name at the top of styles/main.css and use it in @media inside parentheses:

/* styles/main.css */
@custom-media --tablet (width >= 768px);
 
.post-list {
  display: grid;
  gap: 16px;
}
 
@media (--tablet) {
  .post-list {
    grid-template-columns: 1fr 1fr;
  }
}

Like a CSS variable, the name starts with two dashes. After npx postcss styles/main.css -o css/main.css:

.post-list {
  display: grid;
  grid-gap: 16px;
  gap: 16px;
}
 
@media (min-width: 768px) {
  .post-list {
    grid-template-columns: 1fr 1fr;
  }
}

The declaration is gone, and (--tablet) was replaced with the condition. The plugin also turned the range syntax width >= 768px into the familiar min-width: 768px and added grid-gap — the old name of the gap property for grids.

<style>
  .post-list {
    display: grid;
    grid-gap: 16px;
    gap: 16px;
  }
 
  @media (min-width: 768px) {
    .post-list {
      grid-template-columns: 1fr 1fr;
    }
  }
 
  .post-list article {
    padding: 16px;
    background: #f1f5f9;
  }
</style>
 
<div class="post-list">
  <article>Getting to know PostCSS</article>
  <article>Setting up Autoprefixer</article>
  <article>Minifying CSS</article>
</div>

In a narrow window the posts form one column, and from 768 pixels on — two.

Several names

Declare all breakpoints together and combine names with and:

/* styles/main.css */
@custom-media --dark (prefers-color-scheme: dark);
@custom-media --wide (width >= 1024px);
 
@media (--dark) and (--wide) {
  .post-list {
    gap: 32px;
  }
}
@media (prefers-color-scheme: dark) and (min-width: 1024px) {
  .post-list {
    gap: 32px;
  }
}

Now moving a breakpoint means changing one declaration line.

Why not a variable

CSS variables like var(--tablet) do not work inside @media: media queries are evaluated before variable values. So conditions need a separate mechanism, and @custom-media is its future standard syntax.

Common mistake

Declaring the names in one file and using them in another that is processed separately. The plugin sees only the current file: without a declaration it silently leaves @media (--tablet) as is, and the browser ignores the whole block. Include the file with declarations through @import and postcss-import (next chapter) — then all files are joined before processing.

Thanks for reading!

Donate to the site — we work hard for you.