Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

UI/UX Design  Module 6 – Visual design for interfaces

Typography for interfaces

Choose a type scale, line length and line height for MealBox screens, then test text at 200 % size, under user spacing overrides and in Hindi.

  • Beginner
  • 20 minutes
  • Examples run with Node.js 24.21.0, Python 3.14.8 and Pyodide 314.0.7
  • By MySmartCoPilot
Free core, Pro depth: 7 of 20 minutes free
Free: A type scale gives every level a size you can defend · Line length and line height set how far a reader gets. With a pass: 3 in-depth parts and 3 interview answers, about 13 minutes.

What you will learn

  • Choose sizes for interface text from a type scale
  • Set line length and line height for comfortable reading
  • Design for 200 % text, Dynamic Type and user text-spacing overrides
  • Set Devanagari labels so that no mark is clipped

Before you start

A MealBox help article set in 14 px type at a line height of 1.2 runs about 174 characters to a line on a 1280 px screen, more than twice the 80 characters that WCAG 2.2 sets at its highest conformance level. The screen, article and widths in this lesson are invented.

Typography is most of an interface, because most of an interface is text. You will choose sizes from a type scale, set the length and height of lines, and then test the result where designs break: when a visitor enlarges the text, restyles its spacing or reads it in Hindi. All three tests use numbers you can compute.

A type scale gives every level a size you can defend

A type scale: A short list of text sizes in a fixed ratio, for example each step 1.2 times the one before, from which every size in a design is taken. is a short list of sizes in a fixed ratio, so that each level of text is a clear step from the next. This lesson’s scale starts from the 16 px body size and multiplies by 1.2 at each step, a ratio chosen for this lesson. Start from the platform’s own default: MDN documents that a browser’s default font size is usually 16 px, and Apple’s guidance lists 17 pt as the default and 11 pt as the minimum on iOS and iPadOS.

Platform Default Minimum
iOS and iPadOS 17 pt 11 pt
macOS 13 pt 10 pt
Browsers 16 px none set

The program prints the seven steps in px and rem, the unit that follows the visitor’s own default size, and checks that rounding to whole pixels keeps the ratio:

A 1.2-ratio type scale in px and rem Python · type_scale/type_scale.py
# A type scale for MealBox articles: each step is 1.2 times the one before, starting from the 16 px body size.
BASE_PX = 16
RATIO = 1.2
STEPS = [(-1, "caption"), (0, "body"), (1, "small heading"), (2, "heading"), (3, "large heading"), (4, "page title"), (5, "display")]

print(f"ratio {RATIO}, base {BASE_PX} px = 1 rem")
print(f"{'step':>4}  {'role':14}{'px':>7}{'rem':>8}  {'rounded px':>10}")
for step, role in STEPS:
    px = BASE_PX * RATIO ** step
    print(f"{step:>4}  {role:14}{px:>7.2f}{px / BASE_PX:>8.3f}  {round(px):>10}")

sizes = [BASE_PX * RATIO ** s for s, _ in STEPS]
gaps = [b / a for a, b in zip(sizes, sizes[1:])]
print("\nratio between neighbours:", ", ".join(f"{g:.2f}" for g in gaps))
rounded = [round(s) for s in sizes]
print("neighbour ratios after rounding to whole px:", ", ".join(f"{b / a:.2f}" for a, b in zip(rounded, rounded[1:])))

Output

ratio 1.2, base 16 px = 1 rem
step  role               px     rem  rounded px
  -1  caption         13.33   0.833          13
   0  body            16.00   1.000          16
   1  small heading   19.20   1.200          19
   2  heading         23.04   1.440          23
   3  large heading   27.65   1.728          28
   4  page title      33.18   2.074          33
   5  display         39.81   2.488          40

ratio between neighbours: 1.20, 1.20, 1.20, 1.20, 1.20, 1.20
neighbour ratios after rounding to whole px: 1.23, 1.19, 1.21, 1.22, 1.18, 1.21

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 type_scale.py

The page title lands at 33.18 px and the display size at 39.81 px. Rounded to whole pixels the neighbouring ratios wander between 1.18 and 1.23, which is why a scale is stored as numbers, not rounded by eye. Use three or four steps on one screen and let weight and colour do the rest, as the previous lesson showed.

Set sizes in rem

A size in rem scales with the visitor’s chosen default; a size in px does not. The rem column of the output is the value to put in the style sheet.

Checkpoint

Check: A type scale and the body size

  1. One question A scale starts at a 16 px body and multiplies by 1.2 at each step. How large is step 2, in px, to two decimal places?

    Type a number.

    A hint

    Multiply 16 by 1.2 twice.

    Show the answer: One question

    Answer: 23.04 px (anything from 23.03 to 23.05 counts)

    Step 1 is 16 × 1.2 = 19.2 px and step 2 is 19.2 × 1.2 = 23.04 px, which is 16 × 1.2², or 1.44 rem.

Line length and line height set how far a reader gets

A line that is too long loses the reader on the way back to the next line, and one that is too short breaks sentences into fragments. WCAG 2.2 success criterion 1.4.8, a level AAA criterion, asks for lines of no more than 80 characters, or 40 for Chinese, Japanese and Korean, and for line spacing of at least one and a half within paragraphs. MDN gives the same minimum of 1.5 for the main paragraph text and recommends a unitless value, which scales with the font size.

The program estimates characters per line from the column width, assuming an average character is half an em wide:

Characters per line at three window widths Python · line_length/line_length.py
# How many characters fit on one line of body text? An estimate for a MealBox article, with invented page widths.
# Assumption: an average character of a Latin sans-serif face is about 0.5 em wide (real faces differ).
FONT_PX = 16
CHAR_EM = 0.5
LIMIT = 80                      # the longest line WCAG 2.2 success criterion 1.4.8 (AAA) allows, in characters
PAGES = [(360, 16), (768, 32), (1280, 32)]      # (window width, side margin) in px
CAP_PX = 640                    # a cap on the column: 40 rem at 16 px

def chars(width_px):
    return width_px / (FONT_PX * CHAR_EM)

print("window  column  chars/line  within 80   with a 640 px cap")
for width, margin in PAGES:
    column = width - 2 * margin
    capped = min(column, CAP_PX)
    print(f"{width:>6}  {column:>6}  {chars(column):>10.0f}  {'yes' if chars(column) <= LIMIT else 'no':9}   {chars(capped):.0f} chars, {'yes' if chars(capped) <= LIMIT else 'no'}")
print(f"\nlongest column for {LIMIT} characters at {FONT_PX} px: {LIMIT * FONT_PX * CHAR_EM:.0f} px ({LIMIT * CHAR_EM:.0f} em)")

Output

window  column  chars/line  within 80   with a 640 px cap
   360     328          41  yes         41 chars, yes
   768     704          88  no          80 chars, yes
  1280    1216         152  no          80 chars, yes

longest column for 80 characters at 16 px: 640 px (40 em)

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 line_length.py

At 360 px the 328 px column holds 41 characters, comfortably short. At 768 px it holds 88 and at 1280 px it holds 152, both over 80. A cap of 640 px on the column, which is 40 em, brings both to exactly 80. The estimate depends on the typeface, so measure the real page when the number is close.

Two more checks decide whether these settings hold in real use. Text enlarged to 200 % or restyled by the visitor must still fit its box. And scripts such as Devanagari need taller line boxes, because their marks rise higher than Latin letters do.

Checkpoint

Check: Line length and line height

  1. Question 1 of 2 A column is 560 px wide and the text is 16 px, with an average character half an em wide. How many characters fit on a line?

    Type a number.

    A hint

    Divide the column width by the width of one character, 16 × 0.5 px.

    Show the answer: Question 1 of 2

    Answer: 70 characters

    One character is 8 px wide, so 560 ÷ 8 = 70 characters, within the 80 that success criterion 1.4.8 allows.

  2. Question 2 of 2 Why does MDN recommend a unitless value for line-height?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: It scales with the font size of each element, including when the page is zoomed

    A fixed length such as 24px is inherited as 24 px even by a child with a larger font. A unitless 1.5 is multiplied again for each element.

Text that survives enlarging and user spacing, with numbers Pro: opens with a Pro, Premium or Ultimate pass

A design that fits at 100 % can fail the moment a visitor changes their settings. This part reproduces the failure with a button, shows the rule that prevents it, and sets out what the platforms ask for.

In this part:

  • What 200 % text and Dynamic Type require
  • Four user overrides, tried on a button
  • Choosing between fixed and flexible boxes

1 diagram · 1 runnable example (Python) · about 5 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Devanagari marks that fit the line box, measured from a font file Pro: opens with a Pro, Premium or Ultimate pass

Latin line heights that look generous can clip the vowel signs of Hindi, and the clipping is invisible when only English is checked. This part measures the clipping from a real font file, shows the arithmetic, and ends with an exercise on three Hindi buttons.

In this part:

  • How far Devanagari marks rise, from the font’s own tables
  • The line box and the half-leading arithmetic
  • Fixing three Hindi buttons
  • Fix a MealBox article page and its Hindi buttons
    • Results of the sample tests

1 diagram · 1 runnable example (Python) · 1 exercise with sample tests · about 7 minutes

Opening this part with your pass…Pro part. It opens with the same pass as the part above.

Checking a type system with numbers, before and after Pro: opens with a Pro, Premium or Ultimate pass

A type check is quicker and less personal when each check is a number with a threshold. This part runs one invented article through four checks, shows what fixing it costs in length, and sets out a rubric a team can reuse.

In this part:

  • Four checks with thresholds and sources
  • What the fix costs, in length
  • A rubric for checking type

1 runnable example (Python) · about 3 minutes

Opening this part with your pass…Pro part. It opens with the same pass as the part above.

Practise

The questions below cover the scale and the line settings, and the first one comes from whichever you have found hardest:

Practice that adapts to you

Practise this lesson

8 questions about 5 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 8 What does a type scale give a design?

    Choose one answer.

    Show the answer: Question 1 of 8

    Answer: A short list of sizes in a fixed ratio, so each level is a clear step from the next

    A scale is a vocabulary of sizes, which keeps the page consistent and the hierarchy readable.

  2. Question 2 of 8 Why set sizes in rem rather than px?

    Choose one answer.

    Show the answer: Question 2 of 8

    Answer: rem follows the visitor's chosen default size, and px does not

    MDN notes that the default size is usually 16 px, and a visitor can change it. Sizes in rem honour that choice.

  3. Question 3 of 8 With a 16 px body and a ratio of 1.2, what is step 3 in rem, to three decimal places?

    Type a number.

    A hint

    1.2 cubed.

    Show the answer: Question 3 of 8

    Answer: 1.728 rem (anything from 1.727 to 1.729 counts)

    1.2³ = 1.728, which is 27.65 px at a 16 px base.

  4. Question 4 of 8 A team rounds every step of a 1.2-ratio scale to whole pixels, and the ratios between steps drift. Is that a problem?

    Choose one answer.

    Show the answer: Question 4 of 8

    Answer: Slightly; keep the unrounded ratio in the style sheet and let the browser round at render time

    The drift is small but free to avoid: keep the ratio in the style sheet and let the browser do the rounding at render time.

  5. Question 5 of 8 What is the longest line WCAG 2.2 success criterion 1.4.8 allows for most scripts?

    Choose one answer.

    Show the answer: Question 5 of 8

    Answer: 80 characters

    The limit is an AAA criterion, so it is a target to design for rather than a requirement for AA conformance.

  6. Question 6 of 8 At 16 px with an average character half an em wide, what is the widest column that holds 80 characters, in px?

    Type a number.

    A hint

    Multiply 80 by the width of one character.

    Show the answer: Question 6 of 8

    Answer: 640 px

    One character is 16 × 0.5 = 8 px, so 80 characters take 640 px, which is 40 em.

  7. Question 7 of 8 Which body-text line height does MDN suggest as a minimum for main paragraph content?

    Choose one answer.

    Show the answer: Question 7 of 8

    Answer: 1.5

    A unitless 1.5 scales with the font and meets the line spacing that criterion 1.4.8 describes.

  8. Question 8 of 8 A phone column holds 41 characters and a desktop column 152. What do you change?

    Choose one answer.

    Show the answer: Question 8 of 8

    Answer: Leave the phone alone and cap the desktop column at about 40 em

    The cap acts on the width, so it only changes layouts that are wider than the cap.

Interview questions

Warm-up: how do you pick the body text size for a new product?

Start from the platform’s default, which is 16 px in browsers and 17 pt on iOS, and treat it as a floor, not a target. Check it against the people who will read it, since long articles and older readers need the default or more. Set the size in rem so that a visitor’s own setting carries through, then test at 200 % and with a real paragraph in every script you ship. Choose the other sizes from a scale by ratio, and keep to three or four on one screen.

Three harder questions follow. Think about what you would measure first, before you open any of them:

  1. Mid to senior

    Ward Desk officers write reply letters in a template set at 13 px, line height 1.3, across a 1,100 px column. Officers say they tire by the afternoon, and a manager wants 18 px type to fix it. What do you check and change?

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Mid to staff

    MealBox status chips in an order table are 28 px tall. A tester who enlarged the browser text to 200 % sees the labels cut off. The engineer says it is an edge case and not worth fixing. What do you do?

    Model answer, Pro. First step and follow-ups

  3. Senior to staff

    Ward Desk's Hindi buttons look fine in the design file, but on devices the tops of some vowel signs are cut off. The English buttons are fine. The designer says the font is the same. How do you find the cause and fix it?

    Model answer, Pro. First step and follow-ups

Flashcards · 6 cards

Recall it, then check

Say the answer to yourself before you look: recalling it is what makes it stick.

  1. What is a type scale, and where should it start?

    A short list of sizes in a fixed ratio, so each level of text is a clear step from the next. Start from the platform's default body size and multiply, as this track's scale does by 1.2 from 16 px; use three or four steps on one screen.

  2. What default and minimum text sizes do browsers and iOS use?

    Browsers usually default to 16 px, with no minimum set; Apple lists 17 pt as the default and 11 pt as the minimum on iOS and iPadOS, and 13 pt and 10 pt on macOS. Treat the default as a floor for body text, not a target.

  3. Why set text sizes in rem rather than px?

    A size in rem scales with the visitor's chosen default font size; a size in px does not.

  4. How long may a line of body text be under WCAG 2.2 criterion 1.4.8?

    At most 80 characters, or 40 for Chinese, Japanese and Korean, at level AAA. Cap the column in em, such as 40 em, rather than in pixels, and measure the real page when the estimate is close.

  5. What line height suits body text, and in which unit?

    At least 1.5 within paragraphs, as WCAG 1.4.8 and MDN give it, written as a unitless value so it scales with the font size.

  6. Where do typographic settings usually break?

    When a visitor enlarges text to 200 % or restyles its spacing, so text must still fit its box, and in scripts such as Devanagari, whose marks rise higher than Latin letters and need taller line boxes.

Key takeaways

  • A type scale is a fixed ratio from a body size that starts at the platform default, and sizes in rem follow the visitor’s own setting.
  • A line holds at most 80 characters, so cap the column in em, not in pixels, and measure the real page when the number is close.
  • Line height is unitless and at least 1.5 for body text, so that it scales with the font size.
  • Text must still fit its box when it is enlarged to 200 % or restyled by the visitor.
  • Devanagari marks rise as far as the font’s ascent, so a line height that suits Latin letters can clip Hindi.

Terms in this lesson

Dynamic Type
An Apple system setting that lets people choose how large text appears across apps; apps respond by scaling their text styles.
half-leading
Half of the difference between a line's height and its font's content area. CSS adds it above and below the text when it lays out a line box.
type scale
A short list of text sizes in a fixed ratio, for example each step 1.2 times the one before, from which every size in a design is taken.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.