动态点阵背景
flyKot2025/10/20
效果预览
cal
分析原理
可以看出是绝对定位了个canvas在背景上,再在canvas上根据元素的宽高画上相应数量的圆点,再给每个圆点设置随机透明度进行闪烁
1.写出主体结构
<div class="card">
<div class="cvs_box"><canvas id="card_cvs"></canvas></div>
<div class="context">cal</div>
</div>
2.设置css
TIP
内层容器设置mask-image遮罩时,内层容器的边框、shadow等都会被遮挡,所以卡片的边框应写在外层容器
.card {
position: relative;
width: 300px;
height: 300px;
border-radius: 18px;
display: flex;
justify-content: center;
align-items: center;
border: 1.5px solid #ededed;
overflow: hidden;
box-shadow: 0 0 0 calc(1px + 0) color-mix(in oklab, #000 5%, transparent);
}
.cvs_box {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
mask-image: linear-gradient(#fff, #fff), radial-gradient(ellipse farthest-corner at center, black 0, transparent 90%), linear-gradient(#fff, #fff);
mask-composite: intersect;
}
.context {
width: 30px;
height: 30px;
background-color: black;
color: #fff;
text-align: center;
z-index: 2;
}
#card_cvs {
width: 100%;
height: 100%;
z-index: 1;
}
3.实现canvas内容
const canvas = document.getElementById("card_cvs")
//保持canvas的width和style.width一致,否则会出现圆点被拉伸情况,height同width
canvas.width = canvas.offsetWidth;
canvas.height = canvas.offsetHeight;
const ctx = canvas.getContext("2d")
const box_width = canvas.width
const box_height = canvas.height
// 圆点半径
const r = 1.5
const c_width = r
const c_height = r
// 根据卡片宽高计算圆点数量
const c_count_x = Math.round((box_width / c_width) / 2)
const c_count_y = Math.round((box_height / c_height) / 2)
const spacing = 5.5 * r; // 间距
const color = "#b7b7b7";
// 最小透明度
const minAlpha = 0.2
// 最大透明度
const maxAlpha = 1
// 圆点集合
const circles = [];
for (let i = 0; i * spacing < box_width; i++) {
for (let j = 0; j * spacing < box_height; j++) {
circles.push({
x: i * spacing,
y: j * spacing,
radius: r,
// 每个圆点有自己的初始时间偏移(避免完全同步)
time: Math.random() * Math.PI * 2 // 随机相位
});
}
}
function animate() {
// 清空整个画布(只清一次!)
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 更新并绘制每个圆点
circles.forEach(circle => {
// 每个圆点独立推进自己的时间
circle.time += 0.04; // 闪烁速度
// 独立计算透明度
// Math.sin(circle.time)范围是[-1,1],+1为[0,2]再除2,透明度就在[0,1]
const alpha = (Math.sin(circle.time) + 1) / 2;
// max-min得0.8,所以alpha*0.8结果就在[0,0.8]结果再+0.2就得到[0.2,1]
ctx.globalAlpha = minAlpha + alpha * (maxAlpha - minAlpha);
ctx.beginPath();
ctx.arc(circle.x, circle.y, circle.radius, 0, 2 * Math.PI);
ctx.fillStyle = color;
ctx.fill();
});
ctx.globalAlpha = 1.0; // 重置透明度
requestAnimationFrame(animate);
}
animate();
