利用HTML5,無JS實現各種互動效果
本文利用的是HTML5 details, summary
首先
一、瞭解HTML5 details, summary預設互動行為
<details>
標籤在Chrome,Firefox等瀏覽器下預設是有展開收起行為的,例如下面HTML:
<details> <summary>這是摘要1</summary> <p>這裡具體描述,標籤相對隨意,例如這裡使用的<p>標籤。</p> </details>
結果UI表現為:
具體描述為:
-
只顯示了
<summary>
標籤內容,而<p>
預設隱藏了; -
<summary>
標籤前面出現了一個小三角;
小三角圖形的隱喻是:我是可點選的,點選我可能會出現寶箱。
OK,我們不妨就點選一下,結果如下圖:
具體描述為:
-
原本隱藏的
<p>
標籤顯示出來了; -
<summary>
標籤前面的小三角方向朝下了;
此時我們再一次點選,
<p>
標籤內容又會隱藏收起,箭頭方向還原,如下圖:
活脫脫一個天然的展開收起效果。
展開與收起是通過open屬性控制的
通過在
<details>
標籤上新增布林型別的
open
屬性,可以讓我們的詳情資訊預設就是展開狀態,如下HTML示意:
<details open> <summary>這是摘要2</summary> <content>這裡<details>標籤設定了HTML布林屬性open,因此,預設是展開狀態。</content> </details>
結果如下截圖:
如果我們使用JS指令碼手動移除這個
open
屬性,即使沒有點選行為的發生,我們內容也會收起。
<summary>如果預設
<summary>
標籤如果預設,則
<details>
元素會在內部自動建立一個
<summary>
內容,預設的文案是“詳細資訊”。如下HTML程式碼:
<details open> <p>如果<summary>預設,則會自動補上,文案是“詳細資訊”。</p> </details>
結果如下截圖所示:
二、details瀏覽器內建UI可以自定義
<details>標籤預設的小三角樣式有些簡陋,在實際應用的時候,往往不是我們希望的樣子,不要擔心,我們是可以對其進行自定義的。在Chrome等瀏覽器下使用::-webkit-details-marker,在Firefox瀏覽器下使用::-moz-list-bullet可以對小三角進行UI控制,例如改變顏色,改變大小,使用自定義的圖形代替,或者直接隱藏等,我們來看幾個簡單的案例。
案例1:小三角右側顯示同時顏色變淡
HTML程式碼如下:
<details class="details-1" open> <summary>這是示例1</summary> <content>本案例展示對小三角UI重定義:包括顯示在右側,顏色減淡等。</content> </details>
CSS如下:
.details-1 summary { width: -moz-fit-content; width: fit-content; direction: rtl; } .details-1 ::-webkit-details-marker { direction: ltr; color: gray; margin-left: .5ch; } .details-1 ::-moz-list-bullet { direction: ltr; color: gray; margin-left: .5ch; }
結果如下圖所示:
當我們點選摘要標題升起的時候,表現為下圖(截自Firefox):
而實際上實際開發的時候,對小三角UI更便捷的定製方法是:隱藏瀏覽器原生的小三角,然後藉助::before或::after偽元素重新生成我們想要的UI效果,下面這個案例就將展示相關的處理。
案例2:隱藏瀏覽器原生的小三角並使用自定義三角替換
HTML結構還是類似的:
<details class="details-2" open> <summary>這是示例2</summary> <content>本案例隱藏原生小三角,使用自定義小三角。</content> </details>
CSS主要分為2部分,一部分是隱藏瀏覽器原生的小三角,另外一部分是使用偽元素生成自定義的三角效果。
首先看一下隱藏<details>標籤預設的小三角的CSS:
/* 隱藏預設三角 */ .details-2 ::-webkit-details-marker { display: none; } .details-2 ::-moz-list-bullet { font-size: 0; }
可以看到Chrome瀏覽器和Firefox瀏覽器的小三角隱藏採用的是不同的策略。在Chrome瀏覽器下,我們可以直接設定display:none進行隱藏,但是這一招在Firefox瀏覽器下確實沒有效果的,即使設定display:none!important也是如此,根據我的測試,只有font-size:0能夠比較完美的隱藏。類似position:absolute;visibility:hidden這種常見的隱藏也是不行的,因為position:absolute無法生效。
然後是自定義小三角顯示的CSS,這裡採用的是::after偽元素模擬的:
/* 自定義的三角 */ .details-2 summary::after { content: ''; position: absolute; width: 1em; height: 1em; margin: .2em 0 0 .5ch; background: url(./arrow-on.svg) no-repeat; background-size: 100% 100%; transition: transform .2s; } .details-2:not([open]) summary::after { margin-top: .25em; transform: rotate(90deg); }
最終效果如下圖所示:
收起時候:
最後有一點需要注意一下,就是如果
<details>
標籤內並沒有
<summary>
元素,則我們的對三角的自定義程式碼都是無效的,可以使用一個空的
<summary>
元素佔位,類似這樣:
<details> <summary></summary> <content>內容。</content> </details>
三、Chrome瀏覽器下點選時候outline輪廓等體驗處理
UI可以定製了,但是還有個不容忽視的體驗問題,那就是在Chrome瀏覽器下點選時候會出現
outline
輪廓,如下圖所示:
在實際專案開發的時候,產品和設計一定會讓你把這個效果去掉的。以及,當我們
<summary>
元素點選較快的時候,文字會被選中,也不是我們想看到的。
阻止文字選中,我們可以:
summary { -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; }
對於outline輪廓,比較直接的做法是:
summary { outline: 0; }
但是這樣處理對無障礙訪問而是非常不友好的,那有沒有什麼辦法兼顧視覺體驗和無障礙訪問體驗呢?
我的做法是這樣子的:
-
利用<a>標籤的outline互動體驗
瀏覽器對<a>標籤元素的outline輪廓進行了專門的體驗優化處理,滑鼠點選的時候不顯示輪廓,鍵盤訪問時候顯示輪廓。於是我們可採用李代桃僵策略,讓<summary>元素的outline交給<a>元素,方法就是在<summary>中再內嵌一個<a>,同時通過tabindex屬性remove掉<summary>原本的可訪問性。HTML程式碼示意如下:
<details open> <summary tabindex="-1"><a href="javascript:">這是示例</a></summary> <content>點選無外框,鍵盤focus有。</content> </details>
CSS如下:
summary { user-select: none; outline: 0; } summary a { color: inherit; }
此時,在Chrome瀏覽器下,我們點選摘要資訊,沒有任何
outline
輪廓出現;但是當我們使用Tab鍵索引時候,可以看到下圖所示的輪廓效果:
輪廓區域比原生的
<summary>
要小,但這無傷大雅,而且實際專案開發的時候,我們會去掉小箭頭,此時只要設定
<a>
標籤
display:block
,則輪廓就可以和
<summary>
保持一致了。
接下來,我們按下Space空格鍵,就會發現
<details>
元素內的內容資訊不斷的展開與收起:
然後上面實現並不完美,相比原生的<summary>元素,EnterEnter鍵展開收起效果丟失了。這是因為HTML元素中如果多個focusable同時帶click瀏覽器行為元素巢狀的時候,點選裡面的元素,外部元素的瀏覽器行為是不會觸發的。類似的有<label>內嵌<a>標籤。
對於<a>標籤,其瀏覽器行為只能通過Enter鍵觸發,空格鍵是無效的;但是對於<summary>,Enter鍵和空格鍵都能觸發展開收起行為,這就是為什麼上面程式碼空格鍵有效,Enter鍵無效的原因。
如果想要同時支援Enter鍵展開與收起,可以對HTML如下處理:
<details open> <summary tabindex="-1"><a href="javascript:" onClick="this.parentNode.click();">這是示例</a></summary> <content>點選無外框,鍵盤focus有。</content> </details>
需要注意的是上面處理在<summary>自己額外繫結click事件時候可能會有double觸發的問題,此時,阻止<a>元素的冒泡即可。
-
JS捕獲鍵盤行為手動設定outline
這個方法不需要對HTML進行任何的改動,是通過CSS和JS配合對全域性的<summary>元素進行outline優化。
CSS如下:
summary { user-select: none; outline: 0; } summary[focus] { outline: 1px dotted; outline: 5px auto -webkit-focus-ring-color; }
JS如下:
window.addEventListener('keydown', function () { window.isKeyEvent = true; setTimeout(function () { window.isKeyEvent = false; }, 100); }); document.addEventListener('focusin', function (event) { var target = event.target; if (target && target.tagName.toLowerCase() == 'summary' && window.isKeyEvent == true) { target.setAttribute('focus', ''); } }); document.addEventListener('focusout', function (event) { var eleFocusAll = document.querySelectorAll('summary[focus]'); [].slice.call(eleFocusAll).forEach(function (summary) { summary.removeAttribute('focus'); }); });
只要把上面的CSS和JS複製到頁面中,視覺體驗和互動體驗完美支援的<summary>元素outline效果就有了。
表現為,點選<summary>沒有任何outline,鍵盤focus時候出現,且和瀏覽器原生outline效果一模一樣,Space鍵和Enter鍵展開與收起訪問完全保留。
例如下圖就是鍵盤Tab鍵
focus
後回車後的效果:
每每看到如此極致的使用者體驗處理,心情都大好。
原理:
關鍵是全域性監聽
keydown
事件,如果有發生,則認為此100毫秒內的頁面
focus
行為均是鍵盤產生,從而有效區分是點選觸發的
focus
行為還是鍵盤觸發的
focus
行為,如果是鍵盤觸發,給
<summary>
元素手動增加
outline
效果。
四、基於details元素行為的各種互動效果案例
瞭解了
<details>
元素的點選互動行為;解決了UI定製難題;解決了
outline
的體驗問題,下面我們就可以付諸實踐,不借助任何JS來實現各種我們平常見到的互動效果。
案例1:“更多”展開與收起效果
實現最終效果如下gif:
因為“更多”元素是在底部,因此效果實現的要點的所有的內容資訊都放在
<summary>
元素內部,然後通過
<details>
元素的
open
屬性控制UI的變化。
HTML和CSS程式碼如下,其中,最核心部分已經紅色高亮:
<details> <summary> <p>據臺媒報導,大...青睞。</p> <div class="more"> <p>其他幾首歌曲...</p> </div> <a>更多</a> </summary> </details> ::-webkit-details-marker { display: none; } ::-moz-list-bullet { font-size: 0; float: left; } .more { display: none; } [open] .more { display: block; } [open] summary a { font-size: 0; } [open] summary a::before { content: '收起'; font-size: 14px; }
把“更多”對應的資訊放在.more元素內,然後通過[open]屬性選擇器控制器顯示,效果即達成。
案例2:無JS實現點選顯示懸浮選單,自定義下拉框等效果
效果如下gif:
沒有任何JS參與。HTML結構如下:
<details> <summary>我的訊息</summary> <div class="box"> <a href>我的回答<sup>12</sup></a> <a href>我的私信</a> <a href>未評價訂單<sup>2</sup></a> <a href>我的關注</a> </div> </details>
然後CSS讓.box元素絕對定位即可,顯示和隱藏<details>元素內建行為就搞定了。
案例3:accordion多項摺疊效果
此效果常見於條目比較多的垂直導航欄,新聞條目等。
例如下面實現的效果:
這個更加簡單了,就是一堆
<details>
元素並排放置就可以了,如下HTML:
<details open> <summary><dt>訂單中心</dt></summary> <dd><a href>我的訂單</a></dd> <dd><a href>我的活動</a></dd> <dd><a href>評價曬單</a></dd> <dd><a href>購物助手</a></dd> </details> <details open> <summary><dt>關注中心</dt></summary> <dd><a href>關注的商品</a></dd> ... </details> <details open> ... </details>
計算CSS沒有任何設定,效果也天然達成。
案例3中的展開項顯示的時候是非常生硬的突然顯示,實際上我們可以藉助一些選擇器技巧以及CSS3
transition
屬性讓選單展開收起的時候是有動畫效果的,效果如下gif截圖:
此效果實現原理核心是
[open]
屬性選擇器,和加號
+
相鄰兄弟選擇器。
首先看下HTML,展開列表結構發生了變化,不是作為
<details>
的子元素,而是作為其相鄰兄弟元素存在,HTML示意:
<details open><summary>訂單中心</summary></details> <dl> <dd><a href>我的訂單</a></dd> <dd><a href>我的活動</a></dd> <dd><a href>評價曬單</a></dd> <dd><a href>購物助手</a></dd> </dl> ...
上面<dl>定義列表就是展開收起的內容,其作為兄弟元素和<details>元素平起平坐,於是,我們就可以利用點選<summary>元素<details>元素的open屬性會變化的特性實現我們想要的動畫效果,CSS如下:
details + dl { max-height: 0; transition: max-height .25s; overflow: hidden; } [open] + dl { max-height: 100px; }
藉助相鄰兄弟選擇器以及max-height任意元素slideUp/slideDown技術就可以效果達成。
案例5:多級巢狀的樹形選單互動效果
這裡的樹形選單效果實現也很簡單,多個
<details>
元素相互巢狀就可以,效果Gif如下:
HTML結構大致如下:
<details> <summary>我的視訊</summary> <details> <summary>爆肝工程師的異世界狂想曲</summary> <div>tv1-720p.mp4</div> <div>tv2-720p.mp4</div> ... <div>tv10-720p.mp4</div> </details> <details> <summary>七大罪</summary> <div>七大罪B站00合集.mp4</div> </details> <div>珍藏動漫網盤地址.txt</div> <div>我們的小美好.mp4</div> </details>
CSS的主要工作就是繪製選單前面的加號和減號圖形,例如我們可以藉助background線性漸變,相關CSS如下:
details { padding-left: 20px; } summary::before { content: ''; display: inline-block; width: 12px; height: 12px; border: 1px solid #999; background: linear-gradient(to right, #999, #999) no-repeat center, linear-gradient(to top, #999, #999) no-repeat center; background-size: 2px 10px, 10px 2px; vertical-align: -2px; margin-right: 6px; margin-left: -20px; } [open] > summary::before { background: linear-gradient(to right, #999, #999) no-repeat center; background-size: 10px 2px; }
效果即達成!
五、如果只想要details/summary的語義不要行為
如果只想要<details>元素,<summary>元素的語義,但是並不需要點選展開收起的行為,該怎麼處理呢?
例如,某評論,或者某帖子有標題和正文,非常符合詳情-概要-內容的語義,但是希望是純展示的,點選時候不收起,可以這麼處理:
1.<summary>標籤設定tabindex="-1"讓鍵盤無法訪問;
2.設定CSS:
summary { outline: 0; pointer-events: none; }
這樣就不能點,也不會有outline輪廓。
六、相容性以及Polyfill
相容性如下圖:
除了IE和Edge瀏覽器,大好河山一片綠,至少移動端可以用得比較開心。
如果想要在桌面web網頁使用
<details>
元素的棒棒噠特性,我們可以對其進行Polyfill
對鍵盤訪問,事件toggle都做了相容。
如果開發策略是對不支援的IE進行特異處理,則下面的JS判斷是否支援<details>元素的指令碼可能對你有用:
var isSupportDetails = 'open' in document.createElement('details');
最後,無JS實現的好處有:
省了程式碼,載入快了;
實現更簡單了,開發快了;
JS還沒載入互動也能進行,體驗好了;
鍵盤無障礙和aria閱讀裝置無障礙天然支援,體驗檔次高了。
自己是從事了五年的前端工程師,不少人私下問我,2019年前端該怎麼學,方法有沒有?
沒錯,年初我花了一個多月的時間整理出來的學習資料,希望能幫助那些想學習前端,卻又不知道怎麼開始學習的朋友。
如果你依然在程式設計的世界裡迷茫,不知道自己的未來規劃,可以加入web前端學習交流群:731771211 裡面可以與大神一起交流並走出迷茫。新手可進群免費領取學習資料,看看前輩們是如何在程式設計的世界裡傲然前行!群裡不停更新最新的教程和學習方法(進群送web前端系統學習路線,詳細的前端專案實戰教學視訊),有想學習web前端的,或是轉行,或是大學生,還有工作中想提升自己能力的,正在學習的小夥伴歡迎加入
點選: 加入
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69901074/viewspace-2636177/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 藉助HTML5details,summary無JS實現各種互動效果HTMLAIJS
- js利用H5的requestAnimationFrame()API實現動畫效果JSH5requestAnimationFrameAPI動畫
- 原生JS利用transform實現banner的無限滾動JSORM
- js、jQuery實現文字上下無縫輪播、滾動效果JSjQuery
- Android一種翻板式互動效果Android
- Html5實現移動端、PC端 刮刮卡效果HTML
- 【新手指南】App原型設計:如何快速實現這6種互動效果?APP原型
- 「譯」如何實現互動式 WebGL 懸停效果Web
- 互動投影的幾種實現方式
- js實現打字效果JS
- Android 的滑動分析以及各種實現Android
- python與mysql互動中的各種坑PythonMySql
- 企業展廳互動能實現什麼效果
- 實現抖音 “影片無限滑動“效果
- echart 各種圖實現
- 利用es6實現互動的水波特效特效
- 大屏報表元件間的聯動互動效果實現方法元件
- 互動滑軌屏的幾種實現形式
- 直播軟體搭建,利用原生JS實現回到頂部以及吸頂效果JS
- app直播原始碼,利用原生JS實現回到頂部以及吸頂效果APP原始碼JS
- CSS + JS 實現打字機效果CSSJS
- js 實現程式碼雨效果JS
- 原生JS實現拋物線動畫以及動態模糊效果JS動畫
- 【.NET】控制檯應用程式的各種互動玩法
- 報表如何實現行列互換效果?
- 從打字機效果的 N 種實現看JS定時器機制和前端動畫JS定時器前端動畫
- 記錄---實現抖音 “影片無限滑動“效果
- 利用Node實現HTML5離線儲存HTML
- JS實現動態瀑布流及放大切換圖片效果(js案例)JS
- Axure互動效果1
- 單例模式的各種實現單例模式
- JS實現彈幕效果(10.11—10.17)JS
- 利用tensorflow.js實現JS中的AIJSAI
- 利用JavaScript實現註冊頁面省市聯動效果(附程式碼)JavaScript
- Android 原生和 JS 互動實踐AndroidJS
- 物體識別桌利用智慧互動實現資訊傳播
- 一步步教你用HTML5 SVG實現動畫效果HTMLSVG動畫
- 移動端無限滾動載入 js實現原理JS