我正在参与掘金创作者训练营第5期,点击了解活动详情
前言
最近天气温度居高不下,在曾经的四大火盆之一的城市居住,再安逸闲适的城市也让人干燥烦热。就在昨天,新开了一个专栏,主要是想做一个关于CSS特殊效果的专栏,想能给大家带来一丝惬意,继而忘掉燥热的酷暑天气。其实最真实的目的是为了将自己遇见的,好玩有趣的特效收集整理,然后通过掘金这个大平台展现给大家,也让大家来看看这些牛皮扎劲的CSS特效效果到底是怎么实现的,从而启发自己在以后的工作中的思维想法,最后也能写出牛皮酷炫的特效示例。
专栏中会有自己实现的特效,也会有别人实现的特效,前期肯定还是以分享别人的为主。主要原因还是因为平时的工作是和业务代码打交道居多,至于样式效果仅仅只是还原UI设计稿而已,没有太多精力时间像别人去专研那些特效效果,其次就是实力不济呀,所以这次就开个专栏,边分享的同时也试着去理解别人的实现思路,为以后自己亲自操刀打下坚实基础。
背景
前言里面提到了,正是酷暑之季,每天都是把空调开到最低才能抵抗得了这炎热。奈何家境贫寒,承受不了高昂的空调电费,真是吹起一时爽,交费泪两行呀。一直开空调也不是事儿,这不得想个办法减少成本,于是选择在网上冲浪,这应该能降降高温。正浪的飞起时,看到有一个风扇优哉游哉的转着......诶,瞬间感觉清爽了不少,我又是喜欢分享的人,这不,看文章的小伙伴们福利来了,我也把这风扇分享给你们,也让你们清凉一夏。(注意看,我还是给你们开的最大档哦)
(音乐起:怎么大风越狠,我心越荡啊~ 吹啊吹啊~ 我赤脚不害怕~ 吹啊吹啊~ 无所谓扰乱我)
实现
没错,这次就是来看看别人是怎么实现这个风扇特效的,我要好好看看,到底是好大个风扇我搞不定!
一、组织框架和定义变量
万事开头难,没有开头何来过程,何来Ending呢?所以做一件事还是先有个大体的规划,架子搭好,后续往里面不断地填内容就可以了。一个马拉松你可能一鼓作气跑不下来,但是如果把整段路程拆分为多个几个公里,一个几公里一个几公里的去跑完,最后一个马拉松不就跑下来了么,编码依然如此。
1.1 总体框架
总的架子没啥难度,就是使用H5的最新快捷键,一按就生成了。接着就是使用normalize重置默认样式,引入项目样式文件style.css即可。
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>纯CSS3电风扇动画DEMO演示</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="scene">
<div class="fan"></div>
</div>
</body>
</html>
1.2 定义变量
平时开发中我们也是把项目中公用的模块定义好,然后其他模块引入使用的思路,这里同样也是把公用的样式提取出来,定义好即可。
:root {
--blade-speed: 1; /*叶片速度*/
--rotation: 25; /*旋转角度*/
--fan-speed: 2; /*风速*/
--state: running; /*状态*/
--bg: #344c65; /*背景色*/
--shade-one: #f2f2f2;
--shade-two: #e6e6e6;
--shade-three: #d9d9d9;
--shade-four: #ccc;
--shade-five: #bfbfbf;
--shade-six: #b3b3b3;
--shade-seven: #a6a6a6;
--shade-eight: #999;
--cage-one: rgba(255,255,255,0.4);
--cage-two: rgba(255,255,255,0.2);
--height: 70vmin;
--width: 40vmin;
}
说实话,这真是小刀剌屁股,开了眼了。恕我才疏学浅,我第一次知道原生CSS中还可以这样定义变量,工作中都是使用的less和sass去做的,没想到原生CSS中是这样定义变量在全局中使用的,牛👍,涨姿势了!
然后把架子搭建时的容器样式提前写好,后面也是来做样式的填空题就好啦。如下:
.scene {
position: absolute;
height: var(--width);
width: var(--width);
top: 50%;
left: 50%;
transform: translate3d(-50%, -50%, 0vmin) rotateX(-24deg) rotateY(34deg) rotateX(90deg);
}
.fan {
height: var(--height);
width: var(--width);
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) rotateX(-90deg) rotateX(calc(var(--rotateX, 0) * 1deg)) rotateY(calc(var(--rotateY, 0) * 1deg));
}
这样,这个风扇实现的第一步就搞定了,接下来就是一个个挨着填空就可以完成整个特效了。上述代码实现的效果就是一个背景墙而已,如下:
二、底座
定义变量给我挫败感,但是我得坚强的往下走🔜
首先还是来看看底座是如何实现的吧。如果要我来实现这个底座,我觉得我是可以搞出来的,就是代码可能会写得有点多,那还是来看看别人是怎么个实现过程,好好看好好学,眼睛不要打眺,打眺就望不到。
<div class="fan__base">
<div class="cuboid base">
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
</div>
</div>
嗯~这是要用6个盒子组成一个长方体底座的节奏呀,那到底该怎么放置它才能组成一个长方体呢?往下瞧👇
.fan__base {
position: absolute;
bottom: 0;
left: 50%;
transform: translate(-50%, 0);
height: 8%;
width: 80%;
}
.base {
--thickness: calc(40 * 0.8);
}
.base div {
background: var(--shade-two);
}
.base div:nth-of-type(1) {
background: var(--shade-one);
}
.base div:nth-of-type(5) {
background: var(--shade-three);
}
.base div:nth-of-type(4) {
background: va(--shade-six);
}
.cuboid {
width: 100%;
height: 100%;
position: relative;
}
.cuboid__side:nth-of-type(1) {
height: calc(var(--thickness) * 1vmin);
width: 100%;
position: absolute;
top: 0;
transform: translate(0, -50%) rotateX(90deg);
}
.cuboid__side:nth-of-type(2) {
height: 100%;
width: calc(var(--thickness) * 1vmin);
position: absolute;
top: 50%;
right: 0;
transform: translate(50%, -50%) rotateY(90deg);
}
.cuboid__side:nth-of-type(3) {
width: 100%;
height: calc(var(--thickness) * 1vmin);
position: absolute;
bottom: 0;
transform: translate(0%, 50%) rotateX(90deg);
}
.cuboid__side:nth-of-type(4) {
height: 100%;
width: calc(var(--thickness) * 1vmin);
position: absolute;
left: 0;
top: 50%;
transform: translate(-50%, -50%) rotateY(90deg);
}
.cuboid__side:nth-of-type(5) {
height: 100%;
width: 100%;
transform: translate3d(0, 0, calc(var(--thickness) * 0.5vmin));
position: absolute;
top: 0;
left: 0;
}
.cuboid__side:nth-of-type(6) {
height: 100%;
width: 100%;
transform: translate3d(0, 0, calc(var(--thickness) * -0.5vmin)) rotateY(180deg);
position: absolute;
top: 0;
left: 0;
}
看到没有,在base这个容器下定义一个变量--thickness,下面所有的元素都能使用,而base外的其他元素却使用不了,要想使用就只能使用root中定义的,可能这就是原生CSS中的全局变量和局部变量吧。
下面就来看看上述代码最终实现的效果,如下:
三、控制器
接着来实现开关和档位器,其实思路也是和底座相同,也是用6个div来组成,唯一的不同的就是形状而已。要注意的点只是位置上的排列要使其看起来合理就行,其他也就没啥难度,至于控制器的交互放在后面来聊,先来把UI实现了。
<div class="fan__controls">
<label class="fan__control" for="zero">
<div class="cuboid control">
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
</div>
</label>
<label class="fan__control" for="one">
<div class="cuboid control">
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
</div>
</label>
<label class="fan__control" for="two">
<div class="cuboid control">
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
</div>
</label>
<label class="fan__control" for="three">
<div class="cuboid control">
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
</div>
</label>
</div>
看上面的代码,我又学到一个技术点,那就是label标签中的for属性有什么用?如果我没看这个示例,我一时半会不知道,被问及时多半会是懵逼的。label标签中的for属性其实就是将label和表单控件绑定在一起。
怎么理解?比如有个输入框,如果想要选中输入框获得焦点,只有input情况下,只能选中输入框;但加了label,就把label和input绑定在一起后,点击label也可以选中输入框。所以后面控制器的控制功能就是通过for将其和input联系起来,通过使用input的原生属性实现交互功能,而不是通过js逻辑去操作DOM实现的,看到最后你就知道了。
然后,就是来写样式代码,如下:
.fan__controls {
height: 6%;
width: 50%;
position: absolute;
bottom: 6%;
left: 50%;
transform: translate3d(-50%, 0, calc(var(--width) * 0.3));
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-gap: 6%;
}
.control {
--thickness: calc(((40 * 0.5) - ((40 * 0.5) * 0.18)) / 3);
}
.control div {
background: var(--shade-five);
}
.control div:nth-of-type(1) {
background: var(--shade-three);
}
.control div:nth-of-type(5) {
background: var(--shade-six);
}
.control div:nth-of-type(4) {
background: va(--shade-eight);
}
.fan__control:nth-of-type(1) .control {
--shade-three: #f7d4ba;
--shade-five: #f2b78c;
--shade-six: #f0a875;
--shade-eight: #eb8b47;
}
从上面代码可以看到,类名为cuboid__side的盒子并没有写样式,因为在底座的时候已经贴出了,它们两者是共用的,只需要改变宽高即可。这里还需要注意一个点,那就是可以看到选择div容器时使用的是nth-of-type而不是nth-child,这是因为:nth-child()选择器是选取属于其父元素的不限类型的第n个子元素的所有元素。而:nth-of-type()选择器选取的是属于其父元素的特定类型的第n个子元素的所有元素。
意思就是:nth-child()不限制类型,:nth-of-type()限制类型。举个例:
<div id="wrap">
<p>p1</p>
<span>span1</span>
<p>p2</p>
<p>p3</p>
<p>p4</p>
</div>
<style>
#wrap p:nth-of-type(3) {
background: red;
}
#wrap p:nth-child(3) {
background: yellow;
}
</style>
直接上效果,你就知道两者的区别了,如下:
:nth-of-type()会去找<p>标签进行匹配,而:nth-child()只会对其child不限类型的进行匹配。
回过头来,看上面控制器代码实现的效果。如下:
四、立柱
通过上面的代码实现和效果图,可以看到我们离完成这个风扇只差立柱和扇头了,这个电风扇已经有点雏形了。那趁热打铁,来看看立柱是怎么实现的,有没有使用啥我们不知道的技术点,请往下瞧👇
<div class="fan__spine">
<div class="cuboid spine">
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
</div>
</div>
可以看到,和底座、控制器一样,也是使用6个div拼成的立柱。那没有啥好说的,直接看样式代码。如下:
.fan__spine {
height: 57.5%;
bottom: 8%;
width: 20%;
position: absolute;
left: 50%;
transform: translate3d(-50%, 0%, calc(var(--width) * -0.25));
}
.spine {
--thickness: calc(40 * 0.2);
}
.spine div {
background: var(--shade-three);
}
.spine div:nth-of-type(1) {
background: var(--shade-two);
}
.spine div:nth-of-type(5) {
background: var(--shade-four);
}
.spine div:nth-of-type(4) {
background: va(--shade-seven);
}
平平无奇,少了一开始的惊喜✈,那直接看实现效果,如下:
五、旋转轴部分
略过了立柱的平淡,从这里开始到最后都是重头戏,要注意啦!主角往往都是最后登场的,开整!
旋转轴部分其实就是控制扇头摇摆的部分,一般的电风扇这一部分包括2个主件:转子和控制摇头的按钮,下面就挨着实现👇。
5.1 旋转轴
所谓旋转轴,就是电风扇立柱上装转子的那一部分,控制电风扇左右摇摆的主体,所以我们来看看是如何实现的👇
<div class="fan__head">
<div class="fan__rotater">
<div class="cuboid rotater">
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
</div>
</div>
</div>
抱歉,失算了,这个老六😅。还是用的之前的套路实现的,真是一招鲜吃遍天。
.fan__head {
height: var(--width);
width: var(--width);
position: absolute;
top: 0;
left: 0;
transform: translate3d(0, 0, calc(var(--width) * -0.25));
-webkit-animation: fan calc(var(--fan-speed, 1) * 1s) infinite alternate ease-in-out var(--state);
animation: fan calc(var(--fan-speed, 1) * 1s) infinite alternate ease-in-out var(--state);
}
.fan__rotater {
top: 50%;
width: calc(var(--width) * 0.2);
height: calc(var(--width) * 0.2);
position: absolute;
left: 50%;
transform: translate(-50%, -50%);
}
.rotater {
--thickness: calc(40 * 0.2);
}
.rotater div {
background: var(--shade-two);
}
.rotater div:nth-of-type(1) {
background: var(--shade-one);
}
.rotater div:nth-of-type(5) {
background: var(--shade-three);
}
.rotater div:nth-of-type(4) {
background: va(--shade-six);
}
可以看到,代码中出现了animation,它就是CSS中的动画属性,也就是用它来控制电风扇转起来,摇起来的属性。它的用法如下:
至于电风扇怎么转起来的,放在后面来讲,下面来看上述代码实现后的效果,如下:
5.2 摇头杆
然后,接着来实现控制摇头的按钮。👇
<div class="fan__head">
<div class="fan__rotater">
<div class="cuboid rotater">...</div>
<div class="fan__stalk">
<div class="cuboid stalk">
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
</div>
</div>
</div>
</div>
赢了,又是这样的👍。那也不多哔哔,样式代码如下:
.fan__stalk {
height: 150%;
left: 50%;
bottom: 0;
transform: translate(-50%, 0);
transition: transform 0.2s cubic-bezier(0, 1.4, 0.2, 1.4);
width: 25%;
position: absolute;
}
.stalk {
--thickness: calc(40 * 0.05);
}
.stalk div {
background: var(--shade-four);
}
.stalk div:nth-of-type(1) {
background: var(--shade-three);
}
.stalk div:nth-of-type(5) {
background: var(--shade-five);
}
.stalk div:nth-of-type(4) {
background: va(--shade-eight);
}
上述代码实现的效果,如下:
对,控制电风扇是否摇头的就是图中这个灰色的juju(四川话),还是挺逼真的,哈哈哈。
六、连接头
连接头就是把转头扇头连接起来的中间件。应该还是使用之前的套路,go👇
<div class="fan__head">
<div class="fan__rotater">...</div>
<div class="fan__barrel">
<div class="cuboid barrel">
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
</div>
</div>
</div>
</div>
......(😐😷👍)
.fan__barrel {
height: 22.5%;
width: 22.5%;
position: absolute;
top: 50%;
left: 50%;
transform: translate3d(-50%, -50%, calc(var(--width) * 0.3));
}
.barrel {
--thickness: calc(40 * 0.5);
}
.barrel div {
background: var(--shade-three);
}
.barrel div:nth-of-type(1) {
background: var(--shade-two);
}
.barrel div:nth-of-type(5) {
background: var(--shade-four);
}
.barrel div:nth-of-type(4) {
background: va(--shade-seven);
}
来吧,看效果,如下:
七、扇头
看到上面实现的效果,是不是感觉希望就前方了,已经有那味了。那接下来就来实现扇头,千呼万唤始出来呀。电风扇的灵魂来了~
扇头分为了3部分:后罩、扇片和前罩。完全是根据现实中电风扇有的部件来挨着实现的,不得不说是真的周到👍。
7.1 后面罩子
罩子应该是个圆的吧,如果我没想错的话,应该没有长方体或正方体类型的电风扇吧。反正我是没看见过,那看看到底是个啥样的,弄!
<div class="fan__head">
<div class="fan__rotater">...</div>
<div class="fan__barrel">...</div>
<div class="fan__housing">
<div class="fan__housing-rear"></div>
</div>
</div>
好的,第一个顾虑打消✅,没有看到6个div了😁。那看看在样式上会不会被偷塔,如下:
.fan__housing {
height: 150%;
width: 150%;
border-radius: 50%;
top: 50%;
left: 50%;
position: absolute;
border: 1vmin solid var(--shade-one);
background: var(--cage-one);
transform: translate3d(-50%, -50%, calc(var(--width) * 0.45));
}
.fan__housing-rear,
.fan__housing-front {
position: absolute;
top: 50%;
left: 50%;
height: 80%;
width: 80%;
background: var(--cage-two);
border-radius: 50%;
border: 1vmin solid var(--shade-one);
}
.fan__housing-rear {
transform: translate3d(-50%, -50%, calc(var(--width) * -0.1));
border: 1vmin solid var(--shade-two);
}
没问题,这次真的和前面的不一样了。确定的说罩子是个圆的啦,没有非主流✅。看看效果呢,如下:
哈哈哈,跟个信号接收器一样,和以前看电视需要安装的“天锅”有几分神似。有那味了~有那味了~~
7.2 叶片
接着来为上面的“天锅”补点东西,让它不是“天锅”看看。
<div class="fan__head">
<div class="fan__rotater">...</div>
<div class="fan__barrel">...</div>
<div class="fan__housing">
<div class="fan__housing-rear"></div>
<div class="fan__blades">
<div class="fan__blade"></div>
<div class="fan__blade"></div>
<div class="fan__blade"></div>
</div>
</div>
</div>
从代码可以看到,这个电风扇装了3个叶片,至于怎么排放,那就让样式代码来安排它。如下:
.fan__blades {
position: absolute;
top: 50%;
left: 50%;
height: 16%;
width: 16%;
transform: translate3d(-50%, -50%, -1px) rotate(0deg);
-webkit-animation: rotate calc(var(--blade-speed, 0) * 1s) infinite linear;
animation: rotate calc(var(--blade-speed, 0) * 1s) infinite linear;
}
.fan__blade {
height: 300%;
width: 100%;
background: var(--shade-one);
position: absolute;
top: 50%;
left: 50%;
transform-origin: 50% 0;
transform: translate(-50%, 0) rotate(calc(var(--rotate, 0) * 1deg));
}
.fan__blade:nth-of-type(1) {
--rotate: 0;
}
.fan__blade:nth-of-type(2) {
--rotate: calc(360 / 3 * 1);
}
.fan__blade:nth-of-type(3) {
--rotate: calc(360 / 3 * 2);
}
最终,3个叶片的位置排放效果图如下所示:
7.3 前面罩子
现在离完整的电风扇模型就只差一个罩子了,有了后罩的实现,前罩也应该没啥问题。如下:
<div class="fan__head">
<div class="fan__rotater">...</div>
<div class="fan__barrel">...</div>
<div class="fan__housing">
<div class="fan__housing-rear"></div>
<div class="fan__blades">...</div>
<div class="fan__housing-front">
<img src="https://assets.codepen.io/605876/avatar.png"/>
</div>
</div>
</div>
可以看到,为了美观,还给电风扇在前罩上面加了logo。没错,这个电风扇是一个有品牌的电风扇,该有档次也不能掉,安排。
.fan__housing-front {
transform: translate3d(-50%, -50%, calc(var(--width) * 0.11));
}
.fan__housing-front:after {
content: '';
position: absolute;
top: 50%;
left: 50%;
height: 35%;
width: 35%;
transform: translate(-50%, -50%);
border-radius: 50%;
background: var(--shade-one);
}
img {
height: 20%;
position: absolute;
top: 50%;
left: 50%;
transform: translate3d(-50%, -50%, 1px);
filter: grayscale(1);
opacity: 0.5;
}
来吧,代码完成了。看看最后完工的电风扇的效果图。如下:
是不是和现实中的电风扇没啥区别,甚至我觉得还比真实的电风扇还夺目。主要这配色很清新,让人觉得甚是撩人🤌。
八、转动和控制器
电风扇实现了,现在要想法让它转起来,这个示例的标题叫纯CSS3电风扇动画DEMO演示,如果用JS来控制它转动就名不副实了。既然纯CSS3,那就用CSS相关的属性去实现吧。
8.1 转动
转动主要有2个部件需要转动,那就是电风扇的转子和叶片。至于扇头的转动是由于转子的转动带着扇头转动的,所以控制了转子就能控制扇头。
8.1.1 转子转动
首先来让转子转起来→如果细心的小伙伴可以看到,上面的有些样式代码已经把部分动画代码展示出来了,只是没有去绑定动画事件。动画属性animation需要通过@keyframes规则,才能够创建动画。
@keyframes规则要求我们以百分比来规定改变发生的时间,或者通过关键词"from"和"to",等价于0%和100%。0%是动画的开始时间,100%动画的结束时间。为了获得最佳的浏览器支持,应该始终定义0%和100%选择器。
那上面展示的样式代码就不再赘述,直接来看使用@keyframes创建的动画代码。如下:
@-webkit-keyframes fan {
0%, 5% {
transform: translate3d(0, 0, calc(var(--width) * -0.25)) rotateY(calc(var(--rotation, 0) * 1deg));
}
95%, 100% {
transform: translate3d(0, 0, calc(var(--width) * -0.25)) rotateY(calc(var(--rotation, 0) * -1deg));
}
}
@keyframes fan {
0%, 5% {
transform: translate3d(0, 0, calc(var(--width) * -0.25)) rotateY(calc(var(--rotation, 0) * 1deg));
}
95%, 100% {
transform: translate3d(0, 0, calc(var(--width) * -0.25)) rotateY(calc(var(--rotation, 0) * -1deg));
}
}
fan就是animation语法中的name;而@-webkit-keyframes这样的写法是为了兼容浏览器的缘故。
来看看,电风扇转子转动之后的效果。如下:
8.1.2 叶片转动
好,上面已成功的让电风扇左右摇摆了,下面就是来让叶片也转动起来。按照上面转子转动的套路,照猫画虎得到如下代码:
@-webkit-keyframes rotate {
from {
transform: translate3d(-50%, -50%, -1px) rotate(0deg);
}
to {
transform: translate3d(-50%, -50%, -1px) rotate(360deg);
}
}
@keyframes rotate {
from {
transform: translate3d(-50%, -50%, -1px) rotate(0deg);
}
to {
transform: translate3d(-50%, -50%, -1px) rotate(360deg);
}
}
就上面所示的代码得到下图所示的效果。如下:
8.2 控制器
电风扇算是转起来啦!但是感觉风力是有的小呢,本就炎热的天气再看到如此风力的电风扇,反而会让人更加烦躁。所以为了避免电风扇被砸,下面就来为电风扇加上控制器,用于控制电风扇的开和关,还有就是控制风力的大小。
在这篇文章的第三部分的控制器环节,就已经做了引子了。就是要通过label标签的for属性将每个控制与对应的input联系起来,从而达到我们表面操作div,实际上是在操作input的效果。这样就能实现不用js也能控制每个开关的效果了。
<input type="radio" name="fan" id="zero"/>
<input type="radio" name="fan" id="one"/>
<input type="radio" name="fan" id="two"/>
<input type="radio" name="fan" id="three"/>
为电风扇安排了4个开关,所以需要4个input与之对应。然后对应操作的样式代码,如下:
#zero:checked ~ .scene {
--blade-speed: 0;
--state: paused;
}
#zero:checked ~ .scene .fan__stalk {
transform: translate(-50%, 25%);
}
#one:checked ~ .scene {
--blade-speed: 1;
--state: running;
}
#one:checked ~ .scene .fan__control:nth-of-type(2) {
transition: transform 0.1s cubic-bezier(0, 1.4, 0.2, 1.4);
transform: translate(0, 50%);
}
#two:checked ~ .scene {
--blade-speed: 0.5;
--state: running;
}
#two:checked ~ .scene .fan__control:nth-of-type(3) {
transition: transform 0.1s cubic-bezier(0, 1.4, 0.2, 1.4);
transform: translate(0, 50%);
}
#three:checked ~ .scene {
--blade-speed: 0.25;
--state: running;
}
#three:checked ~ .scene .fan__control:nth-of-type(4) {
transition: transform 0.1s cubic-bezier(0, 1.4, 0.2, 1.4);
transform: translate(0, 50%);
}
可以看到,控制电风扇转动和风力的大小是通过设置--blade-speed和--state实现的。要把电风扇关了就把转速设为0,然后状态设为暂停;而电风扇风速为1时,则为第1个档位效果;电风扇风速为0.5时,则为第2个档位效果;电风扇风速为0.25时,则为第3个档位效果。如果要为电风扇默认开启一个档位就给input设置一个checked属性,如下:
<!-- 默认开启电风扇并设置为第1档位 -->
<input type="radio" name="fan" id="one" checked="true"/>
到这里,电风扇的整个实现就完成了。最后的效果就和背景中展示的一样,我们还是来看看实际效果吧。如下:
九、码上掘金
第一次使用码上掘金发布代码片段,挺好,又学会一个技能了💪👍。大家可以到马上掘金看到该示例的效果。
十、临时需求
应评论区朋友们的要求:需要让风扇不转动,一直对着吹的需求。我也是马上对代码进行了改动,最终实现了让风扇可以不转动。具体如下:
<label class="fan__control" for="four">
<div class="cuboid control">
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
<div class="cuboid__side"></div>
</div>
</label>
在控制器容器中增加了一个用于控制电风扇不转动的控制开关,即上述代码。
然后需要对应加上一个控制它的单选input,至于怎么将两者关联起来上述文章已详细讲解,这里就不再展开了。如下:
<input type="radio" name="fan" id="four"/>
接下来就是去对样式代码进行改造,首先要让新增的开关出现,那就需要改动此处代码。如下:
然后就是来写控制代码,也很简单。原理就是开关触发,扇头不转动,就业片转动即可。如下:
#four:checked ~ .scene {
--blade-speed: 0.25;
--state: running;
}
#four:checked ~ .scene .fan__head {
animation: initial;
transform: translate(-20%, -20%) rotateY(-30deg);
}
#four:checked ~ .scene .fan__control:nth-of-type(5) {
transition: transform 0.1s cubic-bezier(0, 1.4, 0.2, 1.4);
transform: translate(0, 50%);
}
.fan__control:nth-of-type(5) .control {
--shade-three: #f77a5b;
--shade-five: #dd512e;
--shade-six: #dd562d;
--shade-eight: #da330a;
}
这里为了让各位朋友吹爽,我设置的风扇不转动时是最大风力。让朋友们一次吹个够,哈哈哈。这样编写代码之后就可以让其控制风扇不转动了。效果如下:
后面我还知道你们肯定会提不转动时要可以改变风力大小,这个需求我就不做了,因为现在用于控制电风扇的开关都是单选,没有使用多选,只能满足一种情况。如果非要加,那就只有继续安排控制开关,电风扇不转动时也是3个风力档位,感兴趣的朋友可以自己去尝试尝试。为了让朋友们明显地知道哪个按钮是控制不转的,我特意加了红色色系用于区分,这也是评论区朋友要求的,这样确实能让体验提升,再次感谢建议哦,栓Q🌹。
好,电风扇不转动的需求就到这里,码上掘金中也更新了最新代码,大家可以去看最新效果。谢谢你因为有你温暖了四季~~~
总结
通过介绍电风扇这个示例的实现过程,还是让我深有感触的。从中还是获得了一些我之前不曾知道的知识和技术点,也对一些我知道的知识点进行了温顾。比如:
- 原生
CSS中是可以通过:root的方式来声明全局变量的,而变量则是通过--xxx声明的;使用则是使用var(--xxx),如:background: var(--bg);; label中的for属性可以将label和表单控件绑定在一起;:nth-child()不限制类型,:nth-of-type()限制类型;- 加深
animation动画属性的使用方法; - 了解
@keyframes规则; - 可以通过
input的checked属性实现关联div的选中效果; - 学会使用码上掘金进行代码片段的插入。
所以我希望我的这次分享也能让你从中获得或多或少的技术知识,而不是单纯的看了就算了,更不想你直接将代码拷贝之后看到效果后乐呵乐呵就算了。分享的目的还是为了让我们查漏补缺,同时去提高我们自身的业务水平和技术能力。
后语
小伙伴们,如果觉得本文对你有些许帮助,点个👍或者➕个关注再走呗^_^ 。另外如果本文章有问题或有不理解的部分,欢迎大家在评论区评论指出,我们一起讨论共勉。