What Are CSS At-Rules
CSS at-rules are statements that begin with an at sign (@) followed by an identifier. They tell the CSS engine how to behave, whether that's importing external stylesheets, defining animations, creating conditional styling rules, or establishing cascade layers. At-rules represent one of the most powerful and versatile features of the CSS language.
At-rules fall into two primary categories: statement at-rules that end with a semicolon, and block at-rules that contain nested rules within curly braces. Each category serves distinct purposes and offers unique capabilities for organizing and enhancing your CSS architecture.
The flexibility of at-rules has grown significantly in recent years, with new additions like @layer for cascade control, @container for responsive component design, and @property for defining typed custom properties. These modern features reflect the evolution of CSS as a capable styling language for complex web applications.
Understanding these at-rules is essential for building modern, responsive, and maintainable websites. Whether you're working on custom web applications or optimizing existing sites, mastering at-rules gives you precise control over how styles are applied and prioritized.
Statement At-Rules
Concise declarations ending with semicolons that perform specific tasks like @charset, @import, @namespace, and @layer.
Block At-Rules
Rules containing nested content within curly braces, including @media, @keyframes, @supports, and @container.
Conditional Rules
Rules like @media and @supports that apply styles only when specific conditions are met.
Modern Features
Latest additions including cascade layers, container queries, and typed custom properties for advanced styling.
Statement At-Rules
Statement at-rules are concise declarations that perform specific tasks without requiring a block of nested content. These rules end with a semicolon and typically provide configuration or instructions to the CSS engine.
@charset
The @charset at-rule specifies the character encoding used in the stylesheet. While most modern documents rely on UTF-8 encoding declared in HTML, this at-rule provides a fallback for external stylesheets.
@charset "utf-8";
This rule must appear at the very beginning of a stylesheet, before any other content.
@import
The @import at-rule allows you to include styles from other stylesheets, promoting modularity and code organization. Stylesheets imported this way are processed before the rest of the CSS, enabling a clean separation of concerns.
@import url("components/buttons.css");
@import "layout/grid.css" screen and (min-width: 768px);
The second example demonstrates how @import can include media queries, applying the imported styles only under specific conditions.
@namespace
The @namespace at-rule defines a namespace prefix for use with XML-based languages like SVG and MathML. When defined, the prefix can qualify selectors to target specific namespaces.
@namespace url("http://www.w3.org/1999/xhtml");
@namespace svg url("http://www.w3.org/2000/svg");
/* Targets HTML links */
a {}
/* Targets SVG anchor elements */
svg a {}
@layer
The @layer at-rule represents one of the most significant additions to modern CSS, providing explicit control over cascade priority. Cascade layers allow you to organize styles into named groups with defined precedence order, making cascade conflicts easier to manage.
/* Declare layer order */
@layer reset, base, components, utilities;
/* Add styles to specific layers */
@layer reset {
*, *::before, *::after {
box-sizing: border-box;
}
}
@layer components {
.card {
border: 1px solid #e2e8f0;
border-radius: 8px;
}
}
@layer utilities {
.text-center { text-align: center; }
}
The cascade prioritizes styles from earlier declared layers over later ones, giving developers fine-grained control over which styles take precedence. This is particularly valuable when working with large-scale CSS architectures where multiple teams contribute to the codebase.
Block At-Rules: Conditional Logic
@media
The @media at-rule is perhaps the most widely used conditional at-rule, enabling responsive design through device and viewport condition testing. Media queries allow styles to adapt based on screen size, resolution, orientation, and other device characteristics.
/* Base mobile-first styles */
.container {
width: 100%;
padding: 1rem;
}
/* Tablet and up */
@media (min-width: 768px) {
.container {
max-width: 720px;
margin: 0 auto;
padding: 1.5rem;
}
}
/* Desktop styles */
@media (min-width: 1024px) {
.container {
max-width: 960px;
}
.sidebar {
display: block;
}
}
/* Print styles */
@media print {
.no-print {
display: none;
}
body {
font-size: 12pt;
}
}
Media queries support a wide range of features including width, height, resolution, orientation, and hover capability. The mobile-first approach shown here demonstrates how to progressively enhance designs for larger screens.
@supports
The @supports at-rule tests whether a browser supports specific CSS features, enabling progressive enhancement strategies. Styles within the block apply only when the browser recognizes and can render the feature.
/* Grid fallback for older browsers */
.grid {
display: flex;
flex-wrap: wrap;
}
/* Modern Grid when supported */
@supports (display: grid) {
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 1rem;
}
}
This at-rule is invaluable for adopting new CSS features while maintaining compatibility with older browsers. It allows developers to provide fallbacks that ensure a functional experience across all browsers.
@container
Container queries represent a paradigm shift in responsive design, allowing components to respond to their parent container's size rather than the viewport. The @container at-rule enables this behavior by defining conditions based on container dimensions.
/* Define a container */
.responsive-container {
container-type: inline-size;
container-name: card-container;
}
/* Container query for card layout */
@container card-container (min-width: 400px) {
.card {
display: grid;
grid-template-columns: 150px 1fr;
}
}
Container queries enable truly modular responsive components that adapt based on their available space. This capability is particularly valuable for component-based design systems and reusable component libraries. When implementing container queries, consider how they can reduce the need for complex JavaScript-based responsive solutions and improve overall site performance.
@scope
The @scope at-rule establishes a styling scope, limiting the reach of selectors to specific elements within a defined scope. This feature helps prevent style leakage and creates more maintainable stylesheets.
/* Define a scope for article content */
@scope (.article-content) {
/* Only targets paragraphs within .article-content */
p {
line-height: 1.6;
margin-bottom: 1rem;
}
/* Only targets headings within the scope */
h2 {
margin-top: 2rem;
}
}
Scopes can optionally define lower boundaries, limiting which elements within the scope receive the styles.
Animation And Transition At-Rules
@keyframes
The @keyframes at-rule defines the intermediate steps of an animation sequence. By specifying styles at various percentages of the animation timeline, you create smooth, complex animations entirely in CSS.
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes pulse {
0%, 100% {
transform: scale(1);
}
50% {
transform: scale(1.05);
}
}
/* Applying animations */
.fade-in {
animation: fadeIn 0.5s ease-out forwards;
}
.pulse-button {
animation: pulse 2s ease-in-out infinite;
}
Keyframe animations can specify multiple intermediate steps using percentage values, create effects that run forwards, backwards, or alternate, and control timing functions for natural motion.
@starting-style
The @starting-style at-rule defines initial property values for transitions from elements that haven't been styled before, such as when transitioning from display: none. This at-rule solves a common challenge with CSS transitions.
/* Modal with transition */
.modal {
opacity: 0;
transform: scale(0.95);
transition: opacity 0.3s, transform 0.3s;
}
/* Define starting state for first render */
@starting-style {
.modal {
opacity: 0;
transform: scale(0.95);
}
}
/* Open state */
.modal[open] {
opacity: 1;
transform: scale(1);
}
Without @starting-style, transitions from initial renders often fail because the browser has no previous state to transition from.
@view-transition
The @view-transition at-rule enables smooth transitions between DOM states during navigation, creating app-like transitions between pages without JavaScript animation libraries. This modern feature can significantly enhance user engagement and perceived performance for AI-powered web applications that prioritize user experience.
/* Enable view transitions */
@view-transition {
navigation: auto;
}
/* Customize transition behavior */
::view-transition-group(*) {
animation-duration: 0.5s;
}
::view-transition-old(root) {
animation: fade-out 0.3s ease-in-out;
}
::view-transition-new(root) {
animation: fade-in 0.3s ease-in-out;
}
View transitions provide a declarative way to animate between page states, with customizable group behaviors and timing functions. This creates polished user experiences without relying on heavy JavaScript libraries.
Font And Text At-Rules
@font-face
The @font-face at-rule declares a custom font for use in a document, specifying the font source and its characteristics. This at-rule enables web fonts beyond system defaults.
/* Define custom font with multiple sources */
@font-face {
font-family: "Inter";
src: url("/fonts/Inter-Regular.woff2") format("woff2"),
url("/fonts/Inter-Regular.woff") format("woff");
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Inter";
src: url("/fonts/Inter-Bold.woff2") format("woff2");
font-weight: 700;
font-style: normal;
}
The font-display descriptor controls how the font appears while loading, with swap ensuring text remains visible using fallback fonts until the custom font loads.
@counter-style
The @counter-style at-rule defines custom counter styles for use with list markers and generated content, extending beyond the predefined counter styles like decimal and roman.
/* Custom decimal with leading zeros */
@counter-style decimal-leading-zero {
system: override decimal;
suffix: ". ";
}
/* Icon-based counter */
@counter-style checkmarks {
system: cyclic;
symbols: "✓";
suffix: " ";
}
ul {
list-style: decimal-leading-zero;
}
.features {
list-style: checkmarks;
}
@property
The @property at-rule defines CSS custom properties with type checking, default values, and inheritance control. This powerful feature enables sophisticated CSS design systems with typed design tokens.
/* Define typed custom properties */
@property --primary-color {
syntax: "<color>";
inherits: false;
initial-value: #3b82f6;
}
@property --spacing {
syntax: "<length>";
inherits: true;
initial-value: 1rem;
}
/* Using typed properties */
.button {
--primary-color: #6366f1;
background-color: var(--primary-color);
padding: var(--spacing);
}
Typed custom properties enable automatic type conversion, validation, and meaningful error messages when values don't match expected types. This feature is essential for design systems requiring strict token contracts.
Page And Position At-Rules
@page
The @page at-rule specifies styling for printed pages, controlling margins, size, and other page-specific properties. This at-rule is essential for creating print-friendly stylesheets.
@page {
size: A4 portrait;
margin: 2cm;
@top-center {
content: "Document Title";
font-size: 10pt;
}
@bottom-center {
content: counter(page);
font-size: 10pt;
}
}
@page :first {
margin-top: 0;
}
@page :left {
margin-right: 3cm;
margin-left: 2cm;
}
@page :right {
margin-left: 3cm;
margin-right: 2cm;
}
The @page at-rule supports pseudo-classes like :first, :left, and :right for different page contexts, and can include margin boxes for headers, footers, and page numbers.
@position-try
The @position-try at-rule defines custom position options for anchor-positioned elements, providing fallback positioning and alignment when space is limited.
/* Define position try options */
@position-try --try-top {
bottom: 100%;
left: 0;
}
@position-try --flip-both {
inset: 0;
margin: auto;
}
/* Using position try options */
.tooltip {
position-anchor: --tooltip-trigger;
position-try: --try-top, --flip-both;
}
This at-rule enables sophisticated anchor positioning with graceful fallbacks when primary positioning would cause overflow.
Cascade Layer Organization
The @layer at-rule's capability as a block at-rule enables sophisticated cascade layer management. Understanding how to use both declaration and block forms is crucial for modern CSS architecture.
/* Declare layer order (statement form) */
@layer reset, base, patterns, components, utilities;
/* Define layer contents (block form) */
@layer reset {
*, *::before, *::after {
box-sizing: border-box;
}
html, body {
margin: 0;
padding: 0;
}
}
@layer base {
:root {
--color-primary: #3b82f6;
--color-text: #1f2937;
--font-sans: system-ui, -apple-system, sans-serif;
}
body {
font-family: var(--font-sans);
color: var(--color-text);
}
}
@layer components {
.card {
background: white;
border-radius: 0.5rem;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
}
@layer utilities {
.text-balance {
text-wrap: balance;
}
}
Cascade Priority (lowest to highest):
- reset layer
- base layer
- patterns layer
- components layer
- utilities layer
- Unlayered styles (highest priority)
This comprehensive example demonstrates how cascade layers create a clear hierarchy: unlayered styles override all layered styles, and within layers, later layers override earlier ones. This organization is essential for maintaining large-scale web applications where multiple developers contribute to the codebase.
Frequently Asked Questions
Best Practices For CSS At-Rules
General Guidelines
- @charset: Must appear first if used, with proper quotation marks
- @import: Use sparingly; consider bundling for production
- @layer: Declare layer order early, use block form for content
- @media: Mobile-first approach works best for most projects
Modern Features
When using modern at-rules like @layer, @container, and @property:
- Provide fallbacks using
@supportsfor graceful degradation - Test across target browsers to verify feature support
- Consider the progressive enhancement strategy for your users
Performance Tips
- Use CSS animations (via @keyframes) over JavaScript when possible
- Include
font-display: swapwith @font-face for better UX - Nest @layer blocks properly for maintainable code organization
- Use container queries for component-level responsiveness to avoid unnecessary viewport recalculations
Browser Compatibility
Newer at-rules like @layer, @container, and @property have excellent support in modern browsers. For older browser support, always include fallback styles using @supports queries.
Mastering CSS at-rules is essential for building modern, performant websites. These powerful directives give you precise control over how styles are applied, organized, and prioritized. Whether you're creating responsive layouts with @media and @container, defining animations with @keyframes, or organizing large codebases with @layer, understanding these at-rules will make you a more effective web developer.
Ready to apply these techniques to your project? Our web development team has extensive experience building responsive, maintainable websites using modern CSS best practices. Contact us to discuss how we can help elevate your web presence.