Skip to content

CSS at-rules ​

In vanilla CSS, it's not possible to write at-rules in an element's attributes. Bring in some additional tooling β€”for example Tailwind CSS, Windi CSS, or in this case UnoCSSβ€” and you can.

TIP

As always with unocss-preset-css, the ruleset can have more than one rule (docs: CSS rulesets > Multiple CSS declarations) and/or block at-rules (docs: CSS block at-rules) and/or customized selectors. For the sake of legibility, the examples on this page use single-rule rulesets with no custom selectors.

πŸ‘€ You can experiment with all of these examples in this UnoCSS Play.

Layers ​

To put CSS rules in a layer block at-rule, write your CSS ruleset in the class attribute prefixed with the @layer_<layer name>.

class="@layer_<layer name>{<property>:<value>}"

TIP

Unlike everywhere else with unocss-preset-css, underscores in <layer name> are not replaced with spaces.

WARNING

You have to tell UnoCSS to use CSS layers, by adding outputToCssLayers: true to your uno.config.(j|t)s configuration.

Input

html
<div class="@layer_stuff{color:red}">
  This is red
</div>
ts
// …
export default defineConfig({
  outputToCssLayers: true,
  // …
})

Output

  • Front end

    This is red
  • CSS

    css
    @layer stuff {
      .\@layer_stuff\{color\:red\} {
        color: red;
      }
    }

You can use multiple layers, and control their order in the cascade.

⚠️ unocss-preset-css does not support statement at-rules. Notably this means you can't write a class name to generate @layer stuff, other;. Instead, use UnoCSS's layer config field (docs).

Input

html
<div class="@layer_other{color:red} @layer_stuff{color:blue}">
  This is red
</div>
ts
// …
export default defineConfig({
  layers: {
    other: 2,
    stuff: 1,
  },
  outputToCssLayers: true,
  // …
})

Output

  • Front end

    This is red
  • CSS

    TIP

    Notice that UnoCSS does not generate a @layer statement at-rule. Instead, it puts each layers' styles in a single @layer block at-rule, and orders those blocks according to the layers config.

    If you have additional CSS not generated by UnoCSS (for example CSS in a separate stylesheet), make sure it comes after the UnoCSS-generated CSS to guarantee the UnoCSS-configured layer order is respected.

    Alternatively, add an @layer statement at-rule before the UnoCSS-generated styles.

    css
    @layer stuff {
      .\@layer_stuff\{color\:blue\} {
        color:blue;
      }
    }
    
    @layer other {
      .\@layer_other\{color\:red\}{
        color:red;
      }
    }

Everything else ​

To put CSS rules in another block at-rule, write your CSS ruleset in the class attribute prefixed with the at-rule.

class="<at-rule>{<property>:<value>}"

TIP

Like everywhere else with unocss-preset-css except for layer block at-rules, underscores in <at-rule> are replaced with spaces. To use a literal underscore, escape it with a backslash (\). Like everywhere else with unocss-preset-css except for layer block at-rules, underscores in <at-rule> are replaced with spaces. To use a literal underscore, escape it with a backslash (\).

Input

html
<div class="@media(width<768px){color:red}">
  Red on windows narrower than 768px.
</div>

<div class="@media(width>=768px){color:red}">
  Red on windows 768px wide or wider.
</div>

Output

  • Front end

    Red on windows narrower than 768px.
    Red on windows 768px wide or wider.
  • CSS

    css
    @media (width < 768px) {
      .\@media\(width\<768px\)\{color\:red\} {
        color: red;
      }
    }
    
    @media (width >= 768px) {
      .\@media\(width\>\=768px\)\{color\:red\} {
        color: red;
      }
    }

Multiple at-rules ​

Layer + arbitrary ​

To combine a layer block at-rule and an arbitrary block at-rule, string the class name prefixes together:

@layer_<layer name><at-rule>{<property>:<value>} or <at-rule>@layer_<layer name>{<property>:<value>}.

Here's an example of supporting aspect-ratio in Safari 13 and 14 (read Adding Safari 14 Support To Tailwind's Aspect Ratio for more info) with inline class CSS.

Input

html
<div
  class="
    {aspect-ratio:1_/_1}
    {border:1px_solid_red}
    {width:4rem}
    @layer_safari-14@supports_not_(aspect-ratio:1_/_1)[&::before]{content:.,float:left.,padding-top:calc(100%)}
    @layer_safari-14@supports_not_(aspect-ratio:1_/_1)[&::after]{clear:left.,content.,display:block}
  "></div>

Output

  • Front end

  • CSS

    css
    @media (width < 768px) {
      .\@media\(width\<768px\)\{color\:red\} {
        color: red;
      }
    }
    
    @media (width >= 768px) {
      .\@media\(width\>\=768px\)\{color\:red\} {
        color: red;
      }
    }

Arbitrary + arbitrary ​

DANGER

unocss-preset-css does not support combining multiple arbitrary at-rule blocks in a single class.

You might be able to use a wrapping element.

Input

html
<div class="{display:none} @supports(-webkit-hyphens:none){display:block}">
  <div class="@media(width<768px){color:red}">
    Red on windows narrower than 768px. Safari.
  </div>

  <div class="@media(width>=768px){color:red}">
    Red on windows 768px wide or wider. Safari.
  </div>
</div>

<div class="{display:none} @supports_not_(-webkit-hyphens:none){display:block}">
  <div class="@media(width<768px){color:red}">
    Red on windows narrower than 768px. Not Safari.
  </div>

  <div class="@media(width>=768px){color:red}">
    Red on windows 768px wide or wider. Not Safari.
  </div>
</div>

Output

  • Front end

    Red on windows narrower than 768px. Safari.
    Red on windows 768px wide or wider. Safari.
    Red on windows narrower than 768px. Not Safari.
    Red on windows 768px wide or wider. Not Safari.
  • CSS

    css
    .\{display\:none\} {
      display: none;
    }
    
    @media (width < 768px) {
      .\@media\(width\<768px\)\{color\:red\}{
        color: red;
      }
    }
    
    @media (width >= 768px) {
      .\@media\(width\>\=768px\)\{color\:red\}{
        color: red;
      }
    }
    
    @supports not (-webkit-hyphens:none) {
      .\@supports_not_\(-webkit-hyphens\:none\)\{display\:block\}{
        display: block;
      }
    }
    
    @supports(-webkit-hyphens:none) {
      .\@supports\(-webkit-hyphens\:none\)\{display\:block\}{
        display: block;
      }
    }

Layer + layer ​

DANGER

unocss-preset-css does not support combining multiple layer at-rule blocks in a single class.

You might be able to use a wrapper element. I'm not sure what it would mean, but maybe there's some interesting use case.

Input

html
<details id="doubled-layers">
  <summary>Toggle me</summary>
</details>

<div class="{display:none} [body:has(#doubled-layers[open])_&]{display:block}">
  <div class="@layer_stuff{color:red}">
    Toggle is open
  </div>
</div>

<div class="{display:none} [body:has(#doubled-layers:not([open]))_&]{display:block}">
  <div class="@layer_stuff{color:red}">
    Toggle is closed
  </div>
</div>
ts
// …
export default defineConfig({
  layers: {
    other: 2,
    stuff: 1,
  },
  outputToCssLayers: true,
  // …
})

Output

  • Front end

    Toggle me
    Toggle is open
    Toggle is closed
  • CSS

    css
    @layer default {
      .\{display\:none\} {
        display: none;
      }
    }
    
    @layer stuff {
      .\@layer_stuff\{color\:red\} {
        color: red;
      }
    }
    
    @layer other{
      .\@layer_other\[body\:has\(\#doubled-layers\:not\(\[open\]\)\)_\&\]\{display\:block\} {
        body:has(#doubled-layers:not([open])) & {
          display: block;
        }
      }
    
      .\@layer_other\[body\:has\(\#doubled-layers\[open\]\)_\&\]\{display\:block\} {
        body:has(#doubled-layers[open]) & {
          display: block;
        }
      }
    }