← Back to CSS Course | Chapter 9: Modern CSS Features | Lesson 14 of 25

CSS At-Rules

Most of CSS is about styling elements, but a handful of special rules -- always starting with an @ symbol -- instead give instructions to the stylesheet itself: what character encoding to expect, how to name an XML namespace, how to scope a block of rules, or how to define custom counter symbols. Think of these at-rules as configuration directives sitting alongside your regular styling rules.

Declaring File Encoding with @charset

@charset tells the browser which character encoding a stylesheet file uses, which matters when your CSS contains non-ASCII characters like curly quotes or accented letters inside content: strings. It must be the literal first characters in the file -- not even a comment can come before it -- or the browser silently ignores it.

Note: Save your CSS file itself as UTF-8 and declare @charset "UTF-8"; together, so the declared encoding always matches the file's actual bytes.

Warning: Any character, comment, or whitespace before @charset in the file causes browsers to ignore the declaration entirely.

Example: Declaring File Encoding with @charset

css
@charset "UTF-8";
p::before {
  content: "“";
}

Naming XML Namespaces with @namespace

@namespace is used mainly in XML-based documents like SVG or XHTML to associate a CSS prefix with an XML namespace URI, letting selectors like svg|circle target elements from a specific namespace only. In plain HTML documents it is rarely needed, since HTML has just one implicit namespace.

Note: Reach for @namespace mainly when styling inline SVG elements that mix custom XML namespaces alongside standard SVG markup.

Warning: @namespace must be declared after any @charset or @import rules but before all other style rules, or it will be ignored.

Example: Naming XML Namespaces with @namespace

css
@namespace svg url(http://www.w3.org/2000/svg);
svg|circle {
  fill: red;
}

Limiting Rule Scope with @scope

@scope wraps a block of CSS rules so their selectors only match elements within a specific DOM subtree, defined by a scoping root and an optional scoping limit. This solves a long-standing problem: applying a rule only "within this card" without needing to prefix every single selector with a unique class name.

Note: Use @scope for component-style CSS where you want a rule like "p { color: red; }" to apply only inside a specific card, not globally across the page.

Warning: The scoping limit you set (to:) excludes elements from that point downward, which can accidentally exclude nested content you meant to still style.

Example: Limiting Rule Scope with @scope

css
@scope (.card) {
  p {
    color: red;
  }
}

Animating Entrances with @starting-style

@starting-style defines the "before" values a transition animates from when an element that was previously display: none (or newly added to the DOM) first becomes visible. Normally CSS transitions cannot animate an element's very first appearance, since there is no prior state to transition from -- @starting-style provides that missing starting point.

Note: Pair @starting-style with transition-behavior: allow-discrete when animating properties like display, so the entrance transition has a defined starting point.

Warning: @starting-style only affects the very first render after a discrete property change (like display: none to block); it does not apply to ordinary hover or class-toggle transitions.

Example: Animating Entrances with @starting-style

css
@starting-style {
  .box {
    opacity: 0;
  }
}
.box {
  opacity: 1;
  transition: opacity 0.3s;
}

Building Custom Counters with @counter-style

@counter-style lets you define an entirely custom counter symbol system beyond the built-in list (decimal, roman, disc, and so on) -- for example, custom bullet glyphs, a specific prefix and suffix, or a repeating custom symbol set. It gives ordered and unordered lists a level of styling control that list-style-type alone cannot reach.

Note: Give your @counter-style a descriptive name and reuse it across multiple lists via list-style-type for consistent custom bullets sitewide.

Warning: @counter-style requires a system descriptor (like cyclic or fixed) to be declared, or the browser will not know how to cycle through your custom symbols.

Example: Building Custom Counters with @counter-style

css
@counter-style thumbs {
  system: cyclic;
  symbols: "👍";
  suffix: " ";
}
ul {
  list-style: thumbs;
}
Common Mistakes
  1. Placing @charset anywhere other than the very first line of the very first stylesheet, where browsers require it to be recognized at all.
  2. Using @scope and assuming it behaves like a CSS class-based namespace, when it actually limits which elements a rule's selectors can match based on DOM position.
  3. Forgetting that @starting-style only applies to a transition when the element is also changing display from none, not on every entrance transition.
Chapter Summary
  • @charset declares a stylesheet's text encoding and must be the very first thing in the file to take effect.
  • @scope limits a block of CSS rules to a specific DOM subtree, and @counter-style defines fully custom counter symbols beyond the built-in list.
  • @starting-style defines the "before" state for CSS transitions that animate an element as it first appears in the DOM.
Browser Support

@charset, @namespace, and @counter-style are broadly supported; @scope and @starting-style are newer additions supported in current Chromium and Firefox releases, with Safari catching up.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.