《css揭秘》笔记:自定义复选框

用纯css实现了switch开关按钮之后,突然想起在《css揭秘》这本书上看到复选框也是采用相同的原理,在此也做一下纪录。

难题
设计师对网页中各种元素都会设计一套自己的样式,但对于复选框和单选框来说,直到今天,它们在绝大多数浏览器中仍然接受默认样式,因此在实现这类效果时,可能会接受默认样式,或者求助于一些糟糕透顶,可访问性极差的hack方案。
有没有一种方法,既可以克服这些限制,又能摆脱臃肿的代码呢?

解决方案

在选择符(第三版)中,我们得到了一个新的伪类:checked,这个伪类只在复选框被勾选时才匹配,不论是由用户交互触发还是由脚本触发。

小提示
伪类选择符:checked和属性选择符[checked]之间的区别在于,后者不会根据用户的交互行为进行更新。
因为用户的交互并不会影响到html标签上的属性。

如果直接对复选框设置样式,那么这个伪类并不实用,因为没有多少样式能对复选框起作用,所以,我们基于复选框的勾选状态借助选择符来给其它元素设置样式,它就是
元素与复选框关联之后,也可以起到触发开关的作用。
我们为它添加生成性内容(伪元素),并基于复选框的状态来为其设置样式。然后,把真正的复选框隐藏起来(但不能完全删除),再把生成性内容美化,顶替原来的复选框。

html代码

1
2
<input type="checkbox" id="nochecked" />
<label for="nochecked">未选中!</label>

接下来生成一个伪元素,作为美化版的复选框。

在这个例子中,我们添加的样式很简单,但实际上是无穷无尽的,甚至可以跳过css美化这一招,直接将图片设置为复选框的各种状态。

1
2
3
4
5
6
7
8
9
10
11
12
input[type="checkbox"] + label::before{
content:'\a0';
display: inline-block;
vertical-align: .2em;
width: .8em;
height: .8em;
margin-right: .2em;
border-radius: .2em;
background: silver;
text-indent: .15em;
line-height: .65;
}

接下来给勾选状态加上不同样式,样式很简单,比如换颜色,再加上勾选标记。

1
2
3
4
input[type="checkbox"]:checked + label::before{
content: '\2713';
background: yellowgreen;
}

现在我们把原来的复选框以一种不损失可访问性的方式隐藏,这意味着不能用display:none

1
2
3
4
input[type="checkbox"]{
position: absolute;
clip: rect(0,0,0,0);
}

这样就完成了,我们得到了一个简单定制化的复选框,我们还可以进一步优化,比如在它聚焦或禁用时改变样式。

1
2
3
4
5
6
7
8
input[type="checkbox"]:focus + label::before{
box-shadow: 0 0 .1em .1em #58a;
}
input[type="checkbox"]:disabled + label::before{
background: gray;
box-shadow: none;
color: #555;
}

效果预览:点击demo

参考:
《css揭秘》