Tutorial

Build your first page with Sumi

In ten short steps you will build a one-page site for a calligraphy studio: navigation, a hero, course cards, a booking form, an FAQ and a dark mode. Most of it is plain HTML. Sumi does the styling.

1Add Sumi to a page

Sumi is a single CSS file with no JavaScript and no build step. Download sumi.min.css, put it next to your HTML file, and link it in the <head>.

Create a file called index.html with this starter:

Open the file in your browser. You should see a centered page with a bold heading, comfortable line spacing and the right colors for your system's light or dark mode.

Two lines matter. The viewport meta tag makes the layout work on phones. The lang attribute lets the browser hyphenate long-form text correctly, so set it to your page's language.

Use sumi.css instead of the minified file while you learn. It has comments that explain every section.

2Lay out the page

Sumi centers three elements automatically when they are direct children of <body>: <header>, <main> and <footer>. They get a maximum width of 72rem, side padding that adapts to the screen, and sensible vertical spacing. You don't add any classes.

Three classes cover the other layout cases:

ClassUse it when
.containerYou want the same centered width on another element, such as a <div> or a <section>.
.container-fluidYou want full width with side padding only.
.narrowYou want a reading column of 44rem, for a blog post or a sign-in form.

4Write the content

Headings, paragraphs, lists, quotes and code are styled from the element alone. Headings follow a fluid scale, so an <h1> is about 33px on a phone and 45px on a wide screen with no media queries on your side.

Three patterns make a hero section look finished:

  • <hgroup> groups a heading with an eyebrow (<h6>) above it and a subtitle (<p>) below it.
  • .lead makes an intro paragraph larger.
  • .display makes a headline larger still, for a landing page.
Calligraphy workshops

Learn to write with a brush

Small evening classes for complete beginners. Ink, brushes and paper are provided.

Long-form text

For an article or a blog post, wrap the text in .prose. It limits lines to about 68 characters, increases the line spacing slightly and turns on hyphenation. Add .serif to switch to a serif typeface, which many readers find calmer for long texts.

Why we grind our own ink

Bottled ink is convenient, but grinding a stick against the stone is part of the lesson. It takes about five minutes, and it slows you down before the first stroke.

One stroke, one breath. You cannot go back over a line.

Workshop rule no. 1

An <article> normally becomes a card (step 6). With .prose it stays plain text, because a long article should not sit in a box.

5Arrange content in a grid

.grid places its children in as many columns as fit, each at least 14rem wide. On a phone they stack into one column. You don't set any breakpoints.

Small groups

Eight students per class, so the teacher sees every stroke.

All materials

Brushes, inksticks, stones and paper are ready on your desk.

Take it home

Every student leaves with a finished, signed piece.

When you need exact columns, add .cols-2, .cols-3, .cols-4, .cols-6 or .cols-12. These apply from 48rem (768px) upwards; below that the grid is a single column. In a 12-column grid, children can take .span-2 to .span-9, or .span-full for a whole row.

For a single row of items, use .row (a wrapping flex row with a gap). Add .spread to push items to both ends. .stack is the vertical version.

6Show options in cards

Every <article> is a card. If the article starts with a <header> or ends with a <footer>, those become shaded bands across its full width. Put cards in a grid and they line up.

Taster evening

One two-hour session. Try the brush, the ink and the basic strokes.

Six-week course

Weekly classes from first strokes to a finished hanging scroll.

Private lesson

One hour with a teacher, at a time that suits you.

.full stretches a button across its container. Buttons come in .secondary and .contrast colors, an .outline style, and .small and .large sizes. You can combine them, as in class="secondary outline small".

7Build a booking form

Form fields need no classes. Wrap each field in its <label> and it gets full width, padding and a focus ring. A <small> placed right after a field becomes helper text.

Experience

Try submitting the empty form. Fields turn red because a small script sets aria-invalid="true" on them. Sumi styles that attribute, and screen readers announce it too. Valid fields get aria-invalid="false" and turn green.

Two more patterns are worth knowing:

  • <input type="checkbox" role="switch"> draws a toggle switch instead of a checkbox.
  • <div role="group"> joins an input and a button into one control, like a search bar.

8Add interactive parts

Sumi styles the browser's own interactive elements, so most of these work with no JavaScript.

FAQ accordion

Each <details> opens and closes on click. Add open to start one expanded.

Do I need any experience?

No. The taster evening and the six-week course both start from the very first stroke.

What should I wear?

Something you don't mind getting ink on. Sumi ink does not wash out of cotton.

Dropdown menu

Add class="dropdown" to a <details> and put a list inside. Add .right as well to align the menu to the right edge.

Modal dialog

Put an <article> inside a <dialog>. Opening a modal needs one line of JavaScript, dialog.showModal(). Closing does not: a button inside <form method="dialog"> closes it, and so does the Esc key.

Cancel your booking?

Your seat will be offered to the next person on the waiting list.

Tooltips, loading and messages

Three attributes and one class cover the remaining feedback you'll need.


Booking confirmed. See you on Thursday at 19:00.
Only two seats left for this date.
  • data-tooltip="…" shows a tooltip on hover and keyboard focus. Add data-placement="bottom" to show it below.
  • aria-busy="true" adds a spinner to any element. Remove the attribute when loading finishes.
  • .callout is a message box. Add .success, .warning or .danger for the color.

9Make it yours

Every color, font, size and radius in Sumi is a CSS custom property that starts with --s-. To rebrand the whole site, put your own values in a stylesheet that loads after Sumi:

Custom properties also work on a single element. These buttons use the same classes as before. Only the parent's style attribute changes them:

Fonts

Sumi uses each system's own interface font by default, so pages load with no font downloads. To use a web font, load it as usual and point a token at it. --s-font-body sets the text, and --s-font-heading sets the headings (it follows the body font unless you set it).

Dark mode

Dark mode is already on. Sumi follows the visitor's system setting. To force a mode, set data-theme on the <html> element:

A theme switch is a few lines of JavaScript. This one remembers the visitor's choice:

data-theme also works on any element, so one section can be dark inside a light page:

Evening classes

Thursdays from 19:00 to 21:00, by candlelight.

The dark palette is defined twice in sumi.css: once for the system setting and once for data-theme="dark". If you change dark colors, change both blocks.

10Add your own CSS

Most of Sumi's element styles sit inside :where(), which gives them zero specificity. Any selector you write wins, without !important and without long selector chains.

Build new components from Sumi's tokens, as the badge above does. They then follow dark mode and your brand colors automatically. The tokens you'll use most are --s-text, --s-muted, --s-bg, --s-surface, --s-border, --s-primary and --s-radius.

To turn off a default for one element, override it with a class. For example, an <article> that should not be a card:

✓The finished page

Here are the pieces put together into one page. The full source is under the preview, ready to copy into index.html.

Calligraphy workshops

Learn to write with a brush

Small evening classes for complete beginners. Ink, brushes and paper are provided.

Taster evening

One two-hour session to try the basic strokes.

Six-week course

From first strokes to a finished hanging scroll.

Private lesson

One hour with a teacher, when it suits you.

Questions

Do I need any experience?

No. Every course starts from the very first stroke.

What should I wear?

Something you don't mind getting ink on.

© 2026 Inkwell Studio · Thursdays 19:00–21:00
Full source of index.html

Where to go next

  • Browse every component, with its HTML, on the components page.
  • Read the comments in sumi.css. Each section explains what it styles and which tokens it uses.
  • Change --s-primary and --s-font-heading first. Those two tokens change the character of a site the most.

Cheat sheet

Every class and attribute Sumi responds to. Everything else is plain HTML.

Class or attributeGoes onEffect
.container .container-fluid .narrowany blockCentered page width, full width, reading width
.gridwrapperAuto-fitting columns, at least --s-grid-min wide
.cols-2 … .cols-12.gridFixed columns from 48rem up
.span-2 … .span-9, .span-fullgrid childSpans several columns
.row .spread .stackwrapperFlex row, row with space between, vertical stack
.display .leadheading, paragraphHero headline, intro paragraph
.prose .seriftext wrapperLong-form reading column, serif typeface
.secondary .contrast .outlinebuttonButton colors and outline style
.small .large .fullbuttonButton sizes, full width
role="button"<a>Link that looks like a button
role="group"wrapperJoins buttons or input + button
role="switch"checkboxToggle switch
aria-invalidfieldRed when true, green when false
aria-busy="true"any elementLoading spinner
aria-current="page"nav linkHighlights the current page
data-tooltip data-placementany elementTooltip, above or below
data-theme<html> or any elementForces light or dark
.dropdown .right<details>Dropdown menu, right-aligned
.callout + .success .warning .dangerblockMessage box
.striped<table>Zebra rows
.muted .small .center .sr-only .overflow-autoany elementUtilities

Browser support

Sumi works in current versions of Chrome, Edge, Firefox and Safari. It relies on :where(), :has() and color-mix(), which are available from Chrome and Edge 111, Firefox 121 and Safari 16.2. Older browsers still show readable pages, with plainer hover and focus colors.