TocTable of Contents
Css baseline 2020
Overview of 2020 baseline css features
All the features are Widely available because they all passed 36 months since being newly available.
::placeholder
The ::placeholder pseudo-element styles the placeholder text displayed in an <input> or <textarea> when the field is empty and no value has been entered. It allows the placeholder’s color, font, and other text properties to be customised.
| |
Browser default placeholder styling is typically a greyed-out version of the input’s text color. ::placeholder lets you override this with any color, opacity, font style, or text transformation. Only a subset of CSS properties apply — primarily text-related properties and opacity.
A common accessibility consideration: placeholder text should not be used as a substitute for a visible label. The contrast ratio of placeholder text is often insufficient for users with low vision, and it disappears when the user starts typing — making it unsuitable as the only description of what a field expects. Visible, persistent labels are always preferable, with placeholder text serving as an optional additional hint.
::placeholder is distinct from :placeholder-shown, which targets the input element itself while its placeholder is visible, rather than the placeholder text.
:default
The :default pseudo-class matches form elements that are the default option in a group of related elements. The most common use cases are the default submit button in a form, the initially selected option in a <select>, and the pre-checked state of checkboxes and radio buttons.
| |
For <button> and <input type="submit"> elements, :default matches the button that would be activated by pressing Enter in the form. For radio buttons and checkboxes, it matches the element that has the checked attribute in the HTML source — the initially selected state — even after the user has changed the selection. This distinguishes it from :checked, which always reflects the current state.
:default is useful for communicating which choice is recommended or pre-selected, and for visually distinguishing the primary action in a form from secondary actions, providing helpful affordance to users without requiring additional markup or classes.
:focus-within
The :focus-within pseudo-class matches an element when it or any of its descendants has focus. It propagates focus state up the DOM tree, allowing ancestor elements to respond to focus events deep within their subtree.
| |
A common use case is styling a form field’s label or wrapper when the input inside receives focus — previously this required JavaScript to add and remove classes. :focus-within makes it a pure CSS operation.
It is also useful for showing contextual UI on keyboard navigation — a dropdown menu that reveals its options when any item inside it is focused, or a card that shows additional actions when a user tabs into it.
:focus-within applies to any element that is a focusable descendant — inputs, buttons, links, and elements with tabindex. It remains active as long as any descendant retains focus, making it suitable for compound widgets where focus moves between several related elements.
:placeholder-shown
The :placeholder-shown pseudo-class matches an input or textarea element while its placeholder text is currently displayed — that is, when the field is empty and the user has not yet typed anything.
| |
A well-known use of :placeholder-shown is the floating label pattern — a label that sits inside the input like placeholder text and floats above it when the user types:
| |
The trick relies on input:not(:placeholder-shown) to detect when the field has content, using a transparent placeholder to keep the pseudo-class active until the user types.
:placeholder-shown is distinct from ::placeholder, which styles the placeholder text itself. :placeholder-shown targets the input element when placeholder text is visible; ::placeholder targets the placeholder text’s appearance directly.
:scope (pseudo-class)
The :scope pseudo-class matches the element that is the scope reference point for a set of selectors. In a stylesheet, :scope is equivalent to :root — it matches the <html> element. Its primary utility is inside @scope blocks, where it refers to the scoping root element itself.
| |
Inside a @scope block, :scope targets the scoping root — the .card element in the example above — giving you a way to style the component root directly from within the scoped rule set, without breaking out of the scope or repeating the selector.
:scope is also used in JavaScript with element.querySelectorAll(':scope > .child'), where it refers to the element on which querySelectorAll is called, making it possible to select direct children of that specific element rather than any matching elements in the document. This JavaScript use case predates the CSS @scope rule and remains the most widely encountered context for :scope.
all
The all property is a shorthand that resets every CSS property — except direction and unicode-bidi — to a specified value in a single declaration. It accepts the CSS-wide keywords: initial, inherit, unset, and revert.
| |
all: revert is the most practical value for component isolation — it rolls styles back to what the browser’s default stylesheet would apply, giving a clean and familiar baseline. all: initial is more aggressive, stripping even browser defaults like display: block on <div>.
all: unset combined with deliberate re-application of only the needed properties is a pattern used to build components that are immune to cascade bleed from external stylesheets. This is useful in widget libraries, email rendering contexts, or anywhere that a component must look consistent regardless of what styles surround it.
Note that all does not reset custom properties (--*) — those are unaffected and continue to inherit normally.
background-blend-mode
The background-blend-mode property sets how an element’s background layers blend with each other. When an element has multiple backgrounds — a combination of images, gradients, and a background color — background-blend-mode determines the compositing mode applied between them.
| |
The blend modes available are the same as those for mix-blend-mode: normal, multiply, screen, overlay, darken, lighten, color-dodge, color-burn, hard-light, soft-light, difference, exclusion, hue, saturation, color, and luminosity.
background-blend-mode only blends backgrounds within the same element — it does not affect how the element blends with content behind it in the stacking context. For that, mix-blend-mode is used instead. When multiple background layers are present, comma-separated values assign a blend mode to each layer individually.
caret-color
The caret-color property sets the color of the text insertion cursor — the blinking vertical line that indicates where typed text will be inserted in an editable element. It applies to <input>, <textarea>, and any element with contenteditable.
| |
The default value auto causes the caret to use currentColor — the element’s text color — which is usually appropriate. Specifying an explicit color allows the caret to match a brand color or stand out against the input’s background color.
caret-color: transparent hides the caret entirely, which can be useful for custom cursor implementations or for building syntax-highlighted editors where a custom cursor is rendered separately.
The property accepts any valid CSS color value. It does not control the caret’s shape or blink rate — those remain under the control of the operating system. On some platforms, the caret may be rendered as a block or underline cursor rather than a vertical bar depending on system accessibility settings, and caret-color colors that cursor shape accordingly.
Case-insensitive attribute selector
CSS attribute selectors are case-sensitive by default for attribute values. The i flag (case-insensitive modifier) added to an attribute selector makes the value match case-insensitively, regardless of how the attribute value is written in the HTML.
| |
The i flag is placed inside the brackets, after the value, separated by whitespace. It applies only to the attribute value — the attribute name itself is always matched case-insensitively in HTML (as HTML attribute names are case-insensitive by nature).
A complementary s flag enforces case-sensitive matching explicitly, which is the default behaviour for HTML attribute values but useful in XML or SVG contexts where case sensitivity is more significant.
Case-insensitive matching is most practical for file extension checks in href attributes, type attributes where user agents may produce inconsistent casing, and custom data-* attributes populated from external data sources where casing cannot be guaranteed.
COLRv0
COLRv0 is the first version of the COLR (Color) OpenType font table format, which allows font glyphs to be composed of multiple colored layers. A COLRv0 font stores each color glyph as a stack of single-color glyph layers, with a corresponding CPAL (Color Palette) table that defines the palette of colors used.
| |
COLRv0 fonts are widely supported across modern browsers and operating systems, and are the format behind many system emoji fonts. The palette colors defined in the font can be customised using @font-palette-values and the font-palette property, allowing a single font file to be recolored for different themes or brand contexts.
COLRv1 (the second version) significantly extends the format with gradient fills, compositing operations, and affine transforms within glyphs, enabling much richer color font artwork. COLRv0 remains relevant for broad compatibility and is the baseline color font format that all modern browsers support reliably.
column-span
The column-span property allows an element to span across all columns in a multi-column layout. It accepts two values: none (the default, where the element stays within a single column) and all (where the element spans the full width of the multi-column container).
| |
When an element with column-span: all appears in the flow, the content before it fills the columns above it, the spanning element is placed across the full width, and the content after it begins a new set of columns below. This is the standard pattern for chapter headings, pull quotes, and full-width images in editorial multi-column layouts.
A spanning element effectively divides the multi-column container into two independent column sets — the content above the span and the content below it are balanced and laid out separately. The spanning element itself creates a new block formatting context.
Only none and all are currently defined — partial column spanning (spanning two of three columns, for example) is not supported.
CSS revert
The revert keyword is a CSS-wide value that resets a property to the value it would have if no author styles had been applied — in other words, the browser’s built-in default.
| Keyword | Resets to |
|---|---|
initial | CSS specification default |
inherit | Parent’s computed value |
unset | Inherited or initial |
revert | Browser user-agent stylesheet |
revert is uniquely useful because browser defaults are often more meaningful than specification defaults. For example, display: revert on a <div> gives back block, while display: initial gives inline.
| |
This single declaration removes every custom style and restores the browser’s native look.
CSS.escape()
CSS.escape() is a static method on the CSS JavaScript interface that escapes a string for use as part of a CSS selector. It produces a string where any characters that would be invalid or have special meaning in a CSS selector are properly escaped, preventing selector injection errors or unintended selector behaviour.
| |
Without CSS.escape(), building a CSS selector from user-provided or dynamic data requires manual escaping logic that is easy to get wrong. Characters that need escaping include digits at the start of an identifier, spaces, and many punctuation marks.
CSS.escape() is particularly important for:
- IDs or class names that start with a digit
- Values containing spaces, slashes, colons, or other special characters
- Any selector component derived from user input or database content
The method is part of the CSS Houdini family of APIs and is available in all modern browsers. For environments without CSS.escape(), the cssesc npm package provides equivalent functionality.
CSS.supports()
CSS.supports() is a static JavaScript method that checks whether the browser supports a given CSS feature, returning a boolean. It is the programmatic equivalent of the @supports at-rule, allowing feature detection to be performed in JavaScript rather than CSS.
| |
The two-argument form takes a property name and a value as separate strings. The single-argument form accepts a condition string using the same syntax as @supports, including and, or, not, and the selector() function.
CSS.supports() is useful when CSS feature detection needs to drive JavaScript behaviour — for example, deciding which polyfill to load, which library to initialise, or which code path to follow based on what the browser can handle. For purely CSS-driven behaviour differences, the @supports at-rule is preferable as it keeps the feature detection in CSS where it belongs.
display: flow-root
display: flow-root creates a new block formatting context (BFC) for an element without any side effects — no clipping, no overflow change, no opacity shift. It is the clean, purpose-built solution for two classic CSS problems: containing floated children and preventing margin collapse.
| |
Before display: flow-root, creating a new BFC required exploiting the side effects of other properties — overflow: hidden was the most common hack (it contains floats but clips content), along with float: left, display: inline-block, or position: absolute (each with their own layout consequences).
display: flow-root does exactly one thing: it establishes a new block formatting context. The element itself participates in the normal block flow of its parent, behaves as a block-level box, and has no visual side effects beyond containing its floats and preventing margin collapse.
| |
It is the modern, semantic replacement for clearfix patterns and overflow: hidden BFC hacks, and should be the default choice when a new block formatting context is all that is needed.
dominant-baseline
The dominant-baseline property specifies the baseline used to align a box’s text and inline content. It is primarily relevant in SVG and in CSS contexts involving mixed scripts or vertical text, where different baselines — alphabetic, ideographic, central, mathematical — are appropriate for different content types.
| |
The dominant baseline establishes the reference point against which child elements align when alignment-baseline or vertical-align is set to baseline. Changing it shifts where that alignment anchor sits relative to the text.
In practice, dominant-baseline is most commonly encountered in SVG — particularly in data visualisations and icon systems — where precise text alignment relative to graphical elements is needed. In HTML, vertical-align and the newer text-box property typically handle similar concerns, but dominant-baseline remains the appropriate tool when working directly with SVG <text> elements or mixing SVG and HTML content.
font-display
The font-display descriptor inside @font-face controls how the browser behaves during the period between a page loading and the custom font becoming available. It manages the trade-off between showing invisible text, showing a fallback font, or waiting for the custom font before rendering anything.
| |
The five values represent different strategies:
auto leaves the decision to the browser — typically similar to block. block gives the font a short block period (usually 3 seconds) during which text is invisible, then swaps to the custom font when ready, with an indefinite swap period. swap immediately shows a fallback font and swaps to the custom font whenever it loads — no invisible text, but potentially a visible layout shift. fallback shows invisible text very briefly (100ms), then a fallback, and only swaps within a 3-second window — after that the fallback remains. optional is the most conservative — the browser decides whether to use the font based on connection speed, and may never swap if it hasn’t loaded quickly enough.
swap is the most commonly recommended value for body text and important content — it avoids invisible text while still using the custom font. optional is best for non-essential decorative fonts where a layout shift would be disruptive. block is appropriate for icon fonts where showing a fallback letter character would be worse than brief invisible text.
font-kerning
The font-kerning property controls whether the browser uses kerning information stored in the font. Kerning adjusts the spacing between specific pairs of characters — such as “AV”, “To”, or “WA” — to produce optically even spacing that metric-based character widths alone cannot achieve.
| |
auto leaves the decision to the browser, which typically applies kerning to larger text sizes but may skip it at small sizes for performance. normal explicitly enables kerning regardless of font size. none disables it entirely, which can be useful in contexts where consistent character widths are needed — such as tabular data or code.
Kerning is part of the broader OpenType feature system. It can also be controlled via font-feature-settings: "kern" 1 (enable) or "kern" 0 (disable), though font-kerning is the higher-level, more readable property for this specific feature.
The visual impact of kerning is most noticeable at large display sizes — headlines and hero text benefit most from careful kerning, while body text at typical reading sizes shows less difference.
font-stretch
The font-stretch property selects a font face based on its width — how condensed or expanded the letterforms are relative to the normal width of that typeface. It is the legacy name for what is now more accurately expressed as font-width, though both properties are equivalent and both are supported.
| |
Keyword values include ultra-condensed, extra-condensed, condensed, semi-condensed, normal, semi-expanded, expanded, extra-expanded, and ultra-expanded. These map to percentage values from 50% to 200%, which are also accepted directly:
| |
For non-variable fonts, the browser selects the closest available face from the font family that matches the requested width. For variable fonts with a wdth axis, any percentage value within the supported range can be used for fine control.
font-stretch is most commonly used in editorial and display typography where condensed or expanded type is a deliberate stylistic choice — fitting more text into a constrained space, or creating a wide, expansive feel for headlines. For new code, font-width is the preferred property name as it more accurately describes what is being controlled, though font-stretch remains fully supported.
font-variant-caps
The font-variant-caps property selects alternate glyphs for capital letters, primarily for rendering small capitals. It controls which capitalisation variant the font uses, drawing from OpenType features built into the font file.
| |
small-caps is the most commonly used value — it replaces lowercase letters with smaller versions of the capital letterforms, ideal for subheadings, abbreviations, and running headers. all-small-caps converts both uppercase and lowercase to small capitals, producing a more uniform typographic color.
petite-caps targets fonts that include an even smaller caps variant, typically sized to match the x-height precisely. titling-caps accesses special capital letterforms designed for large display sizes, where standard capitals may appear too heavy or wide.
If the font does not include true small caps, the browser falls back to synthesised small caps — scaled-down regular capitals — which are typically less refined than designed ones. font-synthesis: small-caps controls whether this synthesis is permitted.
font-variant-east-asian
The font-variant-east-asian property controls the use of alternate glyphs for East Asian scripts — Chinese, Japanese, and Korean (CJK). It provides access to OpenType features that select between different regional glyph standards, width variants, and ruby annotation forms.
| |
The glyph set values — jis78, jis83, jis90, jis04, simplified, and traditional — select which regional or historical character standard to draw from. Many CJK characters have different acceptable forms depending on the target language and standard, and a font may include multiple variants.
Width values control whether CJK characters are set at full width (square ideographic spacing) or proportional width. ruby selects smaller, simplified glyph forms optimised for use as phonetic annotations above or beside CJK characters.
The effectiveness of all these values depends entirely on the font including the relevant OpenType features.
font-variant-ligatures
The font-variant-ligatures property controls which ligature types are used in text rendering. Ligatures are single glyphs that replace two or more adjacent characters — “fi” and “fl” are the most common examples, where the dot of the “i” or the crossbar of the “f” would otherwise collide awkwardly.
| |
The ligature categories are: common ligatures (fi, fl, ff, ffi, ffl), discretionary ligatures (decorative combinations the font designer has chosen to include), historical ligatures (older forms no longer in common use), and contextual alternates (glyphs that change shape based on surrounding characters).
Common ligatures are enabled by default in most browsers. Discretionary and historical ligatures are off by default and must be explicitly enabled. Contextual alternates (contextual / no-contextual) control whether characters adapt their shape based on adjacent characters — common in script and handwriting fonts.
The normal value restores typical browser behaviour (common ligatures on, others off). none disables all ligatures. Individual categories can be combined: font-variant-ligatures: common-ligatures discretionary-ligatures contextual.
font-variant-numeric
The font-variant-numeric property controls the rendering of digits and related glyphs — fractions, ordinals, and zero — using OpenType numeric features built into the font. It allows for fine typographic control over how numbers appear in different contexts.
| |
The two primary axes are figure style and figure spacing. Figure style: lining-nums (uniform height, sits on the baseline) vs oldstyle-nums (varying heights, like lowercase letters). Figure spacing: proportional-nums (varying widths, like regular text) vs tabular-nums (fixed widths for column alignment).
Fraction variants — diagonal-fractions and stacked-fractions — render combinations like “1/2” as proper typographic fractions using dedicated glyphs. ordinal enables superscript suffixes for ordinal numbers. slashed-zero adds a diagonal slash to the zero glyph to distinguish it from the capital O, useful in code and technical contexts.
Multiple values can be combined: font-variant-numeric: oldstyle-nums proportional-nums diagonal-fractions.
font-variation-settings
The font-variation-settings property provides low-level access to variable font axes using four-character axis tags and numeric values. Variable fonts contain multiple design variations along one or more axes — weight, width, slant, optical size, and custom axes — all within a single font file.
| |
Standard registered axes have four-character lowercase tags: wght (weight), wdth (width), ital (italic), slnt (slant), and opsz (optical size). Custom axes defined by the type designer use uppercase tags.
Where high-level CSS properties exist for standard axes — font-weight for wght, font-width/font-stretch for wdth, font-style for ital and slnt, font-optical-sizing for opsz — those should be preferred. font-variation-settings is most useful for custom axes that have no CSS property equivalent, or for animating axes with @keyframes:
| |
Note that font-variation-settings is not inherited as individual axis values — it replaces the whole value, so setting a partial list will reset any axes not included to their defaults.
Host
The :host pseudo-class, used inside a shadow DOM stylesheet, selects the shadow host — the element in the light DOM to which the shadow root is attached. It allows a web component to style its own host element from within its encapsulated styles.
| |
:host accepts an optional selector argument — :host(selector) — which makes it match only when the host element also matches the given selector. This is how a component responds to attributes, classes, or states set by the consumer of the component from outside the shadow DOM.
Styles set on the host element from outside the shadow DOM (in the light DOM) take priority over :host styles, because the shadow DOM encapsulation does not prevent the host element from being styled externally — it only encapsulates the component’s internal styles from affecting the outside. This means :host styles act as sensible defaults that consumers can override.
HSL
The hsl() function defines colors using the HSL color model — Hue, Saturation, and Lightness — which maps colors to a cylindrical representation that is more intuitive for human reasoning about color relationships than RGB.
| |
Hue is expressed as an angle (0–360°) around the color wheel — 0° and 360° are red, 120° is green, 240° is blue. Saturation ranges from 0% (grey) to 100% (fully saturated). Lightness ranges from 0% (black) to 100% (white), with 50% being the pure color.
The modern syntax uses space-separated values without commas, and alpha is added with /: hsl(220 80% 55% / 0.5). The legacy comma syntax hsl(220, 80%, 55%) and hsla(220, 80%, 55%, 0.5) are still supported.
HSL is more intuitive than rgb() for creating color variations — lightening, darkening, or desaturating a color means adjusting a single value. However, HSL is not perceptually uniform — the same lightness value produces colors that appear visually brighter or darker depending on the hue. For perceptually consistent color work, oklch() is a better choice as its lightness channel produces more visually predictable results across all hues.
isolation
The isolation property controls whether an element creates a new stacking context, independent of whether it has any properties that would typically trigger one. Setting isolation: isolate forces the creation of a new stacking context without any visual side effects.
| |
The primary use case is containing mix-blend-mode. By default, an element with mix-blend-mode blends with everything behind it in its stacking context — including content outside a parent component. Wrapping the component in an element with isolation: isolate creates a new stacking context boundary, so blend modes inside it only composite against content within the isolated group, not against the wider page.
| |
A second use case is predictable z-index management. Because isolation: isolate creates a new stacking context without affecting opacity, transform, or other properties, it is a clean way to contain the z-index scope of a component — preventing internal z-index values from competing with unrelated elements on the page.
isolation: auto (the default) means no new stacking context is created unless another property requires it. isolation: isolate is the only other value.
Layout direction override
The direction and unicode-bidi properties control the text direction and bidirectional text handling for an element. Together they can override the Unicode bidirectional algorithm to force a specific layout direction, independent of the language of the content.
direction sets the base text direction: ltr (left to right, the default for most languages) or rtl (right to left, for Arabic, Hebrew, and other RTL languages).
| |
unicode-bidi controls how the Unicode bidirectional algorithm is applied. The key values are normal (default), embed, isolate, bidi-override, and isolate-override.
| |
bidi-override is the most aggressive — it ignores the Unicode bidirectional properties of individual characters and forces everything to the specified direction. isolate isolates the element’s content from the surrounding bidi context, preventing its directionality from affecting adjacent content.
In HTML, the dir attribute and the <bdi> and <bdo> elements handle bidirectional text semantically and are generally preferred over CSS direction overrides, which lack semantic meaning and can affect accessibility. The CSS properties are most appropriate for dynamic direction changes via JavaScript or for styling text in complex bidi layouts.
Link selectors
CSS provides two pseudo-classes specifically for styling hyperlinks based on their visited state: :link and :visited. These are the original link-related pseudo-classes and form part of the classic “LVHA” ordering rule for link styles.
| |
:link matches anchor elements with an href attribute that have not been visited. :visited matches those that the browser history records as visited. The traditional recommendation to declare these in LVHA order (:link, :visited, :hover, :active) ensures each state overrides the previous correctly due to specificity being equal.
For privacy reasons, browsers significantly restrict what CSS properties can be applied to :visited links. Only color, background-color, border-color, outline-color, and the color values of column-rule-color and text-decoration-color can be changed — and JavaScript cannot read the computed styles of visited links to prevent history sniffing. These restrictions mean :visited styling is limited to color changes only.
:any-link is a newer pseudo-class that matches any element with an href — both :link and :visited — making it a convenient selector when you want to style all links regardless of visited state.
min-content and max-content
min-content and max-content are intrinsic size keywords that size an element based on the natural dimensions of its content, rather than the available space in the container.
min-content sizes the element to the smallest it can be without causing overflow — for text, this is the width of the longest unbreakable word or inline element. For images and replaced elements, it is the element’s natural size.
max-content sizes the element to be as wide as it needs to be to fit all content on a single line, without any wrapping. For text this means no line breaks at all; for a container it means the sum of all its content’s natural widths.
| |
Both keywords are valid in width, height, min-width, max-width, and as grid track sizes. In grid layout they are particularly powerful — minmax(min-content, 1fr) creates a column that will not shrink below its minimum content size but will grow to fill available space.
They are also used implicitly: a floated element or an element with display: inline-block uses max-content sizing by default, while a flex or grid item may be constrained to min-content when space is tight.
mix-blend-mode
The mix-blend-mode property sets how an element’s content blends with the content behind it in the stacking context — the elements and backgrounds beneath it in the document. It applies Photoshop-style compositing modes to web elements.
| |
The available blend modes are: normal, multiply, screen, overlay, darken, lighten, color-dodge, color-burn, hard-light, soft-light, difference, exclusion, hue, saturation, color, and luminosity.
mix-blend-mode blends the element with everything behind it in its stacking context. The isolation property on an ancestor can contain blending to a specific subtree — isolation: isolate prevents an element’s children from blending with content outside of it.
Unlike background-blend-mode, which composites multiple backgrounds within a single element, mix-blend-mode composites the element itself against the content that exists behind it in the rendering stack. The two can be combined for complex multi-layer effects.
prefers-color-scheme media query
The prefers-color-scheme media feature detects whether the user’s operating system is set to a light or dark color theme, allowing CSS to adapt the page’s color palette automatically to match the system preference.
| |
The two values are light (the user prefers a light theme, or has no preference) and dark (the user prefers a dark theme). The no-preference value was defined in earlier drafts but has been removed — if the user has not set a preference, light is the fallback.
Using CSS custom properties as the adapter layer — defining all color values as variables on :root and overriding them in the dark mode media query — is the cleanest approach. All components and elements that reference these variables automatically update without needing their own media query blocks.
prefers-color-scheme works alongside color-scheme — the media query handles custom design colors, while color-scheme handles browser-rendered UI elements. Together they provide a complete dark mode implementation. The preference can also be detected and observed in JavaScript via window.matchMedia('(prefers-color-scheme: dark)').
prefers-reduced-motion media query
The prefers-reduced-motion media feature detects whether the user has enabled the “reduce motion” accessibility setting in their operating system. Respecting this preference is an important accessibility requirement for users who experience discomfort, dizziness, or seizures from animated content.
| |
The two values are no-preference (the user has not requested reduced motion, the default) and reduce (the user has enabled the preference).
A more nuanced approach is to default to no animation and only add motion for users who are fine with it — this is sometimes called the “motion-first” pattern:
| |
This approach is particularly valuable for users who rely on reduced motion but whose browser may not perfectly apply the global suppression override.
Not all motion needs to be removed — the preference is for “reduced” motion, not “no” motion. Subtle, functional transitions (like a button changing color) may still be appropriate, while vestibular-triggering effects (large-scale movement, parallax, spinning, zooming) should be suppressed.
RGB
The rgb() function defines colors using the RGB color model — Red, Green, and Blue — expressed as values from 0 to 255 (integers) or 0% to 100% (percentages). It is one of the foundational color functions in CSS, corresponding directly to how displays mix colored light.
| |
The modern syntax uses space-separated values, with alpha added after a slash: rgb(255 0 0 / 0.5). The legacy comma syntax rgb(255, 0, 0) and rgba(255, 0, 0, 0.5) are still supported — rgba() is simply an older alias for rgb() with alpha.
Hex color notation (#rrggbb) is shorthand for rgb() — #3b82f6 and rgb(59 130 246) are identical values. The eight-digit hex format #rrggbbaa includes alpha.
RGB operates in the sRGB color space, which is the standard for most web content and corresponds to the color gamut that standard displays can reproduce. For colors beyond sRGB — the wider gamut available on modern displays — color(display-p3 r g b) or oklch() are more appropriate. For colors that are easier to reason about in terms of hue and lightness relationships, hsl() or oklch() are more intuitive than raw RGB values.
Safe area inset environment variables
Safe area inset environment variables provide the measurements of the areas on a device screen that are obscured by physical features — such as a notch, home indicator, rounded corners, or camera cutout — and should not be covered by interactive content. They are accessed using the env() function.
| |
The four variables are safe-area-inset-top, safe-area-inset-right, safe-area-inset-bottom, and safe-area-inset-left. On devices without obstructions they resolve to 0.
To activate safe area insets on iOS devices, the viewport meta tag must include viewport-fit=cover:
| |
Without this, the browser automatically constrains content to the safe area and the inset values are always zero. With viewport-fit=cover, content can extend under the notch and home indicator, and the CSS inset variables become meaningful for pushing interactive elements clear of obstructions.
The env() function accepts a fallback value as a second argument: env(safe-area-inset-bottom, 0px).
will-change
The will-change property hints to the browser that an element is expected to change in a specific way, allowing it to apply optimisations in advance — typically by promoting the element to its own compositor layer. This can improve animation performance by avoiding layout and paint recalculations during the animation.
| |
The most common values are transform and opacity, which are the two properties most frequently animated and most amenable to GPU compositing. Other accepted values include scroll-position, contents, and any animatable CSS property name.
will-change should be used sparingly and only on elements that genuinely need it. Applying it broadly — such as * { will-change: transform } — consumes significant memory and GPU resources, as each hinted element gets its own compositor layer. The browser’s default behaviour already handles most animations well without hints.
Best practice is to apply will-change just before an animation starts and remove it afterward, using JavaScript:
| |
will-change also creates a new stacking context, which can affect z-index behaviour in the same way as transform and opacity.
Q Unit
The Q unit stands for quarter-millimetre (0.25mm). It is a physical length unit intended primarily for print stylesheets, where exact physical dimensions are critical.
| Q value | Millimetres | Points (approx) |
|---|---|---|
| 4Q | 1mm | ~2.8pt |
| 16Q | 4mm | ~11.3pt |
| 48Q | 12mm | ~34pt |
Background clip
Setting background-clip: text clips any background — gradient, image, or color — to the exact shape of the text characters, creating eye-catching typographic effects in pure CSS.
Setting color: transparent lets the clipped background show through the text.
| |
Animated text background
Conic gradients
conic-gradient() produces a gradient where color transitions happen around a central point, rather than along a line (linear) or from a centre outward (radial).
| |
Font optical sizing
font-optical-sizing enables or disables automatic optical size adjustments in variable fonts that include an opsz axis. When active, the browser fine-tunes letterform details to match the rendered size.
Line break
line-break sets how to break lines of Chinese, Japanese, or Korean (CJK) text when working with punctuation and symbols.
See: line-break
min(), max(), and clamp()
min(), max(), and clamp()
These three comparison functions make responsive design much more fluid by letting any CSS property value adapt within defined boundaries.
min() — Use the Smallest Value
| |
The container is 90% of the viewport, but never wider than 800px.
max() — Use the Largest Value
| |
Font size scales with the viewport but is always at least 1rem.
clamp() — Stay Within a Range
| |
clamp(min, preferred, max) — the font is 5vw, but never smaller than 1.5rem or larger than 3rem.
All three functions accept mixed units in a single expression:
| |
A single clamp() declaration often replaces two or three @media breakpoints for font sizes and spacing.
Overflow shorthand
The overflow property is a shorthand for overflow-x and overflow-y. Understanding its two-value syntax and newer values gives you precise control over scrollable and clipped content.
| |
When two values are given, the first is overflow-x and the second is overflow-y.
| Value | Behaviour |
|---|---|
visible | Content overflows — no clipping |
hidden | Clips and creates block formatting context |
scroll | Always shows scrollbars |
auto | Scrollbar appears only when needed |
clip | Clips without creating a scroll container |
Page orientation
page-orientation is a descriptor used inside @page rules that rotates the page content when printing. It is particularly useful for print stylesheets that include wide tables or charts alongside normal portrait content.
| |
This rotates any .wide-table element onto a landscape page when printing.
| Value | Effect |
|---|---|
upright | Default, no rotation |
rotate-left | Rotates content 90° counter-clockwise |
rotate-right | Rotates content 90° clockwise |
For full landscape pages, combine page-orientation with the size descriptor:
| |
Shadow Parts
The shadow DOM normally blocks external CSS. Shadow Parts give web component authors a way to expose specific internal elements for styling, without opening the entire shadow tree.
Inside the shadow DOM template, add the part attribute to elements you want to expose:
| |
::part() does not support combinators or pseudo-classes (except :hover and :focus ).
With Shadow Parts component authors retain control of their internals while allowing consumers to apply brand and theme styles cleanly.
steps() Easing
The steps() timing function divides an animation into equal, discrete jumps instead of a smooth transition. It is the secret behind sprite-sheet animations and typewriter effects.
| |
This splits the animation into 8 equal steps, jumping between positions rather than interpolating smoothly.
| |
These are shorthand values: step-start equals steps(1, start) and step-end equals steps(1, end).
Text orientation
text-orientation is used in combination with writing-mode: vertical-* to control how characters are oriented — whether they stand upright or are rotated sideways.
Text underline offset
text-underline-offset sets the distance of the line when using text-decoration: underline
| |
Some underlined text
Text underline position
text-underline-position sets the position of the line when using text-decoration: underline
| |
Some underlined text