Hero
.hero
Hero — the band at the top of a page that says what the page is and gives you the one thing to do with it.
Examples
Milan
When is the next one
Type the name of your stop and we will tell you how many minutes away the next tram, bus or train is.
<section class="hero band" aria-labelledby="hero-a">
<div class="center">
<p class="hero-eyebrow">Milan</p>
<h1 class="hero-title" id="hero-a">When is the next one</h1>
<p class="hero-lead">Type the name of your stop and we will tell you how many
minutes away the next tram, bus or train is.</p>
<div class="hero-actions">
<a class="btn btn-primary" href="#stops">Find a stop</a>
<a class="btn" href="#lines">Browse the lines</a>
</div>
</div>
</section>The wrapper inside is not optional and it is not only about width.
A hero is a band that paints, so it contains — and the column's margin-block is what becomes the room inside the colour. That is why this block declares no padding-block at all: a padding would stop the collapse and add to the margin instead of resolving with it. Everything else is subtraction — no radius, no shadow, and one heading doing the work a box used to do.
Open data
Everything happens in your browser
No account, no tracking, no server holding your search.
<section class="hero hero-tall" data-theme="dark" aria-labelledby="hero-b">
<p class="hero-eyebrow">Open data</p>
<h1 class="hero-title" id="hero-b">Everything happens in your browser</h1>
<p class="hero-lead">No account, no tracking, no server holding your search.</p>
<div class="hero-actions">
<a class="btn btn-primary" href="#start">Start</a>
<a class="btn btn-outline" href="#sources">Where the data comes from</a>
</div>
</section>The reversed-out poster treatment is data-theme on the section, not a modifier class.
A class flipping two colours would leave every .btn and .input inside the band reading the page's foreground against the band's background; the mode axis re-resolves all of them, because it is the same mechanism the light/dark toggle uses. On a dark page, write data-theme="light".
Search 2,435 stations
Part of the name is enough.
<section class="hero" aria-labelledby="hero-c">
<h1 class="hero-title" id="hero-c">Search 2,435 stations</h1>
<search class="search hero-search">
<label class="sr-only" for="hero-q">Station</label>
<svg class="icon search-icon" aria-hidden="true"><use href="#icon-search"></use></svg>
<input class="input search-input" id="hero-q" name="q" type="search"
placeholder="Milano Centrale, Bosco, Riccione…" />
</search>
<p class="hero-note">Part of the name is enough.</p>
</section>.hero-search caps the field at 34rem. A search box stretched across a desktop window reads as a page-wide bar rather than as a thing to type in — and a hero that carries a field, five filter chips and a select is a control panel, which is the shape this block exists to avoid.
Lines
Every line in the network, with its stops and its timetable.
<section class="hero hero-sm" aria-labelledby="hero-d">
<h1 class="hero-title" id="hero-d">Lines</h1>
<p class="hero-lead">Every line in the network, with its stops and its timetable.</p>
</section>One step down the type scale, for a section index or a detail page.
The tall version above a table of results is a page that starts twice. A size sets the type and nothing else: the room above and below is the margin of the column inside the band, the same for every band on the page. .hero-plain goes further and drops the ground and the rule altogether.
Tokens 24
Level 2, declared on .hero itself. Set any of them on that selector to restyle this block without touching the skin.
| Token | Default |
|---|---|
| --hero-actions-gap | var(--space-3) |
| --hero-eyebrow-color | var(--color-on-surface-muted) |
| --hero-eyebrow-font-size | var(--font-size-xs) |
| --hero-input-bg | var(--color-surface) |
| --hero-lead-color | var(--color-on-surface-muted) |
| --hero-note-color | var(--color-on-surface-muted) |
| --hero-note-font-size | var(--font-size-sm) |
| --hero-padding-block | 0 |
| --hero-padding-inline | 0 |
| --hero-title-font-family | var(--font-primary) |
| --hero-title-font-size | var(--font-size-3xl) |
| --hero-trail-gap | var(--space-4) |
| --hero-lead-font-size | 1.125rem |
| --hero-lead-measure | var(--measure) |
| --hero-bg | var(--color-surface-sunken) |
| --hero-border-color | var(--color-border-subtle) |
| --hero-border-width | var(--border-width) |
| --hero-color | var(--color-on-surface) |
| --hero-title-color | var(--color-on-surface) |
| --hero-title-font-weight | var(--font-weight-medium) |
| --hero-title-letter-spacing | var(--letter-spacing-title) |
| --hero-title-line-height | var(--line-height-tight) |
| --hero-control-gap | var(--space-6) |
| --hero-search-size | 34rem |
Variants and states
Variants
.hero-plain.hero-sm.hero-tall
Inside it
.breadcrumb.combobox-input.hero-actions.hero-control.hero-eyebrow.hero-lead.hero-note.hero-search.hero-title.input.search-input.select
State it reads
None.
Before you ship it
What you have to do 6 requirements
- Put your own width-limiting wrapper inside the band. The hero is full-bleed on purpose and does not centre its contents; without a wrapper the title runs the full width of a desktop window. There is nothing else to do: the band ships no inline gutter, so your wrapper's padding is the only one and the title lines up with the rest of the page.
- Without a wrapper, ask for the gutter:
--hero-padding-inline: var(--space-4)on.hero. A band with loose text in it and no gutter puts that text against the edge of a phone. This is the way round it is because the wrapper is the ordinary case and the loose text is the exception — the other way round cost three consumers a title indented by twice the page's own gutter, silently, for weeks. .hero-titlegoes on the page's<h1>. It styles a heading, it does not make one: a<div class="hero-title">is a page with no first-level heading, which is how a screen-reader user loses the outline of the site. One<h1>per page, and in a hero it is this one..hero-eyebrowis not a heading. It is a label above the title — a<p>. Marking it up as an<h2>puts a heading above the<h1>and inverts the document outline.- Name the section.
<section class="hero" aria-labelledby="…">pointing at the title, or drop the<section>and let the band be a<header>. A<section>with no accessible name is a landmark nobody can navigate to. - Check the contrast if you set
--hero-bgto a brand colour. The default ground is a skin token whose pair is audited; a colour you chose is not.
src/css/blocks/hero.css · npx mostlycss add hero