Menu

CSS clamp(): cỡ chữ linh hoạt, min() và max()

clamp(MIN, PREFERRED, MAX) trả về giá trị ưu tiên nhưng không bao giờ nhỏ hơn MIN hay lớn hơn MAX. Tìm hiểu cách nó giúp cỡ chữ và khoảng cách co giãn linh hoạt mà không cần media query, cách tính giá trị ở giữa, và quan hệ giữa nó với min() và max().

Trang này có trình soạn thảo chạy trực tiếp. Sửa, chạy và xem đầu ra ngay lập tức.

clamp() làm gì

clamp(MIN, PREFERRED, MAX) nhận ba giá trị và trả về giá trị ở giữa, miễn là nó còn nằm giữa hai giá trị kia. Cách dùng kinh điển là một tiêu đề to dần theo màn hình nhưng dừng lại ở những giới hạn hợp lý, không cần media query:

Giá trị ưu tiên là 1rem + 3vw: 16px cộng 3% chiều rộng. Trong khung xem trước rộng 800px, giá trị này là 16 + 24 = 40px, nằm giữa 24px (1.5rem) và 48px (3rem), nên tiêu đề cỡ 40px. Trên điện thoại rộng 320px, giá trị ưu tiên là 25.6px. Khi rộng hơn 1067px, nó sẽ vượt 48px, nên dừng ở 48px. Hãy thay đổi kích thước cửa sổ để xem con số thay đổi; vw ở đây là phần trăm chiều rộng của khung xem trước.

Xem kết quả mà không cần đổi kích thước cửa sổ

vw bám theo viewport, thứ bạn khó thay đổi trong lúc đang đọc. Đơn vị container query thì bám theo một container: cqi bằng 1% chiều rộng của container. Kéo thanh trượt để thay đổi hộp, và một clamp() tương tự sẽ phản hồi:

Kéo về đầu, tiêu đề dừng ở 20px (MIN). Kéo về cuối, nó dừng ở 40px (MAX). Ở giữa, nó theo 0.5rem + 6cqi. Đây chính là cơ chế của phiên bản dùng vw, chỉ với một cây thước nhỏ hơn.

Ba đối số

font-size: clamp(1rem, 0.8rem + 1vw, 1.5rem);
/*               MIN   PREFERRED     MAX    */
Đối sốVai tròĐơn vị thường dùng
MINgiá trị nhỏ nhất được phéprem
PREFERREDgiá trị thay đổi theo màn hìnhrem + vw (hoặc cqi)
MAXgiá trị lớn nhất được phéprem

Bạn có thể tính toán ngay trong mỗi đối số mà không cần viết calc(): 1rem + 2vw dùng nguyên như vậy là được. Dấu + và - cần một dấu cách ở cả hai bên, nếu không cả khai báo sẽ không hợp lệ.

Nếu MIN lớn hơn MAX, MIN thắng: clamp(3rem, 5vw, 2rem) luôn là 3rem.

Tính giá trị ở giữa

Để cỡ chữ tăng từ 16px trên màn hình 320px lên 24px trên màn hình 1280px:

  1. Độ dốc: (24 − 16) ÷ (1280 − 320) = 8 ÷ 960 = 0.00833, tức là 0.833vw (vw tính trên mỗi 100px).
  2. Điểm xuất phát: 16px − 0.00833 × 320px = 13.33px, tức là 0.833rem.
  3. Đặt các giới hạn bao quanh:
font-size: clamp(1rem, 0.833rem + 0.833vw, 1.5rem);

Ở chiều rộng 320px, kết quả là 13.33 + 2.67 = 16px, ở 1280px là 13.33 + 10.67 = 24px, và ngoài khoảng đó nó giữ ở các giới hạn. Các "công cụ tính clamp" trên mạng làm đúng phép tính này.

min() và max()

clamp() là sự kết hợp của hai hàm đơn giản hơn:

  • min(a, b) trả về giá trị nhỏ hơn, nên nó đặt giới hạn trên.
  • max(a, b) trả về giá trị lớn hơn, nên nó đặt giới hạn dưới.
  • clamp(MIN, VAL, MAX) giống hệt max(MIN, min(VAL, MAX)).

Lúc đầu tên gọi nghe có vẻ ngược: để nói "tối đa 600px", bạn dùng min().

Trong khung xem trước rộng, thẻ đầu tiên dừng ở 420px. Bên trong phần tử cha rộng 260px, 100% là giá trị nhỏ hơn, nên thẻ thứ hai rộng 260px. max(12px, 3%) cho thẻ đầu tiên 3% chiều rộng phần tử cha (body: khoảng 23.5px trong khung xem trước 800px), còn thẻ thứ hai được 12px, vì 3% của 260px (7.8px) thấp hơn mức sàn.

width: min(100%, 420px) thay cho cặp khai báo cũ width: 100%; max-width: 420px; chỉ bằng một khai báo.

Không chỉ cỡ chữ: khoảng cách và chiều rộng

clamp() dùng được trong mọi thuộc tính nhận độ dài. Phần trăm trong giá trị ở giữa khiến một thành phần co giãn theo phần tử cha thay vì theo viewport:

Trong phần tử cha rộng 300px, thẻ rộng 240px (80%) với padding 15px (5% của 300px). Trong phần tử cha rộng 760px, 80% sẽ là 608px, nên thẻ dừng ở mức tối đa 520px, và 5% của 760px là 38px, nên padding dừng ở 32px.

Khả năng tiếp cận: giữ rem trong giá trị ở giữa

Cỡ chữ chỉ dùng vw, như font-size: 5vw, không to lên khi người đọc tăng cỡ chữ mặc định trong cài đặt trình duyệt, và cũng không to lên khi phóng to trình duyệt, vì phóng to làm viewport hẹp lại tính theo pixel CSS. Thêm một phần rem (1rem + 2vw) và các giới hạn bằng rem giúp chữ luôn gắn với cài đặt của người đọc. Trang đơn vị giải thích chi tiết về rem và vw.

Lỗi thường gặp

  • Dùng min() cho giá trị tối thiểu. min() chọn giá trị nhỏ hơn, tức là giới hạn trên. Để có "ít nhất 12px", dùng max(12px, ...).
  • Không có dấu cách quanh + hoặc -. clamp(1rem, 1rem+2vw, 3rem) không hợp lệ, và thuộc tính quay về giá trị trước đó.
  • Chỉ có vw ở giữa. Khi đó chữ bỏ qua cài đặt cỡ chữ của người đọc. Hãy thêm một thành phần rem.
  • MIN lớn hơn MAX. Kết quả luôn là MIN, hiếm khi đúng ý định.
  • Giới hạn bằng px cho cỡ chữ. Chúng chặn kích thước chữ ngay cả với người đọc cần chữ to hơn. Hãy dùng rem.

Câu hỏi thường gặp

clamp() trong CSS dùng để làm gì?

clamp(MIN, PREFERRED, MAX) dùng giá trị ưu tiên khi nó còn nằm giữa hai giới hạn, nếu không thì dùng giới hạn gần nhất. font-size: clamp(1rem, 4vw, 2rem) bám theo 4% chiều rộng viewport nhưng không bao giờ nhỏ hơn 1rem hay lớn hơn 2rem.

Làm sao tạo cỡ chữ responsive bằng clamp?

Đặt một giá trị dựa trên viewport ở giữa và các giới hạn cố định ở hai bên, đồng thời trộn rem vào giá trị ở giữa để chữ vẫn theo cài đặt cỡ chữ của người đọc: font-size: clamp(1.5rem, 1rem + 2vw, 3rem);.

Chuyện gì xảy ra nếu giá trị nhỏ nhất lớn hơn giá trị lớn nhất trong clamp()?

Giá trị nhỏ nhất thắng. clamp(3rem, 5vw, 2rem) luôn cho ra 3rem, vì clamp() áp dụng giá trị nhỏ nhất sau giá trị lớn nhất.

min() và max() trong CSS khác nhau thế nào?

min() trả về giá trị nhỏ nhất trong các giá trị của nó, nên nó đóng vai trò giới hạn trên: width: min(100%, 600px) không bao giờ rộng hơn 600px. max() trả về giá trị lớn nhất, nên nó đóng vai trò giới hạn dưới: font-size: max(1rem, 2vw) không bao giờ nhỏ hơn 1rem.

clamp() có được hỗ trợ trên mọi trình duyệt không?

Có, clamp(), min() và max() chạy trên mọi phiên bản hiện tại của Chrome, Edge, Firefox và Safari, và dùng được trong mọi thuộc tính nhận độ dài, số, phần trăm hoặc góc.

Hình minh họa các ngôn ngữ lập trình của Coddy

Học lập trình cùng Coddy

Bắt đầu