Cả ba đều làm element "biến mất" nhưng khác nhau về layout, tương tác và a11y:
display: none: gỡ element khỏi layout — không chiếm chỗ, không render, con cháu ẩn theo và không ghi đè lại được. Bị loại khỏi accessibility tree (screen reader bỏ qua). Không transition được vì element bị gỡ/gắn lại.visibility: hidden: element vô hình nhưng vẫn chiếm chỗ trong layout. Không nhận sự kiện chuột, không focus được, ẩn khỏi screen reader. Con cháu có thể tự hiện lại bằngvisibility: visible.opacity: 0: chỉ trong suốt về mặt hình ảnh — vẫn chiếm chỗ, vẫn nhận click và focus, vẫn nằm trong accessibility tree. Animate mượt được (chạy trên compositor).
Thực hành: toggle hẳn một khối → display: none; giữ layout ổn định khi ẩn/hiện → visibility; hiệu ứng fade → opacity (nhớ chặn tương tác bằng pointer-events: none hoặc kết hợp visibility khi đã ẩn hoàn toàn).