做为前端工程师,最大的快乐之一就是可以用 CSS 画出各种有趣的效果。
比如我最近画的一个 Button:
画的过程中确实很开心,这也是我当时选择做前端的很大一部分原因。
今天我们就一起来画下这个可爱的 Button 吧!纯 CSS,没用到图片和 JS 呦~
首先我们需要一些前置知识:
border-radius
border-radius 大家用的比较多了。
比如一个这样的 div:
可以分别设置四个圆角的半径:
从效果上也可以看出来分别是左上、右上、左下、右下的圆角。
其实还可以设置椭圆角,椭圆和圆的区别是圆的半径都是一样的,而椭圆则是有长轴和短轴,可以不一样。
可以分别设置长半轴和短半轴的长度,用 / 隔开:
当然,上面这个长短半轴相等了,也就是圆角了。
比如这样设置:
效果是这样的:
分开看每个角:
左上角的横半轴是 20px,竖半轴是 50px,所以是这样的:
左下角横半轴是 40px,竖半轴是 30px,所以是这样的:
通过调整四个角的横竖半轴长度,就可以实现很多形状。
比如三只小鸟的睡觉时的形状:
或者醒的时候的形状:
还有鸟嘴和眼睛的形状:
当然,圆角能画的形状终究还是受限制的,更复杂的形状需要用别的方式来画,比如 clip-path:
clip-path
前面说过,整个按钮都没有用到图片,那按钮的这个背景:
还有这几根鸟毛:
怎么画呢?
border-radius?
border-radius 再怎么调也只是各种椭圆,没法画这种复杂形状。
想实现这些没有规律的复杂形状就要用到 cli-path 了。
比如这样一个 div:
加上这样一个 clip-path:
就会变成这种形状:
或者这样一个 div:
加上这样的 clip-path:
就会变成这种形状:
背景和鸟毛不就出来了么~
这个样式还是很容易理解的,就像剪纸一样,把一块区域按照某个路径进行裁剪(svg 中也有这个)。
当然,不只可以写 path,还支持别的形状:
但是,这个形状怎么来呢?
手写么?
这肯定不靠谱。
其实是可以用 illustrator 等矢量图设计软件来画,导出为 svg 的。
比如 illustrator,用钢笔在左上角画一个形状:
选中它,然后点击“对象 > 复合路径 > 建立”:
再点击导出,这时候导出的就是带 path 的 svg。
有两点需要注意:
- 要从左上角开始画,因为 svg 会把位移保存下来。
- 没有复合路径那一步,导出的可能是 polygon、circle 这种形状,而不是 path
把路径复制到 cli-path 的样式处,就可以看到裁切后的效果了:
这样,涉及到的各种形状我们就都能画了。
再看一眼这个 Button:
是不是就有思路了呢~
接下来我们动手画一下吧。
画 Button
先写出 html 的结构:
比一般的 button 多了一级,这是因为我们要通过每一级的 ::before 和 ::after 加一些伪元素。
设置 .button 的样式:
通过 flex 布局,让子元素居中。设置 width、height,背景颜色、圆角等。
现在效果是这样的:
其中的背景颜色可能会变,更好的方式是抽出一个变量来维护:
然后设置子元素的样式,也就是 .button__warpper:
它同样要设置子元素居中,然后宽高都是 100%。
它的子元素就是 span 文本标签了,也就是 .button__text:
指定字体大小、文字间距和颜色。颜色是可能会变的,所以也抽成变量。
现在的效果是这样的:
然后我们加上一些伪元素做装饰:
先给最外层元素加:
指定宽高和位置,还有背景颜色,再就是裁切的形状(这里用 clip-path 裁剪的是一个箭头的形状)
伪元素用了绝对定位,那元素就要相对定位:
也就是让伪元素相对它来偏移。
效果就是这样的:
然后再往里一层,给 .button__wrapper 加 ::before 和 ::after 伪元素:
分别在前后加上一个伪元素,设置宽高和背景色,裁切的形状。然后分别设置不同的位移,右边要反过来,所以是 rotateY(180deg)。
背景色也可能变,所以抽出一个变量。
这里伪元素用到了 position:absolute,同样要在元素上加上 position: relative;
效果就是这样的:
然后我们先加一些 hover 的效果吧,毕竟也算一个完整的 Button 了。
hover 的时候,让字体间距变大,两个草丛背景分别左右移动,箭头往右移动:
效果是这样的:
过渡有点太生硬了,设置下 transition:
文字 3s,箭头 2s,草丛 5s,都是匀速的过渡。
这样就自然多了。
接下来就是最有意思的部分了:画三只小鸟。
在按钮的 div 的下方,再加一点 div:
一个 birdBox 元素包含着 3 个 bird 的子元素,它还有一层子元素。
设置这些层当然也是为了利用每一层的 ::before、::after 来画一些东西:
先设置 .birdBox 的样式:
设置宽高和绝对定位的位置,大概是在这里:
并且设置内容水平平分剩余空间,竖直居中。
然后设置子元素也就是每只小鸟的样式:
设置圆角:
这里也作为变量抽出来。
分别设置 4 个角的横竖半轴长度,调整得到这样的形状:
然后通过 ::before 伪元素画上鸟毛:
这种不规则形状当然也是通过 clip-path 裁剪出来的。
然后再画上嘴:
在子元素 .bird__face 上画:
设置宽高和定位,背景颜色和圆角,就可以得到鸟嘴:
要居中的话可以在它的父元素设置 display: flex:
然后再通过 ::before 和 ::after 伪元素来画两只眼睛:
设置定位、宽高、位置、圆角、背景颜色即可:
至此,睡着的小鸡就画完了!
核心就是就是元素和伪元素通过定位 + flex 来布局,然后通过 border-radius 和 clip-path 设置形状。
接下来画睡醒以后的小鸡:
只有前两只会醒,所以给它俩单独加个 wakeup 的 class:
当 hover 的时候,wakeup 的小鸡会执行伸展身体的动画:
这个动画里变的是什么呢?
明显是 height 变了,我们设置下:
这样有两个问题,一个是动画没有停住,一执行完就回去了,这个可以设置 animation-fill-mode 来解决:
设置 animation-fill-mode 为 forwards 就是停留在最后一帧的意思:
还有一个问题就是鸟高度变大后,圆角也得重新设置下,不然形状很奇怪:
这样就好多了:
再就是醒来以后眼睛也得睁开,还要眨眼,这个怎么做呢?
看下分解动作就明白了:
设置宽高都为 6px,这样就是睁开眼睛的效果:
瞬间变精神小伙。
这样是之前闭着眼睛的效果:
连起来设置几个关键帧,那就是眨眼动画了:
当然睁眼以后高度变高,top 也得调整下。
然后应用这个动画:
5s 内匀速执行动画,无限次执行。
试一下:
瞬间就有灵气了。
都一样的动作显得有点呆,我们让第二只鸟往右边看一下。
也就是这样的动画:
就是多了一个 translateX 的位移。
给第二支鸟应用这个动画:
再来试下:
更可爱了一点!
最后,还要做一个睡着的动画,睡着的时候随着呼吸,身体也是有起伏的,这个动画也是改 height 和 border-radius:
先试一下:
确实有随着呼吸身体起伏的感觉了!
但不知道同学们有没有发现这个动画的不同之处?
我们多设置了个 alternate,这个是 animation-direction,动画方向的意思。
如果不设置是这样的效果:
每次都从低到高来运动。
但应该是低到高、高到低、低到高这样的循环往复的运动。
animation-direction: alternate 的效果就是正向、反向、正向、反向这样循环。
当然它也有别的取值:
- normal:正向:
- reverse:反向
- alternate:正向、反向、正向、反向...
- alternate-reverse:反向、正向、反向、正向...
至此,这个可爱的 Button 就完成了,我们整体感受一下:
确实很可爱!
全部代码如下:
总结
我们通过纯 CSS 实现了一个可爱的 Button,核心就是用元素 + 伪元素通过 flex + 定位来布局,然后通过 border-radius + clip-path 设置形状,通过 animation + @keyframes 来做复杂的动画,通过 transition 设置过渡效果。
border-radius 可以设置 4 个角的横竖半轴的长度,从而做出很多形状,更复杂的不规则形状可以通过 clip-path 来裁剪出来。
其中要注意的是可以通过设置 animnation-fill-mode: forwards 让动画停在最后一帧,设置 animation-direction: alternate 可以正反交替执行动画。再就是最好通过变量把会变化的样式值提取出来,这样方便配置。
用 CSS 实现一些有趣的效果确实感觉很好,这也是前端工程师专属的快乐。