:has() là parent selector: chọn phần tử dựa trên thứ nó chứa hoặc thứ đứng sau nó. Trước đó CSS chỉ đi xuống, nên mọi trạng thái phụ thuộc con đều phải để JS toggle class.
Ví dụ hay dùng trong dự án:
css
/* card có ảnh thì đổi layout, không cần class .card--has-image do JS gắn */
.card:has(img) { grid-template-columns: 120px 1fr; }
/* label đổi màu khi input bên trong invalid và đã nhập */
.field:has(input:user-invalid) { border-color: var(--rose-ink); }
/* form có checkbox tick thì hiện nút hành động hàng loạt */
.list:has(input[type='checkbox']:checked) .bulk-bar { display: flex; }
/* chỉ thêm khoảng cách khi có heading đứng ngay trước đoạn văn */
h2:has(+ p) { margin-bottom: 8px; }Lưu ý:
- Specificity tính theo selector cụ thể nhất bên trong (giống
:is()), nên.card:has(#hero)nặng bất ngờ. :has()không lồng được:has()khác và không dùng được với pseudo-element.- Trình duyệt phải đánh giá lại khi cây DOM đổi; tránh selector quá rộng kiểu
body:has(...)gắn với thay đổi liên tục, đặc biệt trên danh sách lớn. - Kiểm tra hỗ trợ bằng
@supports selector(:has(a))nếu phải chạy trên trình duyệt cũ.