《 CSS Secrets 》是 @Lea Verou 最新著作,这本书讲解了有关于CSS中一些小秘密。是一本CSSer值得一读的一本书,经过一段时间的阅读,我、@南北和@彦子一起将在W3cplus发布一系列相关的读后感,与大家一起分享。
设计师总是希望能够对Web页面上的每个元素都能有更多的控制。当一个CSS经验有限的图形设计师需要创建一个网站案例时,他们很喜欢自定义表单元素,然后让开发人员来把它转变成CSS。
对于可读性,在这一整节中,我们都会使用“checkbox”,但是讨论的内容都适用于复选框和单选按钮,除非有特别说明。
在CSS刚开始引入的时候,表单样式是非常有限的,而且没有在任何的各种CSS规范中明确定义。但是,浏览器对CSS属性越来越宽松,它们允许表单控制,可以让我们有相当大的空间去给它们添加样式。
可惜的是,复选框和单选按钮不在可控制的表单控件列表中。现在,大多数浏览器基本都是选择不给它们添加样式。结果是,作者要么使用默认外观,要么使用繁琐的标签来完成,如使用 div 和JavaScript来重建它们。
有没有什么办法可以让我们摆脱这些限制,然后自定义我们的复选框样式呢,不要那些臃肿的代码,不要放弃语义性和可访问性?
解决方案
直到几年前,如果不用脚本,这个任务基本是不可能完成的。但是,在 CSS3 中,我们有了一个新的伪类: :checked 。这个伪类只能在复选框被选中时匹配,无论这个选中状态是通过用户交互还是脚本实现的。
:checked 和属性选择器 [checked] 之间有什么不同吗?后者不会基于用户交互更新,因为用户交互不会影响HTML属性。
如果是直接应用于复选框的话并不是特别有用,如——像我们前面提到的——没有多少属性可以让我们成功地给它们应用样式。但是,我们根据复选框的状态,给其它元素添加样式,并把它们组合起来。
你可能会奇怪有什么其它元素可以让我们使用,并能辨别复选框是否处于选中状态。不错,确实存在一种元素可以围绕复选框有不同的状态:
因为标签——不像复选框——不是替换元素,我们可以为它们添加生成的内容,还可以基于复选框的状态给它们应用不同的样式。然后,我们通过某种方式隐藏真正的复选框,但是不从tab键的切换中将其删除,然后将生成的内容伪装成是经过添加样式的复选框!
将复选框嵌入标签中可以让我们从使用 id 中解放,但随后,我们就不能根据复选框的状态来选中标签了,因为我们还没有父选择器。
我们来实践一下。我们可以从下面这个简单的示例开始:
Awesome!
下一步是生成一个伪元素,伪装成我们已添加样式的复选框,并为它应用如下的基本样式:
input[type="checkbox"] + label::before { content: '\a0'; /* non-break space */ display: inline-block; vertical-align: .2em; width: .8em; height: .8em; margin-right: .2em; border-radius: .2em; background: silver; text-indent: .15em; line-height: .65;}
你可以在下图中看到我们的复选框和标签的当前样式。
初始的复选框仍然是可见的,但是我们会在后边把它隐藏掉。现在我们需要给选中状态的复选框应用一个不同的样式。可以简单地应用一个不同的颜色,并添加一个如下的复选标记:
input[type="checkbox"]:checked + label::before { content: '\2713'; background: yellowgreen;}
我们将应用于我们复选框的样式在这些示例中是非常基础的,但是可能性是无穷的!你甚至可以完全跳过CSS样式,然后使用图片表示不同的复选框状态!
如上图所示,这已经是一个具有初步样式的复选框。现在我们需要通过一个可访问的方式隐藏初始的复选框,这也就意味着我们不可以使用 display: none ,因为这样的话就会把它从整个tab键顺序中删掉了。所以,我们可以使用如下的代码:
input[type="checkbox"] { position: absolute; clip: rect(0,0,0,0);}
使用这种宽松的选择器时要小心。使用 input[type="checkbox"] 会隐藏复选框,而且后面不会有一个标签(如,那些嵌入在标签中的),这样会从根本上导致它们无法使用。
就是它了,我们已经做出了一个很基本的自定义复选框!当然我们还可以再做一些提升——比如,在它处于 focused 或 disabled 的状态时改变一下样式:
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;}
效果如下图所示:
从上到下:自定义 focus 状态的复选框,自定义 disabled 状态的复选框, checked 状态的复选框 。
你甚至可以通过应用过渡或动画或弹跳让这些效果更平滑,然后创建像sekuomorphic开关这样的东西,可能性是无穷无尽的!
尽管可能是无穷的,也切记不要把复选框变成圆形:很多用户会把它当成单选按钮。正方形单选按钮也是一样。
Ryan Seddon创建了这个效果的第一个版本,他现在被称为“ the checkbox hack ”。Ryan使用这个方法 实现了很多可以切换状态的小部件 ,如模拟对话框,下拉菜单,选项卡,轮播图等,虽然滥用复选框也导致了可访问性的问题。
开关按钮
你可以使用不同的“the checkbox hack”来模拟开关按钮,因为HTML没有提供一个native的方式来创建它们。开关按钮就是像复选框那样拨动开关:它们用来将某个设置打开或关闭,在选中状态时看起来像是按下的,在未选中状态时看起来就像是没有按下的。从语义上讲,开关按钮和复选框之间并没有真正的区别,所以你都可以使用这些技巧并保持语义纯度。
为了使用这些技巧创建开关按钮,你只需要把标签弄成按钮那样的样式,而不是使用伪元素。例如,创建如图所示的开关按钮
代码如下:
input[type="checkbox"] { position: absolute; clip: rect(0,0,0,0);}input[type="checkbox"] + label { display: inline-block; padding: .3em .5em; background: #ccc; background-image: linear-gradient(#ddd, #bbb); border: 1px solid rgba(0,0,0,.2); border-radius: .3em; box-shadow: 0 1px white inset; text-align: center; text-shadow: 0 1px 1px white;}input[type="checkbox"]:checked + label,input[type="checkbox"]:active + label { box-shadow: .05em .1em .2em rgba(0,0,0,.6) inset; border-color: rgba(0,0,0,.3); background: #bbb;}
所以,要谨慎使用开关按钮。在大多数情况下,开关按钮会妨碍可用性,因为它们会很容易地与普通按钮被按下时将执行的操作相混淆。