
TML新手别慌:用CSS搞定超酷涌动弹簧特效(附实战套路)
- 这玩意儿真不是动效大佬专属
- HTML和CSS到底能玩出啥花样
- 说白了就是一堆小球在那儿弹来弹去还带波浪感
- @keyframes 才是幕后黑手
- 先画几个圆,再让它们排队跳,节奏感拉满
- cubic-bezier(0.5, 1.5, 0.5, -0.5) 这种野路子才够弹
- animation-delay 配合负值,让每个球错开节奏,波浪感直接拿捏
- 看着炫但掉帧,手机上直接卡成PPT
- 有的安卓机对 animation 渲染抽风,得加 will-change: transform 救场
- 直接在 DevTools 里调 keyframes 数值,边看边改爽翻
- 鼠标一划全弹起来,或者滚到这儿才开始蹦,用户立马哇塞
- --spring-speed、--ball-size 这些变量搞起来,一套代码多处复用
- 先看是不是没加 vendor 前缀,再查是不是父级 overflow:hidden 给切了
- 比如根据屏幕宽度动态算 delay,这时候 JS 出手快准狠
- 比如把弹簧改成爱心形状、或者颜色随节奏变,朋友圈点赞收割机
HTML新手别慌:用CSS搞定超酷涌动弹簧特效(附实战套路)
这玩意儿真不是动效大佬专属
说真的,我刚入行那会儿,看到那些花里胡哨的动画效果,第一反应就是:“这得用Canvas吧?或者至少得来个WebGL?再不济也得写个几斤重的JS库?”
结果呢,翻开源码一看,卧槽,就是几个div加上几行CSS。当时我就感觉自己像个傻子,拿着大炮打蚊子打惯了,突然有人告诉我其实用弹弓就能搞定。
所以先给诸位新手吃个定心丸:别被那些"前端动画工程师"的title吓到,什么涌动的弹簧、波浪loading、弹性菜单,纯CSS完全能抡得动。你今天看完这篇,明天就能在你那个满是表格的后台管理系统里偷偷塞一个,惊艳(吓)你的产品经理。
HTML和CSS到底能玩出啥花样
别再以为HTML只是写个div就完事了。是,它确实主要是写div,但关键是你得让这个div动起来,而且是那种看起来有物理感的动。
我知道很多人写CSS就停留在color: red、font-size: 16px这种静态属性上,觉得动画是JS的活儿。兄弟,这都2026年了,CSS早就不是那个只会打扮页面的花瓶了。现在的CSS3,尤其是@keyframes和transform这对黄金搭档,玩起动画来比JS还流畅,毕竟人家是浏览器亲儿子,直接走GPU渲染,不经过JS引擎那一道手。
你想想,就一个loading效果,用JS写你得搞个requestAnimationFrame,得算时间戳,得处理重绘,代码写一大坨。用CSS呢?三十行搞定,还能硬件加速,手机上的电量都省一半。这不是技术选型的问题,这是智商税的问题。
说白了就是一堆小球在那儿弹来弹去还带波浪感
咱们今天搞的这个"涌动弹簧效果",听起来挺高大上,其实拆解开来特别弱智。想象一排水晶球,你摁下第一个,它弹起来,然后第二个跟着弹,第三个跟着弹,形成一波肉眼可见的波浪。就像你小时候玩的那个牛顿摆,但是每个球都有延迟,而且是上下跳不是左右撞。
这种效果用在哪儿?多了去了。页面加载时的loading动画,音乐播放器的节拍可视化,按钮点击后的反馈效果,甚至你那个枯燥的数据 dashboard 里,加一排这个,立马显得你很懂设计。老板看了直呼专业,虽然他可能不知道这东西实现起来比写个表单验证还简单。
@keyframes 才是幕后黑手
行,不废话了,上硬菜。这玩意的核心就仨字:关键帧。@keyframes这玩意儿就是告诉浏览器:“哥们儿,在0%的时候长这样,50%的时候长那样,100%的时候回到原样”,然后浏览器就自动帮你补中间的过程。
先搭个骨架,咱们画五个小球,别多,五个够演示了:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CSS弹簧特效实战</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
min-height: 100vh;
background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%);
display: flex;
justify-content: center;
align-items: center;
/* 让整个容器有点透视感,后面3D变换用得上 */
perspective: 1000px;
}
/* 弹簧容器 */
.spring-container {
display: flex;
gap: 20px; /* 球间距 */
align-items: flex-end; /* 底部对齐,这样跳起来更自然 */
height: 200px;
padding: 0 40px;
}
/* 小球的基础样式 */
.ball {
width: 40px;
height: 40px;
background: radial-gradient(circle at 30% 30%, #ff6b6b, #c92a2a);
border-radius: 50%; /* 变圆 */
box-shadow: 0 4px 15px rgba(0,0,0,0.3); /* 先加个阴影显得立体 */
position: relative;
}
/* 给每个球加反光,显得更晶莹剔透 */
.ball::after {
content: '';
position: absolute;
top: 10%;
left: 15%;
width: 25%;
height: 25%;
background: rgba(255,255,255,0.8);
border-radius: 50%;
filter: blur(2px);
}
</style>
</head>
<body>
<div class="spring-container">
<div class="ball"></div>
<div class="ball"></div>
<div class="ball"></div>
<div class="ball"></div>
<div class="ball"></div>
</div>
</body>
</html>
看到没,先别急着动,把静态的搞定。这里用了radial-gradient做径向渐变,让球看起来有立体感,不是那种扁平的圆圈。::after伪元素加了个高光,这是细节,细节决定你是码农还是工程师。
先画几个圆,再让它们排队跳,节奏感拉满
静态的有了,现在让它们动起来。最基础的上下跳动,用transform: translateY(),千万别用top或者margin-top,那是走布局重排,卡得要死。transform是走合成层,丝滑如德芙。
/* 基础弹跳动画 */
@keyframes bounce {
0%, 100% {
transform: translateY(0); /* 起点和终点都在原位 */
}
50% {
transform: translateY(-100px); /* 中间跳到上面100像素 */
}
}
/* 给所有球加上动画 */
.ball {
/* 前面的样式不变,加上下面这句 */
animation: bounce 1s ease-in-out infinite;
}
这时候你打开页面,五个球一起上下跳,整齐得跟军训似的。但咱们要的是"涌动",是波浪,是错落有致。这就引出了下一个关键点:延迟。
cubic-bezier(0.5, 1.5, 0.5, -0.5) 这种野路子才够弹
等等,在搞延迟之前,咱们先把这个ease-in-out换了。这玩意儿太中规中矩了,像老干部散步,咱们要的是弹簧感,是那种"DuangDuang"的感觉,冲上去 Overshoot 一下,掉下来再反弹一下。
这就需要cubic-bezier,贝塞尔曲线。别被名字吓到,说白了就是四个数字控制速度曲线。默认的ease是(0.25, 0.1, 0.25, 1.0),而弹簧效果需要超过1或者小于0的值,让动画超出范围再回来。
.ball {
/* 前面的样式... */
/* 这个曲线会让球冲过头再弹回来,像真的弹簧 */
animation: bounce 1s cubic-bezier(0.68, -0.55, 0.265, 1.55) infinite;
}
cubic-bezier(0.68, -0.55, 0.265, 1.55)这个值你拿去直接用,这就是传说中的"回弹效果"。前面两个数控制起点切线,后面两个控制终点切线。负数表示先反向走一点(蓄力),超过1表示冲过头(回弹)。
如果你想更狂野,试试cubic-bezier(0.5, 1.5, 0.5, -0.5),那个1.5会让球飞得更高再砸下来,-0.5会让落地时有个小弹跳。多试几个值,浏览器开发者工具里可以直接拖曲线,比瞎蒙强。
animation-delay 配合负值,让每个球错开节奏,波浪感直接拿捏
好了,现在球跳得有弹簧味儿了,但五个还是一起动。重点来了:延迟。animation-delay这属性神就神在它可以设负值。啥意思?比如延迟-0.1秒,相当于这个动画已经开始了0.1秒,你从中间开始播。
这样设置五个球:
/* 第一个球不延迟 */
.ball:nth-child(1) {
animation-delay: 0s;
background: radial-gradient(circle at 30% 30%, #ff6b6b, #c92a2a);
}
/* 第二个球延迟0.1秒 */
.ball:nth-child(2) {
animation-delay: 0.1s;
background: radial-gradient(circle at 30% 30%, #4ecdc4, #087f5b);
}
/* 第三个球延迟0.2秒 */
.ball:nth-child(3) {
animation-delay: 0.2s;
background: radial-gradient(circle at 30% 30%, #ffe66d, #fcc419);
}
/* 第四个 */
.ball:nth-child(4) {
animation-delay: 0.3s;
background: radial-gradient(circle at 30% 30%, #a8e6cf, #69db7c);
}
/* 第五个 */
.ball:nth-child(5) {
animation-delay: 0.4s;
background: radial-gradient(circle at 30% 30%, #ff8b94, #e03131);
}
注意我不仅改了延迟,还给每个球换了颜色,这样波浪动起来的时候颜色也跟着流动,视觉效果翻倍。现在刷新页面,你看,是不是开始有那种此起彼伏的感觉了?就像水波一样,一个带动一个。
如果你想要更密的波浪,加球,把延迟间隔改成0.05秒。如果你想要慢一点的波浪,把延迟间隔拉大。这就是CSS动画的美妙之处,调参数比写代码还快。
看着炫但掉帧,手机上直接卡成PPT
别急着高兴,你现在在自己那台顶配MacBook Pro上看着挺爽,但要是拿到我那台用了三年的红米Note上,分分钟卡成幻灯片。为啥?因为你可能顺手写了box-shadow动画或者filter: blur()动画,这些属性看着帅,但都是性能杀手。
CSS动画性能有个黄金法则:只动transform和opacity。这两个属性浏览器可以走GPU加速,不触发重排重绘。其他的比如width、height、left、margin,甚至box-shadow的变化,都会让浏览器重新计算布局,然后重新渲染,在低端机上就是灾难。
所以刚才代码里的box-shadow我是放在静态样式里的,不是让你去动画它。如果你想做那种阴影随着球跳动而变化的假深度效果,别用box-shadow动画,用伪元素加opacity变化,或者干脆别做,假的弹簧感比真的卡顿强。
还有will-change这个属性,它是用来告诉浏览器:“嘿,这玩意儿马上要变了,你提前准备好”。但别滥用,用多了浏览器内存炸了更卡。一般这么写:
.ball {
will-change: transform; /* 只声明要变的属性 */
/* 动画结束后最好去掉,但在无限循环的动画里就一直挂着吧 */
}
有的安卓机对 animation 渲染抽风,得加 will-change: transform 救场
说到移动端,那真是个大坑。安卓碎片化严重,有的浏览器内核还是三年前的,对CSS3支持得稀烂。最常见的问题就是动画不流畅,或者干脆不动。
除了刚才说的will-change,还有几个救命技巧:
- 加前缀:虽然现在大部分浏览器都不需要前缀了,但保不齐哪个国产浏览器还在用旧内核。把
-webkit-、-moz-、-ms-都写上,保险。
.ball {
-webkit-animation: bounce 1s cubic-bezier(0.68, -0.55, 0.265, 1.55) infinite;
-moz-animation: bounce 1s cubic-bezier(0.68, -0.55, 0.265, 1.55) infinite;
-ms-animation: bounce 1s cubic-bezier(0.68, -0.55, 0.265, 1.55) infinite;
animation: bounce 1s cubic-bezier(0.68, -0.55, 0.265, 1.55) infinite;
-webkit-transform: translateZ(0); /* 强制开启硬件加速 */
transform: translateZ(0);
}
-
避免大渐变:有的安卓机渲染大范围的
linear-gradient或者radial-gradient会掉帧。如果你的球很大,渐变很复杂,考虑用图片代替,或者简化渐变。 -
控制数量:别在一个页面里搞一百个球同时动,移动端同时运行的CSS动画最好控制在十个以内,不然神仙也救不了。
直接在 DevTools 里调 keyframes 数值,边看边改爽翻
调试CSS动画,最傻的方法就是改代码->保存->刷新->看效果->再改。其实Chrome开发者工具(DevTools)里直接就能实时调。
打开F12,找到Elements面板,选中你的小球,在Styles面板里找到@keyframes那一块。Chrome现在支持直接在面板里改关键帧的百分比和属性值,而且改完立刻生效,不用刷新。你可以把translateY(-100px)改成translateY(-150px),看着球飞得更高,满意了再复制回代码里。
更好用的是Animation面板(如果没看到,点右上角三个点->More tools->Animations)。这里能显示页面上所有正在运行的动画时间轴,你可以拖动滑块看每一帧的状态,可以调整速度(慢放0.1倍速看清细节),甚至可以手动覆盖timing-function实时预览不同的贝塞尔曲线效果。
我一般都是先瞎蒙一个cubic-bezier值,然后在Animation面板里手动拖拽曲线,看着舒服了,把数值抄回代码。这效率比刷新页面高十倍。
鼠标一划全弹起来,或者滚到这儿才开始蹦,用户立马哇塞
纯CSS动画好是好,但有个缺点:它页面加载完就开始动,不管你用户有没有看到。要是这个动画在页面底部,用户还没 scroll 到那儿,它可能已经动完一轮了,白瞎。
这时候有两种交互方案:
方案一:Hover触发
这个简单,用:hover伪类,不需要JS:
.spring-container:hover .ball {
animation-play-state: running; /* 鼠标放上来开始动 */
}
.ball {
animation-play-state: paused; /* 默认暂停 */
/* 其他样式... */
}
但这样有个问题,鼠标移开动画就停了,而且是从头开始。想要那种鼠标移开还能保持当前状态慢慢停下来的效果,纯CSS比较难,得用animation-fill-mode,但逻辑还是别扭。
方案二:滚动触发(Scroll Trigger)
这个就得JS出手了,但别担心,不是让你写动画逻辑,是用JS监听滚动,到了位置给元素加个class,CSS负责动。
<!-- HTML结构不变,加个id方便JS找 -->
<div class="spring-container" id="springBox">
<!-- 小球们 -->
</div>
<script>
// 用 Intersection Observer API,比监听scroll事件性能高
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
// 进入视口了,给所有球加上active类
entry.target.querySelectorAll('.ball').forEach((ball, index) => {
// 甚至可以动态计算延迟,根据索引
ball.style.animationDelay = `${index * 0.1}s`;
ball.classList.add('bouncing');
});
} else {
// 离开视口可以去掉class停止动画,节省性能
entry.target.querySelectorAll('.ball').forEach(ball => {
ball.classList.remove('bouncing');
});
}
});
}, {
threshold: 0.5 // 容器进入视口50%时触发
});
observer.observe(document.getElementById('springBox'));
</script>
然后CSS改成:
.ball {
/* 基础样式... */
opacity: 0.3; /* 没动画时暗一点 */
transform: scale(0.8); /* 没动画时小一点 */
transition: all 0.3s;
}
.ball.bouncing {
animation: bounce 1s cubic-bezier(0.68, -0.55, 0.265, 1.55) infinite;
opacity: 1;
transform: scale(1);
}
这样用户滚到这儿,五个球突然亮起来开始蹦,那种"哇"的感觉就出来了。而且离开视口自动停止,省资源。
–spring-speed、–ball-size 这些变量搞起来,一套代码多处复用
写死数值是新手通病,比如width: 40px、animation-duration: 1s。万一老板说这个球太小,要改大,你得改五个地方。用CSS变量(Custom Properties)啊,这东西现在兼容性已经很好了。
在:root或者容器上定义变量:
:root {
--ball-size: 40px;
--ball-gap: 20px;
--spring-height: 100px; /* 弹跳高度 */
--spring-speed: 1s; /* 动画速度 */
--stagger-delay: 0.1s; /* 错开时间 */
--ball-color-start: #ff6b6b;
--ball-color-end: #c92a2a;
}
.spring-container {
gap: var(--ball-gap);
}
.ball {
width: var(--ball-size);
height: var(--ball-size);
background: radial-gradient(circle at 30% 30%, var(--ball-color-start), var(--ball-color-end));
animation: bounce var(--spring-speed) cubic-bezier(0.68, -0.55, 0.265, 1.55) infinite;
}
/* 延迟也可以用变量算 */
.ball:nth-child(1) { animation-delay: calc(var(--stagger-delay) * 0); }
.ball:nth-child(2) { animation-delay: calc(var(--stagger-delay) * 1); }
.ball:nth-child(3) { animation-delay: calc(var(--stagger-delay) * 2); }
.ball:nth-child(4) { animation-delay: calc(var(--stagger-delay) * 3); }
.ball:nth-child(5) { animation-delay: calc(var(--stagger-delay) * 4); }
@keyframes bounce {
0%, 100% {
transform: translateY(0);
}
50% {
transform: translateY(calc(var(--spring-height) * -1)); /* 用变量控制高度 */
}
}
现在你想改球大小,改--ball-size一个地方就行。想让它跳得更高,改--spring-height。甚至可以配合JS动态修改变量,实现用户拖动滑块控制动画速度这种高级交互。
// 用户拖了个滑块,值存在speed变量里
document.documentElement.style.setProperty('--spring-speed', speed + 's');
一行代码,所有球的动画速度全变,这就是工程化思维。
先看是不是没加 vendor 前缀,再查是不是父级 overflow:hidden 给切了
动画写了但没效果?别急,按这个清单排查:
-
拼写错误:
@keyframes写成@keyframe,animation写成aniamtion,这类手残错误我每周都犯。用VS Code的CSS智能提示能避免。 -
前缀问题:虽然2026年了,但万一你的用户还在用IE11(默哀),或者某些奇葩内嵌浏览器,
transform和animation可能需要前缀。Autoprefixer插件能自动帮你加,别手写。 -
被裁掉了:检查父元素有没有
overflow: hidden,如果小球跳起来超出了父容器高度,而父容器又有overflow: hidden,那球上半截就被切了,看着就像没跳起来。给父容器加个padding-top等于跳跃高度,或者把overflow去掉。 -
权重问题:CSS选择器权重不够,被后面的样式覆盖了。打开DevTools,看Elements面板的Computed标签,找到
animation属性,看看到底生效了没,被谁覆盖了。 -
** display问题**:
inline元素不能transform,确保你的球是block或者inline-block。div默认就是block,但如果你换成span做球,记得加display: inline-block。 -
缩写问题:
animation: bounce 1s ease这种缩写,如果后面少写了个参数,整个动画可能失效。建议分开写animation-name、animation-duration,调试时再合并。
比如根据屏幕宽度动态算 delay,这时候 JS 出手快准狠
虽然我一直强调纯CSS能搞定大部分,但有些场景确实需要JS补刀。比如响应式延迟:在大屏幕上,五个球错开0.1秒很优美;但在手机上,屏幕窄,球也少(可能变成三个),还是0.1秒延迟就显得拖沓,应该缩短到0.05秒。
纯CSS的媒体查询没法动态改animation-delay的计算基数(虽然可以用媒体查询覆盖,但麻烦)。JS一句话:
function adjustDelay() {
const width = window.innerWidth;
const balls = document.querySelectorAll('.ball');
const baseDelay = width < 768 ? 0.05 : 0.1; // 手机0.05秒,桌面0.1秒
balls.forEach((ball, index) => {
ball.style.animationDelay = `${index * baseDelay}s`;
});
}
window.addEventListener('resize', adjustDelay);
adjustDelay(); // 初始化先跑一次
还有那种需要根据API返回数据决定有多少个球的场景。比如音乐播放器,根据音频频率生成不同数量的音柱在跳动,这肯定得JS动态创建元素并设置延迟。但动画本身还是CSS在做,JS只负责算数和DOM操作,这叫"各司其职"。
比如把弹簧改成爱心形状、或者颜色随节奏变,朋友圈点赞收割机
基础玩法会了,来点骚的。把圆形改成爱心?别用图片,用CSS画,然后用同样的动画:
/* 爱心形状怎么画?伪元素旋转45度拼出来 */
.heart {
position: relative;
width: var(--ball-size);
height: var(--ball-size);
background: var(--ball-color-start);
transform: rotate(-45deg); /* 先转过来 */
animation: bounce 1s cubic-bezier(0.68, -0.55, 0.265, 1.55) infinite;
}
.heart::before,
.heart::after {
content: '';
position: absolute;
width: 100%;
height: 100%;
background: var(--ball-color-start);
border-radius: 50%;
}
.heart::before {
top: -50%;
left: 0;
}
.heart::after {
top: 0;
right: -50%;
}
/* 注意:爱心跳的时候可能和球的方向不太一样,需要调整keyframes */
@keyframes heartBounce {
0%, 100% {
transform: rotate(-45deg) translateY(0) scale(1);
}
50% {
transform: rotate(-45deg) translateY(-100px) scale(1.1); /* 跳得时候稍微变大一点更有弹性 */
}
}
颜色随节奏变?用filter: hue-rotate()动画,一行代码搞定彩虹色:
.ball {
animation:
bounce 1s cubic-bezier(0.68, -0.55, 0.265, 1.55) infinite,
rainbow 3s linear infinite; /* 同时跑两个动画 */
}
@keyframes rainbow {
0% { filter: hue-rotate(0deg); }
100% { filter: hue-rotate(360deg); }
}
这样球在跳的同时颜色还在渐变,骚气冲天。filter性能开销比直接改background-color小,而且效果更炫。
还有3D版本,把容器设个perspective,然后小球不是上下跳,是绕着X轴转,像波浪一样起伏:
.spring-container {
perspective: 500px;
transform-style: preserve-3d;
}
.ball {
animation: wave 2s ease-in-out infinite;
}
@keyframes wave {
0%, 100% {
transform: rotateX(0deg) translateZ(0);
}
50% {
transform: rotateX(30deg) translateZ(50px); /* 3D起伏 */
}
}
反正核心思路就是:形状用CSS画或者变,运动用@keyframes定义,节奏用animation-delay控制,视觉效果用filter和transform叠加。这几个组合拳打下来,没有你搞不定的loading效果。
最后送你个终极版代码,把今天说的所有技巧都整合进去了,拿去直接用,或者改改参数交差:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>终极弹簧特效</title>
<style>
:root {
--ball-size: clamp(20px, 5vw, 50px); /* 响应式大小 */
--spring-height: clamp(50px, 10vw, 100px);
--spring-speed: 0.8s;
--stagger-delay: 0.08s;
--primary-color: #ff6b6b;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
min-height: 100vh;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
display: flex;
justify-content: center;
align-items: center;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
}
.stage {
display: flex;
gap: 15px;
align-items: flex-end;
height: 200px;
padding: 40px;
background: rgba(255,255,255,0.1);
backdrop-filter: blur(10px);
border-radius: 20px;
box-shadow: 0 8px 32px rgba(0,0,0,0.1);
}
.blob {
width: var(--ball-size);
height: var(--ball-size);
background: var(--primary-color);
border-radius: 50%;
position: relative;
/* 硬件加速三件套 */
will-change: transform;
transform: translateZ(0);
backface-visibility: hidden;
animation: spring var(--spring-speed) cubic-bezier(0.68, -0.55, 0.265, 1.55) infinite;
/* 默认暂停,等JS或hover触发 */
animation-play-state: paused;
}
/* 伪元素做拖尾效果 */
.blob::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: inherit;
border-radius: inherit;
opacity: 0.3;
transform: scale(1);
animation: trail var(--spring-speed) ease-out infinite;
animation-play-state: paused;
}
.blob.active,
.blob.active::before {
animation-play-state: running;
}
/* 每个球的延迟和颜色 */
.blob:nth-child(1) {
animation-delay: 0s;
background: #ff6b6b;
}
.blob:nth-child(2) {
animation-delay: var(--stagger-delay);
background: #4ecdc4;
}
.blob:nth-child(3) {
animation-delay: calc(var(--stagger-delay) * 2);
background: #ffe66d;
}
.blob:nth-child(4) {
animation-delay: calc(var(--stagger-delay) * 3);
background: #a8e6cf;
}
.blob:nth-child(5) {
animation-delay: calc(var(--stagger-delay) * 4);
background: #ff8b94;
}
@keyframes spring {
0%, 100% {
transform: translateY(0) scale(1);
filter: brightness(1);
}
50% {
transform: translateY(calc(var(--spring-height) * -1)) scale(0.9, 1.1);
filter: brightness(1.2);
}
}
@keyframes trail {
0%, 100% { transform: scale(1); opacity: 0.3; }
50% { transform: scale(1.5); opacity: 0; }
}
/* 控制按钮样式 */
.controls {
position: fixed;
bottom: 30px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 10px;
}
button {
padding: 10px 20px;
border: none;
border-radius: 25px;
background: white;
color: #764ba2;
font-weight: bold;
cursor: pointer;
box-shadow: 0 4px 15px rgba(0,0,0,0.2);
transition: transform 0.1s;
}
button:active {
transform: scale(0.95);
}
@media (max-width: 600px) {
:root {
--stagger-delay: 0.05s;
}
.stage {
padding: 20px;
gap: 10px;
}
}
</style>
</head>
<body>
<div class="stage" id="stage">
<div class="blob"></div>
<div class="blob"></div>
<div class="blob"></div>
<div class="blob"></div>
<div class="blob"></div>
</div>
<div class="controls">
<button onclick="toggleAnimation()">开始/暂停</button>
<button onclick="changeColor()">换色</button>
</div>
<script>
// 简单的交互控制
function toggleAnimation() {
document.querySelectorAll('.blob').forEach(blob => {
blob.classList.toggle('active');
});
}
// 随机换主题色
function changeColor() {
const colors = ['#ff6b6b', '#4ecdc4', '#ffe66d', '#a8e6cf', '#ff8b94', '#c7ceea'];
const randomColor = colors[Math.floor(Math.random() * colors.length)];
document.documentElement.style.setProperty('--primary-color', randomColor);
}
// 自动开始
setTimeout(toggleAnimation, 500);
// 响应式调整延迟
window.addEventListener('resize', () => {
const width = window.innerWidth;
const newDelay = width < 600 ? '0.05s' : '0.08s';
document.documentElement.style.setProperty('--stagger-delay', newDelay);
});
</script>
</body>
</html>
这段代码囊括了:CSS变量、响应式、硬件加速、伪元素拖尾、JS交互、媒体查询。拿去改吧改吧,够你水三篇技术博客了。
记住,CSS动画这玩意儿,原理简单,但细节决定成败。多调cubic-bezier,多试animation-delay的组合,你也能做出让人眼前一亮的效果。别老想着上框架,有时候原生的才是最能打。
欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。
推荐:DTcode7的博客首页。
一个做过前端开发的产品经理,经历过睿智产品的折磨导致脱发之后,励志要翻身农奴把歌唱,一边打入敌人内部一边持续提升自己,为我们广大开发同胞谋福祉,坚决抵制睿智产品折磨我们码农兄弟!
| 专栏系列(点击解锁) | 学习路线(点击解锁) | 知识定位 |
|---|---|---|
| 《微信小程序相关博客》 | 持续更新中~ | 结合微信官方原生框架、uniapp等小程序框架,记录请求、封装、tabbar、UI组件的学习记录和使用技巧等 |
| 《AIGC相关博客》 | 持续更新中~ | AIGC、AI生产力工具的介绍,例如stable diffusion这种的AI绘画工具安装、使用、技巧等总结 |
| 《HTML网站开发相关》 | 《前端基础入门三大核心之html相关博客》 | 前端基础入门三大核心之html板块的内容,入坑前端或者辅助学习的必看知识 |
| 《前端基础入门三大核心之JS相关博客》 | 前端JS是JavaScript语言在网页开发中的应用,负责实现交互效果和动态内容。它与HTML和CSS并称前端三剑客,共同构建用户界面。 通过操作DOM元素、响应事件、发起网络请求等,JS使页面能够响应用户行为,实现数据动态展示和页面流畅跳转,是现代Web开发的核心 | |
| 《前端基础入门三大核心之CSS相关博客》 | 介绍前端开发中遇到的CSS疑问和各种奇妙的CSS语法,同时收集精美的CSS效果代码,用来丰富你的web网页 | |
| 《canvas绘图相关博客》 | Canvas是HTML5中用于绘制图形的元素,通过JavaScript及其提供的绘图API,开发者可以在网页上绘制出各种复杂的图形、动画和图像效果。Canvas提供了高度的灵活性和控制力,使得前端绘图技术更加丰富和多样化 | |
| 《Vue实战相关博客》 | 持续更新中~ | 详细总结了常用UI库elementUI的使用技巧以及Vue的学习之旅 |
| 《python相关博客》 | 持续更新中~ | Python,简洁易学的编程语言,强大到足以应对各种应用场景,是编程新手的理想选择,也是专业人士的得力工具 |
| 《sql数据库相关博客》 | 持续更新中~ | SQL数据库:高效管理数据的利器,学会SQL,轻松驾驭结构化数据,解锁数据分析与挖掘的无限可能 |
| 《算法系列相关博客》 | 持续更新中~ | 算法与数据结构学习总结,通过JS来编写处理复杂有趣的算法问题,提升你的技术思维 |
| 《IT信息技术相关博客》 | 持续更新中~ | 作为信息化人员所需要掌握的底层技术,涉及软件开发、网络建设、系统维护等领域的知识 |
| 《信息化人员基础技能知识相关博客》 | 无论你是开发、产品、实施、经理,只要是从事信息化相关行业的人员,都应该掌握这些信息化的基础知识,可以不精通但是一定要了解,避免日常工作中贻笑大方 | |
| 《信息化技能面试宝典相关博客》 | 涉及信息化相关工作基础知识和面试技巧,提升自我能力与面试通过率,扩展知识面 | |
| 《前端开发习惯与小技巧相关博客》 | 持续更新中~ | 罗列常用的开发工具使用技巧,如 Vscode快捷键操作、Git、CMD、游览器控制台等 |
| 《photoshop相关博客》 | 持续更新中~ | 基础的PS学习记录,含括PPI与DPI、物理像素dp、逻辑像素dip、矢量图和位图以及帧动画等的学习总结 |
| 日常开发&办公&生产【实用工具】分享相关博客》 | 持续更新中~ | 分享介绍各种开发中、工作中、个人生产以及学习上的工具,丰富阅历,给大家提供处理事情的更多角度,学习了解更多的便利工具,如Fiddler抓包、办公快捷键、虚拟机VMware等工具 |
吾辈才疏学浅,摹写之作,恐有瑕疵。望诸君海涵赐教。望轻喷,嘤嘤嘤
非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。愿斯文对汝有所裨益,纵其简陋未及渊博,亦足以略尽绵薄之力。倘若尚存阙漏,敬请不吝斧正,俾便精进!

&spm=1001.2101.3001.5002&articleId=157582255&d=1&t=3&u=a74159aa01794c088801aa03349039c2)
2万+

被折叠的 条评论
为什么被折叠?



