首页英雄区改为深海岩层暗色背景,新增右下角跟随鼠标粒子效果与Hyper-seq风格排版

- 替换 hero 渐变背景为深海军蓝岩层质感(多层径向渐变 + SVG噪点纹理)
- 新增 js/particles.js:右下角粒子网络,随鼠标移动产生吸引连线效果
- 首页主标语改为「突破极限 / 生命从此被计算」,引入 Orbitron + Noto Sans SC 粗体字体
- 新增极低成本/高效/灵活/高通量徽标行,呼应参考宣传册排版
This commit is contained in:
Claude
2026-07-14 06:23:00 +00:00
parent 1331c4dd8b
commit f347a99dd9
3 changed files with 319 additions and 20 deletions
+133 -18
View File
@@ -14,6 +14,16 @@
--light-bg: #f5f7fa;
--dark-text: #333;
--light-text: #666;
/* 深海岩层配色(参考 Hyper-seq 宣传册) */
--rock-navy-0: #05070c;
--rock-navy-1: #0a1120;
--rock-navy-2: #121d34;
--rock-navy-3: #1b2c4a;
--ice-blue: #cfe8ff;
--ice-blue-dim: #9cc6ec;
--electric-blue: #38bdf8;
--coral-accent: #ff8a5c;
}
body {
@@ -29,14 +39,54 @@ body {
padding: 0 20px;
}
/* 英雄部分 */
/* 英雄部分 —— 深海岩层背景 */
.hero {
position: relative;
height: 40vh;
min-height: 320px;
max-height: 460px;
height: 62vh;
min-height: 460px;
max-height: 680px;
overflow: hidden;
background: linear-gradient(135deg, var(--primary-blue) 0%, var(--primary-purple) 100%);
background:
radial-gradient(ellipse 60% 45% at 18% 15%, rgba(148, 163, 184, 0.16), transparent 60%),
radial-gradient(ellipse 55% 40% at 78% 10%, rgba(110, 130, 170, 0.14), transparent 60%),
radial-gradient(ellipse 70% 55% at 82% 88%, rgba(56, 189, 248, 0.10), transparent 65%),
linear-gradient(160deg, var(--rock-navy-0) 0%, var(--rock-navy-1) 40%, var(--rock-navy-2) 72%, var(--rock-navy-3) 100%);
}
/* 岩石颗粒质感叠加层 */
.hero::before {
content: "";
position: absolute;
inset: 0;
z-index: 0;
pointer-events: none;
opacity: 0.5;
mix-blend-mode: overlay;
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/><feColorMatrix type='saturate' values='0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
background-size: 240px 240px;
}
/* 岩壁棱线光影 */
.hero::after {
content: "";
position: absolute;
inset: 0;
z-index: 0;
pointer-events: none;
background:
linear-gradient(105deg, transparent 30%, rgba(180, 196, 220, 0.05) 42%, transparent 54%),
linear-gradient(72deg, transparent 55%, rgba(180, 196, 220, 0.04) 63%, transparent 74%);
}
/* 右下角跟随鼠标的粒子网络 */
.hero-particles {
position: absolute;
right: 0;
bottom: 0;
width: 60%;
height: 75%;
z-index: 1;
pointer-events: none;
}
.hero-carousel {
@@ -78,8 +128,9 @@ body {
width: 100%;
height: 100%;
object-fit: cover;
opacity: 0.26;
opacity: 0.16;
z-index: 0;
filter: grayscale(0.3) brightness(0.7);
}
.hero-brand-slide::before {
@@ -87,11 +138,11 @@ body {
position: absolute;
inset: 0;
z-index: 1;
background: var(--hero-overlay-color);
background: radial-gradient(ellipse 70% 60% at 50% 40%, rgba(28, 45, 74, 0.35), rgba(5, 7, 12, 0.55) 80%);
}
.hero-brand-slide > img {
opacity: 0.18;
opacity: 0.1;
}
.hero-content {
@@ -103,8 +154,10 @@ body {
}
.hero-content h1 {
font-family: 'Orbitron', 'Noto Sans SC', 'Segoe UI', sans-serif;
font-size: 2.45rem;
font-weight: bold;
font-weight: 700;
letter-spacing: 0.03em;
margin-bottom: 20px;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
}
@@ -116,7 +169,7 @@ body {
}
.hero-brand-content {
max-width: 920px;
max-width: 960px;
padding: 0 20px;
margin: 0 auto;
}
@@ -138,20 +191,62 @@ body {
filter: drop-shadow(0 8px 18px rgba(0, 0, 0, 0.28));
}
.hero-brand-heading h1 {
color: white;
margin-bottom: 0;
text-shadow: none;
.hero-kicker {
display: inline-block;
font-family: 'Orbitron', 'Noto Sans SC', sans-serif;
font-size: 0.95rem;
font-weight: 700;
letter-spacing: 0.35em;
text-transform: uppercase;
color: var(--ice-blue-dim);
margin-bottom: 14px;
}
.hero-brand-heading h1 {
color: var(--ice-blue);
margin-bottom: 0;
text-shadow: 0 0 30px rgba(56, 189, 248, 0.25);
font-family: 'Orbitron', 'Noto Sans SC', sans-serif;
font-weight: 900;
letter-spacing: 0.02em;
}
.hero-line-1 {
display: block;
line-height: 1.35;
font-size: 3.1rem;
}
.hero-line-1,
.hero-line-2 {
display: block;
line-height: 1.4;
line-height: 1.6;
font-size: 1.4rem;
font-weight: 700;
color: rgba(207, 232, 255, 0.75);
letter-spacing: 0.15em;
margin-left: 0.2rem;
}
.hero-line-2 {
margin-left: 5.5rem;
.hero-badge-row {
display: flex;
flex-wrap: wrap;
gap: 14px;
margin-top: 26px;
}
.hero-badge {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 8px 20px;
border: 1px solid rgba(156, 198, 236, 0.5);
border-radius: 999px;
font-size: 0.85rem;
font-weight: 600;
letter-spacing: 0.05em;
color: var(--ice-blue);
background: rgba(56, 189, 248, 0.06);
backdrop-filter: blur(2px);
}
.hero-brand-btn {
@@ -337,6 +432,8 @@ body {
@media (max-width: 768px) {
.hero-brand-heading {
gap: 20px;
flex-direction: column;
text-align: center;
}
.hero-brand-logo {
@@ -355,6 +452,24 @@ body {
font-size: 1rem;
}
.hero-line-1 {
font-size: 2.1rem;
}
.hero-line-2 {
font-size: 1.1rem;
margin-left: 0;
}
.hero-badge-row {
justify-content: center;
}
.hero-particles {
width: 100%;
height: 55%;
}
.products-preview h2 {
font-size: 2rem;
}
+14 -2
View File
@@ -5,6 +5,9 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>海古纪生物科技 - 精准基因组学解决方案</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@700;900&family=Noto+Sans+SC:wght@700;900&display=swap" rel="stylesheet">
<link rel="stylesheet" href="css/style.css">
<link rel="stylesheet" href="css/nav.css">
<link rel="stylesheet" href="css/footer.css">
@@ -91,6 +94,7 @@
<!-- 首页 -->
<section id="home" class="hero">
<canvas id="hero-particle-canvas" class="hero-particles" aria-hidden="true"></canvas>
<div class="hero-carousel">
<!-- 第一张:公司理念 -->
<div class="hero-slide hero-brand-slide active">
@@ -98,10 +102,17 @@
<div class="hero-brand-heading">
<img class="hero-brand-logo" src="公司资料/公司简介/海古纪logo.png" alt="海古纪 Logo">
<div class="hero-brand-copy">
<span class="hero-kicker">HYPER-GENE · 生命孪生体系</span>
<h1>
<span class="hero-line-1">海古纪 · 生命孪生体系</span>
<span class="hero-line-2">——生命从此被计算</span>
<span class="hero-line-1">突破极限</span>
<span class="hero-line-2">生命从此被计算</span>
</h1>
<div class="hero-badge-row">
<span class="hero-badge">极低成本</span>
<span class="hero-badge">高效</span>
<span class="hero-badge">灵活</span>
<span class="hero-badge">高通量</span>
</div>
</div>
</div>
</div>
@@ -294,6 +305,7 @@
<script src="js/carousel.js"></script>
<script src="js/nav.js"></script>
<script src="js/particles.js"></script>
</body>
</html>
+172
View File
@@ -0,0 +1,172 @@
/**
* 右下角粒子网络效果
* 在英雄区右下角绘制一片跟随鼠标移动的粒子网络,呼应科技/基因数据感。
*/
(function () {
const canvas = document.getElementById('hero-particle-canvas');
if (!canvas) return;
const ctx = canvas.getContext('2d');
const DPR = window.devicePixelRatio || 1;
let width = 0;
let height = 0;
let particles = [];
let animationId = null;
const mouse = { x: null, y: null, active: false };
const config = {
density: 9000, // 每 9000 平方像素一个粒子
maxParticles: 90,
linkDistance: 120,
mouseLinkDistance: 170,
mouseForce: 0.9,
dotColor: '124, 211, 252',
lineColor: '56, 189, 248'
};
function resize() {
const rect = canvas.getBoundingClientRect();
width = rect.width;
height = rect.height;
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() {
const count = Math.min(config.maxParticles, Math.floor((width * height) / config.density));
particles = new Array(Math.max(count, 20)).fill(null).map(() => ({
x: Math.random() * width,
y: Math.random() * height,
vx: (Math.random() - 0.5) * 0.35,
vy: (Math.random() - 0.5) * 0.35,
r: Math.random() * 1.4 + 0.8
}));
}
function step() {
particles.forEach(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) {
const dx = mouse.x - p.x;
const dy = mouse.y - p.y;
const dist = Math.hypot(dx, dy);
if (dist < config.mouseLinkDistance && dist > 0.001) {
const 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 (let i = 0; i < particles.length; i++) {
for (let j = i + 1; j < particles.length; j++) {
const dx = particles[i].x - particles[j].x;
const dy = particles[i].y - particles[j].y;
const dist = Math.hypot(dx, dy);
if (dist < config.linkDistance) {
ctx.strokeStyle = `rgba(${config.lineColor}, ${(1 - dist / config.linkDistance) * 0.5})`;
ctx.lineWidth = 0.6;
ctx.beginPath();
ctx.moveTo(particles[i].x, particles[i].y);
ctx.lineTo(particles[j].x, particles[j].y);
ctx.stroke();
}
}
// 粒子与鼠标的连线
if (mouse.active) {
const dx = particles[i].x - mouse.x;
const dy = particles[i].y - mouse.y;
const dist = Math.hypot(dx, dy);
if (dist < config.mouseLinkDistance) {
ctx.strokeStyle = `rgba(${config.lineColor}, ${(1 - dist / config.mouseLinkDistance) * 0.7})`;
ctx.lineWidth = 0.8;
ctx.beginPath();
ctx.moveTo(particles[i].x, particles[i].y);
ctx.lineTo(mouse.x, mouse.y);
ctx.stroke();
}
}
}
// 粒子本体
particles.forEach(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 = 5;
ctx.fill();
ctx.shadowBlur = 0;
});
// 鼠标光点
if (mouse.active) {
ctx.beginPath();
ctx.arc(mouse.x, mouse.y, 2.2, 0, Math.PI * 2);
ctx.fillStyle = 'rgba(255, 255, 255, 0.9)';
ctx.shadowColor = 'rgba(255, 255, 255, 0.9)';
ctx.shadowBlur = 10;
ctx.fill();
ctx.shadowBlur = 0;
}
}
function loop() {
step();
render();
animationId = requestAnimationFrame(loop);
}
function updateMouseFromEvent(clientX, clientY) {
const rect = canvas.getBoundingClientRect();
const x = clientX - rect.left;
const y = clientY - rect.top;
// 允许鼠标在画布周边一定范围内也能产生吸引效果
const margin = 160;
if (x > -margin && x < width + margin && y > -margin && y < height + margin) {
mouse.x = Math.max(0, Math.min(width, x));
mouse.y = Math.max(0, Math.min(height, y));
mouse.active = true;
} else {
mouse.active = false;
}
}
document.addEventListener('mousemove', e => updateMouseFromEvent(e.clientX, e.clientY));
document.addEventListener('mouseleave', () => { mouse.active = false; });
canvas.addEventListener('touchmove', e => {
if (e.touches && e.touches[0]) {
updateMouseFromEvent(e.touches[0].clientX, e.touches[0].clientY);
}
}, { passive: true });
window.addEventListener('resize', resize);
const prefersReducedMotion = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
resize();
if (!prefersReducedMotion) {
loop();
} else {
render();
}
})();