Popover API & discrete property transitions

Paul Li
7 min readSep 25, 2023
Popover API & discrete property transitions

Introduction

Popover API 一直都是我所關注的重點 Web API,透過 attribute 的設置,便可以立即完成 popup 的效果,不需要撰寫任何的 JavaScript,不僅僅滿足了互動與呈現需求,更能有效節省效能的損耗,讓 Web developers 可以更加專注在細節的呈現。

Chrome VER.114 便率先支援了 Popover API,而 Safari 亦在 VER.17 導入了。主要的兩大瀏覽器陣營都可以支援了,這表示說 Web Developers 是時候可以進來了解它的優雅之處,想想其 use case 並試著將它導入自身負責的服務當中。

實作過程一直是個人最愉悅的時刻,不僅可以加深印象,也可以從刻畫的過程中了解它的行與不能,大夥們如果有興趣的話也可以先點擊範例一睹它的魅力所在~

接下來的內容就會以上述範例跟大家介紹如何使用 Popover API 以及因為它所衍生的其他 CSS animation 支援。

How to use Popover API

套用 popover 其實非常簡單,只要透過 attribute 的設置即可。

如上所示,文件中寫道可以針對 <button /> 以及 <input /> 元件下 popovertarget 來和 popover element 進行關聯(id),而欲成為 popover element 只要下 popover attribute 即可,如此一來,便可以在 button 點擊時,便可以召喚出 popover element 了。

劣者試著用其他 element 搭配 tabindex 或是 role 來偽造 trigger,不過都無法順利喚起 popover element,看來有先鎖一層 tagName 判斷。

除此之外,iOS 17 > Safari 亦隱含著一個 bug,即便是 button[type=button][popovertarget],若置入 <form /> 裡頭的話,那麼點擊事件似乎會被截走,無法正常喚起 popover element(Chrome 可以正常喚起),目前已經回報 WebKit Bugzilla,靜待後續發展。

先來看看 trigger 的部份,除了用 popovertarget 來建立關聯外,也可以透過 popovertargetaction 來指定期待的 action。

  • popovertargetaction:hide || show || toggle

popover element 則和 <dialog /> 非常相似,從 Chrome DevTools > Elements panel 都可以清楚看到它們都是以 #top-layer 的形式存在。呈現與 style 的方法更是雷同,對於有玩過 <dialog /> 的朋友,應該可以很快入手 popover element。

  • popover:auto || manual

popover element 的 popover attribute 亦支援上面這些 value,供不同情境使用,最大的差異莫過於 light dismiss 的功能,只要設置 auto 便可以立即享有點擊空白區域或者鍵盤操作 esc 來立即關閉 popover element。

manual 其實蠻微妙,除了沒有 light dismiss 功能外,我原本以為它會完整阻隔 top-layer 下的元件,但事實不然,使用者依然可以「穿透」它對既有頁面進行操作,比方說選取文字或是點擊按鈕或連結,老實說…詭異非常~

除了原生的 attribute 快速進行功能附加外,popover element 也有提供一些 methods,讓 web developers 可以透過 JavaScript 來進行顯示 / 關閉操作。

Discrete property transitions

如果說 <dialog /> 打開了新世界,那麼 Popover 便是讓它遍地開花的主要助力與手段,雖然可以透過簡單的設置來滿足功能需求。不過要有效 style popover 的進退場機制其實不是那麼容易。(有興趣的朋友可以看看這篇快速回顧一下當初怎麼和 <dialog /> 打交道)

不管透過 transition 或者 animation 來對 element 進行動畫效果,至關重要的先決條件便是該元件的 display 必須要是 block,需要確實存活且顯示在頁面上才能對它進行動畫效果。

也就是說對於「無中生有」的 element 更是搞,append 到 DOM tree 後,需要設個 timer(ex: 50ms) 再附加進場動畫的 className,這麼做的原因是因為如果進場動畫直接寫在 element 的初始狀態,那麼因為 display 的關係,無法立即呈現所導致。

同樣的退場機制也是如此,一但退場機制的 className 裡頭隱含 display: none,那麼便別想退場機制的動畫可以如期播放完。只能自己下 transitionend 或是 animationend 才能對該 element 進行後續操作(display:none 或是移除)。

可想而知,像 popover 從原本 display:none 到真正頁面呈現,如果要附加進退場的機制的話,也絕非易事!這也就是 discrete property transitions 產生的主要原因。

上面範例是透過 CSS nesting 所撰寫的 popover element 的進場機制,Web developers 可以透過 pseudo class :popover-open 來裝飾 popover element 被喚醒的樣式,其中有個有趣的屬性 @ starting-style 也是近期所支援,透過這樣的描述,便可以輕鬆的設置該動畫的初始樣式。

Line 3 ~ 19 便是描述當 popover element 呈現時,我們希望他的樣式從

  • transform: translateY(-20px) scaleY(0);
  • opacity: 0;

變換成

  • transform: translateY(0) scaleY(1);
  • opacity: 1;

Line 26 ~ 27,則是當 popover element 退場時該有的樣式。

透過上面撰寫,便可以輕輕鬆鬆完成進退場動畫的宣告了,當中起了至關重要的角色莫過於 line 32 ~ 32。

  • transition: transform 200ms ease-out, opacity 200ms, display 200ms, overlay 200ms;
  • transition-behavior: allow-discrete;

我們明確定義了針對「display」以及「overlay」下了 transition,並且設定 transition-behavior 為 allow-discrete,如此一來 disaply 以及 overlay 便可以在動畫都跑完之後才會正常運作。也就是說透過它的加持便可以單純透過 CSS 完成不可能的任務 — 即便元件 display:none 狀態依然可以完成動畫設置,不需要撰寫任何 JavaScript 輔助~

Conclusion

以上便是我和 Popover API 打交道的點點滴滴,希望這些實作經驗可以有效地幫助到大家,讓大夥們可以更輕易的入門 Popover API。

感謝大家的閱讀,希望本篇能確切的幫助到大家~ #PopoverAPI #CSS

Reference

--

--

Paul Li

Paul is the lead programmer of the AMP project at Yahoo Taiwan and is always eager for modern web technologies. He is also focusing on UX for vivid user flow.