导航栏滚动收缩功能迭代代码 2026年1月6日
作者: iTxGo |
发布于: 2026-01-08 14:18 |
更新于: 2026-01-17 07:23 |
分类: 笔记 |
浏览: 73 |
导航栏滚动收缩第一版
CSS 代码:
:root {
/* 导航栏滚动缩放 */
--header-height-expanded: 135px;
--header-height-shrunk: 80px;
--transition-duration: 0.2s;
--transition-easing: cubic-bezier(0.4, 0, 0.2, 1);
}
/* ==========================================
导航栏滚动收缩样式
========================================== */
.header-container {
position: sticky;
top: 12px;
height: var(--header-height-expanded);
min-height: unset;
transition: height var(--transition-duration) var(--transition-easing);
z-index: 1000;
}
.header-container.shrunk {
height: var(--header-height-shrunk);
}
/* 收缩态遮罩 */
.header-container.shrunk::before {
content: '';
position: absolute;
inset: -15px 0;
pointer-events: auto;
z-index: -1;
}
header {
padding: 1em 1.6em;
}
/* ===== 行结构 ===== */
.header-top {
display: flex;
align-items: center;
justify-content: space-between;
}
.header-bottom {
display: flex;
align-items: center;
justify-content: space-between;
transform: translateY(0) translateZ(0);
transition: transform var(--transition-duration) var(--transition-easing);
will-change: transform;
pointer-events: auto;
}
.header-container.shrunk .header-bottom {
transform: translateY(-55px) translateZ(0);
pointer-events: none;
}
/* ===== 占位元素 ===== */
.placeholder-top,
.placeholder-bottom {
opacity: 1;
transform: translateY(0) translateZ(0);
transition:
opacity calc(var(--transition-duration) * 0.75) var(--transition-easing),
transform var(--transition-duration) var(--transition-easing);
will-change: transform, opacity;
}
.header-container.shrunk .placeholder-top {
opacity: 0;
transform: translateY(-12px) translateZ(0);
pointer-events: none;
}
.header-container.shrunk .placeholder-bottom {
opacity: 0;
transform: translateY(-20px) translateZ(0);
}
/* 导航按钮不动画 */
.header-bottom nav {
transition: none;
}
/* ===== 交互修正 ===== */
.header-container.shrunk {
pointer-events: none;
}
.header-container.shrunk nav,
.header-container.shrunk .user-menu-container,
.header-container.shrunk .user-menu-trigger {
pointer-events: auto;
}
JS代码:
// =============================
// 14. 导航栏滚动收缩功能
// =============================
function initHeaderShrink() {
const runInit = () => {
const header = document.querySelector('.header-container');
if (!header) return;
// 差值需大于 导航栏展开高度135-收缩后高度80=55
const SHRINK_AT = 65; //80
const EXPAND_AT = 5; //20
let isShrunk = false;
let lastScrollY = window.scrollY;
let ticking = false;
const updateHeaderState = () => {
const scrollY = window.scrollY;
const isScrollingDown = scrollY > lastScrollY;
lastScrollY = scrollY;
if (isScrollingDown && !isShrunk && scrollY > SHRINK_AT) {
header.classList.add('shrunk');
isShrunk = true;
} else if (!isScrollingDown && isShrunk && scrollY < EXPAND_AT) {
header.classList.remove('shrunk');
isShrunk = false;
}
ticking = false;
};
const onScroll = () => {
if (!ticking) {
requestAnimationFrame(updateHeaderState);
ticking = true;
}
};
window.addEventListener('scroll', onScroll, { passive: true });
console.log('✅ 导航栏收缩功能已就绪');
};
if ('requestIdleCallback' in window) {
requestIdleCallback(runInit, { timeout: 100 });
} else {
setTimeout(runInit, 100);
}
}
导航栏滚动收缩第二版 - 优化掉帧
CSS 代码:
:root {
/* 导航栏滚动缩放 */
--header-height-expanded: 135px;
--header-height-shrunk: 80px;
--transition-duration: 0.2s;
--transition-easing: cubic-bezier(0.4, 0, 0.2, 1);
}
/* ==========================================
导航栏滚动收缩样式
========================================== */
.header-container {
transform: translateZ(0);
will-change: height;
position: sticky;
top: 12px;
height: var(--header-height-expanded);
min-height: unset;
transition: height var(--transition-duration) var(--transition-easing);
z-index: 1000;
}
.header-container.shrunk {
height: var(--header-height-shrunk);
}
/* 标签页恢复同步禁止动画一帧 */
.header-container.is-resyncing {
transition: none;
}
/* 收缩态遮罩 */
.header-container.shrunk::before {
content: '';
position: absolute;
inset: -15px 0;
pointer-events: auto;
z-index: -1;
}
header {
padding: 1em 1.6em;
}
/* ===== 行结构 ===== */
.header-top {
display: flex;
align-items: center;
justify-content: space-between;
}
.header-bottom {
display: flex;
align-items: center;
justify-content: space-between;
transform: translateY(0) translateZ(0);
transition: transform var(--transition-duration) var(--transition-easing);
will-change: transform;
pointer-events: auto;
}
.header-container.shrunk .header-bottom {
transform: translateY(-55px) translateZ(0);
pointer-events: none;
}
/* ===== 占位元素 ===== */
.placeholder-top,
.placeholder-bottom {
opacity: 1;
transform: translateY(0) translateZ(0);
transition:
opacity calc(var(--transition-duration) * 0.75) var(--transition-easing),
transform var(--transition-duration) var(--transition-easing);
will-change: transform, opacity;
}
.header-container.shrunk .placeholder-top {
opacity: 0;
transform: translateY(-12px) translateZ(0);
pointer-events: none;
}
.header-container.shrunk .placeholder-bottom {
opacity: 0;
transform: translateY(-20px) translateZ(0);
}
/* 导航按钮不动画 */
.header-bottom nav {
transition: none;
}
/* ===== 交互修正 ===== */
.header-container.shrunk {
pointer-events: none;
}
.header-container.shrunk nav,
.header-container.shrunk .user-menu-container,
.header-container.shrunk .user-menu-trigger {
pointer-events: auto;
}
JS代码:
// =============================
// 14. 导航栏滚动收缩功能
// =============================
function initHeaderShrink() {
const runInit = () => {
const header = document.querySelector('.header-container');
if (!header) return;
// 差值需大于 导航栏展开高度135-收缩后高度80=55
const SHRINK_AT = 65;
const EXPAND_AT = 5;
let isShrunk = false;
let lastScrollY = window.scrollY;
let ticking = false;
// 与 scrollY 强制同步导航栏状态不动画
const syncHeaderState = () => {
const scrollY = window.scrollY;
header.classList.add('is-resyncing');
if (scrollY > SHRINK_AT) {
header.classList.add('shrunk');
isShrunk = true;
} else {
header.classList.remove('shrunk');
isShrunk = false;
}
lastScrollY = scrollY;
ticking = false;
// 下一帧恢复动画能力
requestAnimationFrame(() => {
header.classList.remove('is-resyncing');
});
};
const updateHeaderState = () => {
const scrollY = window.scrollY;
const isScrollingDown = scrollY > lastScrollY;
lastScrollY = scrollY;
if (isScrollingDown && !isShrunk && scrollY > SHRINK_AT) {
header.classList.add('shrunk');
isShrunk = true;
} else if (!isScrollingDown && isShrunk && scrollY < EXPAND_AT) {
header.classList.remove('shrunk');
isShrunk = false;
}
ticking = false;
};
const onScroll = () => {
if (!ticking) {
requestAnimationFrame(updateHeaderState);
ticking = true;
}
};
// 页面恢复可见时重新对齐状态
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') {
syncHeaderState();
}
});
// 初始同步一次
syncHeaderState();
window.addEventListener('scroll', onScroll, { passive: true });
console.log('✅ 导航栏收缩功能已就绪');
};
if ('requestIdleCallback' in window) {
requestIdleCallback(runInit, { timeout: 100 });
} else {
setTimeout(runInit, 100);
}
}