純 CSS 的 Tabs 頁籤 UI

過去使用純 CSS Tabs 時,需要將 tabs 頁籤與內容獨立分開成兩個區塊,雖然視覺上可以達到頁籤的效果,但從 Code 的角度來看,兩個獨立的區塊缺乏群組的關係,維護上也比較困難,沒有一定 HTML&CSS 知識的使用者會很難維護。最近在 stackoverflow 發現一組 CSS Tabs 頁籤的實作,可以讓頁籤及內容更像是一個群組的關係,結構上也很簡單,日後即便是非技術人員也可以輕鬆上手。

下面的 Codepen 是我根據作者的想法改寫的範例:

See the Pen Tabs - CSS Only by ossian (@ossian) on CodePen.

首先,我們先看看 HTML 的結構

<div class="tabs">
  
  
  <!--   tab group -->
  <input type="radio" id="tab-1" name="tab" checked="checked">
  <label for="tab-1">Tab 1</label>
  <div class="tab-content">Content 1</div>
  <!--   tab group end -->
  
  <!--   tab group -->
  <input type="radio" name="tab" id="tab-2">
  <label for="tab-2">Tab 2</label>
  <div class="tab-content">Content 2</div>
  <!--   tab group end -->
  
  <!--   tab group -->
  <input type="radio" name="tab" id="tab-3">
  <label for="tab-3">Tab 3</label>
  <div class="tab-content">Content 3</div>
  <!--   tab group end -->
  
  
</div>

父物件 .tabs 包含數組頁籤及內容,每組頁籤由 input、label 及 div.tab-content 組成。

從 HTML 的結構來看非常簡明易懂,尤其是 input + label 的組合,正是經典 CSS Tabs 的手法,缺點也如前面提到,需要將頁籤與內容拆分成兩個獨立的區塊。所以當自己看完這個 HTML 之後,雖然可以猜的出來作者想實作頁籤的效果,但無從下手。

出於職業上的好奇,研究了一下作者的 CSS,發現他將父物件 .tabs 設為 flex,先將 input、label 及 div.tab-content 都變成 flex-item,並將 flex-wrap 設為 wrap。

接著把 input radio 屬性 name 設為同一個值並將它隱藏起來,label 則模擬成頁籤的效果,負責觸發相同 ID 的 input radio。由於 input radio 已經設為隱藏,所以畫面上只有 label 及 div.tab-content,到目前為止都還算好理解。

常理來看,目前都只是 flex-item 的併排,什麼特別的地方。範例中最神來一筆的地方在於將 div.tab-content 設屬性 order,其值為 1,使其 flex-item 排序在 label 之後,接著將 div.tab-content 的寬度設為 100%,使得 div.tab-content 因為寬度不足而自動斷行。

這就形成兩個結果:

  • 所有的 label 受到 flex-item 的影響,跑著 order 為 0 的預設值而並排,形成頁籤的按鈕。
  • 而 div.tab-content 則因為 order 為 1 且寬度為 100% 的關係,全部都折到下一行,成為頁籤的內容區塊。

一組頁籤的雛形就這麼被硬生生的魔改出來。

最後,你只需要將 div.tab-content 的 display 設為 none,並在 label 觸發相同 id 的 input radio 時,開啟鄰近的 div.tab-content,這樣就可以再多組頁籤中切換內容。

下面是 CSS 範例:

.tabs {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  -moz-column-gap: 5px;
       column-gap: 5px;
  margin: 2em auto;
  max-width: 300px;
  width: 100%;
}
.tabs input[type=radio] {
  display: none;
}
.tabs input[type=radio]:checked + label {
  color: black;
  background-color: white;
  transform: translatey(1px);
}
.tabs input[type=radio]:checked + label + .tab-content {
  display: block;
}
.tabs label {
  padding: 0.5em 0.75em;
  color: #ccc;
  border: 1px solid #ccc;
  border-bottom: unset;
  border-top-left-radius: 5px;
  border-top-right-radius: 5px;
  cursor: pointer;
  order: 0;
}
.tabs label:hover {
  color: black;
}
.tabs .tab-content {
  display: none;
  padding: 1em;
  width: 100%;
  border: 1px solid #ccc;
  border-radius: 5px;
  order: 1;
}

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

返回頂端