CSSCSS At-Rules Overview

CSS At-Rules: The Complete Overview

At-rules are CSS statements that begin with an @ sign and instruct the browser how to behave. While ordinary rules describe how elements should look, at-rules describe conditions, imports, definitions, and scopes — the meta-layer of your stylesheet. Modern CSS ships more than a dozen of them, and several (like @layer and @container) fundamentally change how you architect styles.

The Two Kinds of At-Rules

At-rules come in two structural flavors: statement at-rules end with a semicolon and contain no block, while block at-rules wrap a set of rules (or descriptors) in curly braces.

CSS
/* Statement at-rules — end with a semicolon */
@charset "utf-8";
@import url("reset.css");
@namespace svg url(http://www.w3.org/2000/svg);

/* Block at-rules — contain a { ... } block */
@media (min-width: 768px) {
  .sidebar { display: block; }
}

@font-face {
  font-family: "Inter";
  src: url("/fonts/inter.woff2") format("woff2");
}
Quick Reference

At-rule

Purpose

Type

@media

Apply styles based on viewport / device features

Conditional

@supports

Apply styles only if the browser supports a feature

Conditional

@container

Apply styles based on a container element size

Conditional

@import

Pull in another stylesheet

Statement

@font-face

Define a downloadable font

Definition

@keyframes

Define animation steps

Definition

@layer

Declare cascade layers and their order

Cascade control

@property

Register a typed custom property

Definition

@counter-style

Define custom list counters

Definition

@page

Style printed pages

Print

@scope

Limit rules to a DOM subtree

Scoping

@charset

Declare stylesheet encoding

Statement

@media — Respond to the Environment

The most widely used at-rule. It gates a block of styles behind a media query: viewport size, orientation, color-scheme preference, motion preference, and more.

CSS
/* Classic min-width query */
@media (min-width: 64rem) {
  .layout { grid-template-columns: 240px 1fr; }
}

/* Modern range syntax */
@media (768px <= width < 1200px) {
  .layout { padding-inline: 2rem; }
}

/* User preferences */
@media (prefers-color-scheme: dark) {
  :root { --surface: #111; --text: #eee; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: 0.01ms !important; }
}
@supports — Feature Queries

@supports tests whether the browser understands a property/value pair (or a selector), enabling true progressive enhancement in CSS itself — no JavaScript feature detection required.

CSS
/* Fallback first, enhancement inside @supports */
.gallery {
  display: flex;
  flex-wrap: wrap;
}

@supports (display: grid) {
  .gallery {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  }
}

/* Combine tests with and / or / not */
@supports (display: grid) and (gap: 1rem) {
  .gallery { gap: 1rem; }
}

/* Test selector support */
@supports selector(:has(img)) {
  .card:has(img) { padding: 0; }
}
@import — Load Other Stylesheets

CSS
/* Must appear before all other rules (except @charset / @layer) */
@import url("typography.css");
@import url("print.css") print;
@import url("wide.css") (min-width: 1024px);

/* Import directly into a cascade layer */
@import url("vendor.css") layer(vendor);
Performance
Each @import creates a sequential network request — the browser cannot fetch the imported file until it has downloaded and parsed the importing file. Prefer multiple link elements or a bundler. See the dedicated @import page for details.
@font-face — Custom Fonts

CSS
@font-face {
  font-family: "Inter";
  src: url("/fonts/inter-var.woff2") format("woff2");
  font-weight: 100 900;        /* variable font range */
  font-display: swap;          /* show fallback text immediately */
  unicode-range: U+0000-00FF;  /* only the latin subset */
}
@keyframes — Animation Steps

CSS
@keyframes slide-in {
  from { translate: -100% 0; opacity: 0; }
  60%  { translate: 8px 0; }
  to   { translate: 0 0; opacity: 1; }
}

.toast {
  animation: slide-in 300ms ease-out;
}
@layer — Cascade Layers

@layer lets you declare explicit priority tiers in the cascade. Later layers beat earlier layers regardless of specificity, which finally tames third-party CSS and utility frameworks.

CSS
/* Declare order up front — later wins */
@layer reset, base, components, utilities;

@layer reset {
  * { margin: 0; box-sizing: border-box; }
}

@layer components {
  .button { padding: 0.5rem 1rem; background: navy; }
}

@layer utilities {
  /* Wins over .button even though specificity is equal */
  .bg-red { background: crimson; }
}
@container — Container Queries

Where @media asks about the viewport, @container asks about an ancestor element. This makes components genuinely reusable: a card can rearrange itself based on the column it happens to sit in.

CSS
.card-list {
  container-type: inline-size;
  container-name: cards;
}

@container cards (min-width: 480px) {
  .card {
    display: grid;
    grid-template-columns: 160px 1fr;
  }
}
@property — Typed Custom Properties

@property registers a custom property with a type, initial value, and inheritance behavior — which makes the property animatable.

CSS
@property --progress {
  syntax: "<percentage>";
  inherits: false;
  initial-value: 0%;
}

.meter {
  background: conic-gradient(teal var(--progress), #eee 0);
  transition: --progress 400ms ease; /* now animates smoothly */
}
.meter.done { --progress: 100%; }
@page and @scope

CSS
/* @page — control printed output */
@page {
  size: A4;
  margin: 2cm;
}
@page :first {
  margin-top: 4cm;
}

/* @scope — limit rules to a subtree (donut scoping) */
@scope (.article) to (.comments) {
  p { line-height: 1.7; }
  /* Applies to p inside .article, but NOT inside .comments */
}
Browser Support Snapshot

At-rule

Support status

@media, @import, @font-face, @keyframes, @page

Universal — safe everywhere

@supports

Universal in evergreen browsers

@layer

Baseline widely available (all majors since 2022)

@container

Baseline widely available (all majors since 2023)

@property

Baseline newly available (all majors since 2024)

@scope

Newer — check current support before relying on it

@counter-style

Broad support; some descriptors vary

Nesting At-Rules

Conditional at-rules can nest inside each other and, with native CSS nesting, inside selectors too:

CSS
.card {
  padding: 1rem;

  @media (min-width: 768px) {
    padding: 2rem;

    @supports (backdrop-filter: blur(4px)) {
      backdrop-filter: blur(4px);
    }
  }
}
Where to go next
Each major at-rule has a dedicated deep-dive page in this section:@media, @import, @font-face,@keyframes, and @counter-style. Start with@media — it is the one you will write daily.
Key Takeaways
  • At-rules control conditions, definitions, and cascade behavior — not element appearance directly.

  • Statement at-rules (@import, @charset) end with a semicolon; block at-rules wrap rules in braces.

  • @media queries the viewport; @container queries an ancestor element; @supports queries browser capability.

  • @layer gives you explicit cascade tiers that end specificity wars.

  • @property makes custom properties typed and animatable.

  • Conditional at-rules nest — inside each other and inside selectors with native nesting.