
Ranh giới mong manh giữa CSS States và JavaScript Events: Tương lai của Web Development
Khám phá cách CSS đang dần đảm nhận các tác vụ vốn trước đây chỉ dành cho JavaScript thông qua các pseudo-class hiện đại và đề xuất tương lai đầy hứa hẹn của 'event-trigger'.
Giới thiệu
CSS đang ngày càng trở nên "biết lắng nghe" hơn bao giờ hết. Không phải theo nghĩa đen, mà là CSS đang tích hợp ngày càng nhiều các pseudo-class (lớp giả) mạnh mẽ, cho phép chúng ta phản hồi với các sự kiện người dùng mà không cần phải viết JavaScript phức tạp. Mặc dù các pseudo-class theo dõi "trạng thái" (states) chứ không phải "sự kiện" (events), nhưng chúng đang dần xóa nhòa ranh giới giữa hai khái niệm này.
Trong bài viết này, chúng ta sẽ cùng phân tích các pseudo-class hiện có đóng vai trò như các trình lắng nghe sự kiện (event listeners) và khám phá đề xuất tương lai đầy tham vọng: event-trigger.

Các "Event-listening" Pseudo-classes
:hover và :active
- :hover: Trạng thái này nắm bắt khoảnh khắc từ khi sự kiện
pointerenterkích hoạt cho đến khipointerleavexảy ra. - :active: Khớp với mục tiêu (nút, liên kết) đang được nhấn bởi chuột, ngón tay hoặc bút cảm ứng, tương đương với sự kiện
pointerdownvàpointerup/pointercancel.
Mẹo nhỏ: Bạn có thể sử dụng thuộc tính pointer-events: none trong CSS để ngăn chặn các sự kiện con trỏ kích hoạt trên phần tử đã chọn.
:focus và :focus-visible
Trong khi :focus tương đương với các sự kiện focus và blur trong JavaScript, thì :focus-visible thông minh hơn nhiều. Nó sử dụng các thuật toán của trình duyệt để xác định xem liệu chỉ báo focus có nên hiển thị hay không (ví dụ: người dùng đang dùng bàn phím hay chuột?).
Cách tốt nhất để xử lý logic này trong JavaScript là kiểm tra pseudo-class:
element.addEventListener("focus", (event) => {
if (event.target.matches(":focus-visible")) {
/* Thực hiện logic khi phần tử được focus qua bàn phím */
}
});
:focus-within và :has()
CSS hiện đại đã tiến xa hơn với khả năng kiểm tra mối quan hệ cha-con:
- :focus-within: Khớp nếu bất kỳ phần tử con nào đang có focus.
- :has(): Khớp nếu một mối quan hệ selector tồn tại.
Ví dụ, hai đoạn code sau có tác dụng tương đương:
form:focus-within { /* Style form khi có con bên trong được focus */ }
form:has(:focus) { /* Style form khi có con bên trong được focus */ }
:checked
Tương đương với sự kiện change trong JavaScript. Khi một ô checkbox hoặc radio được chọn, CSS có thể phản hồi ngay lập tức mà không cần script.
Kiểm soát logic ẩn: :valid, :invalid và :autofill
Thay vì phải gọi checkValidity() trong JavaScript, CSS cung cấp các pseudo-class để xử lý xác thực form:
- :valid / :invalid: Kiểm tra trạng thái hợp lệ ngay lập tức.
- :user-valid / :user-invalid: Chỉ kích hoạt sau khi người dùng đã tương tác và rời khỏi phần tử (tương đương với logic của sự kiện
change). - :autofill: Một tính năng cực kỳ hữu ích mà JavaScript khó có thể phát hiện một cách sạch sẽ.
Các pseudo-class cho Media và UI
- Media elements: Các pseudo-class mới như
:volume-lockedsẽ sớm cho phép chúng ta kiểm soát trạng thái audio/video mà không cần lắng nghe sự kiệnvolumechange. - Popover/Dialog: Các pseudo-class như
:popover-open,:open, và:modalthay thế hoàn toàn việc phải lắng nghe sự kiệntoggletrong JS. - :fullscreen: Thay thế cho sự kiện
fullscreenchange. - :target: Thay thế cho việc lắng nghe
hashchangeđể kiểm tra ID trong URL.
Tương lai: Event-trigger (Đề xuất)
Mặc dù chưa được hỗ trợ rộng rãi, event-trigger là một bước tiến lớn trong đặc tả Animation Triggers. Nó cho phép gắn sự kiện trực tiếp vào CSS.
Cấu trúc cơ bản:
button {
event-trigger: --event click;
}
div {
animation-trigger: --event play-forwards;
animation: fade-in 300ms both;
}
Với event-trigger, chúng ta có thể tạo ra các hiệu ứng phức tạp chỉ bằng CSS, ví dụ như kích hoạt animation của phần tử B khi phần tử A được click. Các hành động animation được hỗ trợ bao gồm: play-once, play-forwards, play-backwards, và replay.
Kết luận
Việc CSS đảm nhận nhiều logic hơn không có nghĩa là JavaScript "tệ đi", mà là chúng ta có thêm công cụ để tối ưu hóa hiệu năng và đơn giản hóa mã nguồn. Sự chuyển dịch này giúp giao diện web trở nên phản hồi nhanh hơn và giảm bớt gánh nặng cho luồng thực thi chính (main thread) của JavaScript.
Do you like this post?
Upvote to push this post higher on the community feed
