Lesson 32 of 45 · Web pages

Fonts and text styling

A page is mostly letters, and how they look decides whether people read it. This lesson covers the font properties (which font, how big, how heavy, which features), the text properties (alignment, lines, spacing, wrapping, direction) and the web font element, with examples you can run and a short guide for Persian and Arabic text.

Choosing a font

You cannot know which fonts a visitor has installed. font family therefore takes a list, called a font stack: the browser tries the names from left to right and uses the first font that exists and has the letters it needs to draw. A name that contains spaces goes in single quotes inside the string. The last name should be a generic family, which every browser can always fill: serif (letters with small feet), sans-serif (without feet), monospace (equal width, for code), cursive and fantasy (decorative, and different on every system) and system-ui (the font of the operating system's own windows). ui-monospace is the system's code font.

web-font-family.salam
page:
    title = "Font stacks"
    global: selector = "body" margin = "1.5rem" line height = 1.6 end
    paragraph: font family = "Georgia, 'Times New Roman', serif" content = "Serif: Georgia, then Times New Roman, then any serif font." end
    paragraph: font family = "system-ui, sans-serif" content = "Sans serif: the interface font of the system." end
    paragraph: font family = "ui-monospace, Consolas, monospace" content = "Monospace: every letter is equally wide." end
    paragraph: font family = "cursive" content = "Cursive: the look of handwriting." end
    paragraph: font family = "NoSuchFont, serif" content = "The first name does not exist, so the browser takes the next." end
end

Look at the last line of the preview. The first name does not exist, so the browser skips it silently and takes the next. This is also how a missing Persian glyph is handled: if the first font has no such letter, the browser asks the next font in the list for that single letter.

Put the rule on body with a global element, as the examples do, and every element inherits it. Only set font family on a single element when that element really needs a different font, such as code.

Size

font size accepts a bare number (pixels), or a string with a unit. The useful units are rem, which is relative to the font size of the whole page, em and %, which are relative to the parent element, and vw, which is a part of the window width. There are also keywords from xx-small to xx-large, and clamp(min, preferred, max), which grows with the window but never leaves the two limits. Prefer rem to pixels for text: people who raise the default size in their browser then get bigger text on your page too.

web-font-size.salam
page:
    title = "Font sizes"
    global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" end
    paragraph: font size = 12 content = "12 means 12px" end
    paragraph: font size = 12 + 6 content = "An expression: 12 + 6 is 18px" end
    paragraph: font size = "1.5rem" content = "1.5rem is one and a half root sizes" end
    paragraph: font size = "150%" content = "150% of the parent size" end
    paragraph: font size = "x-large" content = "The keyword x-large" end
    paragraph: font size = "clamp(1rem, 4vw, 2rem)" content = "clamp() grows with the window, within limits" end
end

The second line is an expression. Any number or string that the compiler can compute is a valid value, so you can also use a constant declared above the page, such as font size = BASE * 2, and change one number to resize many elements.

Before the next sections, try the settings yourself. The slider and the list below run small functions that use the dom package, which is explained in its own page. Each time the slider moves, its function reads the value and sets the CSS property font-size of the sample. Inside such a function, CSS properties keep their original names with dashes.

web-font-tester.salam
import dom

page:
    title = "Type tester"
    global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" end
    paragraph: id = "label" content = "Size: 28px" end
    box: display = "flex" gap = 12
        input: id = "size" type = "range" min = 12 max = 64 value = 28
            input = ():
                size := dom.GetValue(dom.ById("size"))
                dom.SetStyle(dom.ById("sample"), "font-size", size + "px")
                dom.SetText(dom.ById("label"), "Size: " + size + "px")
            end
        end
        select: id = "family" change = (): dom.SetStyle(dom.ById("sample"), "font-family", dom.GetValue(dom.ById("family"))) end
            option: value = "Georgia, serif" content = "Serif" end
            option: value = "system-ui, sans-serif" content = "Sans serif" end
            option: value = "ui-monospace, monospace" content = "Monospace" end
        end
    end
    paragraph: id = "sample" font family = "Georgia, serif" font size = 28 content = "Sphinx of black quartz, judge my vow." end
end

Weight, style and width

font weight is a number from 1 to 1000: 400 is normal text, 700 is bold. normal and bold are the same as 400 and 700, and bolder and lighter move one step away from the parent. A font file has only the weights its designer drew. If you ask for 300 and the font has 400 and 700, the browser shows 400, so in the preview below the first lines may look equal. font style chooses upright, italic (a separate design) or oblique (the upright letters leaned over). font stretch and its newer name font width choose narrower or wider designs and only matter for fonts that have them.

web-font-weight.salam
page:
    title = "Weight, style and width"
    global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" line height = 1.6 end
    paragraph: font weight = 300 content = "Weight 300, light" end
    paragraph: font weight = 400 content = "Weight 400, normal" end
    paragraph: font weight = 700 content = "Weight 700, bold" end
    paragraph: font weight = 900 content = "Weight 900, black" end
    paragraph: font style = "italic" content = "Italic: the italic design of the font" end
    paragraph: font style = "oblique" content = "Oblique: the upright letters slanted" end
    paragraph: font stretch = "condensed" content = "Condensed, if the font has a narrow design" end
    paragraph: font = "italic 700 1.25rem/1.4 Georgia, serif" content = "All of it in one shorthand" end
end

The last line uses the shorthand font. It sets style, weight, width, size, line height and family in one string, in this order, with the line height after a slash. Only the size and the family are required.

The shorthand font resets every property it does not mention. If you write font = "16px serif" after a font weight = 700 on the same element, the weight is back to 400. When you only want to change one thing, write that one property.

If a font has no bold or italic design, the browser fakes one by thickening or leaning the normal letters. The result is often a little ugly. font synthesis forbids this, and its parts font synthesis weight, font synthesis style, font synthesis small caps and font synthesis position forbid a single kind of faking.

Web fonts

To use a font that visitors do not have, ship the file with the page. The font element describes one file: name is the name you will use in font family, and url is the address of the file. Salam turns it into an @font-face rule, and the browser downloads the file only when some text uses the font. When one family has several files, write one font element per file with the same name and the weight or style that the file provides.

web-font-face.salam
page:
    title = "A web font"
    font:
        name = "Course Serif"
        url = "/fonts/course-serif.woff2"
        weight = 400
        style = normal
        display = swap
    end
    font:
        name = "Course Serif"
        url = "/fonts/course-serif-bold.woff2"
        weight = 700
        display = swap
    end
    global: selector = "body" font family = "'Course Serif', Georgia, serif" margin = "1.5rem" line height = 1.7 end
    heading: size = 2 content = "Reading in comfort" end
    paragraph: content = "The font files are not part of this preview, so the browser shows the next name in the stack." end
    paragraph: font weight = 700 content = "This line asks for weight 700 and would use the second file." end
end

The two files of this example do not exist in the preview, so the page shows the next font of the stack. That is the right way to build a page: the fallback must always be good enough to read. On your own site, put the files in a folder that your server serves, and the page starts using them. Salam checks the address while compiling: an unsafe address is an error, and a relative file that cannot be found next to the program is a warning. If you leave out type, Salam finds out the format from the end of the address.

Three attributes shape the loading. display = swap shows the fallback font at once and swaps in the real one when it arrives, so the text is never invisible. range lists the Unicode ranges a file covers, so a Persian file is downloaded only by pages that contain Persian letters. weight can be a range such as "100 900" for a variable font.

Every font file is a download, and a page that waits for five of them feels slow. Use one or two families, only the weights you really use, and the woff2 format, which is the smallest. And check the licence: a font on your computer is not always a font you may publish.

Features, variants and variable fonts

A good font contains more than letters: small capitals, several kinds of digits, ligatures (shapes where two letters join, such as fi) and alternate forms. They are called OpenType features, and each has a four letter tag such as smcp or liga. The properties that start with font variant switch the common ones in words: font variant caps, font variant numeric, font variant ligatures, font variant position, font variant alternates, font variant east asian and font variant emoji. font feature settings is the raw version for the rest: "'smcp' 1" turns a feature on, and 0 turns it off. font kerning controls the pair spacing, which is on by default and should stay on.

web-font-variants.salam
page:
    title = "Font variants"
    global: selector = "body" font family = "Georgia, serif" margin = "1.5rem" line height = 1.8 end
    paragraph: font variant caps = "small-caps" content = "Small capitals for a book title" end
    paragraph: font variant numeric = "tabular-nums" content = "1111 and 8888 line up in tables" end
    paragraph: font variant numeric = "oldstyle-nums" content = "Old style figures 2026 sit in the line" end
    paragraph: font variant ligatures = "none" content = "office affinity: ligatures switched off" end
    paragraph: font kerning = "none" content = "AVATAR WAVE: kerning switched off" end
    paragraph: font feature settings = "'smcp' 1" content = "The same small capitals through the raw feature tag" end
    paragraph: font variation settings = "'wght' 650" content = "A variable font reads this axis; others ignore it" end
end

A variable font is one file that contains a whole range of designs along axes, such as weight (wght) or width (wdth). font variation settings sets the axes by their tag, and font optical sizing lets a font with an optical size axis change its shape with the text size. When an ordinary property exists, use it: font weight = 650 sets the weight axis and is easier to read. font palette picks one of the colour sets of a colour font.

Features only work if the font has them. A font without small capitals shows the normal letters or, in some browsers, faked ones, and a line in the preview above may look unchanged. Test with the font you really use.

Aligning and transforming text

text align places the lines of a block. Use start and end and not left and right: they follow the direction of the text, so the same rule is correct for English and for Persian. center centres every line and justify stretches every line but the last to the full width. text align last sets the last line separately, and text justify chooses whether the extra space goes between words or between letters. text indent pushes the first line in, the way books mark a new paragraph. text transform changes the case of the shown letters without changing the text, which is better than typing capitals because a screen reader and a search still see the real text.

web-font-align.salam
page:
    title = "Aligning text"
    global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" line height = 1.6 end
    box: text align = "start" content = "Start: the side where reading begins." border = "1px solid #cbd5e1" padding = 8 margin bottom = 8 end
    box: text align = "center" content = "Center: lines in the middle." border = "1px solid #cbd5e1" padding = 8 margin bottom = 8 end
    box: text align = "end" content = "End: the side where reading ends." border = "1px solid #cbd5e1" padding = 8 margin bottom = 8 end
    box:
        text align = "justify"
        text align last = "center"
        text indent = "2em"
        border = "1px solid #cbd5e1"
        padding = 8
        margin bottom = 8
        max width = 420
        content = "Justified text stretches every line to the same width, and the last line can be placed on its own. The first line is indented by two letters."
    end
    box: text transform = "uppercase" content = "uppercase letters" end
    box: text transform = "capitalize" content = "every word starts large" end
end

Justified text needs wide lines. In a narrow column the gaps between words become large and uneven, so use justify only for wide blocks.

Lines, shadows and outlines

text decoration draws lines on text. It is a shorthand of four properties: text decoration line (underline, overline, line-through), text decoration style (solid, double, dotted, dashed, wavy), text decoration color and text decoration thickness. Two more properties tune underlines: text underline offset moves the line away from the letters, and text decoration skip ink decides if the line jumps over the tails of letters like g and y. text shadow adds one or more shadows, each as horizontal offset, vertical offset, blur and colour; two shadows of the same colour make a glow. webkit text stroke and webkit text fill color outline letters; the name starts with webkit because browsers adopted the idea under that prefix, and all of them still use it.

web-font-decoration.salam
page:
    title = "Decoration and shadow"
    global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" line height = 1.8 font size = 20 end
    paragraph: text decoration line = "underline" text decoration style = "wavy" text decoration color = "crimson" text decoration thickness = 2 content = "A red wavy underline" end
    paragraph: text decoration line = "underline" text underline offset = 6 text decoration skip ink = "none" content = "An underline moved down from the letters" end
    paragraph: text decoration = "line-through 2px #64748b" content = "Crossed out in one shorthand" end
    paragraph: text decoration line = "overline underline" text decoration style = "double" content = "A line above and a double line below" end
    paragraph: text shadow = "2px 2px 4px #94a3b8" font size = 32 font weight = 700 content = "Soft shadow" end
    paragraph: text shadow = "0 0 8px #38bdf8, 0 0 16px #0ea5e9" color = "white" background = "#0f172a" padding = 8 content = "A glow made of two shadows" end
    paragraph: webkit text stroke = "1px #0f172a" webkit text fill color = "transparent" font size = 40 font weight = 700 content = "Outline" end
end

People expect an underline to mean a link. Do not underline other text, and do not remove the underline of real links without another clear sign, such as a different colour plus a weight. Shadows and outlines also reduce contrast, so check that the text stays readable.

Line height and spacing

line height is the most important property for reading. Give it a plain number, without a unit: 1.6 means 1.6 times the font size of that element, and a child with a larger size gets a larger line height by itself. A length such as "24px" is passed to the children as a fixed result and makes big headings overlap. Around 1.5 suits English, and Persian needs about 1.9 because of its dots and marks above and below the line. letter spacing and word spacing add space between letters and between words. A small positive letter spacing is good for capitals, and a tiny negative one for very large headings. vertical align moves an inline element up or down within the line, as super and sub do for powers and indices. tab size sets the width of a tab character in preformatted text.

web-font-spacing.salam
page:
    title = "Spacing"
    global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" end
    box: width = 300 line height = 1 background = "#f1f5f9" margin bottom = 12 content = "line height 1: the lines of this paragraph are packed tightly together." end
    box: width = 300 line height = 1.6 background = "#f1f5f9" margin bottom = 12 content = "line height 1.6: comfortable for reading long text in a paragraph." end
    box: width = 300 line height = 2.2 background = "#f1f5f9" margin bottom = 12 content = "line height 2.2: so open that the lines start to fall apart." end
    box: letter spacing = "0.25em" text transform = "uppercase" font size = 14 margin bottom = 12 content = "Letter spacing for a label" end
    box: word spacing = "0.5em" content = "Words spread apart by half a letter" end
end

Do not use letter spacing on Persian or Arabic. The letters of these scripts are joined, and a gap between them cuts the word into pieces. Browsers treat it differently, and where a gap is added it cuts the word apart, so the safe value is always 0 or nothing.

Wrapping and cutting

Normally the browser breaks a line at spaces. white space changes this: nowrap never breaks, pre keeps the text as typed, pre-wrap keeps it and still wraps, and pre-line keeps only the line breaks. white space collapse is the "what happens to spaces" half of it. When a single word is longer than its box, overflow wrap = "anywhere" lets it break so it does not stick out of the page, which is exactly what a long web address needs. word break = "break-all" breaks everywhere, even where the word would fit, and keep-all is for Chinese, Japanese and Korean, where it forbids breaks inside a word. hyphens = "auto" hyphenates words in languages the browser has a dictionary for, if the element has the right lang. text wrap = "balance" evens out the lines of a short heading, and pretty avoids a last line with one short word.

web-font-wrapping.salam
page:
    title = "Wrapping long text"
    global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" end
    box: width = 180 white space = "nowrap" overflow = "hidden" text overflow = "ellipsis" background = "#f1f5f9" margin bottom = 12 content = "This sentence is far too long for its box" end
    box: width = 180 overflow wrap = "anywhere" background = "#e0f2fe" margin bottom = 12 content = "https://example.com/a/very/long/address/that-does-not-fit" end
    box: width = 180 word break = "break-all" background = "#fef9c3" margin bottom = 12 content = "Break-all cuts at any letter, even in short words." end
    box: width = 180 hyphens = "auto" lang = "en" background = "#dcfce7" margin bottom = 12 content = "Hyphenation helps incomprehensibilities fit narrow columns." end
    box: width = 180 white space = "pre-line" background = "#fae8ff" content = "Line breaks in the source\nare kept\nwith pre-line." end
end

To show only the first lines of a long text, you have two tools. text overflow = "ellipsis" replaces the cut-off end of one line with an ellipsis, and line clamp limits a block to a number of lines. Both are new or fussy, so build the example below the way it is written: with a max height and overflow = "hidden" as a safety net that works everywhere.

web-font-clamp.salam
page:
    title = "Clamping lines"
    global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" end
    box:
        width = 260
        line height = 1.5
        line clamp = 3
        overflow = "hidden"
        max height = "4.5em"
        background = "#f1f5f9"
        padding = "0 10"
        content = "A card preview shows only the first lines of a long text, so every card in a list keeps the same height, however much the author wrote. Everything after the third line is cut off here."
    end
    heading: size = 3 text wrap = "balance" max width = 260 content = "A long headline that is split into two lines of similar length" end
end

text overflow does nothing alone. It needs three properties together: overflow (anything but visible), white space = "nowrap" and a limited width. If you see no ellipsis, one of the three is missing.

Direction and vertical text

direction chooses ltr or rtl for the text of an element. In practice you set the direction with the dir attribute (see the lesson on the head and global attributes) because it tells screen readers too, and use the CSS property only for a rule that applies to many elements. unicode bidi controls how text of mixed directions is ordered, and bidi-override forces the order whatever the letters are; the elements isolate and direction override in the lesson on text elements do the same job.

writing mode goes further and turns the lines themselves: vertical-rl writes down the page and stacks the lines from right to left, as in Japanese and Chinese. text orientation decides whether the letters of other scripts stand up or lie down, and text combine upright squeezes a short run, such as a year, into the space of one character.

web-font-vertical.salam
page:
    title = "Vertical writing"
    global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" end
    box: display = "flex" gap = 32 font size = 22 height = 200
        box: writing mode = "vertical-rl" content = "Vertical lines run top to bottom" end
        box: writing mode = "vertical-rl" text orientation = "upright" content = "UPRIGHT" end
        box: writing mode = "vertical-rl"
            content = "In "
            span: text combine upright = "all" content = "2026" end
        end
    end
end

Ruby and emphasis marks

Ruby is a small annotation above or below a word, mostly the pronunciation of a Chinese or Japanese word, written with the ruby and ruby text elements. ruby position sets the side and ruby align how the annotation is spread over the word. East Asian text has no italics, so emphasis is drawn as small marks on each character, with text emphasis style, text emphasis color and text emphasis position. The shorthand is text emphasis.

web-font-ruby.salam
page:
    title = "Ruby and emphasis"
    global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" font size = 26 line height = 2.2 end
    paragraph:
        ruby: ruby position = "over" ruby align = "center"
            content = "東京"
            ruby parenthesis: content = "(" end
            ruby text: content = "とうきょう" end
            ruby parenthesis: content = ")" end
        end
    end
    paragraph: text emphasis style = "filled dot" text emphasis color = "crimson" content = "Dots mark the emphasis" end
    paragraph: text emphasis style = "open circle" text emphasis position = "under right" content = "Circles below the text" end
end

Persian and Arabic text

Everything above works for Persian, and a few points need care. A page in a Persian file already has lang = "fa" and the right-to-left direction. Then:

  • Choose a font that has Persian letters, and put a safe one at the end of the stack, such as Tahoma. Many fonts made for English have no Persian letters, and the browser fills the gap letter by letter from another font, which looks uneven. A web font such as Vazirmatn or Estedad is the real fix: load it with the font element and the range of the Persian block.
  • Set line height to about 1.9 for body text. Persian letters carry dots and marks that need space above and below.
  • Use text align start and end, never left and right.
  • Keep letter spacing at zero. Do not turn ligatures off either, because the joined forms are the script itself.
  • Digits are characters, not a style. ۱۲۳ and 123 are different letters, and no CSS property converts one into the other. font variant numeric only changes the look of the digits a font has, such as the equal width form for columns.
  • Browsers do not hyphenate Persian, and justify works well if the lines are long.
  • Italics are rare in Persian type. A line that is only oblique looks slanted, which is fine for a short quotation but tiring for a paragraph. Use bold, or a different size, for emphasis.
web-font-persian.salam
page:
    title = "Persian text"
    global: selector = "body" font family = "Tahoma, system-ui, sans-serif" margin = "1.5rem" end
    box: dir = "rtl" lang = "fa" line height = 1.9 margin bottom = 16 border = "1px solid #cbd5e1" padding = 10 max width = 340
        content = "هر کتاب برای خواننده‌ای نوشته می‌شود. این بند ۳ سطر دارد و ارتفاع خطش ۱٫۹ است تا نقطه‌ها و کسره‌ها جا داشته باشند."
    end
    box: dir = "rtl" lang = "fa" line height = 1.2 margin bottom = 16 border = "1px solid #fecaca" padding = 10 max width = 340
        content = "همین متن با ارتفاع خط ۱٫۲ فشرده و خسته‌کننده می‌شود، چون سطرها به هم می‌چسبند و نقطه‌ها روی هم می‌افتند."
    end
    box: dir = "rtl" lang = "fa" line height = 1.9 text align = "justify" max width = 340 border = "1px solid #cbd5e1" padding = 10
        content = "ترازشدن دوطرفه در متن فارسی خوب کار می‌کند، به شرط آنکه خط‌ها به اندازه‌ی کافی بلند باشند."
    end
end

The example puts the same text three times. The first box has a comfortable line height, the second a tight one where the lines nearly touch, and the third is justified. The preview shows the page as the compiler built it, with Persian letters from the system.

Reference: every font and text property

Each entry shows the name in Salam, its name in CSS, the values it accepts and an example. The examples are checked by the compiler, so you can paste any of them inside a page: block. The colour of text, color, belongs to the lesson on colours and backgrounds, and the box around the text to the lessons that follow it. Persian names work in any file, and the Persian lessons use them.

Fonts: family, size, weight and style

These choose the font and its basic look.

PropertyWhat it does and what it acceptsExample
font family
خانواده قلم
font-family
The fonts to try, in order. The browser uses the first one that is installed (or loaded) and has the letters it needs, so always end the list with a generic family: serif, sans-serif, monospace, cursive, fantasy or system-ui. A name with spaces goes in single quotes inside the string. [comma list of names, quoted names and generic families (serif, sans-serif, ...)]box: font family = "Georgia, 'Times New Roman', serif" content = "A serif stack" end
font size
اندازه قلم
font-size
The size of the letters. A bare number means pixels. "1.5rem" is relative to the size of the page root, "1.2em" and percentages to the size of the parent, and vw to the width of the window. The keywords xx-small to xx-large are fixed steps chosen by the browser, and smaller and larger move one step from the parent. [length / percentage / xx-small, x-small, small, medium, large, x-large, ...]box: font size = "1.5rem" content = "One and a half root sizes" end
font size adjust
تنظیم اندازه قلم
font-size-adjust
Rescales a fallback font so that its lowercase letters look as tall as the first font's. The number is the wanted ratio of lowercase height to font size, for example 0.5, and none switches it off. It stops text from jumping in size when a web font is replaced by a fallback. [number / none]box: font size adjust = "0.5" content = "Same apparent size in every font" end
font weight
وزن قلم
font-weight
How heavy the strokes are. Use a number from 1 to 1000 (100 is thin, 400 is normal, 700 is bold, 900 is black) or the words normal and bold. bolder and lighter go one step from the parent. A font that has only two weights shows the nearest one, and a variable font can show every number. [number / normal, bold, bolder, lighter]box: font weight = 700 content = "Bold text" end
font style
سبک قلم
font-style
Chooses the upright, italic or oblique design. italic uses the font's own italic letters if it has them, and oblique slants the upright letters. Persian fonts rarely have an italic design, so the browser slants the letters. [normal, italic, oblique]box: font style = "italic" content = "Italic text" end
font stretch
کشیدگی قلم
font-stretch
Selects a narrower or wider design of the font, from 50% to 200% or with words such as condensed and expanded. It only does something when the font has width variants, and it never squeezes letters by itself. [percentage / normal, condensed, expanded]box: font stretch = "condensed" content = "A narrow design" end
font width
پهنای قلم
font-width
The newer name of font stretch, with the same values. Older browsers only know font stretch, so use that one when the page must work everywhere. [a percentage / a font-stretch keyword]box: font width = "75%" content = "Seventy five percent wide" end
font
قلم
font
The shorthand for style, weight, width, size, line height and family in one string: "italic 700 1.25rem/1.5 Georgia, serif". The size and the family are required, in that order, and every property you leave out is reset to its normal value, so it can wipe settings made earlier. [CSS-wide keywords only]box: font = "italic 700 1.25rem/1.5 Georgia, serif" content = "Style, weight, size, line height and family at once" end
font synthesis
ساخت قلم
font-synthesis
Decides what the browser may fake when the font lacks it: weight (bold), style (italic), small-caps and position (sub and superscript). none forbids all of it, which keeps the shapes true to the type designer. [up to 4 values]box: font synthesis = "none" content = "No faked bold or italic" end
font synthesis weight
ساخت وزن قلم
font-synthesis-weight
Allows (auto) or forbids (none) a bold that the browser draws by thickening the regular letters. [auto / none]box: font synthesis weight = "none" content = "No fake bold" end
font synthesis style
ساخت سبک قلم
font-synthesis-style
Allows (auto) or forbids (none) an italic made by slanting the upright letters. oblique-only keeps the slant but never uses it for italic. [auto / none / oblique-only]box: font synthesis style = "none" content = "No fake italic" end
font synthesis small caps
ساخت حروف کوچک قلم
font-synthesis-small-caps
Allows (auto) or forbids (none) small capitals made by shrinking full capitals. [auto / none]box: font synthesis small caps = "none" content = "No fake small capitals" end
font synthesis position
ساخت جایگاه قلم
font-synthesis-position
Allows (auto) or forbids (none) subscripts and superscripts made by shrinking and moving the normal letters. [auto / none]box: font synthesis position = "none" content = "No fake superscript" end

Fonts: features, variants and variable fonts

These switch the extra forms and axes a font offers. The effect depends on the font.

PropertyWhat it does and what it acceptsExample
font kerning
فاصله‌گذاری قلم
font-kerning
Turns the font's kerning on or off. Kerning pulls certain pairs of letters, such as AV, closer together. auto and normal use it, none does not. Leave it on for text, and only switch it off for tests or special effects. [auto, normal, none]box: font kerning = "none" content = "AVATAR WAVE without kerning" end
font optical sizing
اندازه بصری قلم
font-optical-sizing
Lets a variable font that has an optical size axis change the shape of its letters with the text size: sturdier at small sizes, finer at large ones. auto does it, none keeps one design. It has no effect on ordinary fonts. [auto, none]box: font optical sizing = "none" content = "Same design at every size" end
font variant
نسخه قلم
font-variant
A shorthand that picks several alternate letter forms at once: small-caps, a numeric style, ligatures and so on, or normal to reset them. Use the longer properties below when you want to set only one thing. [up to 99 values]box: font variant = "small-caps" content = "Small capitals" end
font variant caps
حروف بزرگ قلم
font-variant-caps
Chooses capital-letter forms: small-caps (lowercase letters become small capitals), all-small-caps (capitals too), petite-caps, unicase and titling-caps. If the font has no such shapes, browsers may fake the first two. [normal, small-caps, all-small-caps]box: font variant caps = "all-small-caps" content = "Every letter a small capital" end
font variant ligatures
پیوندها نسخه قلم
font-variant-ligatures
Controls ligatures, the joined shapes such as fi. Words: common-ligatures, no-common-ligatures, discretionary-ligatures, historical-ligatures, contextual, or none for all off. Do not switch ligatures off for Persian and Arabic, where joined forms are the script itself. [up to 4 values]box: font variant ligatures = "no-common-ligatures" content = "office affinity without ligatures" end
font variant numeric
عددی نسخه قلم
font-variant-numeric
Chooses the shape and spacing of digits: lining-nums, oldstyle-nums, proportional-nums, tabular-nums (every digit equally wide, for columns), diagonal-fractions, slashed-zero and ordinal. The font must contain these forms. It does not turn English digits into Persian digits: that is a matter of the characters you write. [up to 5 values]box: font variant numeric = "tabular-nums" content = "1111 and 8888 line up" end
font variant east asian
آسیایی شرق نسخه قلم
font-variant-east-asian
Picks forms of Chinese and Japanese characters: simplified, traditional, the JIS standards jis78 to jis04, full-width, proportional-width and ruby. It only matters for a font that carries several forms of the same character. [up to 3 values]box: font variant east asian = "traditional" content = "漢字 in the traditional forms" end
font variant alternates
جایگزین های نسخه قلم
font-variant-alternates
Switches on alternate glyphs the font offers: historical-forms, or the functions stylistic(), styleset(), swash(), ornaments() and annotation(), which take a name defined by a font feature values rule. [up to 9 of historical-forms or a function like swash()]box: font variant alternates = "historical-forms" content = "Historical letter forms" end
font variant position
جایگاه نسخه قلم
font-variant-position
Uses the font's own subscript (sub) or superscript (super) glyphs, which are drawn to match the weight of the text. normal uses neither. [normal / sub / super]box: font variant position = "super" content = "x2 as a real superscript" end
font variant emoji
گونه شکلک قلم
font-variant-emoji
Chooses how characters that exist both as symbols and as emoji are drawn: text (a plain monochrome glyph), emoji (the colour picture), unicode (as the character itself says) or normal (the browser decides). [normal / text / emoji / unicode]box: font variant emoji = "text" content = "A heart as plain text: ❤" end
font feature settings
تنظیمات ویژگی قلم
font-feature-settings
Switches OpenType features by their four letter tags: a comma list such as 'smcp' 1, 'liga' 0, where 1 is on and 0 is off. It is the low level tool, so prefer the font variant properties and use this one for features that have none. [comma list]box: font feature settings = "'smcp' 1, 'liga' 0" content = "Small capitals, no ligatures" end
font variation settings
تنظیمات تغییر قلم
font-variation-settings
Sets the axes of a variable font by their four letter tags, as a comma list such as 'wght' 650, 'wdth' 90. Ordinary fonts ignore it. When a normal property exists, such as font weight for wght, use that property instead. [comma list]box: font variation settings = "'wght' 650, 'wdth' 90" content = "A weight between two steps" end
font palette
پالت قلم
font-palette
Chooses the colour palette of a colour font: light, dark, normal, or the name of a palette defined with a @font-palette-values rule. Fonts without colour layers ignore it. [normal / light / dark / an ident / palette-mix()]box: font palette = "dark" content = "A colour font in its dark palette" end
font language override
جایگزینی زبان قلم
font-language-override
Forces the OpenType language system, written as a four letter tag in quotes such as 'TRK', instead of the one taken from the lang attribute. normal goes back to the default. Rarely needed. [a quoted string / normal]box: font language override = "'TRK'" content = "Turkish forms of the letters" end

Web font element

The font element goes directly inside the page.

font (Persian: قلم)

Declares a web font, which becomes an @font-face rule. name and url are required, and the element goes directly inside the page. Afterwards write the name in font family. Browsers download the file only when some text uses the font, and until then they show the next font of the stack.

font:
    name = "Course Serif"
    url = "/fonts/course-serif.woff2"
    weight = 400
    display = swap
end
box: font family = "Course Serif, Georgia, serif" content = "Set in the course font" end

Required: name, url · Only inside: page · Void element, it cannot have children

AttributeWhat it doesExample
name
نام
The family name you choose for the font. It is free text and has nothing to do with the name of the file: you write the same name later in font family. Required. [string]font: name = "Course Serif" url = "/fonts/course-serif.woff2" end box: font family = "Course Serif, serif" content = "The name is what font family uses" end
url
نشانی
Where the font file is. Write one address, or several separated by spaces, best first: the browser takes the first format it understands (woff2 before woff). A relative address is read from the page, an unsafe one such as javascript: is an error, and a relative file that does not exist next to the program gives a warning. Required. [url (list)]font: name = "Course Serif" url = "/fonts/course-serif.woff2 /fonts/course-serif.woff" end
type
نوع
The file format: woff2, woff, ttf (truetype), otf (opentype) or collection. Leave it out and Salam works it out from the end of the address, then from the bytes of a file next to the program. A type that disagrees with the file is an error. [enum: font_format]font: name = "Course Serif" url = "/fonts/course-serif.bin" type = woff2 end
weight
وزن
The weight this file provides, a number from 1 to 1000 such as 400 or 700. For a variable font give the range inside a string, such as "100 900". A number outside the range is an error. Declare one font per weight with the same name. [string]font: name = "Course Serif" url = "/fonts/course-serif-bold.woff2" weight = 700 end
style
سبک
The style this file provides: normal, italic or oblique. The browser picks the file whose style matches the text. [enum: font_style]font: name = "Course Serif" url = "/fonts/course-serif-italic.woff2" style = italic end
display
نمایش
What the browser shows while the font file is still loading. swap shows the fallback font at once and swaps when the file arrives (the usual choice), block hides the text for a moment, fallback and optional swap late or never on a slow line, and auto leaves it to the browser. [enum: font_display]font: name = "Course Serif" url = "/fonts/course-serif.woff2" display = swap end
range
بازه
The characters this file covers, as Unicode ranges separated by commas. The browser downloads the file only when the page contains a character of that range, so a font split into a Latin file and a Persian file loads only what the page uses. U+0600-06FF is the Arabic and Persian block. [string]font: name = "Course Serif" url = "/fonts/course-serif-arabic.woff2" range = "U+0600-06FF, U+200C-200D" end

Text appearance: alignment, case, lines and shadows

These change how a line of text is placed and drawn.

PropertyWhat it does and what it acceptsExample
text align
ترازمتن
text-align
How the lines of a block sit between its sides: start and end follow the reading direction (right and left in Persian), left and right are fixed, center and justify stretch every line but the last to the full width. Prefer start to left so that one page works in both directions. [start, end, left, right, center, justify]box: text align = "center" content = "Centered text" end
text align last
تراز خط آخر
text-align-last
Sets the alignment of the last line of a block, and of lines that end with a forced break. It takes the same words as text align plus auto. It is mostly used with text align = "justify". [auto, start, end, left, right, center, ...]box: text align last = "center" content = "The last line of a justified block is centered. It wraps over a few lines in a narrow box to show it." end
text justify
چینش متن
text-justify
Where a justified line gets its extra space: inter-word (between words), inter-character (between letters), auto or none. It only matters when text align is justify. [auto, none, inter-word, inter-character]box: text align = "justify" text justify = "inter-character" width = 260 content = "Space is added between letters when the text is justified, which is how Chinese and Japanese are set." end
text indent
تورفتگی متن
text-indent
The empty space before the first line of a block. A length or a percentage, and a negative number pushes the first line out, which together with padding makes a hanging indent. [length / percentage]box: text indent = "2em" content = "The first line of a paragraph starts two letters in. The rest of the lines do not move, so the paragraph reads like in a book." end
text transform
تبدیل متن
text-transform
Changes the case of the shown letters without touching the text itself: uppercase, lowercase, capitalize (the first letter of each word) or none. Persian and Arabic have no case, so it does nothing to them. [none, uppercase, lowercase, capitalize]box: text transform = "uppercase" content = "shout in capitals" end
text decoration
تزیین متن
text-decoration
The shorthand for line, style, colour and thickness of the lines drawn on text: "underline wavy crimson". Links have an underline by default, and "none" removes it. [CSS-wide keywords only]box: text decoration = "underline wavy crimson" content = "A wavy red underline" end
text decoration line
خط تزیین متن
text-decoration-line
Which lines are drawn: underline, overline, line-through or none. You can list several words in one string. [none, underline, overline, line-through; up to 3 values]box: text decoration line = "underline overline" content = "A line above and a line below" end
text decoration style
سبک تزیین متن
text-decoration-style
The look of the line: solid, double, dotted, dashed or wavy. It needs a decoration line to be visible. [solid, double, dotted, dashed, wavy]box: text decoration style = "dashed" content = "A dashed underline" end
text decoration color
رنگ تزیین متن
text-decoration-color
The colour of the decoration line. Without it the line takes the colour of the text. [color]box: text decoration line = "underline" text decoration color = "crimson" content = "A crimson underline" end
text decoration thickness
ضخامت تزیین متن
text-decoration-thickness
The thickness of the line: a length, a percentage of the font size, auto or from-font, which uses what the font recommends. [length / percentage / auto, from-font]box: text decoration line = "underline" text decoration thickness = 4 content = "A thick underline" end
text decoration skip ink
پرش جوهر تزیین
text-decoration-skip-ink
Whether an underline or overline skips the parts of letters it would touch, such as the tail of a g. auto skips, none draws through them, and all skips for every script. [auto, none, all]box: text decoration line = "underline" text decoration skip ink = "none" content = "The line runs through gypsy and jumpy" end
text underline offset
فاصله زیرخط
text-underline-offset
How far the underline sits from the baseline: a length, a percentage or auto. A bigger number moves it away from the letters. [length / percentage / auto]box: text decoration line = "underline" text underline offset = 8 content = "An underline moved down" end
text underline position
جای زیرخط
text-underline-position
Where an underline goes: auto, under (below every descender) or, for vertical text, left and right. Useful for scripts with long descenders. [auto, under, left, right; up to 2 values]box: text decoration line = "underline" text underline position = "under" content = "The line sits below the lowest letters" end
text shadow
سایه متن
text-shadow
One or more shadows, separated by commas. Each one is: horizontal offset, vertical offset, an optional blur and a colour, for example "2px 2px 4px #94a3b8". Several shadows make glows and outlines. Keep enough contrast so the text stays readable. [comma list]box: text shadow = "2px 2px 4px #94a3b8" content = "A soft shadow" end
webkit text stroke
خط دور متن
-webkit-text-stroke
Draws an outline around each letter: a width and a colour, such as "1px #0f172a". Every current browser supports it under the -webkit- name. Combine it with a transparent fill colour for outlined text. [length and color, in either order]box: webkit text stroke = "1px #0f172a" webkit text fill color = "transparent" font size = 36 font weight = 700 content = "Outline" end
webkit text stroke width
ضخامت خط دور متن
-webkit-text-stroke-width
The width of the outline only: a length or thin, medium, thick. A thick stroke eats into the letters, since it is centred on their edge. [length / thin / medium / thick]box: webkit text stroke width = 2 webkit text stroke color = "teal" font size = 36 font weight = 700 content = "Thick outline" end
webkit text stroke color
رنگ خط دور متن
-webkit-text-stroke-color
The colour of the outline only. It needs a stroke width above zero to be seen. [color]box: webkit text stroke width = 1 webkit text stroke color = "crimson" font size = 36 font weight = 700 content = "Red outline" end
webkit text fill color
رنگ پر متن
-webkit-text-fill-color
The colour that fills the letters. It beats color when both are set, and transparent lets the background or the stroke show through. [color]box: webkit text fill color = "#0f766e" content = "Filled with teal" end
text rendering
نمایش متن
text-rendering
A hint about speed against quality: auto, optimizeSpeed, optimizeLegibility (kerning and ligatures on) or geometricPrecision. Browsers may ignore it. [auto, optimizeSpeed, optimizeLegibility, geometricPrecision]box: text rendering = "optimizeLegibility" content = "Optimised for reading" end

Spacing and wrapping

These set the space between lines, letters and words, and decide where lines break or are cut.

PropertyWhat it does and what it acceptsExample
line height
ارتفاع خط
line-height
The height of each line. A bare number (1.6) is multiplied by the font size of the element and is the best choice, because children inherit the number and not a fixed result. A length or a percentage gives a fixed height. Use about 1.5 for English and about 1.9 for Persian. [number / length / percentage / normal]box: line height = 1.7 width = 260 background = "#f1f5f9" content = "Lines that have room to breathe. A number is multiplied by the font size, so it follows the text when the size changes." end
letter spacing
فاصله حروف
letter-spacing
Extra space between letters: a length, best in em so it grows with the text, or normal. A small positive value suits capitals and labels. Never use it on Persian or Arabic, whose letters join and must stay joined. [length / normal]box: letter spacing = "0.2em" text transform = "uppercase" content = "spaced capitals" end
word spacing
فاصله واژه‌ها
word-spacing
Extra space between words: a length, a percentage or normal. A negative value pulls them closer. [length / percentage / normal]box: word spacing = "0.6em" content = "Words pushed apart a little" end
vertical align
تراز عمودی متن
vertical-align
Where an inline element or a table cell sits vertically: baseline, sub, super, top, middle, bottom, text-top, text-bottom, or a length that raises (positive) or lowers (negative) it. It does not centre a box inside its parent. [length / percentage / baseline, sub, super, text-top, text-bottom, middle, ...]box: vertical align = "super" font size = 22 content = "x2 raised on the line" end
white space
فضای سفید
white-space
How spaces and line breaks in the text are treated: normal merges them and wraps, nowrap never wraps, pre keeps everything and never wraps, pre-wrap keeps everything and wraps, pre-line keeps the line breaks only and break-spaces keeps spaces that can wrap. [normal, nowrap, pre, pre-wrap, pre-line, break-spaces]box: white space = "pre-line" width = 220 background = "#f1f5f9" content = "Breaks in the text\nare kept as they are\nin this box." end
white space collapse
ادغام فضای سفید
white-space-collapse
Only the spaces half of white space: collapse (merge), preserve (keep all), preserve-breaks (keep line breaks, merge spaces), preserve-spaces and break-spaces. [collapse, preserve, preserve-breaks, preserve-spaces, break-spaces]box: white space collapse = "preserve-breaks" width = 220 background = "#f1f5f9" content = "Line breaks\nstay, extra spaces go." end
word break
شکستن واژه
word-break
Where a line may break inside words: normal, break-all (between any two letters), keep-all (never inside Chinese, Japanese and Korean words) or break-word. For ordinary text overflow wrap is the better tool. [normal, break-all, keep-all, break-word]box: word break = "break-all" width = 150 background = "#fef9c3" content = "Break-all cuts words anywhere" end
overflow wrap
شکستن سرریز
overflow-wrap
Lets a word that is too long for the box break so it does not stick out. normal never breaks it, break-word breaks only if there is no other way, and anywhere does the same and also counts the break points when the box size is computed. [normal, break-word, anywhere]box: overflow wrap = "anywhere" width = 150 background = "#e0f2fe" content = "https://example.com/an/address/with/no/spaces" end
line break
قاعده شکستن خط
line-break
How strict the rules are for where a line may break, mostly for Chinese and Japanese: auto, loose, normal, strict or anywhere. [auto, loose, normal, strict, anywhere]box: line break = "anywhere" width = 150 background = "#e0f2fe" content = "Strict rules or loose rules for where lines may break." end
hyphens
خط تیره
hyphens
Whether a word may be split with a hyphen at the end of a line: none, manual (only at soft hyphens you write) or auto (the browser decides). auto needs a lang it has a dictionary for, and browsers do not hyphenate Persian. [none, manual, auto]box: hyphens = "auto" lang = "en" width = 160 background = "#dcfce7" content = "Hyphenation helps incomprehensibilities fit narrow columns." end
hyphenate character
نویسه خط تیره
hyphenate-character
The character shown where a word is broken by hyphenation. auto uses the hyphen of the language, and a string such as "~" uses that instead. [string / auto]box: hyphens = "auto" hyphenate character = "\"~\"" lang = "en" width = 160 background = "#dcfce7" content = "Incomprehensibilities break with a tilde." end
hyphenate limit chars
حد نویسه خط تیره
hyphenate-limit-chars
Limits hyphenation to words of a certain size: up to three numbers for the shortest word, the shortest part before the hyphen and the shortest part after it, for example "8 3 3". auto leaves it to the browser. [up to 3 of an integer or auto]box: hyphens = "auto" hyphenate limit chars = "8 3 3" lang = "en" width = 160 background = "#dcfce7" content = "Only long words are hyphenated, never leaving a short stub." end
text wrap
پیچش متن
text-wrap
How lines are broken. wrap is normal, nowrap never breaks, balance makes the lines about equally long (good for headings), pretty avoids a lone short word on the last line, and stable does not reflow lines while you edit the text. [wrap, nowrap, balance, pretty, stable]box: text wrap = "balance" width = 260 font size = 22 font weight = 700 content = "A headline that is split into two even lines" end
text wrap mode
حالت پیچش متن
text-wrap-mode
Only the first half of text wrap: wrap lets lines break and nowrap keeps all text on one line. [CSS-wide keywords only]box: text wrap mode = "nowrap" width = 160 overflow = "hidden" background = "#f1f5f9" content = "A sentence that refuses to wrap" end
text wrap style
سبک پیچش متن
text-wrap-style
Only the second half of text wrap: auto, balance, pretty or stable. [CSS-wide keywords only]box: text wrap style = "pretty" width = 200 background = "#f1f5f9" content = "A paragraph that avoids ending on a single short word" end
text overflow
سرریز متن
text-overflow
What a line shows where it is cut off: clip cuts it, ellipsis ends it with an ellipsis. It works only when the box has overflow other than visible and the text cannot wrap, so it is used together with white space = "nowrap". [clip, ellipsis]box: text overflow = "ellipsis" white space = "nowrap" overflow = "hidden" width = 180 background = "#f1f5f9" content = "This sentence is far too long for its box" end
line clamp
محدود کردن سطرها
line-clamp
Limits a block to a number of lines (an integer) and shows an ellipsis at the cut. It is a new standard property that only recent browsers have, so also give the box max height and overflow as in the example, which cuts the text in every browser. [integer / none]box: line clamp = 2 overflow = "hidden" max height = "3em" line height = 1.5 width = 220 background = "#f1f5f9" content = "A long text that is limited to a number of lines and ends with an ellipsis when it does not fit." end
tab size
اندازه زبانه
tab-size
The width of a tab character: a number of spaces or a length. It only matters in text where tabs survive, that is in white space = "pre" or pre-wrap, such as source code. [integer / length]box: tab size = 2 white space = "pre" font family = "monospace" content = "a\tb\tc" end
orphans
سطرهای یتیم
orphans
In printed or multi-column text, the least number of lines of a paragraph that may stay alone at the bottom of a page or column. An integer, usually 2 or 3. [integer]box: orphans = 3 content = "At least three lines stay at the bottom of a page when printed." end
widows
سطرهای بیوه
widows
The opposite of orphans: the least number of lines of a paragraph that may stay alone at the top of the next page or column. [integer]box: widows = 3 content = "At least three lines go to the top of the next page when printed." end
hanging punctuation
نشانه‌گذاری آویزان
hanging-punctuation
Lets an opening quote or a closing mark hang outside the text edge so the letters line up: first, last, force-end, allow-end or none. Only Safari supports it. [none, first, last, force-end, allow-end; up to 3 values]box: hanging punctuation = "first" content = "“The quote mark hangs outside the edge of the text.”" end
text box
جعبه متن
text-box
The shorthand of text box trim and text box edge: "trim-both cap alphabetic" cuts the empty space above the capitals and below the baseline. normal cuts nothing. [normal or a trim keyword with an edge keyword]box: text box = "trim-both cap alphabetic" font size = 28 background = "#fef9c3" content = "Tight around the letters" end
text box trim
برش جعبه متن
text-box-trim
Removes the half-leading, the extra space the line height adds above the first line and below the last one: trim-start, trim-end, trim-both or none. It is a new property, so check browser support first. [none / trim-start / trim-end / trim-both]box: text box trim = "trim-both" text box edge = "cap alphabetic" font size = 28 background = "#fef9c3" content = "Half-leading removed" end
text box edge
لبه جعبه متن
text-box-edge
Which lines the trimmed edges are measured from: for the top text, cap or ex, for the bottom text or alphabetic, such as "cap alphabetic". Used together with text box trim. [up to 2 of auto, text, cap, ex, alphabetic, ...]box: text box trim = "trim-both" text box edge = "ex alphabetic" font size = 28 background = "#fef9c3" content = "Edges at the x-height" end
initial letter
حرف آغازین
initial-letter
Makes the first letter of a block a drop cap that spans a number of lines, for example 3 for three lines. A second number sets how far it sinks. It applies to the first letter of a block, and browser support is still partial. [normal / number, with an optional drop/raise count]box: width = 260 font size = 18 span: initial letter = 3 color = "crimson" content = "S" end span: content = "alam begins with a tall first letter." end end

Direction and writing modes

These set the direction of the text and turn lines upright.

PropertyWhat it does and what it acceptsExample
direction
جهت متن
direction
The writing direction of the text of an element: ltr (left to right) or rtl (right to left). It decides which side start is, where the punctuation goes and which way the columns of a table run. For a whole element, the dir attribute is the better choice, because it also tells assistive technology. [ltr, rtl]box: direction = "rtl" width = 260 background = "#f1f5f9" content = "Right to left text: (end of the sentence)." end
unicode bidi
دوسویه یونیکد
unicode-bidi
How mixed direction text is ordered. normal uses the standard algorithm, isolate lays the element out on its own, embed opens a new level, bidi-override forces the order of direction whatever the letters are, and plaintext chooses by the first strong letter. [normal, embed, isolate, bidi-override, isolate-override, plaintext]box: unicode bidi = "bidi-override" direction = "rtl" content = "Reversed by force" end
writing mode
حالت نوشتار
writing-mode
The direction in which lines run: horizontal-tb (normal), vertical-rl (lines go top to bottom and are stacked from right to left, as in Japanese) or vertical-lr (stacked left to right). All the logical properties turn with it. [horizontal-tb, vertical-rl, vertical-lr]box: writing mode = "vertical-rl" height = 160 font size = 22 content = "Vertical text runs top to bottom" end
text orientation
جهت‌گیری متن
text-orientation
How letters stand in vertical text: mixed turns Latin letters sideways and keeps East Asian characters upright, upright keeps every letter upright, and sideways turns all of them. [mixed, upright, sideways]box: writing mode = "vertical-rl" text orientation = "upright" height = 160 font size = 22 content = "UPRIGHT" end
text combine upright
ترکیب ایستاده متن
text-combine-upright
In vertical text, sets a short run of characters, such as a year, side by side in the space of one character. all does it for the whole element and none does not. Used on a span inside a vertical block. [none, all]box: writing mode = "vertical-rl" height = 140 font size = 22 content = "Year " span: text combine upright = "all" content = "2026" end end

Ruby, emphasis and East Asian typography

These are made for Chinese, Japanese and Korean, though most of them work with any text.

PropertyWhat it does and what it acceptsExample
ruby align
تراز آوانما
ruby-align
How the small annotation is spread over its base text: start, center, space-between or space-around. It is set on the ruby element. [start, center, space-between, space-around]ruby: ruby align = "space-between" font size = 28 content = "漢字" ruby text: content = "kanji" end end
ruby position
جای آوانما
ruby-position
Which side the annotation goes: over (above horizontal text), under, alternate (above and below by turns) or inter-character (beside the characters, as used for Taiwanese bopomofo). [over, under, alternate, inter-character; up to 2 values]ruby: ruby position = "under" font size = 28 content = "東京" ruby text: content = "Tōkyō" end end
text emphasis
تاکید متن
text-emphasis
The shorthand for the mark drawn on each character, its colour and its place: "filled dot crimson". Used in East Asian text, where italic letters do not exist, but it works with any text. [CSS-wide keywords only]box: text emphasis = "filled dot crimson" content = "Dots mark the emphasis" end
text emphasis style
سبک تاکید متن
text-emphasis-style
The mark: none, a shape (dot, circle, double-circle, triangle, sesame) with filled or open before it, or any single character in quotes. [string; up to 2 values]box: text emphasis style = "open circle" content = "Hollow circles on every letter" end
text emphasis color
رنگ تاکید متن
text-emphasis-color
The colour of the marks. Without it they take the colour of the text. [color]box: text emphasis style = "filled dot" text emphasis color = "crimson" content = "Red dots" end
text emphasis position
موقعیت تاکید متن
text-emphasis-position
Where the marks go: over or under, then right or left (the side they take in vertical text), for example "under right". [up to 2 values]box: text emphasis style = "filled dot" text emphasis position = "under right" content = "Dots below the letters" end
text spacing trim
برش فاصله متن
text-spacing-trim
In Chinese and Japanese, controls whether the empty half of full-width punctuation is trimmed: normal, space-all (never), space-first or trim-start. [normal / space-all / space-first / trim-start]box: text spacing trim = "space-all" font size = 24 content = "「東京」と「大阪」" end
text autospace
فاصله خودکار متن
text-autospace
Adds a small space between Chinese or Japanese characters and Latin letters or digits next to them: normal, no-autospace or the words ideograph-alpha and ideograph-numeric. [up to 3 autospace keywords]box: text autospace = "normal" font size = 24 content = "東京Towerと12個" end

Try it yourself

  • Take the type tester and add a second slider that sets line height between 1 and 3 on the sample. At what value does a paragraph start to feel loose?
  • Write the front of a book: a title in small capitals with letter spacing, an author line in italics, and a paragraph that is justified with a text indent of 2em.
  • Declare a font with a file that does not exist, use it in a font stack with a good fallback, and check that the page is still readable.
  • Make a card that shows the first three lines of a long text and a headline with text wrap = "balance".