復選框的 CSS 魔法

jopen 8年前發布 | 13K 次閱讀 CSS 前端技術

原文: Checkbox Trickery with CSS

翻譯:涂鴉碼龍

Checkbox 復選框相當好用,加對 CSS 魔法有奇效。此文旨在展示一些利用 checkbox 實現的有創意的東西,并且文中的例子 沒用 JavaScript 喲。

基本配方

從 HTML 著手。

<input id="toggle" type="checkbox">
<label for="toggle">

此處無技巧可言。 <label> 的 for 屬性匹配 <input> 的 id 屬性,因此點擊 <label> 可以控制 <input> 復選框。這點尤其重要,因為下一步將隱藏 <input> 。

input {
 position: absolute;
 left: -9999px;
}

為什么不用 display: none ?因為屏幕閱讀機和鍵盤 Tab 會忽略它。此方法讓 <input> 保持在文檔流中,但是讓它離屏隱藏(超出屏幕可見范圍達到隱藏)。

隱藏 <input> 以后,我們更容易大展身手。我們仍需傳達選中/未選兩種狀態,但是可以通過 <label> 完成。真正的派對開始啦。

input:checked + label {
 /* 牛X閃閃的樣式 */
}

我們使用 :checked 偽類, 和相鄰兄弟元素選擇器( + )的組合達到目的,當復選框選中時,找到緊隨其后的 <label> 元素,加上想要的樣式。還可以利用 <label> 中的偽元素( ::before 和 ::after )實現更有創意的想法。

input:checked + label::before {
 /* 指示器的樣式 */
}

來,看看實際效果吧。例子用到了以上提及的基本配方,把一個普普通通的復選框改造得當人眼前一亮。

See the Pen Checkbox Trickery: Simple Toggle by Will Boyd ( @lonekorean ) on CodePen .

最大的好處是,包含在 <form> 中的復選框的值仍然可以被提交。我們只改變了外觀,并沒有影響功能。

隱藏/顯示內容

目前為止,我們都是給 <label> 加樣式,我們可以更進一步。這個例子會根據用戶的選擇,動態地隱藏/顯示表單的部分內容。

See the Pen Checkbox Trickery: Form Disclosure by Will Boyd ( @lonekorean ) on CodePen .

:checked 偽類對單選按鈕同樣奏效,考慮到這一點,“How did you hear about us?”這塊的 HTML 用到了單選按鈕。

<input id="how-friend" name="how" type="radio">
<label for="how-friend" class="side-label">From a friend</label>

<input id="how-internet" name="how" type="radio">
<label for="how-internet" class="side-label">Somewhere on the internet</label>

<input id="how-other" name="how" type="radio">
<label for="how-other" class="side-label">Other...</label>

<div class="how-other-disclosure">
    <label for="how-other-explain" class="top-label">Please explain</label>
    <textarea id="how-other-explain"></textarea>
</div>

單選按鈕指示器利用 <label> 內的 ::before 偽元素(外部的圓環)和 ::after 偽元素(內部的綠點)實現,當單選按鈕選中 / 未選時顯示 / 隱藏 ::after 偽元素相當簡單。

.side-label::after {
 display: none;

 /* 其它樣式 */
}

input:checked + .side-label::after {
 display: block;
}

<div> 一直隱藏,直到“Other…”單選按鈕選中時才顯示。我使用了 display: none 隱藏 <div> ,因為這次我確實想讓屏幕閱讀器和鍵盤 Tab 在內容隱藏時忽略它。當單選按鈕選中時,利用 CSS 顯示 <div> 。

#how-other:checked ~ .how-other-disclosure {
 display: block;
}

之前我們一直使用相鄰兄弟選擇器( + ),不過這次得用一般兄弟選擇器( ~ )。它倆很相似,但是可以找到非相鄰的兄弟元素,比如我們的 <div> 。

樹狀文件夾

我們可以活用之前例子中的技巧,實現一個樹狀文件夾組件,同樣具備隱藏 / 顯示兩種功能。

See the Pen Checkbox Trickery: Folder Tree by Will Boyd ( @lonekorean ) on CodePen .

單個文件夾的 HTML 如下: <label> 是文件夾,兩個 <a> 元素是文件夾里的文件。

<div>
    <input id="n-1" type="checkbox">
    <label for="n-1">Blue</label>
    <div class="sub">
        <a href="#link">Mana Leak</a>
        <a href="#link">Time Warp</a>
    </div>
</div>

Font Awesome 圖標用于表示選中(打開)和未選(關閉)狀態。

label::before, a::before {
 display: block;
 position: absolute;
 top: 6px;
 left: -25px;
 font-family: 'FontAwesome';
}

label::before {
 content: '\f07b'; /* closed folder */
}

input:checked + label::before {
 content: '\f07c'; /* open folder */
}

a::before {
 content: '\f068'; /* dash */
}

文件夾里的內容通過一般兄弟選擇器( ~ )實現顯示 / 隱藏。這就是 HTML 外面包裹額外 <div> 的原因,為了確保選擇器能夠選到元素,打開兄弟文件夾。

input:checked ~ .sub {
 display: block;
}

理所當然,文件夾可以嵌套。只需把另一個文件夾的 HTML 放入 <div class="sub"> 即可。點擊 “Multicolor”看看效果吧。

最后,我們聊一下重置按鈕。

<input type="reset" value="Collapse All">

表單的重置按鈕很少有人用,不過這里巧用了一下。點擊重置按鈕,所有復選框恢復成初始的未選中狀態,關閉了所有文件夾。有意思吧。

Split List(分隔列表)

這個例子依據已做或未做,把列表選項分成兩部分。

See the Pen Checkbox Trickery: To-Do List by Will Boyd ( @lonekorean ) on CodePen .

HTML 像這樣:

<div class="items">
    <input id="item1" type="checkbox" checked>
    <label for="item1">Create a to-do list</label>

    <!-- more items -->

    <h2 class="done" aria-hidden="true">Done</h2>
    <h2 class="undone" aria-hidden="true">Not Done</h2>
</div>

分隔列表是由 CSS flexbox 實現的,這是關鍵的 CSS。

.items {
 display: flex;
 flex-direction: column;
}

.done {
 order: 1;
}

input:checked + label {
 order: 2;
}

.undone {
 order: 3;
}

label {
 order: 4;
}

CSS flexbox 可以使用 order 屬性重排元素。當復選框選中的時候, <label> 的 order 值由 4 變為 2 ,列表選項就從 “Not Done” <h2> 下面移到了 “Done” <h2> 下面。

不幸的是,鍵盤導航和 許多屏幕閱讀器 會遵循元素在 DOM 中的順序,即使它們被 CSS flexbox 做了視覺上的重排。這就導致 “Done”和“Not Done”的標題對于屏幕閱讀器無用,這便是我給它們加了 aria-hidden="true" 的原因 —— 被忽略總比引起混淆強。此外,通過鍵盤和屏幕閱讀器完全可以控制分隔列表,正確顯示列表項的狀態(選中 / 未選)。

如果你對“Done”和“Not Done”其后的計數實現感到好奇,它們用到了 CSS counters。想深入學習的話,可以看 這篇文章

分組篩選

壓軸的例子展示了如何根據篩選條件,高亮顯示交叉區域的數據。

See the Pen Checkbox Trickery: Group Filter by Will Boyd ( @lonekorean ) on CodePen .

這是簡短的 HTML 。注意一下 data-teams 屬性是由空格分隔的列表,它們每一項恰恰與單選按鈕的 id 屬性一致。我就是這么把角色跟隊伍匹配起來的。

<input id="original" type="radio" name="team" checked>
<label for="original">Original X-Men</label>

<!-- 省略更多團隊 -->

<br>
<ul class="characters">
    <li id="angel" data-teams="original force factor hellfire">
        <h2>Angel</h2>
        <img src="ct-angel.png" alt="">
    </li>

    <!-- 省略更多角色 -->
</ul>

關于可訪問性,我使用了空的 alt 屬性,因為角色的名字已顯示在 <h2> 標簽中了 —— 每個名字讀兩次也沒有必要。此外,我沒有真正的隱藏 <img> 元素(只是收縮和漸隱),屏幕閱讀器可以輕易的跳過未高亮的角色。我僅僅需要隱藏 <h2> 。

當選擇團隊的時候,高亮對應的角色,CSS 是這么實現的。

#original:checked ~ .characters [data-teams~="original"] h2,
#force:checked ~ .characters [data-teams~="force"] h2,
#factor:checked ~ .characters [data-teams~="factor"] h2,
#hellfire:checked ~ .characters [data-teams~="hellfire"] h2 {
 /* styles to show character name */
}

#original:checked ~ .characters [data-teams~="original"] img,
#force:checked ~ .characters [data-teams~="force"] img,
#factor:checked ~ .characters [data-teams~="factor"] img,
#hellfire:checked ~ .characters [data-teams~="hellfire"] img {
 /* styles to show character avatar */
}

我清楚這些選擇器看起來有點嚇人,不過也不賴。我們來仔細分析下例子的第一行(譯者注:以 CSS 中最長的選擇器開始算)。當 id 為 ‘original’ 的元素被選中時,找到角色元素里面 data-teams 屬性包含 ‘original’ 的元素,然后找到它里面的 <h2> 。2-4行的 ‘force’, ‘factor’, 和 ‘hellfire’ 重復上一步。8-11行繼續重復上一步,只不過把 <h2> 換成了 <img> 。

綜述

我希望你跟我一樣從這些例子中找到了一些樂趣。通過復選框去實現一些好玩的東西,對我而言非常有趣。我并沒有排斥在適當的時候使用 JavaScript ,但是沒用它也可以實現這么多東西,也是蠻開心的。謝謝閱讀!

來自: http://jinlong.github.io/2016/01/14/checkbox-trickery-with-css/

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!