Note Native CSS nesting works in all major browsers without a preprocessor. Use & for pseudo-classes and pseudo-elements. Media queries can be nested inside rules. You no longer need the & prefix for simple descendant selectors like .child.
Note Layers control the cascade order regardless of specificity or source order within each layer. Later layers in the declaration beat earlier ones. Unlayered styles beat all layered styles. This solves specificity wars with third-party CSS libraries.
@scope (.scope-root) to (.scope-limit) {
/* styles apply between root andlimit */
}
example
@scope (.card) to (.card-footer) {
p {
color: #374151;
line-height: 1.6;
}
a {
color: #2563eb;
text-decoration: underline;
}
}
/* The .card-footer and its contents are excluded */
Note @scope limits where styles apply by defining both a root and an optional lower boundary. Styles only match elements between the root and the limit, not inside the limit. This provides true component scoping without build tools.
Note @property registers a custom property with a specific type, enabling the browser to animate it. Without registration, custom properties are strings that cannot be transitioned. Supported types include <color>, <length>, <angle>, <number>, <percentage>.
at propertytyped variableanimate variablecustom property typegradient animation
/* Dim page when modal is open */
body:has(dialog[open]) {
overflow: hidden;
}
/* Change grid layout based on numberof children */
.grid:has(> :nth-child(4)) {
grid-template-columns: repeat(2, 1fr);
}
.grid:has(> :nth-child(7)) {
grid-template-columns: repeat(3, 1fr);
}
/* Style label when sibling input is focused */
.field:has(input:focus) label {
color: #2563eb;
}
Note :has() can check for any condition: child state, sibling state, attribute presence, or even count of children. It enables previously impossible CSS-only patterns like conditional layouts and form state styling without JavaScript.
has patternsconditional csscount children cssmodal open stylecss only logic
/* Progress bar tied to page scroll */
.scroll-progress {
position: fixed;
top: 0;
left: 0;
height: 3px;
background: #3b82f6;
transform-origin: left;
animation: scaleProgress linear;
animation-timeline: scroll();
}
@keyframes scaleProgress {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
/* Fade in when element enters viewport */
.reveal {
animation: fadeIn linear;
animation-timeline: view();
animation-range: entry 0% entry 100%;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(30px); }
to { opacity: 1; transform: translateY(0); }
}
Note scroll() ties animation progress to scroll position of a scroll container. view() ties it to the element's visibility in the viewport. animation-range controls which portion of the scroll/view timeline the animation occupies. No JavaScript needed for scroll-linked effects.
scroll animationscroll drivenscroll progressreveal on scrollparallax cssscroll timeline
Note Anchor positioning lets you position elements relative to other elements anywhere in the DOM without a shared parent. position-try-fallbacks automatically repositions (flips) when the element would overflow the viewport. This replaces JavaScript-based tooltip/popover positioning libraries.
anchor positioningtooltip positionpopover positionposition relative to elementcss anchoring
Note light-dark() provides dark mode support inline without media queries. It uses the color-scheme property to determine which value to use. Declare color-scheme: light dark on :root to enable it. This is much simpler than managing separate media query blocks for colors.
Note The popover attribute creates a top-layer element that dismisses on outside click or Escape key, with no JavaScript required. It handles focus trapping and accessibility automatically. Style the ::backdrop pseudo-element for the overlay behind it.
popoverpopupdropdown menutoggle popuppopover apidismiss on click outside
@starting-style (Entry Animations)
syntax
@starting-style {
.element {
/* initial state before transition */
}
}
Note @starting-style defines the initial state for elements transitioning from display: none (or not yet rendered). Without it, browsers cannot animate elements that appear for the first time. Combined with allow-discrete on the display property, it enables pure CSS enter/exit animations.
Note balance evenly distributes text across lines (best for headings). pretty avoids orphaned words on the last line (best for paragraphs). stable prevents text from reflowing while the user is editing. These require no JavaScript and are progressive enhancements.
text wrapbalance textpretty textavoid orphansheading wrap
Relative Color Syntax
syntax
color: oklch(fromvar(--base) calc(l * factor) c h);
Note Relative color syntax creates color variations from a base color by decomposing it into components and modifying them with calc(). This works in any color space (oklch, hsl, srgb). It is the most powerful approach for generating color palettes from a single token.
relative colorcolor variationdarken lightencolor palettederive color