Edit9Docs
The language

Text and material

The bundled faces and why there is no font name, vertical setting for CJK, controlling line breaks, and how a photograph enters a document.

A closed list of faces, and no font name

font names one or more typefaces, and the list is closed: every face on it is bundled, and the reference page for <e9-text> shows the whole list with what each one is for.

<e9-text role="title" font="Montserrat">Autumn, together</e9-text>
<e9-text role="title" font="Montserrat, 站酷快乐体">秋天,一起</e9-text>

Closed is the only unusual thing about it. font="Helvetica" is a refusal, because a face this engine does not ship would be resolved against whatever fonts the rendering machine happens to have — which is exactly the dependency the render contract exists to remove. What the refusal gives back is the list of faces that are here.

The spelling is lenient where the face is not. A face also answers to the names it is otherwise known by — Cormorant for Cormorant Garamond, ZCOOL KuaiLe for 站酷快乐体 — and the document keeps the face's own name, so one face has one spelling in a canonical document.

A face is drawn for the scripts it is drawn for, and the list is a fallback order. The browser picks per glyph, first match wins, so the second name in font="Montserrat, 站酷快乐体" is what a Chinese run is set in and the first is what a Latin one is. Name a face for each script the design actually sets.

What you do not name is completed, never left as a hole. Any script no named face serves falls to the shared 黑体 or 宋体 — whichever suits the first face you did name — so font="Montserrat" still renders Chinese, in the workhorse rather than in something chosen. A named face always outranks a completed one.

The consequence is a rule with no way around it. A character no face in the list can draw is a check failure, not a fallback (glyph-coverage). Naming another font cannot fix it, because there is no parameter for a font name outside this list. What fixes it is adding a face that covers the character — the refusal names them — rewriting the copy, or setting that text as artwork and placing it with <e9-image>.

Coverage is a property of the face, not of the engine. The workhorses draw Latin, simplified Chinese, Korean and Japanese between them; the display faces are narrower, and some of them much narrower — a face drawn for Chinese headlines carries GB/T 2312's hanzi and no kana at all. That is why the check asks about the faces you named rather than about the bundled set as a whole.

At most two weights exist, 400 and 700, and any other value would be a weight the browser synthesized — which renders differently across Chromium builds. Not every face has both. Several display faces were drawn once, in one weight, with no italic; asking one of those for a bold or a slant is refused by name, and the refusal points at a face that has it.

italic="true" sets Latin in a bundled italic face. There is no italic Chinese face to bundle, so a Chinese run asked to slant would be slanted by the browser rather than drawn, and the synthesized-style check warns about that by name. Emphasise Chinese with a different weight or face instead.

Roles before sizes

role — title, subtitle, body, caption — supplies the type scale: size, weight and line height together. Choose the role first and override only where the design genuinely departs from it. A set whose every text Block carries an explicit size has flattened its own scale.

Vertical setting

For a column of Chinese or Japanese reading top to bottom, set vertical="true" on <e9-text>. Never rotate: a rotation turns the glyphs on their side, and it cannot make successive columns run right to left, which is half of what vertical setting is. With vertical, the glyphs stay upright, punctuation takes its vertical forms, and a Latin word inside the column lies on its side — which is the convention.

Where a line breaks

Line breaks are controllable, so there is no need to binary-search max-width:

  • &#10; forces a break.
  • &nbsp; keeps two words together.
  • &shy; permits a break inside a long word.
  • wrap="balance" evens out the lines of a heading.

Material the engine does not draw

Photography, textures, brush lettering and logos are source material. The engine never draws them. They are made or fetched outside it, added to the Project's assets, and placed with <e9-image src="asset://…">.

The same is true of shapes the vocabulary cannot draw — arrows, curves, icons. Write the SVG, add it as an asset, place it as an image.

Two things about assets are worth knowing before the first one:

  • A parameter carrying an http, file, data, blob or javascript URI is refused (forbidden-uri). Material is addressed as asset://path, and an asset:// that this Project does not hold is a check failure (missing-asset) rather than a hole in the picture.
  • Artwork that arrived baked onto its own ground — brushed lettering on white, a paper grain — goes down with blend="multiply", so it composites onto the page instead of covering what is beneath it as a rectangle. multiply keeps the darker of the two, so it only erases a ground that is white: commission the asset on white, or leave blend alone.

An SVG that draws live <text> is a warning (asset-font), not an error: an SVG loaded as an image is an isolated document and cannot see the renderer's bundled faces, so it resolves families against the machine's own font list. The render is not wrong; its reproducibility is narrower than everything around it.

On this page