rem, px hay clamp() cho cỡ chữ co giãn

px, rem và em thực sự làm gì, cách suy ra cỡ chữ clamp() từ hai cỡ và hai độ rộng, và vì sao phần vw của chữ co giãn không to lên khi người đọc phóng to trang.

Trong bài này

Cỡ chữ trong CSS trông như chuyện sở thích: px vì dễ đoán, rem vì ai đó khuyên vậy, clamp() vì hiện đại. Nhưng lựa chọn này ảnh hưởng tới người đọc thật, nhất là những người đổi cỡ chữ mặc định hoặc phóng to trang. Bài này giải thích từng đơn vị làm gì, tự tay suy ra một giá trị clamp() (rồi kiểm tra bằng công cụ đổi đơn vị CSS), và cho thấy bằng con số chữ co giãn tương tác với việc phóng to ra sao.

px, rem và em

  • px là điểm ảnh CSS, một đơn vị cố định (1in = 96px). 16px là 16px dù người đọc cài đặt gì.
  • rem là cỡ chữ của phần tử gốc. Trình duyệt mặc định 16px, nhưng người đọc có thể đổi (nhiều người thị lực kém làm vậy), và khi đó mọi cỡ tính bằng rem đổi theo.
  • em là cỡ chữ của phần tử cha (với font-size). Vì bị cộng dồn, danh sách lồng trong danh sách ở 0.9em chỉ còn 0,81 cỡ bên ngoài.

Phóng to trình duyệt làm to mọi thứ, kể cả px. Cài đặt cỡ chữ mặc định chỉ đổi rem và em. Trang web dùng px cho chữ vì vậy bỏ qua cài đặt đó. Đây là lý do chính để dùng rem cho chữ: 1.125rem là 18px với phần lớn người đọc và 22,5px với người đã chọn 20px.

Công cụ hiện một độ dài ở mọi đơn vị: 24px là 1.5rem với cỡ gốc 16px, là 18pt, và là 1.6667vw trên cửa sổ rộng 1440px.

Tự suy ra clamp()

Giả sử chữ thân bài cần 16px trên điện thoại rộng 320px và 24px trên laptop rộng 1280px, tăng mượt ở giữa và giữ nguyên ngoài khoảng đó. Một đường thẳng qua hai điểm:

  1. Độ dốc = (24 − 16) / (1280 − 320) = 8 / 960 = 0,008333 px cho mỗi px chiều rộng. Đổi ra vw (1vw = 1% chiều rộng) là 0.8333vw.
  2. Hệ số chặn = 16 − 0,008333 × 320 = 13,333px, tức 0.8333rem với cỡ gốc 16px.
  3. Kết quả: font-size: clamp(1rem, 0.8333rem + 0.8333vw, 1.5rem);

Kiểm tra ở 800px: 13,333 + 0,008333 × 800 = 20px, đúng điểm giữa như một đường thẳng phải thế. Công cụ cho cùng giá trị, kèm công thức và bảng cỡ chữ theo các độ rộng thường gặp.

Viết hệ số chặn bằng rem thay vì px rất quan trọng: phần rem theo cài đặt cỡ chữ của người đọc, phần vw thì không.

Phóng to làm gì với phần vw

Phóng to 200% không đổi kích thước cửa sổ thật, nhưng làm chiều rộng tính theo điểm ảnh CSS giảm một nửa. Cửa sổ 1280px ở mức 200% là khung nhìn 640px đối với trang web. Lấy giá trị clamp() ở trên trên cửa sổ rộng 1280px:

Mức phóngKhung nhìn (px CSS)Cỡ tính đượcTrên màn hìnhSo với 100%
100%128024px24px1×
200%64018,67px37,3px1,56×
300%42716,89px50,7px2,11×
400%32016px64px2,67×

Chữ có to lên nhưng chậm hơn mức phóng, vì phần vw nhỏ lại khi khung nhìn CSS hẹp đi. Ở đây chữ đạt gấp đôi ở mức phóng 300%. So với chỉ dùng đơn vị khung nhìn, font-size: 2vw: ở 1280px là 25,6px, ở mức phóng 200% còn 12,8px CSS, hiển thị thành 25,6px. Chữ không bao giờ to lên. Đó là lý do chữ chỉ dùng vw không đạt WCAG 1.4.4 (phóng chữ tới 200%).

Hai thói quen giữ chữ co giãn dùng được:

  • Luôn giữ phần rem trong giá trị ưu tiên, như cách suy ra ở trên.
  • Giữ khoảng cỡ vừa phải. Một quy tắc kinh nghiệm từ các phân tích đã công bố về chữ co giãn là cỡ lớn nhất không nên quá 2,5 lần cỡ nhỏ nhất, để chữ vẫn đạt gấp đôi trong khoảng phóng to của trình duyệt. Công cụ cảnh báo khi vượt ngưỡng này. Sau đó hãy thử phóng to thật; quy tắc kinh nghiệm không thay được việc thử.

Thang cỡ chữ

Tiêu đề là nơi cỡ chữ co giãn đáng giá nhất: h1 có thể 32px trên điện thoại và 56px trên máy tính trong khi chữ thân bài gần như không đổi. Thang tỷ lệ nhân cỡ cơ sở với một tỷ lệ cho mỗi bậc. Với 16px và quãng ba trưởng (1,25): 12,8; 16; 20; 25; 31,25; 39,06px. Thang co giãn dùng một cỡ cơ sở và tỷ lệ ở độ rộng nhỏ, một bộ khác ở độ rộng lớn, rồi biến mỗi bậc thành một clamp() riêng. Với 16px và 1,25 ở 320px, 18px và 1,333 ở 1280px, bậc 0 là clamp(1rem, 0.9583rem + 0.2083vw, 1.125rem) và các bậc lớn tăng nhiều hơn. Công cụ xuất ra biến CSS (--step-0, --step-1…) hoặc theme Tailwind.

Những lỗi thường gặp

  • Dùng px cho chữ, bỏ qua cài đặt cỡ chữ mặc định của người đọc.
  • Chỉ dùng vw cho cỡ chữ, chữ không to lên khi phóng.
  • Khoảng co giãn quá rộng, như 16px tới 64px cho cùng một phần tử: phóng to không theo kịp.
  • Đặt cỡ gốc bằng px (html { font-size: 10px }) để 1rem = 10px. Làm vậy bỏ đi cài đặt của người đọc cho cả trang. Nếu muốn tính toán kiểu đó, 62,5% cho cùng kết quả mà vẫn tỷ lệ với lựa chọn của họ.
  • Nhầm em với rem trong các thành phần lồng nhau và bị cộng dồn cỡ chữ.
  • Nhảy cỡ bằng media query từ 16px lên 24px tại một điểm ngắt: clamp() cho một đường dốc mượt thay vào đó.

Với các giá trị bố cục đi cùng thang chữ, công cụ tạo grid và flexbox viết phần CSS còn lại.

Công cụ được nhắc trong bài

Về trang blog