Caption

.caption

.caption — the fifth typographic role: one line of small, quieted text.

Examples

The fifth typographic role

View “The fifth typographic role” as

Milano Centrale

Departures and arrivals, from the operator's own board.

Body copy is the middle of the scale. The lede is one step up and quieted; a caption is one step down and quieted, so the two are never read as each other.

Updated at 09:41. Times come from the operator's own board.

Times are local. Delays under a minute are not shown.

<div class="stack">
  <h1 class="page-title">Milano Centrale</h1>
  <p class="page-lede">Departures and arrivals, from the operator's own board.</p>
  <p>Body copy is the middle of the scale. The lede is one step up and quieted; a caption is one step down and quieted, so the two are never read as each other.</p>
  <p class="caption">Updated at 09:41. Times come from the operator's own board.</p>
  <p class="caption-xs">Times are local. Delays under a minute are not shown.</p>
</div>

title covers the outline of a page in four classes. This is the fifth role, and the one that recurs most: 62 rules across nine consumers were font-size: sm or xs plus color: var(--color-on-surface-muted) and nothing else.

It is a role, not a colour utility

View “It is a role, not a colour utility” as

A caption retuned from an ancestor. The token is read at the point of use and declared nowhere, so a page, a shell or a card can set it and every caption inside picks it up.

The smaller step declares the token on itself, so a retune written above stops here. It is a floor, not a scale point.

<div class="stack" style="--caption-font-size: 0.875rem">
  <p class="caption">A caption retuned from an ancestor. The token is read at the point of use and declared nowhere, so a page, a shell or a card can set it and every caption inside picks it up.</p>
  <p class="caption-xs">The smaller step declares the token on itself, so a retune written above stops here. It is a floor, not a scale point.</p>
</div>

There is no colour-only .muted class: a colour with no size is not a role, it is a decision the page is making about one element.

And neither class carries weight — under /guidelines/#hierarchy the one heading allowed to is a label, at body size, which is a different thing.

Tokens 1

Level 2, declared on .caption itself. Set any of them on that selector to restyle this utility without touching the skin.

Level 2 tokens declared by caption
TokenDefault
--caption-font-sizevar(--font-size-xs)

Variants and states

Variants

None. It is one shape, and the page does the rest.

Inside it

  • .caption-xs

State it reads

None.

Before you ship it

What you have to do 2 requirements

  1. Check the contrast if you change the colour. Both classes are below body size, so they are ordinary text at 4.5:1 and never large text at 3:1. The default clears it on all three grounds the default skin ships, measured identically on Chromium, Firefox and WebKit: 6.34 / 6.51 / 5.87 in light on --color-surface, --color-surface-raised and --color-surface-sunken, and 7.70 / 7.17 / 8.09 in dark. Under prefers-contrast: more it goes to 11.76 and 13.10 on --color-surface. The engines agreeing is worth stating because they have not always: four state colours were found here at 4.41–4.44 and only two of the three engines saw it. --color-on-surface-subtle is the near miss to know about — 5.14 light and 5.02 dark, above the floor but with a fifth of the headroom, and it is a border and icon colour rather than a text one. Substitute deliberately.
  2. Do not use it to shrink something that must be read. A caption is supporting text — the source, the timestamp, the limit of the data. An instruction the reader needs in order to act is body copy, whatever it does to the layout.

src/css/utilities/caption.css · npx mostlycss add caption