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 |
|---|---|---|
| MIN | giá trị nhỏ nhất được phép | rem |
| PREFERRED | giá trị thay đổi theo màn hình | rem + vw (hoặc cqi) |
| MAX | giá trị lớn nhất được phép | rem |
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:
- Độ dốc: (24 − 16) ÷ (1280 − 320) = 8 ÷ 960 = 0.00833, tức là 0.833vw (vw tính trên mỗi 100px).
- Điểm xuất phát: 16px − 0.00833 × 320px = 13.33px, tức là 0.833rem.
- Đặ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ệtmax(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ùngmax(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ầnrem. - MIN lớn hơn MAX. Kết quả luôn là MIN, hiếm khi đúng ý định.
- Giới hạn bằng
pxcho 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ùngrem.
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.