- Chỉ với tính năng mặc định của trình duyệt, có thể tạo giao diện popover nổi phía trên trang, giúp triển khai nhất quán hơn các mẫu như menu, gợi ý và thông báo
- Popover do Popover API tạo ra luôn là không theo kiểu modal, vì vậy với UI cần chặn tương tác với trang thì `` phù hợp hơn
- Các thao tác bật/tắt đơn giản có thể xử lý bằng các thuộc tính HTML như
popover, popovertarget, popovertargetaction, và khi cần thì dùng các phương thức JavaScript để điều khiển trạng thái hiển thị
- Có thể xử lý kiểu dáng và thay đổi trạng thái bằng
::backdrop, :popover-open, beforetoggle, toggle, còn interest invokers hỗ trợ hiển thị bằng hover/focus mà không cần JavaScript
- Đây là tính năng Baseline 2025 hoạt động trên thiết bị và trình duyệt hiện đại từ tháng 1/2025, nhưng vẫn cần kiểm tra khả năng tương thích với môi trường cũ hoặc một số chi tiết tính năng
Vấn đề mà Popover API giải quyết
- Popover API cung cấp cơ chế tiêu chuẩn để hiển thị nội dung popover phía trên các nội dung khác của trang
- Popover có thể được điều khiển chỉ bằng thuộc tính HTML, hoặc dùng JavaScript API để trực tiếp xử lý trạng thái hiện/ẩn
- Các mẫu UI từng được gọi là overlays, popups, popovers, dialogs trên web giờ có thể được triển khai nhất quán hơn bằng tính năng mặc định của trình duyệt
Nếu cần modal, hãy dùng ``
- UI popover nhìn chung được chia thành modal và không modal
- Với modal, người dùng không thể tương tác với phần còn lại của trang khi popover đang hiển thị
- Với không modal, người dùng vẫn có thể tiếp tục tương tác với phần còn lại của trang dù popover đang mở
- Popover tạo bằng Popover API luôn là không modal
- Nếu cần popover dạng modal để chặn tương tác với trang, phần tử `` sẽ phù hợp hơn
- Cách áp dụng
popover lên như cũng hợp lệ, cho phép dùng đồng thời cơ chế điều khiển popover và ngữ nghĩa của dialog
Cách dùng cơ bản
- Popover API có thể thường được dùng cho các UI cần tương tác với người dùng
- menu hành động
- thông báo toast tùy biến
- gợi ý cho phần tử form
- bộ chọn nội dung
- UI hướng dẫn
- Có thể tạo nút bật/tắt popover đơn giản chỉ bằng HTML
Toggle the popover
Popover content
- Trong JavaScript,
HTMLElement.togglePopover() dùng để chuyển đổi giữa trạng thái hiện/ẩn của popover
- API cũng cung cấp các sự kiện phản ứng với thay đổi trạng thái popover và các tính năng CSS hỗ trợ tạo kiểu
Thuộc tính HTML
interestfor
- Xác định các phần tử HTML
, , hoặc phần tử SVG làm interest invoker
- Giá trị là
id của phần tử đích; khi interest xuất hiện hoặc biến mất ở phần tử invoker thì phần tử đích sẽ bị tác động
popover
- Là thuộc tính toàn cục biến một phần tử thành phần tử popover
- Có thể nhận các trạng thái
"auto", "hint", "manual"
popovertarget
- Biến
hoặc thành nút điều khiển popover
- Giá trị là ID của phần tử popover cần điều khiển
popovertargetaction
- Chỉ định hành động mà nút điều khiển sẽ thực hiện với popover
- Các giá trị có thể dùng là
"hide", "show", "toggle"
Xử lý trạng thái hiển thị bằng CSS
::backdrop
- Là pseudo-element toàn màn hình nằm ngay phía sau phần tử popover
- Nếu cần, có thể áp dụng hiệu ứng như làm mờ cho nội dung trang phía sau popover
interest-delay, interest-delay-start, interest-delay-end
- Thêm độ trễ giữa thời điểm người dùng thể hiện hoặc mất interest và thời điểm trình duyệt phản ứng
:interest-source, :interest-target
- Cho phép áp dụng style lần lượt cho invoker và phần tử đích được liên kết khi interest đang được hiển thị
:popover-open
- Là pseudo-class chỉ khớp khi phần tử popover đang hiển thị
- Dùng để tạo kiểu cho popover ở trạng thái mở
Giao diện JavaScript và mở rộng DOM
InterestEvent
- Là đối tượng sự kiện cho các sự kiện
interest và loseinterest
- Bao gồm thuộc tính
source chứa tham chiếu đến phần tử interest invoker được liên kết
ToggleEvent
- Biểu diễn sự kiện xảy ra khi phần tử popover chuyển đổi giữa trạng thái hiển thị và ẩn
- Là đối tượng sự kiện của
beforetoggle và toggle
interestForElement
- Lấy hoặc thiết lập tham chiếu đến phần tử mà interest invoker nhắm tới
- Có thể dùng trên
HTMLButtonElement, HTMLAnchorElement, HTMLAreaElement, SVGAElement
HTMLElement.popover
- Lấy hoặc thiết lập trạng thái popover của phần tử bằng JavaScript
- Dùng các giá trị
"auto", "hint", "manual", đồng thời cũng hữu ích cho việc phát hiện tính năng
- Phản ánh giá trị của thuộc tính toàn cục HTML
popover
popoverTargetElement
- Lấy hoặc thiết lập phần tử popover mà nút điều khiển quản lý trên
HTMLButtonElement và HTMLInputElement
- Là phần tương ứng trong JavaScript của thuộc tính HTML
popovertarget
popoverTargetAction
- Lấy hoặc thiết lập hành động popover sẽ được thực hiện trên
HTMLButtonElement và HTMLInputElement
- Dùng các giá trị
"hide", "show", "toggle" và phản ánh thuộc tính popovertargetaction
Phương thức và sự kiện
HTMLElement.hidePopover()
- Gỡ phần tử popover khỏi top layer và ẩn nó bằng cách áp dụng
display: none
HTMLElement.showPopover()
- Thêm phần tử popover vào top layer để hiển thị
HTMLElement.togglePopover()
- Chuyển đổi phần tử popover giữa trạng thái hiển thị và ẩn
beforetoggle
- Xảy ra ngay trước khi trạng thái của phần tử popover chuyển giữa hiển thị và ẩn
- Có thể dùng để ngăn việc mở popover, hoặc cập nhật các phần tử khác tùy theo trạng thái popover
toggle
- Xảy ra ngay sau khi trạng thái popover thay đổi
interest
- Xảy ra trên phần tử đích của interest invoker khi interest được hiển thị
loseinterest
- Xảy ra trên phần tử đích của interest invoker khi interest biến mất
Ví dụ và liên kết đặc tả
1 bình luận
Các ý kiến trên Hacker News
Popover API có vẻ sẽ tạo ra một thay đổi rất lớn khi có thêm CSS Anchor Positioning
Anchor positioning cho phép đặt vị trí một phần tử dựa trên một phần tử khác trên trang
Kết hợp với Popover API, có thể triển khai tooltip tùy chỉnh hoặc menu ngữ cảnh theo cách khai báo, và cũng không còn cần các thư viện như PopperJS nữa
https://developer.chrome.com/blog/tether-elements-to-each-ot...
https://popper.js.org/docs/v2/
https://developer.chrome.com/blog/anchor-positioning-api
https://caniuse.com/css-anchor-positioning
Tuần trước tôi đã thử tạo và triển khai thứ gì đó bằng Popover API mới, nhưng do thiếu hỗ trợ định vị trên mọi trình duyệt nên các trường hợp sử dụng bị hạn chế đáng kể
Trình duyệt cuối cùng là Firefox dường như cũng đã đưa anchor positioning vào bản beta, nên chắc sẽ không mất lâu nữa
titlethì thật đáng ngạc nhiênNếu cần hộp thoại modal thì cũng có phần tử
<dialog>https://developer.mozilla.org/en-US/docs/Web/HTML/Element/di...
<details>cho “dropdown”Lạ là, khác với
<dialog>hay<details>, có vẻ<popover>không thể tạo trạng tháiopentheo cách khai báo chỉ bằng thuộc tínhCảm giác như một tính năng bị thiếu, và hy vọng quyết định này có cơ sở
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/de...
Hoàn toàn có thể làm được, nhưng chắc chắn không phải việc nhỏ
Hỗ trợ Safari mất một thời gian, nhưng giờ có thể dùng ở mọi nơi
Tôi cho rằng như vậy tốt hơn là tự ghép các thẻ lại với nhau
Nếu được triển khai cùng với hệ thống cửa sổ của hệ điều hành chủ thì tính năng này rõ ràng có vẻ cần thiết
Vì hiện nay popover luôn phải được mô phỏng theo cách không phải lúc nào cũng hoạt động tốt
Ví dụ,
<select>native của trình duyệt có thể mở rộng vượt ra ngoài ranh giới cửa sổ trình duyệt nên không phải lo bị cửa sổ cắt mất, nhưng các select giả hào nhoáng của những toolkit như Quasar thì không làm được vậy, khiến các lựa chọn bố trí bị hạn chếĐể làm đúng, trên win32 mỗi popover có lẽ cần có
HWNDnative riêng, còn trên Cocoa/macOS thì có lẽ phải nằm trongNSViewriêngTôi tò mò liệu hiện nay các trình duyệt có thực sự triển khai như vậy không, hay chỉ vẽ chồng bên trong cửa sổ trình duyệt
Nếu cho phép website vẽ ra ngoài viewport được chỉ định, thì ngoại trừ vài trường hợp cực kỳ hạn chế như
alert(),confirm(),[title], việc giả mạo hộp thoại của trình duyệt hoặc hệ điều hành một cách thuyết phục sẽ dễ hơn nhiềuVí dụ, một trang có thể giả mạo widget mở khóa của tiện ích quản lý mật khẩu
Đây là một rủi ro bảo mật lớn, và tôi cho rằng không đáng so với lợi ích hạn chế
Đây không phải là mối lo trên lý thuyết
Những kẻ lừa đảo trong nhiều năm đã tạo ra các UI giả rất thuyết phục, như cửa sổ popup giả có cả chrome của trình duyệt, thậm chí còn kéo thả được
Việc không thể vẽ ra ngoài ranh giới viewport gần như là hạn chế duy nhất mà họ chưa vượt qua được
Trên thiết bị nhỏ, trình duyệt web hầu như luôn phủ toàn màn hình, và ngay cả trên màn hình lớn thì thường cũng chạm ít nhất một góc
Khả năng truy cập và khả năng crawl cũng vậy, và cũng hữu ích khi ai đó muốn tạo plugin “chặn popup”
Tính năng này được bộc lộ thông qua các phần tử XUL, chỉ có thể dùng trong [X]HTML có đặc quyền được render trong tiến trình chính của trình duyệt
Tôi không nghĩ có nhà phát triển trình duyệt nào muốn trao cho các trang web thông thường quyền tạo cửa sổ hệ điều hành không viền
Việc một số control tiêu chuẩn hoạt động như vậy là tác dụng phụ triển khai tùy OS do chúng được triển khai bằng native của hệ điều hành, và cũng không nhất thiết phải triển khai theo cách đó
Trình duyệt có trình chặn popup tích hợp sẵn, nên việc tạo ra một API như thế này hơi buồn cười
Tôi biết là có khác biệt, nhưng dù vậy vẫn thấy thế
Tôi đủ tuổi để nhớ cuộc chiến popup/popunder cuối thập niên 90 và đầu những năm 2000
Có vẻ như chúng ta đã thắng trận đó, nhưng cuộc chiến giành sự chú ý của chúng ta thì vẫn còn rất dài
Popover là phần tử nổi hiển thị thông tin theo ngữ cảnh khi cần
Thứ được nhắc tới là một chuyện hoàn toàn khác
Popup rải các cửa sổ rác lên hệ điều hành, trong trường hợp tệ nhất còn cản trở cả việc sử dụng máy tính
Hộp thoại popover thì chỉ cần đóng tab là xong
Kiểu popover này khá hữu ích để hiển thị thông tin, nên đã được dùng từ lâu rồi
Nó có thể bị dùng theo cách gây khó chịu, nhưng cũng có nhiều use case thật sự như modal
Ngay bây giờ vẫn có thể triển khai popover bằng
divhiện có, v.v.Ví dụ: https://getbootstrap.com/docs/5.3/components/popovers/
Điểm khác biệt là có thể triển khai popover mà không cần thêm thư viện “ma thuật” nào
Có chặn phần tử “popover” tường minh thì mọi người cũng chỉ tiếp tục dùng thư viện tùy biến mà thôi
Lý do mọi người ghét popup là vì chúng xâm nhập và có cửa sổ riêng
API này thay thế
divmodal, giúp giảm thời gian và code cho lập trình viênAPI này không phá vỡ ranh giới đó
Khi ranh giới đó bị phá vỡ, tính khả dụng và an toàn của hệ thống giảm đi, nên đó không phải hướng mong muốn
Có câu “Popover được tạo bằng Popover API luôn là phi modal. Nếu muốn tạo modal popover thì phần tử
<dialog>mới là phù hợp”, nhưng tôi không hiểu vì saoĐây là một use case chính đáng của popover
Đặc biệt nếu khi mở ra nền bị làm mờ, và nếu các nút bị làm mờ có thể bị click nhầm bởi người dùng, thì tôi tự hỏi vì sao lại cung cấp tính năng đó
Tìm thử thì thấy có thể kết hợp cả hai
Kiểu như “Nếu muốn kết hợp điều khiển popover với ngữ nghĩa hộp thoại, bạn có thể biến phần tử
<dialog>thành popover”Vậy thì ở đây một thuộc tính như
modalcó vẻ hợp lý hơnVì họ rõ ràng đang thừa nhận use case đó
<dialog>đã tồn tại sớm hơn nhiềuRất hay
Nếu tôi hiểu đúng thì thay vì đưa vào một tính năng mới, nó có vẻ đơn giản hóa những phần trước đây cần modal
div, maskdiv, containerdivvà CSS định vị phiền phứcCũng có thêm pseudo-class giúp styling dễ hơn, tôi thích điều đó
Không cần ép dùng checkbox ẩn nữa
Tôi không biết các popover có styling và animation sẽ đi được đến đâu nếu không có JS, nhưng hỗ trợ không-JS với xử lý focus đúng là tốt
Tôi muốn nói rằng hỗ trợ accessibility cũng được tích hợp sẵn, nhưng hiện không tìm thấy trong spec
Nếu nó xử lý luôn việc thông báo phần tử cho các công cụ accessibility như screen reader thì sẽ rất hữu ích
Vì khi làm thủ công, khá dễ bỏ sót
Rõ ràng là hữu ích
Demo: https://mdn.github.io/dom-examples/popover-api
Vì chưa ai triển khai độ trễ trước khi submenu biến mất trong Chrome hay Firefox
Hàng thập kỷ nghiên cứu trải nghiệm người dùng đã biến mất, và điều này gần như đúng như dự đoán
https://mdn.github.io/dom-examples/popover-api/nested-popove...
Trông rất tuyệt, nhưng tôi không hiểu vì sao trang này không có một hình ảnh nào cho thấy popover là gì
https://mdn.github.io/dom-examples/popover-api/
Dù có liên kết tới ví dụ tương tác, nhưng style mặc định của popover trông không thú vị lắm
https://mdn.github.io/dom-examples/popover-api/
Tuyệt vời
Phần triển khai tùy biến bằng Stimulus dùng Popper nằm ở đây
https://github.com/tramlinehq/tramline/blob/main/app/javascr...
Và phần triển khai cho hộp thoại nằm ở đây
https://github.com/tramlinehq/tramline/blob/main/app/javascr...