Button 的设计
Button 作为基本的 Web 元素,看似简单,却需要非常用心的设计,因为 Button 作为按钮,是具有多个不同的状态,每种状态都基本上需要进行一些特殊的优化设计,以让组件更生动美观。
注:所有的长度单位均采用 rem 而非 px,需要在 html 标签下设定 font-size 的 CSS 样式,一般我都是设置:font-size:12px,1440 x 900 的分辨率,如果分辨率更高的话,可以自己调整。当然你改写成 px 作为度量衡也是 OK 的。
Example:
Default Inverse Primary Success Info Warning Danger
Button的几种状态:
我们设计 Button 的样式,基本按照以下几个状态来设计:
- :focus - 当按钮获取焦点(可以是 JS 控制获取焦点,也可以是用 Tab 键一个一个切换从而获得焦点)
- :hover - 当鼠标处于悬停状态时
- :active - 当按钮处于点击状态时(按下但还没有放手的情况下)
- :active:hover - 当按钮处于点击,且鼠标依然悬停的情况下(比如你按下去,但是鼠标还不放手,然后把鼠标拖拽着挪开按钮,此时就会出现这个状态的反例)
- :active:focus - 当按钮处于点击且获取焦点的情况(这个情况的反例我也不知道反例应该怎么举)
- 正常状态,这我就不用解释了。
- .focus - 通过 class 设置的获取焦点状态
- .active - 通过 class 设置的点击状态
Button 的状态变化
我们先来梳理一下,Button 对应不同的动作,所产生的相应的变化。
正常状态
┣ A:鼠标悬停 -> S:hover -> A:鼠标按下 -> S:active:hover/:active:focus(*) -> A:鼠标移开 -> S:active/:active:focus(*) ->A:鼠标松开 -> S:focus
┗ A:Tab 选中 -> S:focus -> A:空格按下 -> S:active:focus -> A:Tab 移开焦点 -> S:active -> A:空格松开 -> S:focus
注: A = Action , S = Status
这边值得注意的是我打星号的位置: A:鼠标按下 -> S:active:hover/:active:focus(*) -> A:鼠标移开 -> S:active/:active:focus(*) ,这个位置有点特别,不同的浏览器有不同的实现效果:
-
- Chrome:在 CSS 文件中,active:hover 跟 active:focus 定义的顺序会影响到上面这个步骤的实现,定义在后的会优先显示给用户(距离用户越近),比如给按钮定义了如下的 CSS 效果:
-
1 .btn-default:active:focus { 2 color: #000; 3 background-color: #eeeeee; 4 border-color: #000000; 5 } 6 7 .btn-default:active:hover, 8 .btn-default.active:hover{ 9 color: #000; 10 background-color: #e6e6e6; 11 border-color: #000000; 12 }
那当我们按下鼠标的时候,看到的是 hover 的 CSS 效果,但是如果定义的顺序相反,鼠标按下以后,显示的是 active:focus 的 CSS 样式,如果是用空格键按下,也是这个规律,所以在 chrome 当中,鼠标按下(若键盘按下但是鼠标同时也悬停在上的话,情况也是一样),其实是有三个状态叠加而成,分别是 :active:hover+:active:focus+:active,当通过操作比如移除鼠标悬停再tab 键移除焦点(这些操作前提都是在鼠标按下或空格按下没松手的情况),那就会显示 active的样式,这一点弄明白了很重要。
- Safari:不存在上述优先顺序,空格键按下就是 active:focus,鼠标按下就是 active:hover,而且这两个状态是独立的,不会层叠覆盖,也就是说,在 safari 当中,只会有两个样式叠加,通过鼠标按下的就是 :active:hover+:active,通过键盘空格按下的,就是:active:focus+:active。
- 其他浏览器我暂时还么有测试。
Button 基础样式
我们首先要来设计一个基础的 Button 样式,我们可以这样子来做:
1 .btn { 2 display: inline-block; /*允许横排布局且支持设置宽高*/ 3 padding: 0.5rem 1rem; /*设置内边距,避免文字直接贴在边框上*/ 4 margin-bottom: 0; /*默认按钮是紧贴外部容器的底部*/ 5 font-size: 1.2rem; /*文字大小*/ 6 font-weight: normal; /*正常字体*/ 7 line-height: 1.42857143; /*设置行高*/ 8 text-align: center; /*文字居中*/ 9 white-space: nowrap; /*强制文本在一行显示,不允许换行*/ 10 vertical-align: middle; /*垂直居中*/ 11 cursor: pointer; /*设置鼠标悬停时的光标样式*/ 12 background-image: none; /*不设置背景图*/ 13 border: 0.1rem solid transparent; /*设置边框样式,但不设置颜色,颜色交由后续其他类来配合设置*/ 14 border-radius: 0.5rem; /*圆角*/ 15 }做了这些设置以后呢,我们的默认样式按钮就是这样子了:
然后我们再对 focus、hover 做一些设置:
1 /*鼠标悬停*/ 2 .btn:hover, 3 .btn.focus{ 4 text-decoration: none; 5 -webkit-box-shadow: 0 0.2rem 0.2rem rgba(0, 0, 0, .525); /*下阴影(兼容)*/ 6 box-shadow: 0 0.2rem 0.2rem rgba(0, 0, 0, .525); /*下阴影*/ 7 }这样的效果是,当鼠标悬停增加一个下阴影,让按钮感觉是浮起来,等待你按下意思,本来我是不打算把.focus 放入的,希望跟:focus 保持一致,但是后来想一想,如果我们都主动的设置了 focus 这个类的话,肯定是希望它凸显的,而不加入:focus 是因为,当两个按钮并排的时候,点选一个按钮结束后会进入 :focus状态,此时按钮凸起,但是我如果想点击另一个按钮,鼠标移动到第二个按钮,第二个按钮也会凸起,这时候就有两个按钮同时凸起,然后当按下第二个按钮时由于第一个按钮会回到正常状态,正常状态下是不会有凸起而是平滑的,那两个按钮同时变化就会有两个按钮同时被按下的错觉,这种感觉就很不对了,而对于:focus 的状态而言,我们可以通过等会儿要讲的风格变化,通过颜色的变化凸显来解决:
接着还要对 :active(.active)、:active:focus、:active:hover 三个状态来做设置,设置一个内阴影,
/*鼠标按下且悬停、键盘空格按下且未松手*/ /*当空格按下没有松手,直接用tab键切换焦点后,被按下的组件将一直保持按下即:active状态*/ .btn:active:hover, .btn:active:focus, .btn:active, .btn.active { background-image: none; -webkit-box-shadow: inset 0 0.2rem 0.2rem rgba(0, 0, 0, .525); /*内阴影(兼容)*/ box-shadow: inset 0 0.2rem 0.2rem rgba(0, 0, 0, .525); /*内阴影*/ }能够给人一种“按钮被按下去”的感觉:
我觉得这最需要做一个说明了,为啥 active:focus 要设置内阴影,而 focus 不用呢?因为前者代表的意思是通过点击后获取焦点,后者则并没有这条限制,所以当你用 Tab 键来让按钮获取焦点的时候,自然不能代表按钮被按下。所以要做一个区分。另外还有一点要做一个说明,那就是 active 也要做同样的设置,因为我们设置了 active:hover,会有一个问题,就是当我们按下并且鼠标悬停在按钮上的时候,才会有内阴影,但是如果此刻你鼠标不悬停,而是“拖拽”着让光标离开了这个按钮,为了要让按钮依旧保持被按下(因为你的鼠标此刻依旧处于按下的状态没松手),那 active 就要做相同的设置,否则按钮会回到最初的状态,那这样就没有被按下的那种直观感觉了。
最后我们还要做一个基本设置:
1 /*去除键盘Tab选中、鼠标点击时的边框*/ 2 .btn:focus, 3 .btn:active { 4 outline: 0; 5 }因为一些浏览器,会默认的加上这个属性,在你点击按钮时,会自动生成一个外边框,这个外边框我个人不喜,因为当我的组件是圆角矩形的时候,边框依旧还是直角矩形,这非常不好,超级难看,比如:
outline 不能设置为圆角(除了火狐独有这个属性,但兼容性不好,所以不打算采用这个样式),网上我看到其他替代方案,是用 box-shadow 来模仿的,效果还可以,但是一个 box 只能有一个 shadow,这样就等于让我放弃使用 box-shadow 所以最后我还是不打算采用这种样式,感觉也不是很重要,就算没有 outline 也可以将按钮通过添加一些颜色来使其很醒目。
同时我们增加了.focus 和.active 两个类样式,这样我们就可以通过设置 class 属性,来让我们的按钮主动的显示聚焦或点击的样式了。
OK 了,这是最基本的样式设计,兼容性稳稳的,不论哪个浏览器,效果都是一样的。当你看到“基础”两个字的时候,就应该知道,咱们的文章,不可能就这么完了,那多没意思呀。
现在 CSS 都流行使用嵌套或覆盖等手法,做一些多样性的扩展,我们当然也要追逐潮流啦。
Button 的多样化:
我们设计 Button 的基础模型,但是基础模型依旧还是很单调的,而且有很多状态其实是共用样式,如何让我们的按钮显得更加生动呢?这就是我们接下来要干的活了。
我们设计出以下7种风格以供选择:
- btn-default:
- btn-inverse:
- btn-primary:
- btn-success:
- btn-info:
- btn-warning:
- btn-danger:
看着是不是很眼熟呀?没错,3-7的风格取名字是参照 Bootstrap 的,毕竟 Bootstrap 已经是非常流行的框架了,树立了一种标准,我们在设计样式表的时候,如果能保持一致,那使用者使用的时候,就会降低很多重复学习的门槛,用起来也比较方便,而我自己最后加了1个风格:btn-inverse,因为我个人是黑白党,很喜欢黑白风,而且有的场景使用这种比较严肃的配色也挺好。
Default Default
我们已经定义了 Button 的基础样式,现在我们要定义的是风格状态,定义风格状态基本上只需要修改三个属性:
- color
- background-color
- border-color
然后我们要根据之前说的,button 的不同状态,来进行编写,首先书写正常状态:
1 .btn-default { 2 color: #000; 3 background-color: #ffffff; 4 border-color: #000000; 5 }然后在设计当鼠标悬停或者 tab 选中时的效果,同时还要加入,当我们手动将按钮设置为 focus 状态或设置了 active 状态下的 focus 状态,来保持状态的一致性:
1 .btn-default:hover, 2 .btn-default:focus, 3 .btn-default.focus, 4 .btn-default.active:focus{ 5 color: #000; 6 background-color: #ebebeb; 7 border-color: #000000; 8 }接下来就是比较需要细心的部分了,这部分 hover 和 focus 是有定义先后顺序的,我们来设置当按钮被按下后的样式:
1 .btn-default:active:focus { 2 color: #000; 3 background-color: #eeeeee; 4 border-color: #000000; 5 } 6 7 .btn-default:active:hover, 8 .btn-default.active:hover{ 9 color: #000; 10 background-color: #e6e6e6; 11 border-color: #000000; 12 } 13 14 .btn-default:active, 15 .btn-default.active { 16 color: #000; 17 background-color: #ffffff; 18 border-color: #000000; 19 }OK,最后效果就像这组按钮一样了,第二个是设置了active 状态,第三个是设置了 focus 状态。
Default Default Default
好了,我们基本上是按照这个范式来设计不同的风格即可,只需要简单地调节一下颜色,基本上可以理解为按下的颜色为最“深”,鼠标有悬停比没悬停颜色更“深”,有焦点比没焦点颜色更“深”,正常状态下颜色最“浅”,这样的一个思维,再对比 Button 的不同状态来设计就行了,然后细节上再做一些调整,搭配出一个你最喜欢的。
我们最后再来设计一个,比较特殊的,就是黑色的按钮(深色系按钮也可以参照这个逻辑):
Inverse Inverse
深色系跟浅色系设计师不同的,为什么呢?其实是因为我们设计的基础样式的原因,简单的说,我们基础样式里,阴影是黑色的,如果我们的按钮背景是黑色,那内阴影就看不到了,自然是没办法识别出按钮被按下的状态,这个想像一下就应该可以理解,所以我们要做一些调整。
.btn-inverse { color: #ffffff; background-color: #000000; border-color: #404040; } .btn-inverse:hover, .btn-inverse:focus, .btn-inverse.focus, .btn-inverse.active:focus { color: #ffffff; background-color: #282828; border-color: #404040; } .btn-inverse:active:focus { color: #ffffff; background-color: #383838; border-color: #000000; } .btn-inverse:active:hover, .btn-inverse.active:hover { color: #ffffff; background-color: #4d4d4d; border-color: #000000; } /*调整内阴影为白色,并且 Y 轴的位移改为"-"的,就是自下而上,内阴影的状态也添加了几种,大家可以自己去调试看看效果,就知道为什么要加了*/ .btn-inverse:active:hover, .btn-inverse.active:hover, .btn-inverse:active:focus, .btn-inverse:active, .btn-inverse.active { -webkit-box-shadow: inset 0 -0.2rem 0.2rem rgba(255, 255, 255, 0.52); /*内阴影(兼容)*/ box-shadow: inset 0 -0.2rem 0.2rem rgba(255, 255, 255, 0.52); /*内阴影*/ } .btn-inverse:active, .btn-inverse.active { color: #ffffff; background-color: #232323; border-color: #000000; }深色系的按钮组件基本可以参考这个模板来对色彩进行调配。值得关注的就是内阴影的状态多了几种,并且内阴影自身的属性有一些变化,具体如下:
Inverse Inverse Inverse
其实这没有什么很厉害的东西,前端设计,关键在于一个思路,如何把复杂繁多的样式,通过一些抽象、分类的思想,逐渐的形成一个思路,再根据思路进行统一的,有条理的设计,这样就能够保持整体风格一致的情况下,灵活创建一些很棒的样式,CSS还有很多内容,一篇文章说不完,有心得朋友应该可以发现,我写的样式已经应用到了我的博客当中,我希望通过一点一点的努力,最终能够形成一套,属于自己的框架。