2

CSS 練習 - Checkbox 呈現部分選取狀態

 1 year ago
source link: https://blog.darkthread.net/blog/partial-selected-checkbox-w-css/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

CSS 練習 - Checkbox 呈現部分選取狀態

2023-08-04 10:46 PM 0 1,537

最近遇到的前端小需求,分類項目清單允許使用者勾選整個類別,也可以展開類別勾選個別項目,操作起來類似以下這個樣子:

Fig1_638267573697352669.gif

這種互動操作不難實作,弄個 { Catg: 'FrontEnd', Name: 'Vue.js', Checked: false } 物件模型,拿出 Vue.js 簡單搭一下,插電、開機、輕鬆秒殺,用起來也沒什麼問題。

但有點美中不足 - 以上面的示範為例,從類別清單看不出來 FrontEnd 及 Web 類別下有項目被勾選。

於是我幫自己訂了個題目,希望做到類別下有項目被勾選時,類別 Checkbox 要呈現部分選取狀態(灰色底、淺色勾勾之類的效果)以示區別。

研究了一下,決定用 CSS ::before 虛擬元素實現,當類別下有項目被選取時,用 Vue v-bind:class 加上 partial 樣式,並設定以下樣式:

input.partial {
    position: relative;
}
input.partial::before {
    content: '\2714';
    font-size: 0.8em;
    position: absolute;
    top: -2px;
    left: 2px;
    opacity: 0.8;
}
input.partial:checked::before {
    display: none;
}

input.partial 設定 position: relative 允許 before 虛擬元素能用 position: absolute 彈性調整顯示位置;虛擬元素用 content 放上「✔」(U+2714) 勾勾符號,用 top/left 調座標以剛好嵌入方格正中央,最後加上 opacity 做成半透明。當 Checkbox 被勾選時 ✔ 要隱藏,用 input.partialchecked:before 選擇器配上 display: none 便大功告成。

Fig2_638267573699649587.gif

試了 Chrome/Edge/Safari 都 OK,要開心收工前試了一下 Firefox,可惡,這招在 Firefox 上不管用(早知裝沒事就算了)。

爬文得知在 Firefox ::before/::after 只對容器元素有效,無法用在 Checkbox 上,得另外想法子。

我的第一個嘗試是在 input 外包一層 span,改用 span:has(input.partial)::before 插入虛擬元素,很不幸,Firefox 不支援 :has()

:has() 不能用,span 放後面再用 input.partial + span::before (Adjacent Sibling Combinator (+)) 總行了吧?

<input type="checkbox" class="partial" /><span></span>
<style>
input.partial + span {
    position: relative;
    margin: 0;
}
input.partial + span::before {
    content: '\2714';
    position: absolute;
    font-size: 0.8em;
    top: -2px;
    left: -14px;
    opacity: 0.4;
}
input.partial:checked + span::before {
    display: none;
} 
</style>

顯示是成功了,但 span::before 虛擬元件會蓋在 Checkbox 上方使它沒法被勾選啊啊啊啊~~

Fig3_638267573701432507.png

幸好,前陣我學會一個新武器 pointer-events,能讓元素對滑鼠操作隱形,在 input.partial + span::before 加上 pointer-events: none,終於,成功跨越 Chrome/Edge/Safari/Firefox。(下圖為 Firefox 操作展示)

Fig4_638267573703605032.gif

線上展示

其實我的應用只需要支援 Chrome/Edge 就可以了,不過跨瀏覽器總是能逼你學會更多,啊,福氣啦!

【2023-08-04 更新】

貼完文章,感謝讀者 Chester Fung 分享更完美的原生 API 解法 - Checkbox 有所謂的 Indeterminate State / 狀態未定,Checkbox 有個 indeterminate 屬性,設為 true 時勾選方格會呈現第三種狀態(在 Edge 是方格中有一條橫線);indeterminate 是元素 Property 不是 Attribute,Vue.js 要設定其值需使用 propName.prop 修飾詞或用 .propName 縮寫。所以其實可以完全不用 CSS,加上 .indeterminate="ElementSelected(c.Name)" 就搞定了:

<input type="checkbox" v-model="c.Checked" .indeterminate="ElementSelected(c.Name)" />

Fig5_638267611777478597.png

如果覺得呈現樣式不好看,可透過 CSS input:indeterminate 選擇器自訂。但有個小缺點是設定 indeterminate=true 後,使用者勾選或取消勾選該屬性會被清掉,需自己掛載事件或透過變數連動把它設回去。

線上展示


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK