尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

六个HTML动态背景源码实战:从嵌入到性能优化

六个HTML动态背景源码实战:从嵌入到性能优化 简介这是一份面向前端开发者与网页设计爱好者的HTML动态背景效果源码合集针对页面视觉表现力不足、背景单调的问题提供可直接嵌入项目的现成方案。包内共44个文件涵盖14个html示例页、8个css样式表、4个js脚本以及9张png、7个gif和1个ico等图片素材压缩包约46.74MB结构清晰、便于按效果逐个查阅与复用。资源包含五种酷炫动态背景图片轮动、星空流星、动态美女、动态屋雨、动态街道与动态夜幕等场景每种效果均配有独立页面与配套样式脚本方便对照修改参数、替换素材。目前已有5961人学习下载适合需要快速提升页面氛围感、制作活动页或个人主页的初中级前端开发者参考借鉴。1. 六个能直接嵌进项目的 HTML 动态背景这套源码到底值不值得拆上周帮朋友改一个后台管理系统的登录页设计稿要求背景得有“呼吸感”不能是一张死气沉沉的静态图。我第一反应是上 Canvas 手写粒子结果调了俩小时性能没压住低端安卓机上直接掉到 20 帧。后来翻出这套html多个好看的背景动态效果(附源码).zip六个独立页面每个都是纯 HTML CSS JS没有构建工具没有 npm 依赖双击就能跑。它解决的不是“从零造轮子”的问题而是“快速验证视觉方案、直接抠代码嵌进现有项目”的问题。适合谁前端切图仔、全栈但不想在动效上耗时间的后端、还有做课程设计需要交 HTML 网页综合项目实战的学生。你不需要懂 WebGL只要会改 CSS 变量和 JS 里的几个参数就能把星空流星、雨打屋檐、夜幕街道这些效果搬到自己的登录页、大屏或者个人主页上。2. 拆包看结构六个效果怎么组织资源目录为什么这么摆拿到压缩包先别急着双击 index.html花两分钟把目录结构过一遍后面改代码能省一半时间。解压后根目录下是index.html到index6.html六个入口文件外加一个好的前后端资源源码.html作为导航页。css文件夹里只有一个index.cssjs文件夹里只有一个index.jsimg文件夹塞了1.png到6.png以及2.gif、4.gif这些素材resource下面按bg1到bg6分了六个子目录。这个结构说明作者是刻意把公共样式和脚本抽出来复用每个效果靠页面上的类名或 data 属性来切换。2.1 入口文件与资源映射关系先看index.html的头部它引的是css/index.css和js/index.js然后 body 上挂了一个类似classbg-star的标识。六个页面共用同一套 CSS 和 JS区别只在 body 的类名和resource下加载的图片路径。我一般会先打开readme.txt扫一眼里面写了每个效果对应的页面编号和大致原理虽然写得简略但能帮你快速定位到想抄的那个。!-- index.html 精简后的结构重点看 body 的 class 和资源引用 -- !DOCTYPE html html langzh-cn head meta charsetutf-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title动态背景效果/title link relstylesheet hrefcss/index.css /head body classbg-star !-- 星空流星效果canvas 由 js/index.js 动态插入 -- script srcjs/index.js/script /body /html这段代码里最关键的是body classbg-star。index.js在 DOMContentLoaded 之后会读取这个类名然后决定初始化哪套动画逻辑。如果你想把星空效果嵌到自己的项目里最省事的做法不是把整个index.js搬过去而是找到bg-star对应的那个初始化函数把里面创建 canvas、设置粒子数量、绑定 resize 的那几十行抠出来。参数说明bg-star控制流星密度和拖尾长度bg-rain控制雨滴下落速度和倾斜角bg-street控制灯光闪烁频率。这些在 JS 里都是硬编码的数字改起来没有玄学改完刷新就能看到。2.2 公共 CSS 与独立效果的边界css/index.css里大部分是 reset 和布局辅助类真正跟动态背景相关的样式集中在文件末尾。作者用body.bg-xxx的选择器把每个效果的容器定位、层级、透明度隔离开。比如星空效果会把 canvas 设为position: fixed; top: 0; left: 0; z-index: -1;而雨滴效果用的是多个绝对定位的 div 加 CSS animation。这里有个血泪经验如果你直接复制index.css全文到自己项目记得检查body的overflow和margin作者为了演示效果把滚动条隐藏了嵌到内容页里会导致页面滚不动。/* index.css 中与动态背景相关的片段注意 z-index 和 pointer-events */ body.bg-star canvas { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; z-index: -1; pointer-events: none; /* 防止 canvas 挡住按钮点击 */ } body.bg-rain .rain-drop { position: absolute; width: 2px; height: 80px; background: linear-gradient(transparent, rgba(174, 194, 224, 0.6)); animation: fall linear infinite; }pointer-events: none这行是必须的少了它你的登录按钮、输入框全点不动这是新手最容易翻车的地方。z-index: -1也要配合父容器的position使用如果父级有transform或者filterfixed 定位会失效canvas 会跟着页面滚。我一般会先把背景层单独放在一个div里给它position: fixed; inset: 0; z-index: 0;然后把内容层设为position: relative; z-index: 1;这样层级关系最稳。3. 把星空流星效果嵌进登录页参数怎么调性能怎么压星空流星是六个效果里最讨喜的也是我实际用得最多的一个。它的原理不复杂一个全屏 canvas上面画几百个静态星点再随机生成几颗流星流星带拖尾用requestAnimationFrame逐帧擦除重绘。难点不在写而在调参和性能。默认配置在 1080p 屏幕上跑 60 帧没问题但如果你嵌到已经有大量 DOM 的页面里或者用户用的是几年前的千元机就得动手改。3.1 从 index.js 里抠出星空初始化逻辑打开js/index.js搜索bg-star或者star能找到类似下面这段。我把它精简了一下保留了核心的粒子创建和动画循环去掉了作者写的兼容性判断。// 星空流星核心逻辑从 index.js 中提取并简化 function initStarBackground() { const canvas document.createElement(canvas); document.body.appendChild(canvas); const ctx canvas.getContext(2d); let width canvas.width window.innerWidth; let height canvas.height window.innerHeight; // 参数区星星数量、流星速度、拖尾长度 const STAR_COUNT 200; // 星星数量低端机降到 80 const METEOR_SPEED 4; // 流星移动速度越大越快 const TRAIL_LENGTH 20; // 拖尾长度越大尾巴越长 const stars []; for (let i 0; i STAR_COUNT; i) { stars.push({ x: Math.random() * width, y: Math.random() * height, radius: Math.random() * 1.5, alpha: Math.random() * 0.8 0.2 }); } const meteors []; function createMeteor() { meteors.push({ x: Math.random() * width, y: -50, len: Math.random() * 80 40, speed: Math.random() * METEOR_SPEED 2 }); } function draw() { // 用半透明黑色覆盖形成拖尾效果 ctx.fillStyle rgba(0, 0, 0, 0.1); ctx.fillRect(0, 0, width, height); // 画星星 stars.forEach(s { ctx.beginPath(); ctx.arc(s.x, s.y, s.radius, 0, Math.PI * 2); ctx.fillStyle rgba(255, 255, 255, ${s.alpha}); ctx.fill(); }); // 画流星 meteors.forEach((m, index) { ctx.beginPath(); ctx.moveTo(m.x, m.y); ctx.lineTo(m.x - m.len, m.y - m.len); ctx.strokeStyle rgba(255, 255, 255, 0.8); ctx.lineWidth 2; ctx.stroke(); m.x m.speed; m.y m.speed; // 超出屏幕就移除 if (m.y height 100) { meteors.splice(index, 1); } }); // 随机生成新流星 if (Math.random() 0.02) { createMeteor(); } requestAnimationFrame(draw); } draw(); // 窗口大小变化时重置 canvas 尺寸 window.addEventListener(resize, () { width canvas.width window.innerWidth; height canvas.height window.innerHeight; }); }逻辑说明ctx.fillStyle rgba(0, 0, 0, 0.1)这行是拖尾的关键它不直接清空画布而是盖一层半透明黑上一帧的流星残影会慢慢淡出形成尾巴。参数说明STAR_COUNT直接决定 CPU 绘制压力200 个星星在桌面端无感但如果你页面里还有别的动画建议降到 80 到 120。METEOR_SPEED和TRAIL_LENGTH是视觉参数调大流星更猛调小更含蓄。Math.random() 0.02控制流星生成频率0.02 大概每秒冒一两颗改成 0.05 会密集很多。3.2 性能压测与降级策略把这段代码嵌进登录页后我用 Chrome DevTools 的 Performance 面板录了 10 秒发现主要开销在ctx.arc和ctx.stroke的调用次数上。星星数量 200 时每帧大约 200 次 arc 加几次 stroke帧率稳定在 60。但如果在低端安卓机上跑帧率会掉到 35 左右。我的降级策略是先检测navigator.hardwareConcurrency小于 4 就把STAR_COUNT砍半再监听requestAnimationFrame的实际间隔如果连续 10 帧超过 30ms就动态减少流星生成概率。这套逻辑不用写得太复杂几行判断就能兜住。// 简易性能降级根据 CPU 核心数和帧间隔动态调整 const isLowEnd navigator.hardwareConcurrency navigator.hardwareConcurrency 4; const STAR_COUNT isLowEnd ? 80 : 200; let lastTime performance.now(); let slowFrames 0; function checkPerformance(now) { const delta now - lastTime; lastTime now; if (delta 30) { slowFrames; if (slowFrames 10) { // 降级减少流星生成概率 meteorProbability 0.005; } } else { slowFrames 0; } requestAnimationFrame(checkPerformance); }注意hardwareConcurrency在部分浏览器里返回的是逻辑核心数不一定准所以只作为第一道判断。真正靠谱的还是看帧间隔。另外如果你的页面是后台管理系统用户可能长时间挂着不关记得在visibilitychange事件里暂停动画切回标签页再恢复不然电池扛不住。4. 雨滴、夜幕、街道三个效果的 CSS 变量改造与复用星空是 canvas 方案雨滴和夜幕街道则是 DOM CSS 方案。这两种方案各有各的坑。DOM 方案的好处是可以用 CSS 变量统一控制颜色、速度、密度改起来比 canvas 直观坏处是元素多了之后浏览器的重排重绘压力比 canvas 大。我一般会把雨滴效果用在内容页的背景因为它对 CPU 占用低而且雨滴的倾斜角可以跟着页面滚动做微调视觉上更自然。4.1 用 CSS 自定义属性统一控制雨滴参数原版index.css里雨滴的样式是写死的颜色是固定的淡蓝色下落速度也是固定值。我把它改成了 CSS 变量这样嵌到不同项目里只要覆盖几个变量就能换风格。/* 改造后的雨滴样式用 CSS 变量控制参数 */ :root { --rain-color: rgba(174, 194, 224, 0.6); --rain-speed: 0.8s; --rain-angle: 15deg; --rain-count: 50; } body.bg-rain .rain-container { position: fixed; inset: 0; z-index: -1; pointer-events: none; overflow: hidden; } body.bg-rain .rain-drop { position: absolute; top: -100px; width: 2px; height: 80px; background: linear-gradient(transparent, var(--rain-color)); transform: rotate(var(--rain-angle)); animation: fall var(--rain-speed) linear infinite; } keyframes fall { to { transform: translateY(100vh) rotate(var(--rain-angle)); } }逻辑说明--rain-speed控制单滴雨的下落周期值越小雨越急。--rain-angle控制倾斜角配合transform: rotate让雨滴斜着下。--rain-count不是 CSS 能直接用的需要在 JS 里读取这个变量然后动态生成对应数量的.rain-drop元素。参数说明雨滴数量建议控制在 30 到 80 之间超过 100 在移动端会明显卡顿。每滴雨的animation-delay用Math.random()打散不然所有雨滴会同步下落看起来像一堵墙在移动很假。// 根据 CSS 变量生成雨滴元素 function initRain() { const container document.createElement(div); container.className rain-container; document.body.appendChild(container); const count parseInt(getComputedStyle(document.documentElement) .getPropertyValue(--rain-count)) || 50; for (let i 0; i count; i) { const drop document.createElement(div); drop.className rain-drop; drop.style.left Math.random() * 100 vw; drop.style.animationDelay Math.random() * 2 s; drop.style.animationDuration (Math.random() * 0.5 0.5) s; container.appendChild(drop); } }这段代码里animationDuration的随机化很重要它让每滴雨的速度略有差异看起来更自然。left用vw单位保证在不同屏幕宽度下雨滴分布均匀。注意如果你在页面里用了transform做整体缩放position: fixed会失效雨滴容器会跟着内容滚这时候要把容器改成position: absolute并挂到最外层。4.2 夜幕街道效果的图片轮动与层级管理夜幕街道效果本质上是多张背景图叠加配合 CSS 动画做缓慢位移和透明度变化模拟灯光闪烁和车流。resource/bg5和bg6里放的就是这些图层素材。原版用img标签直接堆在 body 里层级靠z-index硬编码。我建议改成background-image加background-blend-mode这样更容易控制混合模式也方便做响应式。/* 夜幕街道多图层叠加 */ body.bg-street .street-layer { position: fixed; inset: 0; z-index: -1; background-size: cover; background-position: center; animation: streetMove 20s linear infinite alternate; } body.bg-street .street-layer:nth-child(1) { background-image: url(../resource/bg5/street-base.png); opacity: 0.9; } body.bg-street .street-layer:nth-child(2) { background-image: url(../resource/bg5/street-lights.png); opacity: 0.6; animation-duration: 15s; } keyframes streetMove { from { transform: scale(1) translateX(0); } to { transform: scale(1.05) translateX(-20px); } }逻辑说明两层背景图底层是街道基础图上层是灯光图用不同的animation-duration让它们错开移动产生视差感。scale(1.05)是为了避免移动时边缘露白。参数说明animation-duration越大移动越慢20s 到 30s 比较合适太快会晕。opacity控制图层混合程度灯光层透明度低一点更柔和。注意图片素材如果太大记得用 TinyPNG 压一下原包里bg5的图有几张超过 1MB直接上线会影响首屏加载。5. 避坑与排查六个效果嵌进真实项目时最容易翻车的五件事这套源码在演示页里跑得很顺但一旦嵌到真实项目各种问题就冒出来了。下面这五条是我和身边同事踩过的坑每条都按现象、原因、解决来写你遇到类似情况可以直接对号入座。5.1 现象背景把按钮和输入框全挡住了点不动原因canvas 或背景容器没有设置pointer-events: none或者z-index设成了正值盖在了内容层上面。原版演示页没有交互元素所以作者没暴露这个问题。解决给所有动态背景容器加pointer-events: none;并把z-index设为-1或0同时确保内容层的z-index比它高。如果父级有transform改用position: absolute并挂到 body 直接子级。5.2 现象页面滚动时背景跟着滚或者背景只覆盖首屏原因position: fixed在父级有transform、filter、perspective属性时会降级为absolute导致背景跟着内容滚。另外如果背景容器高度设的是100vh在移动端浏览器地址栏收起时会出现空白。解决把背景容器直接挂在body下避免嵌套在带transform的父级里。高度用100%配合html, body { height: 100%; }或者用inset: 0加position: fixed。移动端可以用100dvh替代100vh兼容性现在已经很好了。5.3 现象低端安卓机上动画卡顿帧率掉到 20 以下原因星星数量或雨滴数量太多每帧的绘制调用次数超出 GPU 和 CPU 的处理能力。另外requestAnimationFrame在后台标签页里不会暂停长时间挂着会持续消耗资源。解决按 3.2 节的降级策略根据hardwareConcurrency和帧间隔动态减少粒子数量。监听visibilitychange事件页面隐藏时cancelAnimationFrame显示时重新启动。雨滴效果优先用 CSS animation浏览器会自动合成层比 JS 逐帧改top性能好。5.4 现象图片轮动效果在 Safari 上闪烁或者图片加载顺序错乱原因Safari 对background-image的渲染和opacity动画配合时有已知的闪烁问题尤其是多图层叠加时。另外如果图片没有预加载轮动到下一张时会出现短暂空白。解决给背景图层加will-change: transform, opacity;提升为合成层减少闪烁。图片预加载用new Image()提前加载所有素材或者用 CSSpreload提示。如果还是闪把opacity动画改成transform: scale配合filter: brightness避开 Safari 的 opacity 合成 bug。5.5 现象把代码复制到自己项目后样式全乱了原因原版index.css里有全局的body样式和 reset直接复制会覆盖你项目里的基础样式。另外类名如.container、.layer太通用容易和现有样式冲突。解决不要整个文件复制只抠跟动态背景相关的选择器。把body.bg-xxx改成你自己项目的命名空间比如.myapp-bg-star。CSS 变量定义在:root里也要检查是否和现有变量重名。最稳妥的做法是把背景效果封装成一个独立的div所有样式都限定在这个div内部不污染全局。6. 进阶把六个效果封装成一个可配置的背景组件如果你不止在一个页面用这套效果或者团队里其他人也想用手动复制粘贴迟早会乱。我的习惯是把它封装成一个轻量的 JS 组件通过data属性或者配置对象来切换效果和参数。这样既保留了源码的零依赖特性又有了复用性。// 简易背景组件封装支持效果切换和参数覆盖 class DynamicBackground { constructor(options {}) { this.type options.type || star; // star / rain / street / night this.container options.container || document.body; this.params Object.assign({ starCount: 200, meteorSpeed: 4, rainCount: 50, rainColor: rgba(174, 194, 224, 0.6) }, options.params); this.init(); } init() { switch (this.type) { case star: this.initStar(); break; case rain: this.initRain(); break; case street: this.initStreet(); break; default: console.warn(未知的背景类型:, this.type); } } initStar() { // 复用第 3 章的星空逻辑参数从 this.params 读取 const canvas document.createElement(canvas); canvas.style.cssText position:fixed;inset:0;z-index:-1;pointer-events:none;; this.container.appendChild(canvas); // ... 后续绘制逻辑 } initRain() { // 复用第 4 章的雨滴逻辑 const container document.createElement(div); container.className rain-container; container.style.cssText position:fixed;inset:0;z-index:-1;pointer-events:none;; this.container.appendChild(container); // ... 生成雨滴 } destroy() { // 清理 canvas 和 DOM防止内存泄漏 const bg this.container.querySelector(canvas, .rain-container); if (bg) bg.remove(); } } // 使用示例 const bg new DynamicBackground({ type: star, params: { starCount: 120, meteorSpeed: 3 } });逻辑说明constructor接收效果类型和参数init根据类型分发到不同的初始化方法。destroy方法用于页面切换时清理资源避免 canvas 和事件监听器残留。参数说明starCount和meteorSpeed对应星空效果rainCount和rainColor对应雨滴效果。如果你用的是 Vue 或 React可以把这套逻辑包在onMounted和onUnmounted里效果一样。验证方法封装完之后我一般会写一个简单的测试页把六种效果都实例化一遍然后快速切换看有没有内存泄漏或者样式冲突。Chrome DevTools 的 Memory 面板拍两次快照对比Detached DOM数量如果切换十次之后 detached 节点持续增长说明destroy没清干净。另外用 Lighthouse 跑一下性能分确保背景效果没有把 LCP 拖垮。从那以后我每次嵌动态背景都强制先跑一遍pointer-events检查和低端机降级再好看的动效点不动按钮就是事故。希望帮到你。本文还有配套的精品资源点击获取
返回列表