文章目录
- [一、元素滚动 scroll 系列属性案例 - 右侧固定侧边栏](#一、元素滚动 scroll 系列属性案例 - 右侧固定侧边栏)
-
- 1、需求说明
- [2、HTML 结构](#2、HTML 结构)
- 3、右侧固定侧边栏解析
-
- [① 相关代码](#① 相关代码)
- [② 绝对定位](#② 绝对定位)
- [③ 位置设置](#③ 位置设置)
- [4、window.pageYOffset 属性](#4、window.pageYOffset 属性)
-
- [① window.pageYOffset 属性简介](#① window.pageYOffset 属性简介)
- [② scroll 滚动事件监听](#② scroll 滚动事件监听)
- [③ 向下滚动 侧边栏 由 绝对定位 -> 固定定位](#③ 向下滚动 侧边栏 由 绝对定位 -> 固定定位)
- [④ 向上滚动 侧边栏 由 固定定位 -> 绝对定位](#④ 向上滚动 侧边栏 由 固定定位 -> 绝对定位)
- [⑤ 判断 返回顶部 按钮 显示 / 隐藏](#⑤ 判断 返回顶部 按钮 显示 / 隐藏)
- 二、代码示例
一、元素滚动 scroll 系列属性案例 - 右侧固定侧边栏
1、需求说明
在右侧 显示 固定侧边栏 ,
右侧固定侧边栏 一开始是 绝对定位 , 刚开始 向下滑动 时 , 随着 banner 一起滑动 ,
当 banner 区域 向上滑动 开始有隐藏区域 时 , 此时 将 右侧固定侧边栏 设置为 固定定位 , 其位置 固定在 浏览器 中的固定位置 ,
继续向下滑动 , 当 主体部分 开始有 隐藏区域 时 , 右侧固定侧边栏 内部 显示 返回顶部 文本 ,
滚动到底部后 , 开始向上滚动 ,
当 主体部分 的 顶部 显示出来时 , 右侧固定侧边栏 内部 隐藏 返回顶部 文本 ,
继续向上滚动 , 当 banner 区域 顶部 显示出来 时 , 将 右侧固定侧边栏 设置为 绝对定位 , 恢复到最初状态 ;

2、HTML 结构
上述 HTML 结构如下 :
html
<body>
<!-- 侧边滑块容器 , 用于承载返回顶部按钮 -->
<div class="slider-bar">
<!-- 返回顶部按钮元素 , 默认通过 CSS 隐藏 , 滚动到指定位置显示 -->
<span class="goBack">返回顶部</span>
</div>
<!-- 页面头部区域 , 应用 w 类 实现 1200px 固定宽度 + 水平居中 -->
<div class="header w">头部区域</div>
<!-- 页面横幅区域 , 应用 w 类 实现 1200px 固定宽度 + 水平居中 -->
<div class="banner w">banner区域</div>
<!-- 页面主体内容区域 , 应用 w 类 实现 1200px 固定宽度 + 水平居中 , 高度较高产生滚动 -->
<div class="main w">主体部分</div>
</body>
显示结构如下 :

3、右侧固定侧边栏解析
① 相关代码
右侧固定侧边栏
html
<!-- 侧边滑块容器 , 用于承载返回顶部按钮 -->
<div class="slider-bar">
<!-- 返回顶部按钮元素 , 默认通过 CSS 隐藏 , 滚动到指定位置显示 -->
<span class="goBack">返回顶部</span>
</div>
对应的样式如下 :
css
.slider-bar {
/* 定义类名为 slider-bar 的元素样式 ( 侧边滑块/悬浮栏 ) */
/* 定位方式 : 绝对定位 , 脱离正常文档流 , 可通过 left/top 精准定位 */
position: absolute;
/* 左侧定位 : 距离包含块 ( 默认是 body ) 左边缘 50% 的位置 */
left: 50%;
/* 顶部定位 : 距离包含块上边缘 300 像素 */
top: 300px;
/* 左外边距 : 向右偏移 600 像素 , 微调绝对定位元素的最终水平位置 */
margin-left: 600px;
/* 设置滑块宽度为 45 像素 */
width: 45px;
/* 设置滑块高度为 130 像素 */
height: 130px;
/* 设置滑块背景颜色为粉色 , 用于可视化区分 */
background-color: pink;
}
子容器 span 对应的 样式如下 :
css
span {
/* 定义所有span标签的样式 ( 滑块内的子元素 , 如 按钮/提示文字 ) */
/* 显示方式 : 隐藏 ( 默认不显示 , 通常通过 JS 控制显示/隐藏 ) */
display: none;
/* 定位方式 : 绝对定位 , 相对于最近的已定位父元素 ( .slider-bar ) 定位 */
position: absolute;
/* 核心修改1:垂直方向定位到父容器50%位置(基于span的左上角) */
top: 50%;
/* 核心修改2:水平方向定位到父容器50%位置(基于span的左上角) */
left: 50%;
/* 核心修改3:将span自身向左、向上平移50%,使span的中心点对齐父容器中心点 */
transform: translate(-50%, -50%);
}
② 绝对定位
右侧侧边栏 slider-bar 使用了绝对定位 , 按照 " 子绝父相 " 的 定位规则 , 它本应 基于 最近的 相对定位 父容器定位 , 但它的 父容器 body 并没有设置相对定位 ;
" 子绝父相 " 的核心是 : 绝对定位 元素 优先以 最近的 已定位 祖先元素 为基准 , 无则以 视口 为基准 ;
- 绝对定位
position: absolute的元素会 脱离 正常 文档流 , 其定位基准是 最近的 已定位 祖先元素 , " 已定位 " 指 position 值为 relative、absolute、fixed、sticky , 而非默认的 static ; - 如果没有找到任何 已定位 的 祖先元素 , 绝对定位 元素会以 初始包含块 作为定位基准 , 初始包含块 通常等价于 浏览器视口 可视区域 , 该区域 一般 与 body 元素的 视觉范围 基本重合 ;
body 默认的定位模式是 position: static , 这里有布局上的隐患 , 建议 给 body 添加 position: relative 样式 ;
③ 位置设置
右侧固定侧边栏 设置为了 绝对定位 , 这是 以 父容器 body 为基准 的 绝对定位 ,
设置了 left: 50% , 这是将 容器 的 左侧 设置在了 body 正中心位置 ,
然后 又设置了 margin-left: 600px 左侧外边距 , 向右偏移 600 像素 , 结合上面的 中心位置 , 这里说明 容器左侧 设置在了 中心偏右 600 像素距离 ;
css
/* 定位方式 : 绝对定位 , 脱离正常文档流 , 可通过 left/top 精准定位 */
position: absolute;
/* 左侧定位 : 距离包含块 ( 默认是 body ) 左边缘 50% 的位置 */
left: 50%;
/* 顶部定位 : 距离包含块上边缘 300 像素 */
top: 300px;
/* 左外边距 : 向右偏移 600 像素 , 微调绝对定位元素的最终水平位置 */
margin-left: 600px;
4、window.pageYOffset 属性
① window.pageYOffset 属性简介
window.pageYOffset 属性 是 BOM 中 window 对象的只读属性 , 该属性 用于 返回 当前文档 在垂直方向上 已经滚动的 像素值 , 简单说就是 页面 向下滚动的距离 ;
把网页看作一张 超长的纸 , 浏览器窗口是一个 " 取景框 " , window.pageYOffset 属性 就是这个 取景框 相对于 纸张顶部 向下移动的像素数 , 页面没滚动时 , 该属性的值是 0 , 向下滚动 200px , 该属性的值就是 200 ;
window.pageYOffset 属性 有一个别名 window.scrollY , 二者 功能完全等价 , scrollY 是更现代的写法 , pageYOffset 属性 兼容性 更好 ;
window.pageYOffset 属性 对应的 水平滚动距离 属性 是 window.pageXOffset , 对应的 别名 scrollX 属性 ;
② scroll 滚动事件监听
为整个 HTML 文档绑定 滚动事件 scroll 监听器 , 当你滚动页面时,传入的匿名回调函数会被持续触发(每滚动一小段距离就会执行一次)。这是实现所有 "滚动交互效果" 的基础,比如导航吸顶、回到顶部按钮、滚动加载等。
javascript
// 2. 为文档添加滚动事件监听 : 页面滚动时持续触发回调函数
document.addEventListener('scroll', function() {})
document.addEventListener('scroll', function() {}) 和 window.addEventListener('scroll', function() {}) 效果几乎完全一致 , 因为 页面滚动 的本质是 window 的滚动 , 日常开发中两种写法都很常见 ;
回调函数默认会接收一个 事件对象 , 通常命名为 e , 但 document 和 window 对象的 滚动事件 中 一般用不到 event 事件 , 可省略 ;
③ 向下滚动 侧边栏 由 绝对定位 -> 固定定位
向下滚动页面 , 开始时 " 右侧固定侧边栏 " 跟随 banner 滑动 , 当 banner 开始隐藏时 , 由 绝对定位 变为 固定定位 ;

在 文档页面 滚动时 触发回调函数 , 使用 window.pageYOffset 属性 获取 页面垂直方向 被卷去的 头部距离 , 根据这个距离 判定 " 右侧固定侧边栏 " 的 样式设置 ;
" 右侧固定侧边栏 " 初始状态 是 绝对定位 ;
当 页面滚动距离 ≥ banner 顶部距离时 , 切换 " 右侧固定侧边栏 " 为 固定定位 ;
同时设置 固定定位 的 top 值 , 保证 " 右侧固定侧边栏 " 滑块位置 与 原 绝对定位 时对齐 ;
javascript
// 3. 判断 : 当页面滚动距离 ≥ banner 顶部距离时 , 切换滑块为固定定位
if (window.pageYOffset >= bannerTop) {
// 将 滑块 定位方式改为 固定定位 ( fixed ) , 脱离文档流 , 固定在可视区域
sliderbar.style.position = 'fixed';
// 设置 固定定位 的 top 值 , 保证滑块位置与原绝对定位时对齐 , 不偏移
sliderbar.style.top = sliderbarTop + 'px';
}
计算 " 右侧固定侧边栏 " 滑块 固定定位 时的 top 值 : " 右侧固定侧边栏 " 滑块 初始 top 值 - banner 顶部距离 , 保证 固定定位 后位置与原 绝对定位 对齐 ;
banner 顶部距离 可以 通过 banner 元素 获取 距离文档顶部 的距离 , 也就是 banner.offsetTop , 该值是 只读属性 , 不随滚动变化 ;
javascript
// banner.offsetTop : 获取 banner 元素 距离文档顶部 的 初始距离 ( 只读 , 不随滚动变化 ) , 必须写在滚动事件外
var bannerTop = banner.offsetTop;
// 计算滑块 固定定位 时的 top 值 : 滑块初始 top 值 - banner 顶部距离 , 保证 固定定位 后位置与原 绝对定位 对齐
var sliderbarTop = sliderbar.offsetTop - bannerTop;
④ 向上滚动 侧边栏 由 固定定位 -> 绝对定位
向上滚动页面 , 开始时 " 右侧固定侧边栏 " 是固定定位 , 当页面向上滚动时 , 主体部分刚显示时 , 由 固定定位 变为 绝对定位 ;

banner 顶部刚刚显示出来时 , 恢复 " 右侧固定侧边栏 " 滑块的 绝对定位 , 同时 恢复 绝对定位 的 初始 top 值 , 也就是 " 右侧固定侧边栏 " 滑块的 绝对定位 时 在 css 样式中设置的值 ;
javascript
// 3. 判断 : 当页面滚动距离 ≥ banner 顶部距离时 , 切换滑块为固定定位
if (window.pageYOffset >= bannerTop) {
} else {
// banner 顶部刚刚显示出来时 , 恢复滑块的绝对定位 ( absolute )
sliderbar.style.position = 'absolute';
// 恢复 绝对定位 的 初始 top 值 ( 与 CSS 中设置的 300px 一致 )
sliderbar.style.top = '300px';
}
这个 " 右侧固定侧边栏 " 滑块 初始 绝对定位时 , 样式如下 , 上面 恢复 绝对定位 top 值 sliderbar.style.top = '300px'; 时 的 300px 就在此处 ;
css
.slider-bar {
/* 定义类名为 slider-bar 的元素样式 ( 侧边滑块/悬浮栏 ) */
/* 定位方式 : 绝对定位 , 脱离正常文档流 , 可通过 left/top 精准定位 */
position: absolute;
/* 左侧定位 : 距离包含块 ( 默认是 body ) 左边缘 50% 的位置 */
left: 50%;
/* 顶部定位 : 距离包含块上边缘 300 像素 */
top: 300px;
/* 左外边距 : 向右偏移 600 像素 , 微调绝对定位元素的最终水平位置 */
margin-left: 600px;
/* 设置滑块宽度为 45 像素 */
width: 45px;
/* 设置滑块高度为 130 像素 */
height: 130px;
/* 设置滑块背景颜色为粉色 , 用于可视化区分 */
background-color: green;
/* 核心:设置文本为白色 */
color: white;
}
⑤ 判断 返回顶部 按钮 显示 / 隐藏
向下滚动 , 直到 主体部分 开始隐藏 , 此时 显示 " 返回顶部 " 按钮 ,
再次向上滚动时 , 主体部分 顶部 显示出来时 , 隐藏 " 返回顶部 " 按钮 ,

当页面滚动距离 ≥ main 顶部距离时 , 显示 返回顶部 按钮 , 设置 display 属性为 block , 即可见的 块级显示方式 ;
未滚动到 main 位置 , 隐藏 返回 顶部按钮 , 设置 display 属性为 none ;
javascript
// 4. 判断 : 当页面滚动距离 ≥ main 顶部距离时 , 显示返回顶部按钮
if (window.pageYOffset >= mainTop) {
// 显示 返回顶部 按钮 ( block 为可见的 块级显示方式 )
goBack.style.display = 'block';
} else {
// 未滚动到 main 位置 , 隐藏 返回顶部按钮 ( none 为完全隐藏 , 不占空间 )
goBack.style.display = 'none';
}
二、代码示例
1、代码示例
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>右侧固定侧边栏</title>
<style>
.slider-bar {
/* 定义类名为 slider-bar 的元素样式 ( 侧边滑块/悬浮栏 ) */
/* 定位方式 : 绝对定位 , 脱离正常文档流 , 可通过 left/top 精准定位 */
position: absolute;
/* 左侧定位 : 距离包含块 ( 默认是 body ) 左边缘 50% 的位置 */
left: 50%;
/* 顶部定位 : 距离包含块上边缘 300 像素 */
top: 300px;
/* 左外边距 : 向右偏移 600 像素 , 微调绝对定位元素的最终水平位置 */
margin-left: 600px;
/* 设置滑块宽度为 45 像素 */
width: 45px;
/* 设置滑块高度为 130 像素 */
height: 130px;
/* 设置滑块背景颜色为粉色 , 用于可视化区分 */
background-color: green;
/* 核心:设置文本为白色 */
color: white;
}
.w {
/* 定义 通用容器类 w 的样式 ( 统一页面主体宽度和居中 ) */
/* 设置容器固定宽度为 1200 像素 ( PC 端常用的页面主体宽度 ) */
width: 1200px;
/* 外边距 : 上下10像素 , 左右自动分配 ( 实现元素水平居中 ) */
margin: 10px auto;
}
.header {
/* 定义类名为 header 的页面头部区域样式 */
/* 设置头部区域高度为 150 像素 */
height: 150px;
/* 设置背景颜色为紫色 , 便于区分页面区块 */
background-color: blue;
/* 文本水平居中 */
text-align: center;
/* 设置文本为白色 */
color: white;
}
.banner {
/* 定义类名为 banner 的页面横幅区域样式 */
/* 设置横幅区域高度为 250 像素 */
height: 250px;
/* 设置背景颜色为天蓝色 , 便于区分页面区块 */
background-color: red;
/* 文本水平居中 */
text-align: center;
/* 设置文本为白色 */
color: white;
}
.main {
/* 定义类名为 main 的页面主体内容区域样式 */
/* 设置主体区域高度为 1000 像素 , 该高度 足够高 以产生页面滚动条 */
height: 1000px;
/* 设置背景颜色为黄绿色 , 便于区分页面区块 */
background-color: purple;
/* 文本水平居中 */
text-align: center;
/* 设置文本为白色 */
color: white;
}
span {
/* 定义所有span标签的样式 ( 滑块内的子元素 , 如 按钮/提示文字 ) */
/* 显示方式 : 隐藏 ( 默认不显示 , 通常通过 JS 控制显示/隐藏 ) */
display: none;
/* 定位方式 : 绝对定位 , 相对于最近的已定位父元素 ( .slider-bar ) 定位 */
position: absolute;
/* 核心修改1:垂直方向定位到父容器50%位置(基于span的左上角) */
top: 50%;
/* 核心修改2:水平方向定位到父容器50%位置(基于span的左上角) */
left: 50%;
/* 核心修改3:将span自身向左、向上平移50%,使span的中心点对齐父容器中心点 */
transform: translate(-50%, -50%);
}
</style>
</head>
<body>
<!-- 侧边滑块容器 , 用于承载返回顶部按钮 -->
<div class="slider-bar">
<!-- 返回顶部按钮元素 , 默认通过 CSS 隐藏 , 滚动到指定位置显示 -->
<span class="goBack">返回顶部</span>
</div>
<!-- 页面头部区域 , 应用 w 类 实现 1200px 固定宽度 + 水平居中 -->
<div class="header w">头部区域</div>
<!-- 页面横幅区域 , 应用 w 类 实现 1200px 固定宽度 + 水平居中 -->
<div class="banner w">banner 区域</div>
<!-- 页面主体内容区域 , 应用 w 类 实现 1200px 固定宽度 + 水平居中 , 高度较高产生滚动 -->
<div class="main w">主体部分</div>
<script>
// 1. 获取页面元素 ( 提前获取避免滚动事件内重复查询 DOM , 优化性能 )
// 获取侧边滑块容器的 DOM 元素
var sliderbar = document.querySelector('.slider-bar');
// 获取 banner 区域的 DOM 元素
var banner = document.querySelector('.banner');
// 获取 main主体区域 的 DOM 元素
var main = document.querySelector('.main');
// 获取 返回顶部按钮 的 DOM 元素
var goBack = document.querySelector('.goBack');
// banner.offsetTop : 获取 banner 元素 距离文档顶部 的 初始距离 ( 只读 , 不随滚动变化 ) , 必须写在滚动事件外
var bannerTop = banner.offsetTop;
// 计算滑块 固定定位 时的 top 值 : 滑块初始 top 值 - banner 顶部距离 , 保证 固定定位 后位置与原 绝对定位 对齐
var sliderbarTop = sliderbar.offsetTop - bannerTop;
// 获取 main 元素 距离 文档顶部 的初始距离 , 用于判断 显示 返回顶部 按钮的时机
var mainTop = main.offsetTop;
// 2. 为文档添加滚动事件监听 : 页面滚动时持续触发回调函数
document.addEventListener('scroll', function() {
// window.pageYOffset : 获取页面垂直方向被卷去的头部距离 ( 滚动距离 )
// 3. 判断 : 当页面滚动距离 ≥ banner 顶部距离时 , 切换滑块为固定定位
if (window.pageYOffset >= bannerTop) {
// 将 滑块 定位方式改为 固定定位 ( fixed ) , 脱离文档流 , 固定在可视区域
sliderbar.style.position = 'fixed';
// 设置 固定定位 的 top 值 , 保证滑块位置与原绝对定位时对齐 , 不偏移
sliderbar.style.top = sliderbarTop + 'px';
} else {
// banner 顶部刚刚显示出来时 , 恢复滑块的绝对定位 ( absolute )
sliderbar.style.position = 'absolute';
// 恢复绝对定位的初始 top 值 ( 与 CSS 中设置的 300px 一致 )
sliderbar.style.top = '300px';
}
// 4. 判断 : 当页面滚动距离 ≥ main 顶部距离时 , 显示返回顶部按钮
if (window.pageYOffset >= mainTop) {
// 显示 返回顶部 按钮 ( block 为可见的 块级显示方式 )
goBack.style.display = 'block';
} else {
// 未滚动到 main 位置 , 隐藏 返回顶部按钮 ( none 为完全隐藏 , 不占空间 )
goBack.style.display = 'none';
}
})
</script>
</body>
</html>
2、执行结果
