html font-size quyết định rem thế nào | Root 16px, 62.5% và lỗi scale
rem không phải hằng số 16 — nó là bội số của html font-size. Mặc định trình duyệt ≈ 16px → 1rem = 16px. Đổi root (62.5%, 14px, clamp) thì mọi rem nhảy theo. Muốn scale cả design system: đổi một chỗ (html). Muốn convert Figma: chia đúng root đang chạy, không chia 16 theo thói quen. Kiểm tra nhanh trên PX ↔ REM (chạy trình duyệt, đổi base tùy project).
Junior Việt paste font-size: 1.5rem vì “reviewer bảo dùng rem”. Sprint sau lead thêm html { font-size: 62.5% } copy blog cũ — toàn bộ card, gap, modal phóng to lệch Figma. Bug không nằm ở “rem xấu”, mà ở không ai chốt root.
Bài này đi sâu góc html font-size: rem tính từ đâu, 62.5% thực sự làm gì, đổi root theo breakpoint, và checklist trước khi merge token.
Ai nên đọc
- Frontend inherit repo khách (outsourcing) không rõ root 16 hay 10
- Ai migrate Figma px → CSS rem lần đầu
- Team đang tranh luận “cấm px” nhưng layout border bị vỡ
rem gắn với root — không gắn với body
html { font-size: 16px; } /* root */
body { font-size: 18px; } /* không đổi 1rem */
.card {
font-size: 1rem; /* = 16px, không phải 18px */
padding: 1.5rem; /* = 24px theo root */
}
Định nghĩa ngắn: 1rem = 1 × computed font-size của phần tử gốc (thường html, hoặc :root tương đương trong tài liệu HTML).
| Bạn viết | rem nhìn vào | Hệ quả |
|---|---|---|
Chỉ body { font-size } | Vẫn html | Text mặc định đổi; token rem không scale theo body |
html { font-size: 14px } | 14px | Mọi 1rem = 14px |
html { font-size: 62.5% } | ~10px nếu default 16 | 1rem ≈ 10px |
| User tăng font mặc định trình duyệt | Root lớn hơn | rem lớn theo — điểm mạnh a11y |
Vì sao mọi người nhớ “1rem = 16px”
Hầu hết browser desktop mặc định 16px cho root khi user không đổi. Công thức quen:
rem = px ÷ 16
24px → 1.5rem
14px → 0.875rem
32px → 2rem
Công thức này sai ngay khi:
- User đặt cỡ chữ trình duyệt 20px
- Project dùng
html { font-size: 62.5% } - Bạn set root theo media (
html { font-size: 14px }trên mobile) - Extension / OS accessibility đổi default
Luôn hỏi: root đang bao nhiêu px trên máy thật? DevTools → chọn html → Computed → font-size.
Ba kiểu đặt root phổ biến
| Kiểu | Ví dụ | Khi nào hợp |
|---|---|---|
| A. Giữ 16 (khuyến nghị mặc định) | html { font-size: 100%; } hoặc không set | Tailwind, hầu hết design system 2024–2026. Token nghĩ bằng rem (1.5rem) thay vì ‘10px base’. |
| B. Trick 62.5% | html { font-size: 62.5%; } + body { font-size: 1.6rem; } | Team thích 24px → 2.4rem. Phải document; đừng trộn với Tailwind mặc định. |
| C. Root theo breakpoint / fluid | html { font-size: clamp(14px, 2vw, 18px); } | Scale cả trang bằng một nút. Test kỹ form và fixed UI. |
Trick 62.5% — đúng toán, dễ cháy team
html {
font-size: 62.5%; /* 16 × 0.625 = 10px (khi default = 16) */
}
body {
font-size: 1.6rem; /* 16px — đọc bình thường */
}
h1 {
font-size: 2.4rem; /* 24px — dễ nhớ */
}
Ưu: Não nghĩ “px ÷ 10”.
Nhược: Người mới mở PX ↔ REM vẫn để base 16 → convert sai cả bảng. Plugin Figma “px to rem” cũng hay giả định 16.
Quy tắc: một repo = một base. Ghi vào README design token dòng đầu: Root = 10px (62.5%) hoặc Root = 16px.
Root đổi theo media — scale toàn hệ
html { font-size: 14px; }
@media (min-width: 768px) {
html { font-size: 16px; }
}
Mọi padding: 1rem, gap: 0.5rem, text-sm: 0.875rem nhảy cùng tỉ lệ. Đây là sức mạnh — và cũng là chỗ sticky footer / max-height modal dễ “đụng trần”. Checklist: mở form đăng ký, bảng giá, drawer mobile trước khi merge.
Công thức convert (và chỗ hay sai)
rem = px ÷ rootPx
px = rem × rootPx
Ví dụ cùng 24px trên Figma:
| Root thực tế | rem đúng |
|---|---|
| 16px | 1.5rem |
| 10px (62.5%) | 2.4rem |
| 14px | ≈ 1.714rem (nên làm tròn theo thang token: 1.75rem) |
Sai phổ biến trong team outsourcing: designer gửi bảng “÷16”, codebase khách lại 62.5% → spacing phình ~1.6×.
Thử ngay (đổi Kích thước font chữ cơ sở cho khớp project):
🔄 Chuyển đổi px và rem ngay tại đây
Công cụ chỉ làm phép tính local trên trình duyệt — không upload stylesheet.
Case study: “rem đúng nhưng UI lệch Figma”
Triệu chứng A — mọi thứ nhỏ hơn mock: Lead merge html { font-size: 62.5% } trong khi token/Tailwind vẫn được nghĩ như root 16. 1rem giờ ≈ 10px → spacing và chữ “xẹp” so với Figma chia ÷16.
Triệu chứng B — layout phình / scroll ngang: Ai đó set html { font-size: 18px } hoặc user tăng font mặc định; toàn bộ gap/padding rem phình theo. Nửa UI còn width: 320px cứng → cảm giác “vỡ tỉ lệ”.
Cách khoanh nhanh: DevTools → computed font-size của html. Tạm html { font-size: 16px !important; }. Nếu về đúng Figma → thủ phạm là root, không phải từng component.
Checklist trước khi ship token rem
- Document một root (16 / 10 / fluid) trong design-token README
- Convert bảng Figma với đúng base trên PX ↔ REM
- Border / hairline / outline quan trọng: giữ px
- Không đặt
font-size“giả root” trên#apprồi kỳ vọng rem theo đó — rem không nhìn#app - Test: default font trình duyệt lớn + zoom 150% + (nếu có) breakpoint đổi root
- PR ghi rõ: “Root giả định = …px”
Muốn góc khi nào chọn px vs rem vs em (border, padding nút, media query): xem thêm px vs rem trong CSS. Bài này chỉ chốt root quyết định rem thế nào.
Liên kết liên quan
- Công cụ PX ↔ REM — đổi base, xem kết quả tức thì
- px vs rem — dùng đơn vị nào
- Danh sách công cụ