侧边栏固定是网页布局中非常实用的功能,既能保证导航类内容始终可见,又不会影响主体内容的正常滚动展示。目前主流的实现方式有两种,分别是基于scroll事件监听和CSS原生sticky属性,下面分别介绍两种方式的实践技巧。
一、基于scroll事件的侧边栏固定实现
这种方式通过监听页面滚动事件,计算侧边栏距离视口顶部的位置,动态添加或移除固定定位的类名来实现效果,兼容性较好,适合需要兼容旧版本浏览器的场景。
实现思路
- 首先获取侧边栏的初始偏移量和高度,以及主体内容的高度
- 监听窗口的scroll事件,获取当前滚动距离
- 判断滚动距离是否超过侧边栏的初始顶部偏移量,超过则给侧边栏添加固定定位样式
- 当滚动距离接近主体内容底部时,限制侧边栏继续跟随滚动,避免超出内容区域
代码示例
// 获取DOM元素
const sidebar = document.querySelector('.sidebar');
const mainContent = document.querySelector('.main-content');
// 获取侧边栏初始顶部偏移量
const sidebarOffsetTop = sidebar.offsetTop;
// 获取侧边栏和主体内容的高度
const sidebarHeight = sidebar.offsetHeight;
const mainHeight = mainContent.offsetHeight;
// 监听滚动事件
window.addEventListener('scroll', function() {
// 获取当前滚动距离
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
// 计算主体内容底部距离视口顶部的距离
const mainBottom = mainContent.offsetTop + mainHeight;
// 如果滚动距离超过侧边栏初始顶部偏移量,且未到达主体内容底部
if (scrollTop > sidebarOffsetTop && scrollTop + sidebarHeight < mainBottom) {
sidebar.classList.add('fixed');
} else {
sidebar.classList.remove('fixed');
}
});
对应的CSS样式如下:
.sidebar {
width: 240px;
padding: 20px;
background-color: #f5f5f5;
transition: all 0.3s ease;
}
.sidebar.fixed {
position: fixed;
top: 20px; /* 固定后距离顶部的距离 */
width: 240px; /* 保持固定时宽度和原来一致 */
}
.main-content {
margin-left: 280px; /* 侧边栏宽度+间距 */
padding: 20px;
}
二、基于CSS sticky属性的侧边栏固定实现
CSS原生sticky属性是position属性的一个取值,结合了相对定位和固定定位的特点,元素在跨越特定阈值前为相对定位,之后为固定定位,实现起来更简洁,不需要编写JS逻辑,适合现代浏览器场景。
实现原理
sticky定位的生效需要满足两个条件:一是元素自身设置top、bottom、left、right任意一个阈值,二是元素的父容器不能有overflow:hidden、overflow:auto等属性,否则sticky会失效。
代码示例
/* 父容器样式,不要设置overflow隐藏 */
.container {
display: flex;
padding: 20px;
}
.sidebar {
width: 240px;
padding: 20px;
background-color: #f5f5f5;
/* 设置sticky定位,距离顶部20px时固定 */
position: sticky;
top: 20px;
align-self: flex-start; /* 避免flex布局下高度被拉伸 */
height: fit-content; /* 高度自适应内容 */
}
.main-content {
flex: 1;
margin-left: 40px;
padding: 20px;
}
对应的HTML结构如下:
<div class="container">
<div class="sidebar">
<ul>
<li>导航项1</li>
<li>导航项2</li>
<li>导航项3</li>
</ul>
</div>
<div class="main-content">
<p>这里是主体内容区域</p>
<p>可以填充大量文本来测试滚动效果</p>
</div>
</div>
三、两种方案的对比与选择
| 对比维度 | scroll事件实现 | CSS sticky实现 |
|---|---|---|
| 兼容性 | 支持所有浏览器,包括IE等旧版本 | 不支持IE,现代浏览器支持较好 |
| 实现复杂度 | 需要编写JS逻辑,处理滚动边界情况 | 仅需几行CSS,无需JS |
| 性能表现 | 频繁触发scroll事件,需要节流优化 | 浏览器原生实现,性能更优 |
| 适用场景 | 需要兼容旧浏览器,或需要复杂滚动逻辑的场景 | 现代浏览器项目,简单侧边栏固定需求 |
四、实践注意事项
- 使用scroll事件实现时,一定要给scroll事件添加节流处理,避免滚动时频繁执行回调影响性能,示例节流代码如下:
// 节流函数
function throttle(fn, delay) {
let timer = null;
return function() {
if (!timer) {
timer = setTimeout(() => {
fn.apply(this, arguments);
timer = null;
}, delay);
}
};
}
// 使用节流后的滚动监听
window.addEventListener('scroll', throttle(function() {
// 之前的滚动逻辑
}, 100));
- 使用sticky属性时,如果侧边栏高度超过视口高度,固定后会出现内容被截断的情况,此时可以设置侧边栏最大高度为视口高度,超出部分滚动:
.sidebar {
position: sticky;
top: 20px;
max-height: calc(100vh - 40px); /* 减去上下间距 */
overflow-y: auto; /* 内容超出时内部滚动 */
}
总的来说,两种侧边栏固定方案各有适用场景,开发者可以根据项目的浏览器兼容要求、功能复杂度来选择最合适的实现方式,两种方案都能很好地满足侧边栏固定的需求。