mikexxz
All posts

Translating Apple's HIG into Web Design Tokens

一块半白半黑的玻璃质感苹果形物体,字号阶梯与彩色色块从中飞出,下方有一条弹簧曲线。

This post was machine-translated from Chinese. Read the original

Apple's Human Interface Guidelines were written for native apps, but many of their principles (clear hierarchy, content first, respect for the user's system settings) hold just as well on the Web. The hard part is translating concepts like pt, Dynamic Type, and semantic colors into CSS.

Font Size: Dynamic Type → rem

iOS default font sizes are specified in pt. On the Web, divide by 16 to convert them to rem:

Style iOS (pt) Web (rem)
Large Title 34 2.125
Title 1 28 1.75
Title 2 22 1.375
Body 17 1.0625
Footnote 13 0.8125

The advantage of rem over px is that when users increase the default font size in their browser, the whole site scales up proportionally. That is more or less the Web version of Dynamic Type.

iOS Dynamic Type 字号阶梯
The nine default font sizes of iOS Dynamic Type, with their converted rem values.

Semantic Colors

Components don't use #000; they use var(--color-label). Dark mode then only needs to redefine the variables in one place:

:root {
  --color-label: #000000;
  --color-background: #ffffff;
}

@media (prefers-color-scheme: dark) {
  :root {
    --color-label: #ffffff;
    --color-background: #000000;
  }
}

Where This Conflicts with the HIG

On a white background, iOS's secondaryLabel has a contrast ratio of only about 3.4:1, short of the 4.5:1 required by WCAG AA. Native apps can fall back on the system's "Increase Contrast" option, but the Web has no such switch, so here I raised its opacity from 0.6 to 0.75.

Likewise, #007AFF as a body link color reaches only about 4.0:1, so link text uses a slightly darker #0066CC instead.

Motion: Spring Curves

CSS's linear() function can describe an arbitrary curve with a series of sample points. That means we can sample a real damped spring equation and write the result into CSS, instead of approximating it with cubic-bezier.

弹簧曲线与 ease-out 曲线对比
A spring with a damping ratio of about 0.8 slightly overshoots the end point before settling back, while ease-out comes to a smooth stop.

The spring overshoots by about 1.4% near the end point. That is a very small amount, but it is exactly what makes press feedback feel "springy".

Comments

Delete this comment?

Its content will be removed. This can’t be undone.