从Codepen移植的CSS与JavaScript动画无法运行问题排查
Let's break down the issues stopping your animation from running and walk through the fixes:
1. Missing GSAP Library Dependency
The biggest issue is that your code uses TweenLite (from the GSAP animation library) to animate the floating points, but you haven't included GSAP in your HTML page. Without this library, the browser doesn't recognize TweenLite, so the shiftPoint function (which drives the core movement) fails silently (or throws an error in the console).
Fix: Add GSAP to Your Page
Include the GSAP Core library via CDN in your <head> section. This gives you access to TweenLite and the Circ easing function needed for the animation:
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/gsap.min.js"></script>
(Note: Newer GSAP versions still support TweenLite as an alias, so this works seamlessly with your existing code.)
2. Unclosed HTML Tags
Your <h1> element has mismatched <span> tags, which can cause DOM parsing issues that might indirectly affect script behavior:
<!-- Before (broken) --> <h1 class="main-title"><span class="thin">TitleGoes <span class="thin">.here</h1> <!-- After (fixed) --> <h1 class="main-title"><span class="thin">TitleGoes</span> <span class="thin">.here</span></h1>
3. Missing Initial active Property in Circle Class
The Circle class's draw method checks for an active property, but this isn't initialized in the constructor. Adding it prevents potential undefined value warnings:
// Inside the Circle constructor function (function() { _this.pos = pos || null; _this.radius = rad || null; _this.color = color || null; _this.active = 0; // Add this line to initialize the active property })();
Full Fixed Code
Here's the complete corrected HTML with all fixes applied:
<html> <head> <style> /* Header */ .large-header { position: relative; width: 100%; background: #333; overflow: hidden; background-size: cover; background-position: center center; z-index: 1; } #large-header { background-image: url("https://www.marcoguglie.it/Codepen/AnimatedHeaderBg/demo-1/img/demo-1-bg.jpg"); } .main-title { position: absolute; margin: 0; padding: 0; color: #f9f1e9; text-align: center; top: 50%; left: 50%; -webkit-transform: translate3d(-50%, -50%, 0); transform: translate3d(-50%, -50%, 0); } .demo-1 .main-title { text-transform: uppercase; font-size: 4.2em; letter-spacing: 0.1em; } .main-title .thin { font-weight: 200; } @media only screen and (max-width: 768px) { .demo-1 .main-title { font-size: 3em; } } </style> <!-- Add GSAP Library --> <script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/gsap.min.js"></script> </head> <body> <div id="large-header" class="large-header"> <canvas id="demo-canvas"></canvas> <!-- Fixed span tags --> <h1 class="main-title"><span class="thin">TitleGoes</span> <span class="thin">.here</span></h1> </div> <script> (function() { var width, height, largeHeader, canvas, ctx, points, target, animateHeader = true; // Main initHeader(); initAnimation(); addListeners(); function initHeader() { width = window.innerWidth; height = window.innerHeight; target = {x: width/2, y: height/2}; largeHeader = document.getElementById('large-header'); largeHeader.style.height = height+'px'; canvas = document.getElementById('demo-canvas'); canvas.width = width; canvas.height = height; ctx = canvas.getContext('2d'); // create points points = []; for(var x = 0; x < width; x = x + width/20) { for(var y = 0; y < height; y = y + height/20) { var px = x + Math.random()*width/20; var py = y + Math.random()*height/20; var p = {x: px, originX: px, y: py, originY: py }; points.push(p); } } // for each point find the 5 closest points for(var i = 0; i < points.length; i++) { var closest = []; var p1 = points[i]; for(var j = 0; j < points.length; j++) { var p2 = points[j] if(!(p1 == p2)) { var placed = false; for(var k = 0; k < 5; k++) { if(!placed) { if(closest[k] == undefined) { closest[k] = p2; placed = true; } } } for(var k = 0; k < 5; k++) { if(!placed) { if(getDistance(p1, p2) < getDistance(p1, closest[k])) { closest[k] = p2; placed = true; } } } } } p1.closest = closest; } // assign a circle to each point for(var i in points) { var c = new Circle(points[i], 2+Math.random()*2, 'rgba(255,255,255,0.3)'); points[i].circle = c; } } // Event handling function addListeners() { if(!('ontouchstart' in window)) { window.addEventListener('mousemove', mouseMove); } window.addEventListener('scroll', scrollCheck); window.addEventListener('resize', resize); } function mouseMove(e) { var posx = posy = 0; if (e.pageX || e.pageY) { posx = e.pageX; posy = e.pageY; } else if (e.clientX || e.clientY) { posx = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft; posy = e.clientY + document.body.scrollTop + document.documentElement.scrollTop; } target.x = posx; target.y = posy; } function scrollCheck() { if(document.body.scrollTop > height) animateHeader = false; else animateHeader = true; } function resize() { width = window.innerWidth; height = window.innerHeight; largeHeader.style.height = height+'px'; canvas.width = width; canvas.height = height; } // animation function initAnimation() { animate(); for(var i in points) { shiftPoint(points[i]); } } function animate() { if(animateHeader) { ctx.clearRect(0,0,width,height); for(var i in points) { // detect points in range if(Math.abs(getDistance(target, points[i])) < 4000) { points[i].active = 0.3; points[i].circle.active = 0.6; } else if(Math.abs(getDistance(target, points[i])) < 20000) { points[i].active = 0.1; points[i].circle.active = 0.3; } else if(Math.abs(getDistance(target, points[i])) < 40000) { points[i].active = 0.02; points[i].circle.active = 0.1; } else { points[i].active = 0; points[i].circle.active = 0; } drawLines(points[i]); points[i].circle.draw(); } } requestAnimationFrame(animate); } function shiftPoint(p) { TweenLite.to(p, 1+1*Math.random(), {x:p.originX-50+Math.random()*100, y: p.originY-50+Math.random()*100, ease:Circ.easeInOut, onComplete: function() { shiftPoint(p); }}); } // Canvas manipulation function drawLines(p) { if(!p.active) return; for(var i in p.closest) { ctx.beginPath(); ctx.moveTo(p.x, p.y); ctx.lineTo(p.closest[i].x, p.closest[i].y); ctx.strokeStyle = 'rgba(156,217,249,'+ p.active+')'; ctx.stroke(); } } function Circle(pos,rad,color) { var _this = this; // constructor (function() { _this.pos = pos || null; _this.radius = rad || null; _this.color = color || null; _this.active = 0; // Initialize active property })(); this.draw = function() { if(!_this.active) return; ctx.beginPath(); ctx.arc(_this.pos.x, _this.pos.y, _this.radius, 0, 2 * Math.PI, false); ctx.fillStyle = 'rgba(156,217,249,'+ _this.active+')'; ctx.fill(); }; } // Util function getDistance(p1, p2) { return Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2); } })(); </script> </body> </html>
After applying these fixes, the animation will work exactly as it does on Codepen: points will float randomly, and connecting lines will appear when your mouse moves near them.
内容的提问来源于stack exchange,提问作者Compoot

