2021年7月1日 星期四

製作 TAB 頁籤選單最簡單的架構﹍純 CSS 實現技巧整理

製作 TAB 頁籤選單最簡單的架構﹍純 CSS 實現技巧整理

Wayne Fu 0 A+
最近有個需求是製作 TAB 頁籤選單,這功能很常見,理應沒什麼難度。然而客戶希望將來能自行編修、調整選單內容,並製作大量相關頁面,這對於不是熟悉前端程式碼、架構的人來說,要無腦編修 TAB 頁籤的 HTML/CSS 內容實在不太可能(因為這案子的選單內容區塊架構很複雜),而且我也不想順便再教幾堂基礎 HTML/CSS 課程。 於是花了些時間研究,TAB 選單有沒有架構最簡單的實現方式,如果能以純 CSS 實現、不另外處理 JS 更好,研究結果請見本篇的整理。 (圖片出處: .peakpx.com)

一、各種方案比較

第 1 個頁籤內容區塊
第 2 個頁籤內容區塊
第 3 個頁籤內容區塊
1. 理想架構 上面是一個簡單的 TAB 頁籤效果,對於目標是建立一個可以無腦維護、容易複製編修重作的架構,我理想中的 TAB 頁籤程式碼模組希望能符合以下需求:
  • 能只用 HTML/CSS 處理、不另外寫 JS 最好
  • 維護時最好只需複製、編修 HTML 區塊,不用另外動到 CSS,也就是 CSS 寫法需要能萬用,如此可減少人為操作失誤
  • 根據前一點,選單頁籤區塊與內容區塊最好位於同一處
    • 根據多年經驗,選單的架構一定是頁籤區塊一處、內容區塊一處,頁籤區塊的順序必須與內容區塊的順序一致
    • 那麼日後增、減內容時,不小心兩邊不一致就會讓頁籤與內容不符合,更別說不熟悉前端的人一定會搞混
    • 所以如果能有一種架構,是頁籤區塊與內容區塊可以打包在一起,日後維護絕對不會出問題
接著以下整理一些純 HTML/CSS 頁籤架構的方案。 2. 利用 :target 可參考這篇「純CSS製作HTML頁籤切換的效果與實例」,其原理為:
  • 點擊頁籤的部分利用 A 連結的錨點功能
  • CSS 處理內容區塊切換的技巧為使用偽類 :target,很是巧妙
此方案不符合本篇需求的原因為:
  • 選單架構 HTML 為傳統的頁籤區塊一處、內容區塊一處,維護不便
  • 使用錨點會讓應用方式受限,如果整個選單位於畫面需要捲動之處,點擊頁籤後就只能看到內容、看不到頁籤
3. 利用 input 單選按鈕(1) 可參考這個 CodePen 範例「CSS Only Tabbed Content」,其原理為:
  • 使用 Input 單選按鈕製作頁籤效果,原理可參考「如何製作無圓點單選、多選按鈕﹍純 CSS 技巧
  • HTML 使用傳統的 TAB 頁籤架構,頁籤一區、內容一區
  • CSS 處理內容區塊切換的技巧為,使用 input 單選按鈕獨有的偽類 :checked,然而有幾個頁籤就必須設定幾個控制代碼,也是這個架構下無可奈何的事
此方案不符合本篇需求的原因為:
  • 傳統的頁籤選單 HTML 架構維護不便
  • 只要新增頁籤、內容,就必須新增對應的 CSS 控制,維護麻煩
4. 利用 input 單選按鈕(2) 可參考這個 stack overflow 討論串「Accessible CSS-only tab view」,其原理為:
  • 同前範例,使用 Input 單選按鈕製作頁籤效果
  • 這是我首次看到使用非傳統 HTML 頁籤架構,頁籤與內容區塊合而為一!
  • CSS 處理內容區塊切換的技巧同上,使用 input 單選按鈕獨有的偽類 :checked
  • 內容區塊的版面處理則是必須使用 position: absolute 定位,否則無法出現在該有的版面位置
此方案的感想:
  • 這是目前為止接近滿分的方案,頁籤與內容區塊合而為一,要複製、修改、刪除都非常方便,只要處理一處適合無腦維護
  • CSS 部分為萬用代碼,無論如何新增、刪除頁籤,都不需動到 CSS
  • 唯一的缺點是使用 position: absolute 來定位,這會使應用方式受限,必須為內容區塊設定高度(否則版面會爆掉),導致內容區塊無法根據內容彈性調整高度
就差那麼一點點,於是繼續尋找有沒有更好的方案。

二、利用 flexbox

最後找到這個方案,參考這個 CodePen 範例「Pure CSS Tabs 」,其原理為:
  • 同前範例,使用 Input 單選按鈕製作頁籤效果,並且使用非傳統 HTML 頁籤架構,頁籤與內容區塊合而為一!
  • 唯一不同處,內容區塊的版面處理使用 display: flex,這是 CSS 新世代的 flexbox 排版技巧
此方案特點:
  • 目前為止最接近完美的方案,幾乎符合我所有需求。
  • 日後要複製、修改、刪除時,只有一點不方便,必須手動為個別 input 單選按鈕設定 id,且對應的 label 標籤也要設定 for 參數
  • 不過上一點的不便之處,可以另外寫一行 JS 來自動處理,那麼給客戶使用時就能無腦維護了

三、範例程式碼

以下提供整理過,版面效果較佳的範例程式碼: <div class="tab_css"> <!-- TAB1 打包區塊 start --> <input id="tab1" type="radio" name="tab" checked="checked"/> <label for="tab1">頁籤 1</label> <div class="tab_content"> 第 1 個頁籤內容區塊<br/> WFU BLOG | Blogger 調校資料庫<br/> </div> <!-- TAB1 打包區塊 end --> <!-- TAB2 打包區塊 start --> <input id="tab2" type="radio" name="tab"/> <label for="tab2">頁籤 2</label> <div class="tab_content"> 第 2 個頁籤內容區塊<br/> WFU BLOG | Blogger 調校資料庫<br/> 第 2 個頁籤內容區塊<br/> WFU BLOG | Blogger 調校資料庫<br/> </div> <!-- TAB2 打包區塊 end --> <!-- TAB3 打包區塊 start --> <input id="tab3" type="radio" name="tab"/> <label for="tab3">頁籤 3</label> <div class="tab_content"> 第 3 個頁籤內容區塊<br/> WFU BLOG | Blogger 調校資料庫<br/> 第 3 個頁籤內容區塊<br/> WFU BLOG | Blogger 調校資料庫<br/> 第 3 個頁籤內容區塊<br/> WFU BLOG | Blogger 調校資料庫<br/> </div> <!-- TAB3 打包區塊 end --> </div> <style> .tab_css{display:flex;flex-wrap:wrap;justify-content:center;} .tab_css input{display:none} .tab_css label{margin: 0 5px 5px 0; padding: 10px 16px; cursor: pointer; border-radius: 5px; background: #999; color: #fff; opacity: 0.5;} .tab_content{order:1;display: none; width:100%; border-bottom: 3px solid #ddd; line-height: 1.6; font-size: .9em; padding: 15px; border: 1px solid #ddd; border-radius: 5px;} .tab_css input:checked + label, .tab_css label:hover{opacity: 1; font-weight:bold;} .tab_css input:checked + label + .tab_content{display: initial;} </style>

四、展示效果

範例程式碼的 DEMO 效果如下:
第 1 個頁籤內容區塊
WFU BLOG | Blogger 調校資料庫
第 2 個頁籤內容區塊
WFU BLOG | Blogger 調校資料庫
第 2 個頁籤內容區塊
WFU BLOG | Blogger 調校資料庫
第 3 個頁籤內容區塊
WFU BLOG | Blogger 調校資料庫
第 3 個頁籤內容區塊
WFU BLOG | Blogger 調校資料庫
第 3 個頁籤內容區塊
WFU BLOG | Blogger 調校資料庫
更多 CSS 相關技巧:
0 0
如這篇文章對你有幫助,歡迎「分享」到 FB、「追蹤」粉絲團、「訂閱」最新文章
TOP