diff --git a/index.html b/index.html
index 25c12a7..cacdd8b 100644
--- a/index.html
+++ b/index.html
@@ -446,19 +446,10 @@
/* 移动端痛点沉浸式布局 */
@media (max-width: 900px) {
- /* 逐屏吸附:整个页面每次滚动就是一屏 */
- body {
- scroll-snap-type: y mandatory;
- scroll-behavior: smooth;
- }
- .hero, #solutions, #approach, #geo, #contact, footer {
- scroll-snap-align: start;
- }
/* 痛点半块单列全屏 */
#pain-points {
overflow: visible;
text-align: center;
- scroll-snap-align: start;
}
#pain-points .section-label {
margin-bottom: 40px;
@@ -516,8 +507,6 @@
overflow: visible;
position: relative;
z-index: 1;
- scroll-snap-align: start;
- scroll-snap-stop: always;
}
.pain-item::before { display: none; }
.pain-item:hover { background: transparent; }
@@ -985,6 +974,14 @@
// 移动端:入场动画 + 视差滚动
if (window.innerWidth <= 900) {
+ // 移除 CSS scroll-snap(不可靠),用 JS 实现
+ document.body.style.scrollSnapType = 'none';
+ document.querySelectorAll('[style*="scroll-snap"]').forEach(el => {
+ el.style.scrollSnapType = 'none';
+ el.style.scrollSnapAlign = 'none';
+ el.style.scrollSnapStop = 'normal';
+ });
+
// 1. 入场动画(一次性)
const mobileItems = document.querySelectorAll('#pain-points .pain-item, #approach .approach-item');
const mobileObserver = new IntersectionObserver((entries) => {
@@ -1000,21 +997,11 @@
function updateParallax() {
painNums.forEach(num => {
- // 获取数字所在的父卡片(.pain-item)
const card = num.parentElement;
if (!card) return;
-
- // 计算卡片相对于视口顶部的距离
const rect = card.getBoundingClientRect();
-
- // 核心视差逻辑:
- // rect.top 越大(卡片在屏幕越下方),位移越大(向上推数字)
- // 随着卡片向上滚动(rect.top 变小),数字向下回落
- // 这会产生数字比文字"慢半拍"的悬浮感
- // 速度因子 0.15 意味着视差幅度为卡片移动距离的 15%
const speed = 0.15;
const yOffset = -(rect.top * speed);
-
num.style.transform = `translateY(${yOffset}px)`;
});
ticking = false;
@@ -1026,9 +1013,67 @@
ticking = true;
}
}, { passive: true });
-
- // 初始化一次
updateParallax();
+
+ // 3. JS 逐屏吸附
+ // 收集所有吸附点
+ const snapTargets = [];
+ // Hero
+ const hero = document.querySelector('.hero');
+ if (hero) snapTargets.push(hero);
+ // 痛点每个卡片
+ document.querySelectorAll('#pain-points .pain-item').forEach(item => snapTargets.push(item));
+ // 其他 section
+ ['solutions', 'approach', 'geo', 'contact'].forEach(id => {
+ const el = document.getElementById(id);
+ if (el) snapTargets.push(el);
+ });
+
+ let scrollEndTimer = null;
+ let isSnapping = false;
+ let touchStartY = 0;
+ let lastScrollTop = 0;
+
+ document.addEventListener('touchstart', (e) => {
+ touchStartY = e.touches[0].clientY;
+ }, { passive: true });
+
+ window.addEventListener('scroll', () => {
+ // 清除之前的定时器
+ clearTimeout(scrollEndTimer);
+ // 300ms 无滚动视为停止
+ scrollEndTimer = setTimeout(() => {
+ if (isSnapping) return; // 正在吸附中不触发
+ snapToNearest();
+ }, 200);
+ lastScrollTop = window.scrollY;
+ }, { passive: true });
+
+ function snapToNearest() {
+ const vh = window.innerHeight;
+ const center = window.scrollY + vh * 0.4; // 吸附点偏上 40% 位置
+
+ let nearest = null;
+ let minDist = Infinity;
+
+ snapTargets.forEach(target => {
+ const rect = target.getBoundingClientRect();
+ const top = rect.top + window.scrollY;
+ const dist = Math.abs(top - center);
+ if (dist < minDist) {
+ minDist = dist;
+ nearest = target;
+ }
+ });
+
+ if (nearest) {
+ isSnapping = true;
+ const targetY = nearest.getBoundingClientRect().top + window.scrollY;
+ window.scrollTo({ top: targetY, behavior: 'smooth' });
+ // 吸附完成后解锁
+ setTimeout(() => { isSnapping = false; }, 800);
+ }
+ }
}