我正在参加「初夏创意投稿大赛」详情请看:初夏创意投稿大赛
效果图
实现思路
电扇分为头部和底部俩个盒子,头部装风叶,脚部装遥控装置和电扇底座
电扇头部使用一个盒子包住之后在写一个无序列表用来装风叶,然后通过css扭曲属性和旋转属性在结合定位的方式实现头部的样式,在通过css3动画的方式使得风叶有旋转的效果
电扇脚部分为遥控器和底座和电扇杆,遥控器通过无序列表结合flex布局的方式实现开关的排列,在通过电线杆伪元素的方式实现一个底座,底座采用定位的方式定位到最底部
在通过类名管理转速,用js给按钮添加上管理类名的函数
页面结构
<div class="box"> <!-- 电扇圈 --> <div class="fanbox"> <!-- 电扇叶盒子 --> <ul id="motor"> <!-- 扇叶 --> <li></li> <li></li> <li></li> </ul> </div> <!-- 电扇座 --> <div class="pedestal"> <!-- 遥控 --> <ul class="telecontrol"> <li id="slow">1</li> <li id="middle">2</li> <li id="tall">3</li> <li id="derail">开/关</li> </ul> </div> </div>
电扇外框
我们先画一个盒子,用盒子来装电扇头部,给上边框,这样电扇头外框的样式就好了,我们这里提前给盒子设置好flex布局主轴侧轴居中,这是为了风扇叶盒子能够居中在电扇头的最中心
/* 电扇圈 */ .fanbox { box-sizing: border-box; width: 300px; height: 300px; background: rgb(215, 202, 145); border-radius: 50%; padding: 15px; display: flex; justify-content: center; align-items: center; border: 2px solid #000; overflow: hidden; }
电扇内框
我们给个比外框小的盒子,然后设置宽高,也同样给盒子设定一个边框及通过边框的属性实现圆形,这里我们采用无序列表实现,因为风叶采用li比较层次分明
/* 电扇叶盒子 */ .fanbox>ul { position: relative; box-sizing: border-box; width: 100%; height: 100%; background: rgb(242, 235, 135); border-radius: 50%; padding: 10px; border: 2px solid #000; }
电扇风叶
这里我们用到css的扭曲属性,先是用css属性做出一个扇形在通过扭曲属性把他延伸成一个长方形的扇形,充当扇叶
/* 扇叶 */ .fanbox>ul li { position: absolute; top: 35px; left: 50%; width: 100px; height: 100px; border-radius: 100px 0 0; background: rgb(248, 222, 70); }
这里我们把扇叶进行扭曲
transform: translate(-50%, -43%) rotate(45deg) skew(12deg, 11deg);
电扇总共三个扇叶,其他俩个照搬,跳转好旋转角度,在通过扭曲属性进行扭曲
.fanbox>ul li:nth-child(1) { transform: translate(-50%, -43%) rotate(45deg) skew(12deg, 11deg); } .fanbox>ul li:nth-child(2) { transform-origin: 71% 117%; transform: translate(-50%, -40%) rotate(168deg) skew(12deg, 11deg); } .fanbox>ul li:nth-child(3) { transform-origin: 88% 141%; transform: translate(-50%, -40%) rotate(278deg) skew(12deg, 11deg); }
通过CSS属性进行扭曲,在使用边框属性设置边框
border: 2px solid #000;
在使用电扇内框盒子做一个风扇电机的盖子这样显得好看,且能遮盖住三个扇叶之间的空隙,这里我们使用内框的伪元素来做
.fanbox>ul::after { content: ''; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 20px; height: 20px; border-radius: 50%; background: rgb(230, 216, 109); border: 2px solid #000; }
电扇杆
这里我们给个宽高就在通过定位的方式,定位到头部上一点的位置就好了
.pedestal { position: relative; top: -10px; width: 30px; height: 300px; background: rgb(157, 152, 128); border: 2px solid #000; }
电扇底座
底座我们采用电扇杆的伪元素来做,在通过定位,定位到最下面,底座上面是有一个鼓起的圆包的,我们这里采用css的边框圆角的方式实现
先设置搞宽高,定位到最底部
/*底座 */ .pedestal::after{ content:''; width: 200px; height: 30px; background: rgb(157, 152, 128); border: 2px solid #000; position: absolute; left: 50%; bottom: 0; transform: translate(-50%, 94%); }
在通过边框属性实现圆包
border-top-left-radius: 50%; border-top-right-radius: 50%;
遥控器
遥控器我们也采用无序列表的方式实现,先给一个大盒子,定位到电扇杆合适的位置,在设置上边框,采用flex布局的方式让子元素能够平分空间这样显得好看,我们先设置好
/* 遥控器 */ .telecontrol { box-sizing: border-box; position: absolute; top: 0; left: 50%; transform: translate(-50%, 50%); width: 90px; height: 100px; padding: 5px 0; background: rgb(232, 223, 150); border-radius: 5px; border: 2px solid #000; display: flex; flex-direction: column; justify-content: space-around; align-items: center; }
在通过子元素实现开关和开关的样式
.telecontrol>li { cursor: pointer; user-select: none; padding: 0 10px; height: 15px; display: flex; justify-content: center; align-items: center; font-size: 12px; border: 1px solid #000; border-radius: 8px; background: rgb(169, 157, 90); color: #fff; }
电扇转动的实现
样式排完了之后,我们来让电扇转起来,电扇转起来使用css动画结合css类名的方式,每个类名对应了不同的档位触发不同转速的动画
/* 档位 */ .gear1 { animation: Firstgearrotate1 3s linear infinite; } .gear2 { animation: Firstgearrotate2 3s linear infinite; } .gear3 { animation: Firstgearrotate3 3s linear infinite; } /* 一档 */ @keyframes Firstgearrotate1 { from { transform: rotate(0deg); } to { transform: rotate(1080deg); } } /* 二档 */ @keyframes Firstgearrotate2 { from { transform: rotate(0deg); } to { transform: rotate(2160deg); } } /* 三档 */ @keyframes Firstgearrotate3 { from { transform: rotate(0deg); } to { transform: rotate(3240deg); } }
风扇按钮控制
最后在通过js获取到按钮元素,进行管理,在通过不同的下标值给风扇内框盒子添加上不同的类名实现转动
// 获取档位和开关 // 低档 const slow = document.getElementById('slow'); // 中档 const middle = document.getElementById('middle'); // 高档 const tall = document.getElementById('tall'); // 开关 const derail = document.getElementById('derail'); // 风扇 const motor = document.getElementById('motor'); // 转速 const speed = ['gear1', 'gear2', 'gear3']; //按钮,开关按钮必须在最后一个 const disjunctor = [slow, middle, tall, derail]; disjunctor.map((R, index) => { const fn=Gear.bind(this,index) R.addEventListener('click', fn, false); }); // 按钮函数 function Gear(index){ // 删除所有类名,存在即删除 speed.map(A=>{ if(motor.classList.contains(A)){ motor.classList.remove(A); } }) // 如果当前是开关按钮则不继续,开关按钮必须在最后一个 if (!speed[index])return; motor.classList.add(speed[index]); };