TocTable of Contents
Css baseline 2023
Overview of 2023 baseline css features
calc() keywords
CSS now supports named mathematical constants inside calc() and other math functions: e, pi, infinity, -infinity, and NaN. These bring expressive mathematical notation directly into CSS without any JavaScript.
| |
pi — Pi (~3.14159)
Useful for circular geometry calculations:
| |
e — Euler’s Number (~2.71828)
Useful for exponential scaling curves:
| |
infinity and -infinity
| |
NaN (Not a Number) resolves to 0 when used as a length. It is mostly useful as an intermediate value in complex math expressions where an invalid result needs to be handled gracefully.
These constants compose naturally with pow(), sqrt(), sin(), and cos():
| |
:dir()
The :dir() pseudo-class matches elements based on their text directionality — left-to-right or right-to-left — as determined by the document or the dir attribute.
| |
Basic Example
| |
:dir() uses the computed directionality from the HTML dir attribute or Unicode bidirectional algorithm — not just a CSS property. This makes it more semantically robust than [dir="rtl"].
Difference from [dir] Attribute Selector
| |
When to use
- Flipping directional icons (arrows, carets)
- Swapping border sides for blockquotes and list indents
- Adjusting text alignment in bidirectional documents
:nth-child() of
The of <selector> syntax for :nth-child() lets you count only elements that match a given selector, rather than counting all siblings and then filtering.
| |
Without of, :nth-child(2) picks the second child regardless of its type or class. With of .featured, it picks the second element that has the .featured class.
| |
Cap unit
The cap unit represents the cap height of the current font — that is, the approximate height of uppercase letters. This is distinct from the em unit, which is based on the full em square of the font, and from ex, which approximates the x-height of lowercase letters.
Using cap lets you size elements in relation to the visual height of capital letters rather than the theoretical em square. This makes it particularly useful when you want spacing or sizing to feel optically aligned with uppercase text in a way that em alone cannot guarantee, since cap height varies significantly between typefaces.
| |
Because cap is a font-relative unit, it responds automatically to changes in font-size and font-family, making it a reliable choice for designs where elements need to stay in proportion with the uppercase letterforms around them.
color-gamut media query
The color-gamut media feature detects the approximate color gamut of the user’s display, letting you serve enhanced wide-gamut colors to capable screens.
| |
Values are inclusive — a p3 display also matches srgb.
| |
Use for
- Vivid brand colors on capable displays
- Enhanced photography and illustration rendering
- Wide-gamut gradient backgrounds
color-mix()
color-mix() mixes two colors together in a specified color space, producing a new color. It is the CSS equivalent of blending paint.
| |
Arguments: color space, first color + percentage, second color + percentage.
| |
oklch and lab produce more perceptually natural results.
| |
Alpha values are also mixed proportionally.
Container queries
Container queries let you apply styles based on the size of a parent element rather than the viewport. A component can now respond to its own available space, making it truly reusable across any layout.
| |
When .sidebar is at least 300px wide, widgets switch to a flex layout — regardless of the viewport width.
| |
Container Units
Inside a container query, use cqi, cqb, cqw, cqh units relative to the container size:
| |
CSS typed object model
The CSS Typed Object Model (Typed OM) is a JavaScript API that exposes CSS property values as typed objects rather than plain strings, making programmatic CSS manipulation faster, safer, and easier.
| |
CSS Factory Functions
| |
Why this is better than getComputedStyle
- No string parsing — values come as typed objects with
.valueand.unit - Math is straightforward:
width.value + 10instead ofparseFloat(width) + 10 - Errors are caught early with meaningful messages
display animation
Animate To and From display: none
CSS can now animate elements to and from display: none using transition-behavior: allow-discrete combined with @starting-style, enabling true enter and exit animations without JavaScript.
| |
How does this work
- Entering
- —
@starting-styledefines where the transition begins when the element first renders - Exiting
- —
allow-discretedelaysdisplay: noneuntil the transition completes
When used on <dialog> and Popovers
| |
font-synthesis-small-caps
font-synthesis-small-caps controls whether the browser synthesises small-caps glyphs by scaling down regular capitals when the font has no true small-caps variant.
Faux small caps are regular capitals scaled down ~75%. They look thinner and lighter than the surrounding text because they are not designed at that size — unlike true small-caps, which are drawn with appropriate stroke weights.
| |
With synthesis disabled, font-variant-small-caps has no effect on fonts without true small caps — preserving typographic integrity.
| |
Pair font-synthesis-small-caps: none with a font that includes genuine small-caps, or avoid using font-variant-small-caps on fonts that lack them.
font-synthesis-style
font-synthesis-style controls whether the browser synthesises italic by algorithmically slanting the roman (upright) glyphs when the font has no true italic variant.
Synthesised italic is a geometric shear of the regular glyphs. It lacks the curves, alternate letterforms, and optical corrections of a properly drawn italic, producing a poor typographic result.
| |
When disabled, font-style: italic renders as upright text if no italic font file is available.
| |
If you load only the regular weight of a variable or web font, disable style synthesis to prevent <em> and <i> elements from rendering a faux slant:
| |
font-synthesis-weight
font-synthesis-weight controls whether the browser synthesises bold by artificially thickening glyphs when the font has no true bold variant available.
Synthesised bold adds uniform stroke weight to the regular font. The result looks uneven — spacing between letters is not adjusted, and the glyphs lack the design refinements of a true bold cut.
| |
With synthesis disabled, font-weight: bold on a font without a bold variant renders at normal weight rather than a faux bold.
| |
font-synthesis-weight is a longhand of font-synthesis:
| |
Always load the bold font file if your design uses bold text. Use font-synthesis-weight: none to catch cases where the bold variant has not loaded — it will fail visibly rather than silently substituting a degraded faux version.
font-variant-alternates
The font-variant-alternates property enables access to alternate glyph forms defined in OpenType fonts — stylistic sets, swashes, ornaments, annotations, and character variants. These are additional glyphs the type designer has included as alternatives to the standard letterforms.
| |
The @font-feature-values at-rule maps human-readable names to the numeric feature indices defined in the font, making the code more readable than using raw font-feature-settings values.
The functional values accepted by font-variant-alternates include stylistic() (a single alternate glyph), styleset() (a complete alternate style set), character-variant() (specific character alternates), swash() (decorative letterforms), ornaments() (decorative non-letter glyphs), and annotation() (enclosed or circled numerals and letters).
The availability of these features depends entirely on the font — not all fonts include alternate glyphs. Tools like the browser’s font inspector or applications like Wakamai Fondue help identify which OpenType features a specific font supports.
Hyphenate character
hyphenate-character sets the character displayed at the end of a hyphenated line when hyphens: auto breaks a word. By default, the hyphen-minus (-) is used.
| |
The Unicode hyphen character (‐, U+2010) is typographically correct for hyphenation — distinct from the hyphen-minus (-) used in code and arithmetic.
| |
Lets the browser or language setting choose the most appropriate character.
In professional publishing contexts — print stylesheets, ebooks, editorial web typography — the distinction between - and ‐ is typographically meaningful. Most readers will never notice, but the difference is there.
lh unit
The lh unit equals the computed line-height of the element it is used on. It lets you size and space things in terms of text lines, making vertical rhythm much simpler to express.
| |
Before lh, achieving one line of spacing meant calculating 1.5rem (or whatever your line height happened to be), then updating it manually if the line height changed. 1lh always stays in sync.
Difference from em and rem
1em= font-size of the current element1lh= line-height of the current element (typically ~1.5× the font-size)1rlh= line-height of the root element
Vertical Rhythm
| |
linear() easing
The linear() easing function lets you define a custom animation timing curve by providing a list of progress points. It is the foundation for recreating spring physics, bounces, and complex custom easings in pure CSS.
| |
Values are output progress (0–1) sampled at evenly spaced input intervals. Three values means: at 0% input → 0 output, at 50% → 0.5, at 100% → 1.
| |
You can specify the input position explicitly for more control:
| |
Tools like the linear() generator
let you draw a curve visually and export the linear() function.
Media query range syntax
The range syntax for media queries uses standard comparison operators (<, >, <=, >=) instead of min- and max- prefixes, making breakpoints cleaner and more intuitive.
| |
| |
The old min-width/max-width naming is counterintuitive — “min-width: 600px” means “when the viewport is at least 600px”. The range syntax reads as plain mathematics.
It also removes the off-by-one edge case: max-width: 599px and min-width: 600px left exactly 1px ambiguity. < 600px and >= 600px are unambiguous.
Nesting
CSS now supports native nesting — writing selectors inside other selectors — without any preprocessor like Sass or Less. Nested rules inherit the context of their parent.
| |
| |
& refers to the outer selector.
Media Queries Inside Rules
| |
Native nesting reduces repetition, keeps related styles co-located, and makes stylesheets much easier to scan and maintain — previously requiring a build step.
Oklab and OkLCh
oklab() and oklch() are improved perceptually uniform color spaces that fix known issues with the older Lab and LCH spaces — producing more predictable palettes, gradients, and color mixing.
| |
L (0–1), a (green–red), b (blue–yellow). Range is 0–1 unlike Lab’s 0–100.
| |
L (lightness), C (chroma), H (hue 0–360). The most intuitive of the perceptual spaces.
Because regular LCH produces unwanted hue shifts — especially blues turning purple at high chroma, OkLCh was added to correct this, giving true hue-stable chroma variation.
| |
Overflow media queries
The overflow-block and overflow-inline media features detect how the device handles content that overflows the viewport — whether it scrolls, paginates, or clips it entirely.
| |
| |
Mostly used for print stylesheets that behave differently from screen.
pow(), sqrt(), hypot(), log(), and exp()
CSS now includes pow(), sqrt(), hypot(), log(), and exp() for use inside calc() and other math contexts, enabling expressive mathematical layouts without JavaScript.
pow(base, exponent)
| |
sqrt(value)
| |
hypot(a, b, ...) — Euclidean Distance
| |
log(value, base?) and exp(value)
| |
log() defaults to natural log (base e). exp(x) returns eˣ.
Possible usage:
| |
Rlh unit
The rlh unit equals the computed line-height of the root element (<html>). It is the root-relative counterpart to lh, useful for consistent global vertical rhythm.
| |
lh vs rlh
lh= line-height of the current element (changes with font-size overrides)rlh= line-height of the root element (constant across the page)
| |
rlh is the natural companion to rem for typographically grounded layout: rem for font-size-relative sizing, rlh for line-height-relative spacing.
scripting media query
The scripting media query detects whether JavaScript is available and enabled in the user’s browser, letting you provide meaningful CSS fallbacks for no-JS environments.
| |
| |
Rather than relying on adding a js class to <html> with JavaScript, scripting lets CSS handle this detection natively.
Use for:
- Showing static content when a JS-powered widget would otherwise be empty
- Adjusting navigation for no-JS users
- Print stylesheets where JS-triggered states may not apply
sin(), cos(), tan(), asin(), acos(), atan(), and atan2()
CSS now supports sin(), cos(), tan(), asin(), acos(), atan(), and atan2() — enabling geometric calculations directly in CSS without JavaScript.
| |
atan2(y, x) takes two arguments for the correct quadrant handling.
Functions that accept an angle work with deg, rad, turn, and grad. Inverse functions return values in rad — convert with / 1rad * 1deg if needed.
Subgrid
subgrid lets a child grid participate in its parent’s track sizing, so columns and rows automatically align across nested components without any duplication of grid definitions.
The problem without subgrid is that if the parent changes, the child must be manually updated.
| |
With subgrid:
| |
The child’s columns mirror the parent’s exactly — always.
subgrid can be uses on both axes
| |
Best used for card grids:
| |
Card images, titles, and footers align across all cards automatically.
Update frequency media query
The update media feature describes how quickly the output device can refresh its display — letting you disable animations for e-ink screens and print output that cannot handle them.
| |
update is related to prefers-reduced-motion
update— hardware capability (can the screen even refresh?)prefers-reduced-motion— user preference (do they want reduced motion?)
Check both for the most accessible experience:
| |
:user-valid and :user-invalid
:user-valid and :user-invalid are like :valid and :invalid — but they only apply after the user has interacted with the field, preventing error styles from showing on page load before the user has typed anything.
The problem with :invalid is that users see errors before they’ve done anything.
| |
These styles only activate after the user has interacted with and then left the field.
| |
When they trigger
:user-invalid— after the user edits the field and it fails validation:user-valid— after the user edits the field and it passes validation
color()
The color() function lets you specify colors in color spaces beyond standard sRGB — including display-p3, a98-rgb, prophoto-rgb, and more — unlocking richer, more vivid colors on capable displays.
| |
Values are in the range 0–1 for each channel (red, green, blue in display-p3).
Supported color spaces:
srgb— standard web colorsdisplay-p3— wider gamut, ~25% more colors than sRGBa98-rgb— Adobe RGB, used in print workflowsrec2020— very wide gamut for HDR videoxyz,xyz-d50,xyz-d65— device-independent
| |
CSS @counter-style
The @counter-style at-rule lets you define entirely custom counter styles for lists, going far beyond the built-in disc, decimal, or lower-roman options.
| |
Each list item now gets a 👍 as its marker.
system— how symbols are cycled (cyclic,numeric,alphabetic,additive)symbols— the characters or images used as markerssuffix— what follows the marker (default is". ")prefix— what precedes the markerrange— which counter values this style applies to
| |
extends lets you tweak an existing style rather than building from scratch.
Use it for:
- Emoji bullet points
- Custom legal or academic numbering (1.1, 1.2…)
- Language-specific list conventions
image-set()
image-set() is the CSS equivalent of the HTML srcset attribute — it lets you provide multiple versions of a background image at different resolutions, and the browser picks the most appropriate one.
| |
On a high-DPI screen, the browser uses hero@2x.jpg. On a standard screen, it uses hero.jpg.
Resolution descriptors:
| |
The type() function lets you provide modern formats with fallbacks:
| |
Include -webkit-image-set() for wider compatibility alongside the standard version.
Lab and LCH
CSS lab() and lch() express colors in perceptually uniform color spaces — meaning equal numerical steps produce equal-looking differences in color, which sRGB does not guarantee.
| |
Creating color palettes in sRGB can produce steps that look visually uneven — some jumps appear larger than others. Lab and LCH produce palettes that look evenly spaced to the human eye.
oklch() is a newer, improved version of LCH with better perceptual uniformity. Many design systems are adopting it for design tokens.
| |
Two-value display property
CSS now supports a two-value syntax for display that separates the outer display type (how the element participates in layout) from the inner display type (how it lays out its children).
| |
The traditional single-value keywords (block, inline-flex, grid) are shorthand for combined inner and outer values. The two-value syntax makes this explicit and more logical.
Common mappings
| Legacy | Two-value |
|---|---|
block | block flow |
inline | inline flow |
inline-block | inline flow-root |
flex | block flex |
inline-flex | inline flex |
grid | block grid |
Most developers still use the legacy single-value keywords — they are shorter and widely understood. The two-value syntax is more useful for understanding how display works conceptually and when teaching CSS.
CSS contain-intrinsic-size
When you use CSS containment (content-visibility: auto), the browser skips rendering off-screen elements. But without a size hint, it treats them as zero-sized, causing layout jumps. contain-intrinsic-size solves this.
contain-intrinsic-size tells the browser how large a contained element probably is before it has been rendered.
| |
Here, the browser reserves 200px of height for each .card even while it is off-screen.
Using auto as a value lets the browser remember the last known rendered size and use it as the hint on subsequent renders — the best of both worlds.
| |
- Prevents large scroll position jumps
- Improves Cumulative Layout Shift (CLS) scores
- Pairs perfectly with
content-visibility: autofor long pages
CSS counter-set
The counter-set property allows you to assign a specific value to a CSS counter, making it easy to control numbering in lists, chapters, or any sequenced content.
Unlike counter-reset (which always resets to zero or a default) and counter-increment (which adds to a counter), counter-set lets you jump directly to any number you choose.
| |
This sets the section counter to 5 immediately, so the next increment will produce 6.
Combine counter-set with counter-increment and content in ::before pseudo-elements for fully custom, CSS-driven numbering systems without touching your HTML markup.
Hyphenation
The hyphens property controls whether the browser automatically inserts hyphens when breaking long words across lines. It is a simple but effective way to improve text flow in narrow columns.
| |
| |
The lang attribute on your HTML element is required for auto to work correctly, as the browser uses language-specific hyphenation dictionaries.
| |
Even with hyphens: manual, you can place soft hyphens in HTML to suggest break points:
| |
The soft hyphen (­) is invisible unless the line breaks there.
It’s best for justified text, narrow sidebars, and responsive layouts where long words cause overflow.
Css :has()
The long awaited ‘parent’ selector :has() finally landed in 2023 in all major browsers.
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
| |