CSS ngày nay làm được nhiều việc trước kia cần JavaScript: chọn theo con, truy vấn theo khung chứa, lồng quy tắc.
- Dùng :has() chọn phần tử cha theo con
- Dùng container queries
- Viết CSS lồng nhau (nesting)
- Dùng dialog và popover không cần thư viện
- Container query
- Điều kiện CSS theo kích thước của khung chứa, không phải toàn cửa sổ.
- Nesting
- Viết quy tắc con bên trong quy tắc cha.
- Popover
- Thuộc tính HTML tạo hộp nổi, tự quản lý đóng/mở.
Khái niệm và lý thuyết
Trong nhiều năm, những việc dưới đây cần JavaScript hoặc thư viện. Nay trình duyệt hỗ trợ sẵn:
| Tính năng | Giải quyết vấn đề gì |
|---|---|
| :has() | Chọn phần tử cha dựa trên con (selector "cha") |
| Container query | Thành phần đổi bố cục theo khung chứa, không theo cả cửa sổ |
| CSS nesting | Viết quy tắc lồng nhau, mã gọn như Sass |
| dialog, popover | Hộp thoại, menu nổi có sẵn, xử lý được bàn phím và lớp phủ |
| aspect-ratio, gap, clamp() | Tỉ lệ khung, khoảng cách, cỡ chữ linh hoạt |
Container query là bước tiến lớn của thiết kế đáp ứng: trước đây media query chỉ biết chiều rộng cửa sổ, nên cùng một thẻ đặt trong thanh bên và trong vùng chính vẫn bị ép cùng bố cục. Giờ thẻ "tự biết" chỗ đặt của nó và thích nghi, giúp component thật sự tái sử dụng được.
Khi dùng tính năng mới, hãy kiểm tra mức hỗ trợ trên caniuse.com và dùng @supports để cung cấp phương án dự phòng.
:has() - bộ chọn "cha"
/* thẻ có chứa ảnh thì chia hai cột */
.the:has(img) { display: grid; grid-template-columns: 120px 1fr; }
/* nhãn đổi màu khi ô nhập không hợp lệ */
label:has(+ input:invalid) { color: crimson; }Container queries
.khung { container-type: inline-size; }
.the { display: block; }
@container (min-width: 480px) {
.the { display: flex; gap: 16px; }
}Thẻ tự đổi bố cục theo chỗ đặt: trong thanh bên hẹp thì xếp dọc, trong vùng chính rộng thì xếp ngang.
CSS lồng nhau
.menu {
display: flex;
a {
padding: 8px 14px;
&:hover { background: #e8f5e9; }
&.active { font-weight: 700; }
}
}dialog và popover
<dialog id="hop">
<p>Bạn chắc chắn muốn xóa?</p>
<form method="dialog"><button>Hủy</button><button value="ok">Xóa</button></form>
</dialog>
<button onclick="hop.showModal()">Xóa</button>
<button popovertarget="goi-y">Gợi ý</button>
<div id="goi-y" popover>Nội dung hiện khi bấm, bấm ngoài là đóng.</div>Ví dụ: hộp thoại không cần JavaScript phức tạp
<dialog id="hop"> <p>Bạn có chắc muốn xóa?</p> <form method="dialog"><button>Đóng</button></form> </dialog> <button onclick="hop.showModal()">Xóa</button>
Thẻ dialog có sẵn lớp nền mờ, bẫy bàn phím và nút Esc để đóng. Trước đây bạn phải tự viết rất nhiều mã để có đủ những thứ này. Trước khi dùng tính năng mới, hãy tra độ hỗ trợ tại Can I use.
Một vài tính năng hay khác
aspect-ratio: 16/9giữ tỉ lệ khung.gapcho cả flex và grid.color-mix()trộn màu,text-wrap: balancecân tiêu đề.scroll-snap,position: stickylàm cuộn đẹp.@layerkiểm soát thứ tự ưu tiên.
Cùng một component thẻ nhưng đặt vào trang chủ, thanh bên và giỏ hàng. Container query giúp thẻ tự co giãn mà không cần viết lại CSS cho từng chỗ.
Kiểm tra mức hỗ trợ trình duyệt tại caniuse.com; các tính năng trong bài đều có trong trình duyệt hiện đại.
Nếu cần hỗ trợ trình duyệt rất cũ, hãy dùng @supports để dự phòng.
- Dùng
:has()đổi viền khung biểu mẫu khi có ô sai. - Tạo hộp thoại xác nhận bằng thẻ dialog.
- Viết lại một đoạn CSS dài bằng nesting.
:has(), container queries, nesting đều dùng được ngay.dialogvàpopoverthay thế nhiều thư viện modal.- Luôn kiểm tra hỗ trợ trình duyệt.