Contents
  1. Universal border-box and zero spacing
  2. Root line height and system font
  3. No mobile text inflation
  4. Block-level main
  5. Heading sizes and logical margins
  6. Balanced heading wraps
  7. Paragraph spacing
  8. Anchor scroll offset
  9. Transparent link backgrounds
  10. Skip-ink on default links
  11. Dotted abbreviation underlines
  12. Monospace sizing
  13. Subscript and superscript offsets
  14. Inherited control typography
  15. Borders on text fields
  16. Button padding
  17. Pointer cursor on enabled buttons
  18. Vertical textarea resize
  19. Placeholder contrast
  20. List indentation
  21. Unstyled semantic lists
  22. Responsive media
  23. Icon fill from current color
  24. Open dialog layout
  25. Table color and indent
  26. Hide closed dialogs
  27. The hidden attribute
  28. Frameless iframes
  29. Collapsed table borders
Universal border-box and zero spacing

User agents size boxes from the content edge, and they add margin and padding that differ by element and browser. This rule switches every element, and both pseudos, to border-box, so width and height include padding and border, and it clears that spacing so layout starts from the same empty box. Ships in the full build and in mini.

*,
*::before,
*::after {
  box-sizing: border-box;
  padding: 0;
  margin: 0;
}
Root line height and system font

Body text inherits line height and font from the root, and those defaults differ between engines. The root sets a 1.5 line height and a system UI stack, including color emoji fonts, so unread text matches the platform. Full build only.

:where(:root) {
  line-height: 1.5;
  font-family: system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
}
No mobile text inflation

Mobile browsers enlarge text they consider too small, which changes a layout that set its own type size. text-size-adjust: none, with the WebKit and Firefox prefixes, keeps the font size you wrote. Full build only.

:where(html) {
  -webkit-text-size-adjust: none;
  -moz-text-size-adjust: none;
  text-size-adjust: none;
}
Block-level main

Older browsers left main as inline, so it sat in the line and its margins did not behave like a section. display: block makes it a normal block container. Full build only.

:where(main) {
  display: block;
}
Heading sizes and logical margins

User-agent heading margins use physical margin-top and margin-bottom, so the rhythm breaks in a vertical writing mode. These rules restore the classic size ladder with logical margin-block and zero inline margin. Mini ships this same ladder, and also sets font-weight: normal and line-height: 1.5 on h1–h6.

:where(h1) {
  font-size: 2em;
  margin-block: 0.67em;
  margin-inline: 0;
}

:where(h2) {
  font-size: 1.5em;
  margin-block: 0.83em;
  margin-inline: 0;
}

:where(h3) {
  font-size: 1.17em;
  margin-block: 1em;
  margin-inline: 0;
}

:where(h4) {
  margin-block: 1.33em;
  margin-inline: 0;
}

:where(h5) {
  font-size: 0.83em;
  margin-block: 1.67em;
  margin-inline: 0;
}

:where(h6) {
  font-size: 0.67em;
  margin-block: 2.33em;
  margin-inline: 0;
}
Balanced heading wraps

A long heading can wrap so the last line holds one short word. text-wrap: balance on h1–h4 evens the line lengths. Ships in the full build and in mini.

:where(h1, h2, h3, h4) {
  text-wrap: balance;
}
Paragraph spacing

The universal spacing reset removes the gap between paragraphs. Adjacent paragraphs (p + p) get 1rem of block-start margin, so body copy still separates, and a paragraph after a heading stays tight to that heading. Full build only.

:where(p + p) {
  margin-block-start: 1rem;
}
Anchor scroll offset

A fragment link scrolls the :target flush with the top of the viewport, where a sticky header covers it. scroll-margin-block: 5ex leaves room above the target. Full build only.

:where(:target) {
  scroll-margin-block: 5ex;
}
Dotted abbreviation underlines

An abbr with a title has an expansion, and engines disagree on whether they show that. A dotted underline is the cue. Full build only.

:where(abbr[title]) {
  text-decoration: underline dotted;
}
Monospace sizing

WebKit and others shrink code, kbd, samp, and pre below 1em in some parents. Pinning a monospace family and font-size: 1em keeps inline code the same size as the surrounding text. Full build only.

:where(code, kbd, samp, pre) {
  font-family: monospace, monospace;
  font-size: 1em;
}
Subscript and superscript offsets

Default sub and sup enlarge the line box. A 75% font size, zero line-height, and a relative offset keep the line height of the parent steady. Full build only.

:where(sub, sup) {
  font-size: 75%;
  line-height: 0;
  position: relative;
  vertical-align: baseline;
}

:where(sub) {
  bottom: -0.25em;
}

:where(sup) {
  top: -0.5em;
}
Inherited control typography

Form controls use the browser’s own font. font: inherit and line-height: inherit on buttons, inputs, selects, and textareas make them match the surrounding type. Full build only.

:where(button, input, optgroup, select, textarea) {
  font: inherit;
  line-height: inherit;
}
Borders on text fields

Browsers give text fields different default borders. Text-like inputs and textareas get a consistent 1px border in currentColor. Button, checkbox, color, file, hidden, image, radio, range, reset, and submit inputs are excluded so native chrome is unchanged. Full build only.

:where(
  input:not([type="button"]):not([type="checkbox"]):not([type="color"]):not(
      [type="file"]
    ):not([type="hidden"]):not([type="image"]):not([type="radio"]):not(
      [type="range"]
    ):not([type="reset"]):not([type="submit"]),
  textarea
) {
  border: 1px solid currentColor;
}
Button padding

Zero padding makes native buttons too small to hit comfortably. button and the button-like types get 1px 6px of padding back. Full build only.

:where(button, [type="button"], [type="reset"], [type="submit"]) {
  padding: 1px 6px;
}
Pointer cursor on enabled buttons

Several browsers keep the arrow cursor on buttons. Enabled buttons, and enabled button, reset, and submit inputs, use cursor: pointer. Disabled controls stay on the default cursor. Full build only.

:where(button):not(:disabled),
:where([type="button"]):not(:disabled),
:where([type="reset"]):not(:disabled),
:where([type="submit"]):not(:disabled) {
  cursor: pointer;
}
Vertical textarea resize

The default resize handle lets a textarea grow sideways and overflow the layout. resize: vertical keeps the handle and limits growth to the vertical direction. Full build only.

:where(textarea) {
  overflow: auto;
  resize: vertical;
  vertical-align: top;
}
Placeholder contrast

Placeholder text is often a fixed gray that disappears on a dark field. Inheriting the field color at opacity: 0.5 keeps the hint visible and tied to the text color. The selector is ::placeholder itself, so :where() does not lower its specificity. Full build only.

::placeholder {
  color: inherit;
  opacity: 0.5;
}
List indentation

Clearing padding on every element also removes the space that holds list markers. ul, ol, and menu get padding-inline-start: 40px so markers stay visible in either writing direction (#382). Ships in the full build and in mini.

:where(ul, ol, menu) {
  padding-inline-start: 40px;
}
Unstyled semantic lists

Navigation and toolbars often use a list with role="list" and should render the items in a line of controls. Those lists drop the marker and the indent. Ships in the full build and in mini.

:where(ul[role="list"], ol[role="list"]) {
  list-style: none;
  padding-inline-start: 0;
}
Responsive media

img, picture, video, canvas, and svg are inline by default and can spill out of a narrow parent. They become blocks, cap their inline size at 100%, and the replaced elements keep block-size: auto so the aspect ratio holds (#389). Ships in the full build and in mini.

:where(img, picture, video, canvas, svg) {
  display: block;
  max-inline-size: 100%;
}

:where(img, video, canvas, svg) {
  block-size: auto;
}
Icon fill from current color

An inline SVG ignores the text color when it has no fill. SVGs without a fill attribute use currentColor, so icons follow the surrounding color. Full build only.

:where(svg:not([fill])) {
  fill: currentColor;
}
Open dialog layout

An open dialog is sized and colored differently across engines. This rule centers it, paints it with Canvas and CanvasText, and fits the box to its content. A closed dialog is hidden by the unlayered rule below. Full build only.

:where(dialog) {
  background-color: Canvas;
  border: solid;
  color: CanvasText;
  display: block;
  block-size: fit-content;
  inline-size: fit-content;
  inset-inline: 0;
  margin: auto;
  padding: 1em;
}
Table color and indent

A table can inherit a text indent from an ancestor, and its border color may stay on the user-agent default. text-indent: 0 and border-color: inherit follow the surrounding text. Full build only. Mini collapses table borders in its own rule, further down.

:where(table) {
  text-indent: 0;
  border-color: inherit;
}

Hide closed dialogs

A dialog without the open attribute has to stay off screen. This rule sets display: none on that state. It lives outside @layer reset, so an unlayered author style is what overrides it, and a rule inside the reset layer cannot reveal a closed dialog. Full build only.

:where(dialog):not([open]) {
  display: none;
}
The hidden attribute

The hidden attribute has to win against a class that sets display. The selector is written without :where(), so its specificity is (0, 2, 0). hidden="until-found" is left alone so find-in-page can reveal it. This rule is also outside @layer reset. Full build only.

[hidden]:not([hidden="until-found" i]) {
  display: none;
}
Frameless iframes

Browsers draw a border around iframe. Mini removes it. Mini only.

:where(iframe) {
  border: 0;
}
Collapsed table borders

Separate table borders leave a gap between cells. Mini collapses the borders and clears the spacing. Mini only.

:where(table) {
  border-collapse: collapse;
  border-spacing: 0;
}