Files
Claude 431b0a7c38 全站统一深色岩层背景+粒子特效;导航/底部无缝融合;底部导航结构调整
- body 改为固定(background-attachment: fixed)的深色岩层渐变+噪点纹理,作为全站统一背景,所有子页面的主体区域都与首页品牌视觉背景一致
- 新增全局唯一的跟随鼠标粒子画布(.site-particles,position:fixed铺满视口),替换掉原来仅限首页hero/子页面page-hero局部的粒子画布
- about.css/pages.css/resources.css 全面转换为深色主题配色:白色卡片背景改为半透明深蓝玻璃质感,深色文字改为冰蓝/浅蓝,浅色边框改为半透明冰蓝边框
- 顶部导航:默认完全透明,滚动后切换为与背景同色调的深色玻璃底色,不再出现白色导航栏
- 底部导航:footer-fade渐变上色改为与页面背景一致(rock-navy-0),下色改为更深的近黑色,形成无缝过渡
- 底部导航结构调整:合作伙伴模块删除,合并为「关于海古纪」列表下的一个链接项;「关于海古纪」下的隐私协议链接删除,改为footer-bottom的“隐私政策”链接跳转到实际隐私协议内容
- 联系信息电话号码字体与其余文字保持一致(去除等宽字体特殊样式)
- footer-section标题颜色统一改为与首页“最新动态”一致的冰蓝色(--ice-blue)
2026-07-15 03:04:15 +00:00

152 lines
5.0 KiB
JavaScript

/**
* 全站深色岩层背景上的粒子网络效果
* 固定在视口内(position: fixed),任意页面、任意滚动位置都可见,跟随鼠标移动。
*/
(function () {
var canvas = document.querySelector('.site-particles');
if (!canvas) return;
var ctx = canvas.getContext('2d');
var DPR = window.devicePixelRatio || 1;
var prefersReducedMotion = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
var width = 0;
var height = 0;
var particles = [];
var mouse = { x: null, y: null, active: false };
var config = {
density: 9000,
maxParticles: 130,
linkDistance: 150,
mouseLinkDistance: 220,
mouseForce: 1.1,
dotRadiusMin: 1.6,
dotRadiusMax: 3.4,
dotColor: '124, 211, 252',
lineColor: '56, 189, 248'
};
function resize() {
width = window.innerWidth;
height = window.innerHeight;
canvas.width = Math.max(1, Math.round(width * DPR));
canvas.height = Math.max(1, Math.round(height * DPR));
ctx.setTransform(DPR, 0, 0, DPR, 0, 0);
createParticles();
}
function createParticles() {
var count = Math.min(config.maxParticles, Math.floor((width * height) / config.density));
particles = new Array(Math.max(count, 30)).fill(null).map(function () {
return {
x: Math.random() * width,
y: Math.random() * height,
vx: (Math.random() - 0.5) * 0.4,
vy: (Math.random() - 0.5) * 0.4,
r: Math.random() * (config.dotRadiusMax - config.dotRadiusMin) + config.dotRadiusMin
};
});
}
document.addEventListener('mousemove', function (e) {
mouse.x = e.clientX;
mouse.y = e.clientY;
mouse.active = true;
});
document.addEventListener('mouseleave', function () { mouse.active = false; });
function step() {
particles.forEach(function (p) {
p.x += p.vx;
p.y += p.vy;
if (p.x <= 0 || p.x >= width) p.vx *= -1;
if (p.y <= 0 || p.y >= height) p.vy *= -1;
p.x = Math.max(0, Math.min(width, p.x));
p.y = Math.max(0, Math.min(height, p.y));
if (mouse.active) {
var dx = mouse.x - p.x;
var dy = mouse.y - p.y;
var dist = Math.hypot(dx, dy);
if (dist < config.mouseLinkDistance && dist > 0.001) {
var pull = (1 - dist / config.mouseLinkDistance) * config.mouseForce;
p.x -= (dx / dist) * pull;
p.y -= (dy / dist) * pull;
}
}
});
}
function render() {
ctx.clearRect(0, 0, width, height);
for (var i = 0; i < particles.length; i++) {
for (var j = i + 1; j < particles.length; j++) {
var dx = particles[i].x - particles[j].x;
var dy = particles[i].y - particles[j].y;
var dist = Math.hypot(dx, dy);
if (dist < config.linkDistance) {
ctx.strokeStyle = 'rgba(' + config.lineColor + ', ' + ((1 - dist / config.linkDistance) * 0.45) + ')';
ctx.lineWidth = 0.7;
ctx.beginPath();
ctx.moveTo(particles[i].x, particles[i].y);
ctx.lineTo(particles[j].x, particles[j].y);
ctx.stroke();
}
}
if (mouse.active) {
var mdx = particles[i].x - mouse.x;
var mdy = particles[i].y - mouse.y;
var mdist = Math.hypot(mdx, mdy);
if (mdist < config.mouseLinkDistance) {
ctx.strokeStyle = 'rgba(' + config.lineColor + ', ' + ((1 - mdist / config.mouseLinkDistance) * 0.65) + ')';
ctx.lineWidth = 0.9;
ctx.beginPath();
ctx.moveTo(particles[i].x, particles[i].y);
ctx.lineTo(mouse.x, mouse.y);
ctx.stroke();
}
}
}
particles.forEach(function (p) {
ctx.beginPath();
ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2);
ctx.fillStyle = 'rgba(' + config.dotColor + ', 0.85)';
ctx.shadowColor = 'rgba(56, 189, 248, 0.8)';
ctx.shadowBlur = 7;
ctx.fill();
ctx.shadowBlur = 0;
});
if (mouse.active) {
ctx.beginPath();
ctx.arc(mouse.x, mouse.y, 2.6, 0, Math.PI * 2);
ctx.fillStyle = 'rgba(255, 255, 255, 0.85)';
ctx.shadowColor = 'rgba(255, 255, 255, 0.85)';
ctx.shadowBlur = 12;
ctx.fill();
ctx.shadowBlur = 0;
}
}
function loop() {
step();
render();
requestAnimationFrame(loop);
}
window.addEventListener('resize', resize);
resize();
if (!prefersReducedMotion) {
loop();
} else {
render();
}
})();