2 điểm bởi GN⁺ 2024-05-11 | 1 bình luận | Chia sẻ qua WhatsApp
  • 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 modalkhô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 interestloseinterest
    • 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 beforetoggletoggle
  • 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 HTMLButtonElementHTMLInputElement
    • 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 HTMLButtonElementHTMLInputElement
    • 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

 
GN⁺ 2024-05-11
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/

    • Tôi vừa đăng một bài mới về cách dùng CSS Anchor API, dự kiến sẽ được đưa vào Chromium tuần tới
      https://developer.chrome.com/blog/anchor-positioning-api
    • Có thể xem tình trạng hỗ trợ của trình duyệt tại đây
      https://caniuse.com/css-anchor-positioning
    • Nếu CSS Anchor Positioning đã có trong vài năm qua thì chắc đã tiết kiệm được một lượng thời gian khổng lồ
    • Đây chính là mảnh ghép cốt lõi còn thiếu
      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
    • Đã là năm 2024 mà HTML/CSS vẫn không có thuộc tính tooltip như title thì thật đáng ngạc nhiên
  • Nế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...

    • Nếu cần nội dung mở rộng/thu gọn, hoặc hơi gượng ép một chút thì cũng có thể dùng <details> cho “dropdown”
      Lạ là, khác với <dialog> hay <details>, có vẻ <popover> không thể tạo trạng thái open theo cách khai báo chỉ bằng thuộc tính
      Cả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...
    • Tôi muốn cảnh báo rằng để đưa animation và hành vi modal thông thường lên mức kỳ vọng hiện nay thì cần khá nhiều công sức
      Hoàn toàn có thể làm được, nhưng chắc chắn không phải việc nhỏ
    • Như đã được chỉ ra, animation khó hơn, nhưng nó có khả năng truy cập, hỗ trợ đóng bằng phím Esc, nền tích hợp sẵn và focus trap tích hợp sẵn
      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
    • Vài đoạn đầu của bài viết đã đề cập đến điều này rồi
  • 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ó HWND native riêng, còn trên Cocoa/macOS thì có lẽ phải nằm trong NSView riêng
    Tô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

    • Các popover này chỉ là node DOM thông thường và được style bằng CSS thông thường
      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ều
      Ví 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
    • Tôi không biết tính năng như vậy thực tế sẽ hữu ích đến mức nào
      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
    • Về mặt ngữ nghĩa thì có vẻ cũng sẽ dễ phát hiện hơn
      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”
    • Firefox về mặt kỹ thuật có hỗ trợ tính năng cho phép một phần nội dung trang “bật ra” thành cửa sổ cấp hệ điều hành riêng
      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
    • Có vẻ web app sẽ chưa sớm có được tích hợp hệ thống cửa sổ native như tưởng tượng
      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

    • Có vẻ như đang so sánh những thứ khác nhau
      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
    • Tôi hiểu ý bạn muốn nói, nhưng thực tế có vẻ không phải là đối tượng để so sánh
      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
    • Thấy nhiều phản ứng như thế này, nhưng hơi vô lý
      Ngay bây giờ vẫn có thể triển khai popover bằng div hiệ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
    • Đây không phải là popup
      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ế div modal, giúp giảm thời gian và code cho lập trình viên
    • Cách triển khai popup nguyên thủy phá vỡ ranh giới giữa nội dung ứng dụng và hệ điều hành, còn trình chặn popup là để ngăn điều đó
      API 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ư modal có vẻ hợp lý hơn
    Vì họ rõ ràng đang thừa nhận use case đó

    • Có lẽ một trong nhiều lý do là <dialog> đã tồn tại sớm hơn nhiều
  • Rấ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, mask div, container div và CSS định vị phiền phức
    Cũng có thêm pseudo-class giúp styling dễ hơn, tôi thích điều đó

    • Nó cũng cho phép dùng chức năng cơ bản không cần JavaScript
      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
    • API này cho phép điều khiển trạng thái hiển thị của phần tử popover trong DOM ngay cả khi không có JavaScript
      Rõ ràng là hữu ích
  • Demo: https://mdn.github.io/dom-examples/popover-api

    • Trong demo popover lồng nhau, không thể di chuyển chéo từ Pizza sang Ham
      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...
    • Theo bảng hỗ trợ trình duyệt thì nói là được, nhưng có vẻ không hoạt động trên iOS Safari
  • 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ì

  • 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...