用CSS画个三角形实现漏斗定时器吧
CSS 三角形 漏斗 定时器
起源于面试官问我如何用css实现一个三角形。我一想这还不简单,我之前都没有把这一题放在我的面经里。然后。。。我就开始描述,发现自己描述不清。唉,果然好记性不如烂笔头,又一次深深的感悟了!回来,我就开始写样式。嗯,确实一写就又会了。
但是!写都写了,怎么能只画一个三角形。于是我又画了一个,又一个,又一个。。。成漏斗了。那就索性再加点动画,做个漏斗定时器吧。
提示:以下是本篇文章正文内容,下面案例可供参考
一、CSS三角形?
确实是一个比较基础的内容了。主要通过设置一个盒子的border。一个没有宽高的盒子,设置border的宽度,颜色为透明。然后再设置三角形对应方向上的border颜色为你想要的颜色。
.triangle-up {
/* 水平垂直居中 */
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
/* 画三角形 */
border: 50px solid transparent;
border-top-color: white;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
z-index: 5;
/* 要让沙子叠到下面的漏斗上面 */
}
.triangle-down {
/* 水平垂直居中 */
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
/* 画三角形 */
border: 50px solid transparent;
border-bottom-color: rgb(231, 107, 221);
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
}
二、组个漏斗
漏斗由上下两个三角组成triangle-up和triangle-down,上面的是白色,下面的是粉色。内部再添加有颜色的三角triangle-up-inner和triangle-down-inner,固定好位置与外层的三角重叠。js控制内部三角的border的宽度变化。初始时,上面全是沙子,则内部蓝色三角的border宽度和外部相等;下方内部三角为白色,也覆盖外层。每隔一段时间,沙子下落,triangle-up-inner的边框宽度减少,triangle-down-inner的边框宽度也减少。
为沙子添加下落的动画。
1.HTML结构
<div class="container">
<!-- 漏斗 -->
<div class="triangle-up">
<div class="triangle-up-inner">
<div class="sand-box">
<!-- 沙子 -->
<div class="sand sand1"></div>
<div class="sand sand2"></div>
<div class="sand sand3"></div>
<div class="sand sand4"></div>
<div class="sand sand5"></div>
<div class="sand sand6"></div>
</div>
</div>
</div>
<div class="triangle-down">
<div class="triangle-down-inner"></div>
</div>
</div>
上面画两个三角形,一个是最外层的三角,设置为白色;里面的是漏斗的填充物,设置为蓝色。下面的两个三角行也是同样的设置。然后再加点沙子。
2.CSS样式
代码如下(示例):
.triangle-up-inner {
border: 50px solid transparent;/* 漏斗定时开始,上面全蓝,随着 */
border-top-color: rgb(17, 20, 167);/* 蓝色 */
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.triangle-down-inner {
border: 50px solid transparent;/* 蓝色 */
border-bottom-color: white;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.sand {
position: absolute;
width: 5px;
height: 5px;
border-radius: 5px;
background-color: rgb(17, 20, 167);
}
.sand1 {
left: 2px;
animation: sandDown 1s linear infinite;
}
.sand2 {
animation: sandDown 1.6s linear infinite;
}
.sand3 {
left: -1px;
animation: sandDown 2.2s linear infinite;
}
.sand4 {
left: 1px;
animation: sandDown 2.3s linear infinite;
}
.sand5 {
animation: sandDown 2.6s linear infinite;
}
.sand6 {
left: -2px;
animation: sandDown 3.2s linear infinite;
}
@keyframes sandDown {
from {
transform: translateY(0);
}
to {
transform: translateY(45px);
}
}
3.JS漏斗定时器
无非就是开一个定时器,每隔一定的时间,上下三角的边框宽度变化。之前想练练手,考虑用requestAnimationFrame()去做。发现有点大材小用,requestAnimationFrame()提供逐帧渲染的方式去实现动画,重绘的频率和屏幕刷新的频率保持一致。但是这里的话不太合适也麻烦,因为我需要的是漏斗隔固定时间下降1px(css最小单位是1px或0.5px),不需要逐帧的渲染。所以用个定时器setInterval就够了。每隔delay,漏斗的边框宽度减少1px。delay的计算根据border的宽度得到的。
但是确实是setInterval定时会有一丢丢误差,一直开着,也会导致累计误差。没办法,只能用new Date()计算每次定时的时延,然后把时延加到下一次的定时器里。这样总的时延就少了(因此漏斗是定时一分钟)。
/* 设置一个一分钟的无限循环定时器 */
let t = 60;
var triangle = document.querySelector('.triangle-up');
var triangle_down = document.querySelector('.triangle_down');
const height = triangle.offsetHeight/2;//获取漏斗的高度
var triangle_up_inner = document.querySelector('.triangle-up-inner');
var triangle_down_inner = document.querySelector('.triangle-down-inner');
var sandBox = document.querySelector('.sand-box');
var step =- 1;//设置移动的步长
var delay = (t-1)/height*1000;
//初始化,漏斗上边是满的,下边是空的
function init() {
triangle_up_inner.style.borderWidth = `${height}px`;
triangle_down_inner.style.borderWidth = `${height}px`;
}
init();
let begin = +new Date();
play();
function play() {
let startTime=+new Date();
let timer = setTimeout(function down(){
let offset = +new Date()-startTime-delay;//修正定时器时间
var up_inner_height = triangle_up_inner.offsetHeight/2;
if ((up_inner_height + step) <= 0 ) {
console.log(+new Date()-begin);
begin = +new Date();
clearTimeout(timer);
init();
play();
} else {//设置1秒中移动一个step
triangle_up_inner.style.borderWidth = `${up_inner_height + step}px`;
triangle_down_inner.style.borderWidth = `${up_inner_height + step}px`;
clearTimeout(timer);
startTime =+new Date();
setTimeout(down,delay-offset);
}
},delay)
}
总结
写个博客确实挺花时间。我要去刷算法题了。唉,今年找实习可真难。