CSS 揭秘 - 读书笔记(其五)

发表于: 2016-09-04分类于:CSS

选用合适的鼠标光标

鼠标光标的作用不单单是用来指定鼠标在屏幕上的位置,根据鼠标光标的不同样式还能告诉用户当前能做什么操作,比如手指形状可以告诉用户当前可以进行点击操作。

合理地运用光标可以提升用户体验。比如在按钮不可按的时候,可以使用 cursor:not-allowed 来告诉用户当前不能操作。在全屏模式下看视频的时候可能需要将光标隐藏起来,这个时候可以使用 cursor:none 来隐藏光标,然后监听鼠标的 move 事件,以便于在适当的时候把光标显示出来。

扩大可点击区域

一个可交互的 UI 组件的尺寸如果太小,用户会花更多时间才能将光标对准到它上面。所以有必要扩大按钮等可交互的元素的可点击区域,让用户更快地进行交互。

给元素设置一个透明的边框,可以扩大元素的点击区域,但是往往我们需要将边框用作他用。幸运的是我们可以将元素的 ::after::before 伪元素设置为透明,且比宿主元素大,然后将其覆盖在宿主元素上,这样就达到了扩大点击区域的效果。

.btn{
    position: relative;
}
.btn::after{
    content: '';
    position: absolute;
    top: -10px; bottom: -10px;
    left: -10px; right: -10px;
}

自定义复选框

一些表单元素的样式是不能被改变的,或者说不易被改变,但是这不能阻止我们去美化它们。一个思路是给需要美化的表单元素关联一个 label 标签(理应这样),由于点击 label 标签也能触发表单元素的各种状态(比如 checkbox 的选中或者取消选中),因此可以将表单元素隐藏起来,然后用美化过的 label 标签代替它。

对于 input[type=checkbox],我们还需要给它被选中的时候设置样式,这个时候需要用到 checked 伪类。:checked 伪类只有在 checkbox 为选中的时候才会生效,且不管它是被脚本选中的还是用户手动选中的。

下面自定义一个 input[type=checkbox] 作为例子,这个大伙应该很熟悉了,微信中的开关:

css 代码如下:

input[type=checkbox]{
    display: none;
}
input[type=checkbox]+label{
    display: inline-block;
    position: relative;
    width:80px;
    height: 20px;
    border-radius: 3px;
    border: 1px solid #aaa;
    background: #aaa;
}
input[type=checkbox]+label::after{
    content: '';
    position: absolute;
    left: 0;
    display: inline-block;
    width:50%;
    height: 100%;
    border-radius: 2px;
    background: #fff;
}
input[type=checkbox]:checked+label{
    background: #39ca39;
    border: 1px solid #39ca39;
}
input[type=checkbox]:checked+label::after{
    left: 50%;
}

利用 checkbox 的这种能够维持状态的特性,可以做出很多有两种状态的东西。

通过阴影来弱化背景

常常看到一些弹出层,使用一个黑色的半透明遮罩层覆盖住整个窗口,再把需要和用户进行交互的内容放在遮罩层上面。为了实现这种效果,常常需要一个额外的 HTML 元素来作为遮罩,但在某些情况下,我们可以使用需要突出显示的元素的伪元素来作为遮罩层,从而不需要添加额外的 HTML 元素。但需要注意的是伪元素上不能绑定事件,因此在需要点击遮罩层后关闭弹出层的场景下,这可能并不适用。

另外还可以使用 box-shadow 给突出显示的元素添加一个非常大的半透明阴影来模拟遮罩层,这个时候要注意 box-shadow 不能阻止用户点击遮罩层后面的元素。

通过模糊来弱化背景

你可能还见过这样的场景,弹出层使用的是一个模糊的页面作为遮罩层。这种效果并不容易实现,因为我们需要对整个页面进行模糊,但是需要突出显示的内容也存在于 body 中,因此如果给 body 进行模糊那需要突出显示的内容也会被模糊掉。

因此为了实现这种效果,需要保证突出显示的元素不能包含在页面主题内容中。解决办法是,使用一个 div 包裹住主题内容,然后将突出显示的内容和该 div 并列放置。

根据兄弟元素的数量来设置样式

这一节内容相当有意思,想象这样一种需求,一个列表中有一个或多个子项,现在要根据子项的数量来给子项设置不同的颜色。比如只有一个的时候将子项设置为红色,有两个时设为黄色,三个时设为绿色。

CSS 中没有能够计算子元素数量的方法,难道一定要借助于 JavaScript 吗,不用,CSS 是能够搞定这样的需求的。

一个元素的时候:

两个元素的时候:

三个元素的时候:

这里用到了伪类选择器 first-childnth-last-child,实现的原理还是很好理解的。考虑下面代码:

ul li:first-child:nth-last-child(1){

}

对一个子元素同时运用这两个伪类选择器,意味着该元素既是第一个元素也是最后一个元素,也就是说目前只有一个子元素,那么再考虑下面这段代码:

ul li:first-child:nth-last-child(2){

}

该元素既是第一个元素也是倒数第二个元素,也就是说存在两个子元素,Ok,这个时候,我们再用上兄弟选择器 ~

ul li:first-child:nth-last-child(2),
ul li:first-child:nth-last-child(2) ~ li{

}

选中所有子元素,前提是目前仅存在两个子元素。按这个思路,上面的需求就能轻松实现了。

根据兄弟元素的数量范围来匹配元素

现在又有了一个需求,当子元素超过 4 个的时候将它们设为黑色,否则设置为黄色。这个时候需要用到 nth-last-child(an+b) 这种模式,考虑:

ul li:first-child:nth-last-child(n+4){}

因为 n 可以是 0 ~ 正无穷,因此只有当存在大于或等于四个子元素的时候才会匹配到第一个元素上,在考虑下面代码:

ul li:first-child:nth-last-child(-n+4){}

这意味着括号里面的值是 负无穷 ~ 4 ,因此仅当存在小于 4 个子元素的时候才会匹配至第一个子元素上。

有了以上思路,再加上兄弟选择器就能实现前面提出的需求了:

三个子元素的时候:

六个子元素的时候:

CSS 代码:

ul li:first-child:nth-last-child(-n+4),
ul li:first-child:nth-last-child(-n+4) ~ div{
    background: yellow;
}
ul li:first-child:nth-last-child(n+4),
ul li:first-child:nth-last-child(n+4) ~ div{
    background: black;
}

根据兄弟元素的数量的奇偶来设置样式

有没有办法根据元素数量的奇偶来设置不同的样式呢?稍微改变一下,很容易就实现了:

奇数个子元素时:

偶数个子元素时:

CSS 代码:

ul li:first-child:nth-last-child(2n),
ul li:first-child:nth-last-child(2n) ~ div{
    background: black;
}
ul li:first-child:nth-last-child(2n+1),
ul li:first-child:nth-last-child(2n+1) ~ div{
    background: yellow;
}