This skill is intended to align typography implementation decisions for Japanese-centric or multilingual UIs based on tak-dcxi's Typography gist.
It is organized on the premise that kiso.css is adopted, and if it is not adopted, use it on the premise of porting the necessary reset to @layer reset is used on the premise of porting to.
Situations for using this skill
font-familyやfont-weightWhen deciding the policy for- When designing line wrapping for headings and body text that mix Japanese and English
text-wrap,font-kerning,font-feature-settings,text-autospaceWhen deciding how to useline-height,text-box-trim,hanging-punctuation,line-clampWhen reviewingclamp()When deciding how to use fluid typography usingpx/remWhen deciding how to use- When handling details of text composition such as manual line breaks, phrase line breaks, and prohibition of separation
- When checking whether AI-generated typesetting CSS contains any dangerous specifications
Premises
- Assume that kiso.css is adopted for the reset CSS
- If kiso.css is not adopted,
overflow-wrap,line-break,text-autospace,text-spacing-trim, for Japanesefont-stylereset, etc., port the necessary reset to@layer resetport to hyphens,font-kerning,text-wrap, for Japanese exception handling,langAssume that the attribute is attached- Prioritize solid setting for Japanese body text, and tighten only headings and short text as exceptions
Things to decide first
- Is that text body text, a heading, or a UI label?
- Is the primary language Japanese, English, or mixed?
- Should solid setting be prioritized, or should tightening of headings be prioritized?
- Where should that rule be placed in
@layer reset,@layer base,@layer utilitieswhere it should be placed in - Is the value something that should follow the user's text enlargement setting, or something that should be fixed as decoration?
Responsibilities by layer
@layer reset
- Root line wrapping specifications should be handled by reset
text-autospaceとtext-spacing-trimEstablish the overall policy with reset- Japanese
em,cite,dfnAlso handle italic removal, etc., with reset
@layer base
- Default by language
font-kerningPlace in base - Heading
font-feature-settings: "palt"and English headingtext-wrap: balanceGive in base - Also align default line-height and bold tokens in base
line-heightAlso align bold tokens in base
@layer utilities
- Place only opt-in utilities
- Typical examples are
-fluid-text,-text-center,-trim-both,-kerning,-auto-phrase,-hanging,-tabular-nums,-uppercase,-hyphens,-line-clamp,-br,-wbris
Implementation rules
font-family
- If there is no special specification, in Japanese UI
font-family: sans-serifonly is sufficient - In Japanese environments,
system-uiDo not use it casually. On Windows, Yu Gothic-style UI typefaces tend to come to the front, easily resulting in an unintended appearance - For mechanisms such as Tailwind CSS where
system-uiis inserted when unset, always inspect them - When there is a requirement to force Noto Sans JP or Noto Serif JP on all devices,
@font-faceprioritize local fonts with and avoid double loading - Mincho may be missing on Android, so do not build on the premise of device dependence
font-style と font-weight
- In Japanese,
em,cite,dfn,i,addressdo not assume italics for - If not using kiso.css,
:lang(ja)limited to, cancel italics andemsupplement bolding in reset font-weightprioritizes numeric specification over keywords, and--font-bold: 700align to tokens like- If kiso.css has keyword specifications, override them with numeric values in the base layer
Wrapping and alignment
- For the root, assume
overflow-wrap: anywhereとline-break: strictassume text-align: centerWhen usingtext-wrap: balanceconsider as a set- English body text uses
text-wrap: pretty, English headings usetext-wrap: balanceas the basis - Do not normally include
text-wrapin Japanese body text. Because it easily disrupts solid setting - For Japanese headings, make
word-break: auto-phraseとtext-wrap: balancethe first candidate combination, and apply progressively only to supported browsers - In Safari, Japanese
text-wrap: prettyis easily disrupted, so avoid it for now - Only when you want to slightly tidy the rag of a paragraph, consider
inline-size: round(down, 100%, 1ic)consider
Letter tightening and OpenType features
:lang(en)Givefont-kerning: normalto:lang(ja)Givefont-kerning: noneas the default, and prioritize solid setting for Japanese body text- However, this policy includes the tradeoff that English words within Japanese text will also no longer be kerned. Consider exceptions for projects that prioritize the appearance of Western text
- Give
font-kerning: normalto headings and captions - Use
font-feature-settings: "palt"for Japanese headings. In vertical writing, usevpaluse font-feature-settings: "pwid"When usingfont-variant-east-asian: proportional-widthprioritize the upward-compatible- For UIs where you want to align numbers, use
font-variant-numeric: tabular-numsuse
Whitespace handling and line spacing
text-autospace: normalMakepre,time,input,textarea,[contenteditable]Explicitly specifytext-autospace: no-autospacefortext-spacing-trim: trim-startas the default, andpreonly forspace-allexplicitly specify- The default
line-heightshould be 1.5 or greater line-heightuses a unitless number and tokenizes it- Guideline for body text is 1.7 to 2 for Japanese, 1.5 to 1.8 for English; guideline for headings is 1.25 to 1.5 for Japanese, 1.2 to 1.4 for English
- If you want to remove half-leading, consider
text-box-trim/text-box-edgeconsider text-box-trimis used as progressive enhancement. In English,text-box-edge: cap alphabetic, in Japanese prioritize the default valuetextprioritize- Only when you want strict tightening, additionally consider
margin-block: calc((1em - 1lh) / 2)consider adding
Punctuation, ellipsis, hyphenation
hanging-punctuationuse only in paragraphs- Hanging punctuation can trigger horizontal scrolling, so design it together with inline-direction spacing
- In English,
hanging-punctuation: first allow-end last, in Japanese,last allow-endas the basis line-clampimplement with a prefix.display: -webkit-boxと-webkit-box-orientと-webkit-line-clampset together- For overflow control when truncated,
overflow: hiddenrather thanoverflow-block: clipmake the first candidate - In the fallback,
overflow-y: clipuse.overflow: hiddenはstickyeasily breaks hanging punctuation hyphens: autoはlang="en"use only when there is an explicit language declaration such as- Do not write capitalization directly into the selector;
text-transform: uppercasehandle it with the utility
Annotations, phrase line breaks, manual line breaks
- Do not assume indentation in normal Web paragraphs
- For annotations, add
role="note", andtext-indent: hanging 1icuse word-break: auto-phraselimit to Japanese headings, captions, short text, etc.- Do not extend phrase line breaking to entire Japanese paragraphs. It tends to create unnatural gaps
- If phrase line breaking is required in Firefox and Safari as well, consider BudouX
- Other than semantic line breaks,
<br>do not increase - When you want to control line break positions only for Japanese headings,
display: contentsとdisplay: inline flow-root/block flowuse to break lines with CSS - Avoid manual line breaks in paragraphs because they are incompatible with responsive design
- For words you do not want separated,
‍join with and make the intent explicit
Fluid typography and unit selection
font-sizeBefore dividingclamp()with queries, consider- Avoid dependence on external generators that erase the calculation process; manage it in a form where the formula remains
- Separate API-like custom properties from custom properties for internal calculation
- If changing smoothly for the entire page,
100svi, and if changing locally within a component,100cqiuse 100cqiuse only when a valid container is guaranteed. For unit decisions, also refer to the conventions in the responsive skillremとpxuse according to role- For font size, line height, vertical paragraph spacing, widths containing text, and breakpoints,
rem/emprioritize - For border widths, fine details, and values you do not want to scale in conjunction with font size,
pxconsider remIf using , verify with the browser's text enlargement feature enabled
Recommended base implementation
:where(:lang(en)) {
font-kerning: normal;
}
:where(:lang(ja)) {
font-kerning: none;
}
:where(h1, h2, h3, h4, h5, h6, caption) {
font-kerning: normal;
&:lang(en) {
text-wrap: balance;
}
&:lang(ja) {
font-feature-settings: "palt";
@supports (word-break: auto-phrase) {
word-break: auto-phrase;
text-wrap: balance;
}
}
}
:where(p:lang(en)) {
text-wrap: pretty;
}
Recommended utilities
.-fluid-text {
--_u-relative-max-width: var(--fluid-text--relative-max-width, 1280);
--_u-relative-min-width: var(--fluid-text--relative-min-width, 375);
--_u-min-font-size: var(--fluid-text--min-font-size, 14);
--_u-max-font-size: var(--fluid-text--max-font-size, 16);
--_u-base-font-size: var(--fluid-text--base-font-size, 16);
--_u-relative-unit: var(--fluid-text--relative-unit, 100svi);
--_u-fluid-slope: calc(
(var(--_u-max-font-size) - var(--_u-min-font-size)) /
(var(--_u-relative-max-width) - var(--_u-relative-min-width))
);
--_u-fluid-intercept: calc(
var(--_u-min-font-size) - var(--_u-fluid-slope) *
var(--_u-relative-min-width)
);
font-size: clamp(
var(--_u-min-font-size) / var(--_u-base-font-size) * 1rem,
var(--_u-fluid-slope) * var(--_u-relative-unit) + var(--_u-fluid-intercept) /
var(--_u-base-font-size) * 1rem,
var(--_u-max-font-size) / var(--_u-base-font-size) * 1rem
);
}
.-text-center {
text-align: center;
text-wrap: balance;
}
.-trim-both {
text-box-trim: trim-both;
&:lang(en) {
text-box-edge: cap alphabetic;
}
}
.-kerning {
font-kerning: normal;
&:lang(ja) {
font-feature-settings: "palt";
}
}
.-auto-phrase {
&:lang(ja) {
@supports (word-break: auto-phrase) {
word-break: auto-phrase;
text-wrap: balance;
}
}
}
.-hanging {
hanging-punctuation: last allow-end;
&:lang(en) {
hanging-punctuation: first allow-end last;
}
}
.-tabular-nums {
font-variant-numeric: tabular-nums;
}
.-uppercase {
text-transform: uppercase;
}
.-hyphens {
hyphens: auto;
}
.-line-clamp {
display: -webkit-box;
overflow-block: clip;
-webkit-box-orient: block-axis;
-webkit-line-clamp: var(--line-clamp--limit, 3);
@supports not (overflow-block: clip) {
overflow-y: clip;
}
}
.-br {
display: contents;
&:lang(ja) {
display: block flow;
}
}
.-wbr {
display: contents;
&:lang(ja) {
display: inline flow-root;
}
}
Policy for output
- First clarify whether the target text is body text or a heading, and what the primary language is
- Explain separately the reset absorbed by kiso.css and the base / utilities added this time
font-kerning,text-wrap,text-box-trim,word-break: auto-phraseWhen using , briefly add browser differences and trade-offsline-clamp, for manual line breaks and annotation indentation, also state markup requirements as well as CSS when necessaryremとpxWhen choosing, indicate whether it should follow text enlargement as a reason for the decision
Final check
langwhether the attribute is present- whether kiso.css is used, or if not adopted, whether the necessary reset has been ported
- In a Japanese UI,
system-uiwhether it is not used carelessly text-align: centerとtext-wrap: balancewhether it is not separated- into Japanese body text,
text-wrapwhether it is not inserted line-clampでoverflow: hiddenwhether it is not used carelesslyhyphens: autowhether there is an explicit language specification- whether manual line breaks have not been brought into paragraphs
remとpxwhether there is a reason for the distinction in use and whether it has been verified with text enlargement