TML新手别慌:用CSS搞定超酷涌动弹簧特效(附实战套路)

在这里插入图片描述

HTML新手别慌:用CSS搞定超酷涌动弹簧特效(附实战套路)

这玩意儿真不是动效大佬专属

说真的,我刚入行那会儿,看到那些花里胡哨的动画效果,第一反应就是:“这得用Canvas吧?或者至少得来个WebGL?再不济也得写个几斤重的JS库?”

结果呢,翻开源码一看,卧槽,就是几个div加上几行CSS。当时我就感觉自己像个傻子,拿着大炮打蚊子打惯了,突然有人告诉我其实用弹弓就能搞定。

所以先给诸位新手吃个定心丸:别被那些"前端动画工程师"的title吓到,什么涌动的弹簧、波浪loading、弹性菜单,纯CSS完全能抡得动。你今天看完这篇,明天就能在你那个满是表格的后台管理系统里偷偷塞一个,惊艳(吓)你的产品经理。

HTML和CSS到底能玩出啥花样

别再以为HTML只是写个div就完事了。是,它确实主要是写div,但关键是你得让这个div动起来,而且是那种看起来有物理感的动。

我知道很多人写CSS就停留在color: redfont-size: 16px这种静态属性上,觉得动画是JS的活儿。兄弟,这都2026年了,CSS早就不是那个只会打扮页面的花瓶了。现在的CSS3,尤其是@keyframestransform这对黄金搭档,玩起动画来比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动画性能有个黄金法则:只动transformopacity。这两个属性浏览器可以走GPU加速,不触发重排重绘。其他的比如widthheightleftmargin,甚至box-shadow的变化,都会让浏览器重新计算布局,然后重新渲染,在低端机上就是灾难。

所以刚才代码里的box-shadow我是放在静态样式里的,不是让你去动画它。如果你想做那种阴影随着球跳动而变化的假深度效果,别用box-shadow动画,用伪元素加opacity变化,或者干脆别做,假的弹簧感比真的卡顿强。

还有will-change这个属性,它是用来告诉浏览器:“嘿,这玩意儿马上要变了,你提前准备好”。但别滥用,用多了浏览器内存炸了更卡。一般这么写:

.ball {
    will-change: transform; /* 只声明要变的属性 */
    /* 动画结束后最好去掉,但在无限循环的动画里就一直挂着吧 */
}

有的安卓机对 animation 渲染抽风,得加 will-change: transform 救场

说到移动端,那真是个大坑。安卓碎片化严重,有的浏览器内核还是三年前的,对CSS3支持得稀烂。最常见的问题就是动画不流畅,或者干脆不动。

除了刚才说的will-change,还有几个救命技巧:

  1. 加前缀:虽然现在大部分浏览器都不需要前缀了,但保不齐哪个国产浏览器还在用旧内核。把-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);
}
  1. 避免大渐变:有的安卓机渲染大范围的linear-gradient或者radial-gradient会掉帧。如果你的球很大,渐变很复杂,考虑用图片代替,或者简化渐变。

  2. 控制数量:别在一个页面里搞一百个球同时动,移动端同时运行的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: 40pxanimation-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 给切了

动画写了但没效果?别急,按这个清单排查:

  1. 拼写错误@keyframes写成@keyframeanimation写成aniamtion,这类手残错误我每周都犯。用VS Code的CSS智能提示能避免。

  2. 前缀问题:虽然2026年了,但万一你的用户还在用IE11(默哀),或者某些奇葩内嵌浏览器,transformanimation可能需要前缀。Autoprefixer插件能自动帮你加,别手写。

  3. 被裁掉了:检查父元素有没有overflow: hidden,如果小球跳起来超出了父容器高度,而父容器又有overflow: hidden,那球上半截就被切了,看着就像没跳起来。给父容器加个padding-top等于跳跃高度,或者把overflow去掉。

  4. 权重问题:CSS选择器权重不够,被后面的样式覆盖了。打开DevTools,看Elements面板的Computed标签,找到animation属性,看看到底生效了没,被谁覆盖了。

  5. ** display问题**:inline元素不能transform,确保你的球是block或者inline-blockdiv默认就是block,但如果你换成span做球,记得加display: inline-block

  6. 缩写问题animation: bounce 1s ease这种缩写,如果后面少写了个参数,整个动画可能失效。建议分开写animation-nameanimation-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控制,视觉效果用filtertransform叠加。这几个组合拳打下来,没有你搞不定的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等工具

吾辈才疏学浅,摹写之作,恐有瑕疵。望诸君海涵赐教。望轻喷,嘤嘤嘤

非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。愿斯文对汝有所裨益,纵其简陋未及渊博,亦足以略尽绵薄之力。倘若尚存阙漏,敬请不吝斧正,俾便精进!

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DTcode7

客官,赏个铜板吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值