跳到正文
misoto22 design

展示

Heading 标题

一个标题,元素和字号是两个各自独立的决定。

用法

什么时候用它

任何标题。level 跟着文档大纲走,size 跟着设计走,并且默认从 level 推出来。
TSX
import { Heading } from '@misoto22/design'

说明

一个标题,元素和字号分开决定。

每一个只收一个数字的标题组件都会在这里搞错,而且只有两种错法:要么为了拿到一个字号把大纲掰弯(页面中间冒出一个 <h1>,只因为设计想要大字),要么为了守住大纲把字号掰弯(一个区块标题被压到 20px,只因为它排在第四级)。两种都只差一个 prop 就对了,所以这里给了两个。

level 是文档,size 是页面。默认值经由这套系统的字号阶把两者绑在一起,所以只写 level 就是对的——而一旦它们真的要分开,调用处会把这件事说出来。

和这套系统里每一个标题一样,用书刊衬线体、字重 400。它还带着 scroll-margin-top,所以一个有 id、被目录链过来的标题会停在顶栏下面,而不是被顶栏盖住。

结构

Heading anatomy
部件说明
Element必填level, 1 to 6, rendered as the matching <h1>–<h6>. This is the document outline — what a screen reader navigates by — so it follows the section the heading opens, never the size it wants to be.
Step必填size, one of title, lead, heading, sub, item and label. Defaults from level through the system ladder, so writing only level is correct.
Anchor offset必填scroll-margin-top: var(--scroll-offset), carried by every heading, so one given an id and linked from a table of contents comes to rest below the masthead instead of under it.

实践建议

推荐

  • Write level alone unless the outline and the design genuinely disagree. The default ladder is 1→title, 2→heading, 3→sub, 4→item, 5 and 6→label — the same map article.css applies to rendered Markdown, which is what makes a post and a component page read as one publication.
  • Notice that the default ladder SKIPS lead between levels 1 and 2, and skip a step yourself when you set size by hand: --fs-lead over --fs-heading is a ratio of 1.14 and reads as a rendering accident, where --fs-title over --fs-heading is 1.86 and reads as a hierarchy.
  • Give a heading an id when anything links to it. The component already carries the scroll offset the anchor needs; nothing else on the page does.

避免

  • Do not raise level to get a bigger heading. Two <h1>s on a page make its outline unnavigable, and size is one prop away.
  • Do not reach past size="title". The ladder ends there because a page has exactly one thing larger than its own records; a bigger heading is className territory and it is the moment the page stopped being in the system.
  • size="label" is the mono kicker at 11px and --ink-3-aa, not a small serif heading — it is what levels 5 and 6 should look like, and setting it on an <h2> makes the section title read as metadata.

示例

level and size

The two decisions, apart. level is the document outline — what a screen reader navigates by — and size is the page. The default binds them through the system ladder, which SKIPS a step between the first two: --fs-lead over --fs-heading is a ratio of 1.14 and reads as an accident, where --fs-title over --fs-heading is 1.86 and reads as a hierarchy. The mono eyebrow is the ladder's fifth rung, worn here by an h4 so this run does not skip a level in the outline; the last pair is a semantically-correct h3 that had to look like a page title.

The White Reset

A record title

A sub-head inside it

Metadata

Third level, page-title sized

The last one is an h3. Nothing about the outline moved.

anchored headings

Two headings a table of contents can link into. Every Heading carries scroll-margin-top: var(--scroll-offset), so one given an id comes to rest below the masthead rather than under it — nothing else on a page does that, which is why an anchor into a hand-rolled h2 lands with its own title hidden behind the bar. The id is the caller's, and it has to be stable: it is what every link to this section already says.

Installation

One package, and one stylesheet next to it.

Upgrading

Minor versions add exports; they never move one.

a fragment that starts at h2

A panel dropped into a page that already has its h1. The outline decides level — this opens a section, so it is an h2 and its sub-heads are h3s — and size decides how big it looks, which is the whole reason they are two props. Raising level to reach the larger step would give the page two first-level headings and an outline nobody can navigate, for a difference one prop already covers.

Publish 0.4.1

What ships

Five display components, and the examples that explain them.

What it breaks

Nothing — every export in 0.4.0 is still exported here.

类型

TSX
export type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6
export type HeadingSize = 'title' | 'lead' | 'heading' | 'sub' | 'item' | 'label'

无障碍

  • level 渲染的是真正的标题元素,所以这份大纲是能被导航的,而不只是看得见。
  • 两个决定是两个 prop,正是这一点让一个语义上正确的 h3 可以长得像页面标题,而不必把大纲掰弯。
  • 带 scroll-margin-top,所以锚点跳过去的标题不会被固定的顶栏盖住(实践中的 WCAG 2.4.7)。