The at-rule
is a statement that provides CSS with instructions to perform or how to behave. Each statement begins with an @
followed directly by one of several available keywords that acts as the identifier for what CSS should do. This is the common syntax, though each at-rule
is a variation of it.
Regular Rules
Regular rules follow a regular syntax:
@[KEYWORD] (RULE);
@charset
This rule defines the character set used by the browser. It comes in handy if the stylesheet contains non-ASCII characters (e.g. UTF-8). Note that a character set that is placed on the HTTP header will override any @charset
rule.
@charset "UTF-8";
@import
This rule is inserted at the very top of the file and instructs the stylesheet to request and include an external CSS file as if the contents of that file were right where that line is.
@import 'global.css';
With the popularity of CSS preprocessors that support @import, it should be noted that they work differently than native CSS @import
is a separate HTTP request for that file.
@namespace
This rule is particularly useful for applying CSS to XML HTML (XHTML) so that XHTML elements can be used as selectors in the CSS.
/* Namespace for XHTML */
@namespace url(http://www.w3.org/1999/xhtml);
/* Namespace for SVG embedded in XHTML */
@namespace svg url(http://www.w3.org/2000/svg);
Nested Rules
Nested rules contain a subset of additional statements, some of which might be conditional to a specific situation.
@[KEYWORD] {
/* Nested Statements */
}
@document
This rule specifies conditions for styles that apply to a specific page. For example, we can provide a URL and then customize the styles for that particular page. Those styles will be ignored on other pages.
@document
/* Rules for a specific page */
url(https://css-tricks.com/),
/* Rules for pages with a URL that begin with... */
url-prefix(https://css-tricks.com/snippets/),
/* Rules for any page hosted on a domain */
domain(css-tricks.com),
/* Rules for all secure pages */
regexp("https:.*")
{
/* Start styling */
body { font-family: Comic Sans; }
}
The browser support for @document
is pretty weak at the time of this writing:
Chrome | Safari | Firefox | Opera | IE | Android | iOS |
---|---|---|---|---|---|---|
No | No | Limited | No | No | No | No |
@font-face
This rule allows us to load custom fonts on a webpage. There are varying levels of support for custom fonts, but this rule accepts statements that create and serve those fonts.
@font-face {
font-family: 'MyWebFont';
src: url('myfont.woff2') format('woff2'),
url('myfont.woff') format('woff');
}
Learn more about @font-face
How to use @font-face in CSS
The New Bulletproof @Font-Face Syntax
What’s the deal with declaring font properties on @font-face?
The @font-face dilemma
Don’t just copy the @font-face out of Google Fonts URLs
How To Rename a Font in CSS
Custom Fonts in Emails
FOUT, FOIT, FOFT
The Best Font Loading Strategies and How to Execute Them
Public Service Announcement: Watch Your @font-face font-weight
@keyframes
This rule is the basis for keyframe animations on many CSS properties, by allowing us to mark the start and stop (and in-between) marks for what is being animated.
@keyframes pulse {
0% {
background-color: #001f3f;
}
100% {
background-color: #ff4136;
}
}
Learn more about @keyframes
Keyframe Animation Syntax
Debugging CSS Keyframe Animations
Starting CSS Animations Mid-Way
CSS Keyframe Animation with Delay Between Iterations
A New Way to Delay Keyframes Animations
Animate to Different End States Using One Set of CSS Keyframes
How much specificity do @rules have, like @keyframes and @media?
Using Custom Properties to Wrangle Variations in Keyframe Animations
“Shake” CSS Keyframe Animation
@media
This rule contains conditional statements for targeting styles to specific screens. These statements can include screen sizes, which can be useful for adapting styles to devices:
/* iPhone in Portrait and Landscape */
@media only screen
and (min-device-width: 320px)
and (max-device-width: 480px)
and (-webkit-min-device-pixel-ratio: 2) {
.module { width: 100%; }
}
Or applying styles only to the document when it is printed:
@media print {
}
Learn more about @media
A Complete Guide to CSS Media Queries
Naming Media Queries
Nested Media Queries
The New CSS Media Query Range Syntax
Logic in CSS Media Queries (If / Else / And / Or / Not)
An Introduction to the Reduced Motion Media Query
Bandwidth Media Queries
Animated Media Queries
CSS Media Queries & Using Available Space
How much specificity do @rules have, like @keyframes and @media?
@page
This rule defines styles that are to individual pages when printing the document. It specifically contains pseudo-elements for styling the :first
page as well as the :left
and :right
margins of the page.
@page :first {
margin: 1in;
}
@property
CSS variables have been around a while now. We can define them pretty easily for any values we use regularly, like colors.
:root {
--primary-color: oklch(70% 0.183 42.88);
}
body {
color: var(--primary-color);
}
This is awesome, of course. But it’s not all sparkles and unicorns. For example, it’s impossible to animate between two variables, like say, the colors of a gradient. You might think it’s possible to rotate through the entire color wheel by setting up a variable for a color’s hue in a color function like this:
:root {
--hue: 0;
}
body {
animation: hue 5s linear infinite;
background-color: hsl(var(--hue) 80% 50%);
}
@keyframes hue {
0% { --hue; }
100% { --hue: 360; }
}
That certainly looks valid! But it just don’t work. That’s because CSS recognizes that number as a string as opposed to an actual number. We have to register what’s called a custom property in order to wire it all up.
That’s where @property
comes in. It’s used to not only register a CSS variable, but also to define its type, the initial value it defaults to, and whether or not it inherits values from other properties. It’s a lot like defining our very own specification for a specific type of data!
Getting back to that animated gradient, let’s set up our custom property:
@property --hue {
syntax: "<number>";
initial-value: 0;
inherits: false;
}
Now we can actually use --hue
to rotate around the full color wheel between 0deg
and 360deg
:
body {
animation: hue 5s linear infinite;
background-color: hsl(var(--hue) 100% 50%);
}
@keyframes hue {
0% { --hue; }
100% { --hue: 360; }
}
See the article “Interpolating Numeric CSS Variables” for a complete explanation of how @property
works as well as a demo of the animated gradient.
Learn more about @property
A Complete Guide to Custom Properties
@property
Using @property for CSS Custom Properties
Exploring @property and its Animating Powers
Interpolating Numeric CSS Variables
Custom Property Brain Twisters
Build Complex CSS Transitions using Custom Properties and cubic-bezier()
Image Fragmentation Effect With CSS Masks and Custom Properties
@supports
This rule tests whether a browser supports a feature, and then applies the styles for those elements if the condition is met. It’s sort of like Modernizr but tailored specially for CSS properties.
/* Check one supported condition */
@supports selector(::thumb) {
/* If ::thumb is supported, style away! */
}
/* Check multiple conditions */
@supports (color: oklch(50% .37 200)) and (color: color-mix(white, black)) {
background-color:
}
The not
operator is a way to check whether a browser does not support a feature to set fallback styles for those cases.
.element {
color: oklch(50% .37 200);
}
/* If the oklch() color function is not support, set a fallback color */
@supports not (color: oklch(50% .37 200)) {
.element {
color: #0288D1;
}
}
Here’s the, uh, support for @supports
:
Chrome | Edge | Safari | Firefox | Opera | IE | Android | iOS |
---|---|---|---|---|---|---|---|
28+ | 12+ | 9+ | 22+ | 12.1+ | No | 4.4+ | 9+ |
Learn more about @supports
@container
This at-rule was introduced in February 2023 with the release of Container Queries, a feature that allows you to register an element as a container
and apply styles to other elements when the container meets a certain condition. It’s a lot like @media
queries, but @container
looks at a specific element instead of the viewport size.
.parent {
container: article / inline-size;
}
.child {
display: flex;
}
@container article (width > 800px) {
.child {
flex-direction: column;
}
}
Learn more about container queries
A Cornucopia of Container Queries
The Origin Story of Container Queries
Digging Deeper Into Container Style Queries
Container Units Should Be Pretty Handy
Container Queries: Once More Unto the Breach
iShadeed’s Container Queries Lab
Container Query Discussion
Next Gen CSS: @container
Say Hello to CSS Container Queries
251: Container Queries are the Future
256: When to use @container queries
Wrapping Up
The at-rule
is where it’s at for making CSS do some crazy and interesting things. While the examples here are basic, we can see how they might be used to handcraft styles to very specific conditions, thereby creating user experiences and interactions that match a scenario.
It may be worth adding that ‘@import’ MUST precede all other types of rules except @charset — Can easily waste an enormous amount of time if you don’t know that ;)
https://developer.mozilla.org/en-US/docs/Web/CSS/@import
Word. So true–added a note about this.
What do people prefer for print styling? Including it in your main stylesheet with @print and save a http request? Or create a separate print stylesheet and save some weight on your base stylesheet?
I would imagine the amount of print styles would favour one method over the other, i.e. just a few styles would be placed in your stylsheet but a more complex print layout with many styles might be better as a separate file. Any other considerations?
Browsers will download both either way, so you might as well lump them rogether. And print styles are usually pretty small additional to base styles, at least that was my experience.
If you use pre-processor you can have a partial _print.scss for print styles wrapped in the
@media print{}
. In the end they should all be a single file to avoid multiple requests as setting a media=”print” on link wouldn’t stop the browser from downloading print .It’s good to know that @charset is not actually parsed as a rule. The parser just checks whether there file starts with the “@charset …;” sequence.
That means that you can’t use single quotes or whitespace in the declaration, and that it must be the very first one (even before @import rules).
http://www.w3.org/TR/css-syntax-3/#charset-rule
Didn’t know about the @document rule. I’ll have to keep that in mind. That’s a good alternative to WordPress’ body classes for styling different pages.
I’m not a fan- it’s a separation of concerns issue for me.
I’d be careful- you can always change classes, but it’s not always as easy to change the URL structure of a site.
This article doesn’t really mention browser support, but according to the MDN,
@document
has been postponed to CSS4 and is only supported by Firefox with the-moz-
prefix… https://developer.mozilla.org/en-US/docs/Web/CSS/@document@Qbe Root, there is no CSS4: http://www.xanthir.com/b4Ko0
I wish Chrome supported
@document
:/https://developer.mozilla.org/en-US/docs/Web/CSS/@document#Browser_compatibility
I was getting so excited about it until I read on about its support… one day!
Agreed! The lack of support for
@document
is a bummer. I went ahead and updated the post to show current support so we don’t create too much excitement yet. :)Hey Chris, I think you have a typo in the @import section. Unless prepreprocessors do exist and I am just way out of touch :)
Thanks for heads up! Fixed. :)
I thought prepreprocessors were for when you’re doing something cray cray?
Thanks for sharing this great post, I found it very helping in one of my web designing project.