
本文介绍如何在 react 中实现固定头部(sticky header)实时感知当前视口下方的区块,并动态切换背景色与文字色,适用于深色/浅色主题区域交替的网页设计。
本文介绍如何在 react 中实现固定头部(sticky header)实时感知当前视口下方的区块,并动态切换背景色与文字色,适用于深色/浅色主题区域交替的网页设计。
在构建现代单页应用时,常需让导航栏或 Logo 根据页面滚动位置“智能响应”——例如当头部滑过深色区块时显示白色文字,滑过浅色区块时自动切为黑色文字与透明背景。这种效果无需第三方库,仅靠原生 DOM API 与 React Hooks 即可稳健实现。
核心思路是:监听 scroll 事件,遍历所有带语义标识的区块(如 .section),通过 getBoundingClientRect() 判断其是否与固定头部的底部位置发生重叠(即“位于头部正下方”),进而读取该区块预设的 data-color 和 data-text-color 属性,更新头部样式。
以下是完整可运行的组件实现:
import { useState, useEffect } from 'react';
import './_dHeader.css';
export const DynamicHeader = () => {
const [headerStyle, setHeaderStyle] = useState({
backgroundColor: 'black',
color: 'white',
});
const handleScroll = () => {
const header = document.getElementById('sticky-header');
if (!header) return;
const sections = document.querySelectorAll('.section');
const headerHeight = header.offsetHeight;
sections.forEach((section) => {
const rect = section.getBoundingClientRect();
// 判断:区块顶部 ≤ 头部高度(即已进入视口下方),且区块底部 ≥ 头部高度(即尚未完全滑出)
if (rect.top = headerHeight) {
setHeaderStyle({
backgroundColor: section.dataset.color || 'transparent',
color: section.dataset.textColor || 'inherit',
});
}
});
};
useEffect(() => {
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
const sections = [
{ color: 'white', textColor: 'black', content: 'Light Section' },
{ color: 'black', textColor: 'white', content: 'Dark Section' },
{ color: '#f0f9ff', textColor: '#1e40af', content: 'Blue-Tint Section' },
];
return (
<div>
<header id="sticky-header" style="{headerStyle}">
Sticky Header
</header>
{sections.map((section, index) => (
<div key="{index}" classname="section" style="{{" backgroundcolor: section.color color: section.textcolor height: display: alignitems: justifycontent: data-color="{section.color}" data-text-color="{section.textColor}">
<h2>{section.content}</h2>
</div>
))}
</div>
);
};
配套 CSS(_dHeader.css)确保基础布局稳定:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
overflow-x: hidden;
}
header {
position: fixed;
top: 0;
left: 0;
width: 100%;
padding: 1rem;
text-align: center;
z-index: 1000;
transition: background-color 0.3s ease, color 0.3s ease;
}
.section {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
.section h2 {
font-size: 2.5rem;
margin: 0;
font-weight: 700;
}
⚠️ 注意事项:
-
getBoundingClientRect()返回的是相对于视口的坐标,因此判断逻辑基于header.offsetHeight(即头部高度),而非0—— 这能精准捕捉“正下方”而非“正上方”区块; - 建议为每个
section设置明确的data-color和data-text-color,避免 fallback 值导致样式异常; - 若页面存在动态插入/卸载区块,需在
useEffect清理函数中重新绑定或使用MutationObserver增强鲁棒性; - 性能优化:对高频
scroll事件建议添加防抖(如useThrottle)或改用IntersectionObserver(更现代、性能更优,适合复杂场景)。
该方案轻量、可扩展,既满足基础主题切换需求,也为后续集成 Logo 动画、导航高亮、锚点平滑跳转等交互打下坚实基础。










