各位前端小伙伴,今天我们来聊聊------position: sticky。无论你是刚入行的新人,还是有一定经验的开发者,掌握 position: sticky都能让你在开发页面时游刃有余。 position: sticky 是一个非常实用的 CSS 属性,它可以让元素在滚动时"粘"在某个位置,像是 相对定位 和 固定定位 的混合体。简单来说,在元素跨越特定阈值之前,它表现为相对定位;一旦跨越阈值,就变成固定定位,直到其容器滚出视口。
通俗点来说,sticky 就是: "在父容器范围内,滚动到指定位置就固定,父容器滚走它就跟着滚走" 。
它不像 fixed 那样死死钉在屏幕上一个地方不动,也不像 relative 那样完全随波逐流。它是两者的"混血儿",聪明又灵活。
所以做网页时,你想让某个元素(导航栏、标题、侧边栏)在滚动时"粘"在某个位置,但又不想让它超出自己的地盘,用 sticky 就对了!
下面详细介绍它的用法,并附上可直接运行的代码实例。
1. 基本语法
css
css
.sticky-element {
position: sticky;
top: 0; /* 可选:left/bottom/right,至少指定一个阈值 */
}
必须指定 top、bottom、left 或 right 中的一个,元素才会在到达该阈值时"粘"住。
2. 工作原理
- 元素在父容器范围内时,遵循正常文档流(相对定位)。
- 当滚动到指定阈值(例如
top: 10px)时,元素变为固定定位(相对于视口),直到其父容器完全滚出视口。 - 关键限制 :粘性效果只在父容器内生效,且父容器不能设置
overflow: hidden或overflow: auto等(会破坏粘性)。
3. 📁案例一:粘性导航栏
文件名建议 :sticky-nav-demo.html
效果:导航栏在滚动到顶部时固定,始终可见。
html
xml
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>案例1:粘性导航栏 · position: sticky</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Roboto, sans-serif;
background: linear-gradient(145deg, #f1f5f9 0%, #e6edf5 100%);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
}
.card {
max-width: 700px;
width: 100%;
background: white;
border-radius: 40px;
box-shadow: 0 30px 50px -20px rgba(0,30,60,0.25);
padding: 30px;
}
h2 {
font-weight: 550;
color: #0f172a;
margin-bottom: 6px;
font-size: 2rem;
display: flex;
align-items: center;
gap: 8px;
}
h2 span {
background: #2563eb;
color: white;
font-size: 0.9rem;
padding: 4px 12px;
border-radius: 30px;
}
.desc {
color: #475569;
margin-bottom: 30px;
padding-left: 12px;
border-left: 5px solid #2563eb;
background: #f8fafc;
padding: 12px 18px;
border-radius: 20px;
}
/* 演示区域:固定高度+滚动 */
.demo-scroll-box {
height: 380px;
overflow-y: auto;
border-radius: 24px;
background: #ffffff;
border: 2px solid #d9e2ef;
scroll-behavior: smooth;
}
.demo-header {
background: #cbd5e1;
padding: 20px;
text-align: center;
font-weight: 600;
color: #1e293b;
}
.sticky-nav {
position: sticky;
top: 0;
background: #0f172a;
color: white;
padding: 16px 20px;
text-align: center;
font-weight: 500;
letter-spacing: 0.8px;
box-shadow: 0 6px 12px rgba(0,0,0,0.1);
z-index: 10;
}
.content p {
background: #f9f9fc;
padding: 18px 22px;
margin: 20px;
border-radius: 20px;
border: 1px solid #e2e8f0;
box-shadow: 0 2px 5px rgba(0,0,0,0.02);
}
.note {
margin-top: 30px;
background: #fef9c3;
border-left: 6px solid #eab308;
padding: 16px 22px;
border-radius: 24px;
color: #854d0e;
}
</style>
</head>
<body>
<div class="card">
<h2>📌 案例1 <span>sticky</span></h2>
<div class="desc">⚓ 粘性导航栏 --- 滚动时自动吸附在顶部,无需JavaScript。</div>
<!-- 可滚动的演示区域 -->
<div class="demo-scroll-box">
<div class="demo-header">我是普通头部(会滚走)</div>
<div class="sticky-nav">🧲 导航栏 · 粘在顶部 (top:0)</div>
<div class="content">
<p>📄 第1条内容:继续向下滚动,观察导航栏。</p>
<p>📄 第2条内容:它会一直固定在顶部。</p>
<p>📄 第3条内容:直到父容器滚出视口才消失。</p>
<p>📄 第4条内容:原理是 position: sticky; top:0。</p>
<p>📄 第5条内容:兼容现代浏览器,简单高效。</p>
<p>📄 第6条内容:可以替代传统的JS监听滚动。</p>
<p>📄 第7条内容:再加一条,看看滚动条长度。</p>
</div>
</div>
<div class="note">
💡 核心点:<code>position: sticky;</code> 必须搭配 <code>top</code> / <code>bottom</code> 使用;父容器不能设置 <code>overflow:hidden</code>。
</div>
</div>
</body>
</html>
效果 :当滚动使导航栏触碰到视口顶部时,它会固定在上方,直到父容器 .content 完全离开视口。

📁 案例二:粘性章节标题(通讯录效果)
文件名建议 :sticky-sections-demo.html
效果:每个分组的标题在滚动到顶部时固定,直到被下一个标题推上去。
html
xml
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>案例2:粘性章节标题 · position: sticky</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Roboto, sans-serif;
background: #eef2f6;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
}
.card {
max-width: 600px;
width: 100%;
background: white;
border-radius: 40px;
box-shadow: 0 30px 50px -20px rgba(0,20,40,0.25);
padding: 30px;
}
h2 {
font-weight: 550;
color: #0f172a;
margin-bottom: 6px;
font-size: 2rem;
display: flex;
align-items: center;
gap: 8px;
}
h2 span {
background: #2563eb;
color: white;
font-size: 0.9rem;
padding: 4px 12px;
border-radius: 30px;
}
.desc {
color: #475569;
margin-bottom: 30px;
padding-left: 12px;
border-left: 5px solid #2563eb;
background: #f8fafc;
padding: 12px 18px;
border-radius: 20px;
}
/* 可滚动容器 */
.scroll-sections {
max-height: 420px;
overflow-y: auto;
border-radius: 24px;
background: #ffffff;
border: 2px solid #d1dbe9;
}
.section {
background: white;
}
.sticky-title {
position: sticky;
top: 0;
background: #2563eb;
color: white;
padding: 12px 20px;
margin: 0;
font-size: 1.4rem;
font-weight: 600;
border-bottom: 3px solid #1e3f8f;
box-shadow: 0 2px 8px rgba(37,99,235,0.3);
z-index: 5;
}
/* 为了让不同标题视觉区分 */
.section:nth-child(2) .sticky-title {
background: #c2410c;
border-bottom-color: #9a3412;
}
.section:nth-child(3) .sticky-title {
background: #2b6f4b;
border-bottom-color: #1e4b34;
}
.section p {
padding: 14px 22px;
margin: 0;
border-bottom: 1px solid #e9edf3;
font-size: 1.1rem;
}
.section p:last-child {
border-bottom: none;
}
.note {
margin-top: 30px;
background: #fef9c3;
border-left: 6px solid #eab308;
padding: 16px 22px;
border-radius: 24px;
color: #854d0e;
}
</style>
</head>
<body>
<div class="card">
<h2>📇 案例2 <span>sticky</span></h2>
<div class="desc">🗂️ 粘性分区标题 --- 类似通讯录,当前标题固定,直到被下一个顶替。</div>
<div class="scroll-sections">
<div class="section">
<h3 class="sticky-title">🌟 A 组 · 设计部</h3>
<p>Alice Chen</p>
<p>Amanda Li</p>
<p>Alex Wang</p>
<p>Angela Zhao</p>
<p>Adam Brown</p>
</div>
<div class="section">
<h3 class="sticky-title">🔥 B 组 · 市场部</h3>
<p>Bob Zhang</p>
<p>Bella Xu</p>
<p>Ben Liu</p>
<p>Bianca Wu</p>
<p>Bruce Huang</p>
</div>
<div class="section">
<h3 class="sticky-title">🌿 C 组 · 技术部</h3>
<p>Chris Sun</p>
<p>Ciara Zhou</p>
<p>Carlos Lin</p>
<p>Catherine Ma</p>
<p>Clark Lee</p>
</div>
</div>
<div class="note">
💡 关键点:每个标题都是 <code>sticky</code>,后一个会把前一个顶上去,形成通讯录效果。父容器滚动区域必须足够高。
</div>
</div>
</body>
</html>
效果:滚动时,当前章节的标题会固定在顶部,直到被下一个章节的标题推上去。这正是 iOS 通讯录常用的交互。

📁 案例三:粘性侧边栏
文件名建议 :sticky-sidebar-demo.html
效果:在双栏 Flex 布局中,左侧边栏滚动到指定位置后固定。
html
xml
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>案例3:粘性侧边栏 · position: sticky</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Roboto, sans-serif;
background: #e7edf5;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
}
.card {
max-width: 800px;
width: 100%;
background: white;
border-radius: 40px;
box-shadow: 0 30px 50px -20px rgba(0,30,50,0.25);
padding: 30px;
}
h2 {
font-weight: 550;
color: #0f172a;
margin-bottom: 6px;
font-size: 2rem;
display: flex;
align-items: center;
gap: 8px;
}
h2 span {
background: #2563eb;
color: white;
font-size: 0.9rem;
padding: 4px 12px;
border-radius: 30px;
}
.desc {
color: #475569;
margin-bottom: 30px;
padding-left: 12px;
border-left: 5px solid #2563eb;
background: #f8fafc;
padding: 12px 18px;
border-radius: 20px;
}
/* flex 演示容器 */
.demo-flex {
display: flex;
align-items: flex-start; /* 防止拉伸,保证粘性有效 */
gap: 20px;
background: #ffffff;
border-radius: 24px;
border: 2px solid #ccdbe9;
min-height: 380px;
}
.sidebar {
position: sticky;
top: 20px; /* 距离父容器顶部20px时固定 */
width: 180px;
background: #dbeafe;
padding: 30px 16px;
border-radius: 18px;
border: 2px solid #2563eb;
color: #1e3a8a;
font-weight: 600;
text-align: center;
margin: 18px 0 18px 18px;
box-shadow: 0 8px 18px rgba(37,99,235,0.12);
}
.main-content {
flex: 1;
padding: 16px 20px 16px 0;
height: 380px;
overflow-y: auto;
}
.main-content p {
background: #f1f5f9;
padding: 16px 20px;
border-radius: 16px;
margin: 18px 0;
border: 1px solid #dce3ef;
}
.note {
margin-top: 30px;
background: #fef9c3;
border-left: 6px solid #eab308;
padding: 16px 22px;
border-radius: 24px;
color: #854d0e;
}
</style>
</head>
<body>
<div class="card">
<h2>🧩 案例3 <span>sticky</span></h2>
<div class="desc">📌 粘性侧边栏 --- 在双栏布局中,侧边栏滚动到距离父容器顶部20px时固定。</div>
<div class="demo-flex">
<aside class="sidebar">
⚡ 侧边栏<br>
<span style="font-size:0.9rem;">top:20px 固定</span>
</aside>
<div class="main-content">
<p>📘 第1条:侧边栏会粘在距离父容器顶部20px的位置。</p>
<p>📘 第2条:注意父容器要设置 align-items: flex-start。</p>
<p>📘 第3条:并且不能有 overflow:hidden 限制。</p>
<p>📘 第4条:增加内容方便滚动查看粘性效果。</p>
<p>📘 第5条:直到父容器完全离开视口,侧边栏才会消失。</p>
<p>📘 第6条:纯CSS实现,比JS方案更流畅。</p>
</div>
</div>
<div class="note">
💡 小提示:侧边栏的父容器(flex容器)必须有足够高度,并且侧边栏自身不能是 flex 拉伸的高度(使用 <code>align-self: flex-start</code> 或父级 <code>align-items: flex-start</code>)。
</div>
</div>
</body>
</html>
注意 :要保证侧边栏的父容器(.container)有足够的高度,并且没有溢出隐藏。同时,侧边栏的兄弟元素(主内容)高度应大于侧边栏,否则侧边栏可能提前停止粘性。

这三个文件各自独立,展示了 position: sticky 最常见的应用场景。每个页面都包含了清晰的说明和可交互的滚动区域,非常适合作为技术博客的嵌入示例。读者可以分别打开,直观感受粘性定位的魅力。
4. 注意事项
- 父容器限制
sticky元素的活动范围仅限于其父容器内。当父容器滚出视口时,粘性元素也随之消失。 - 溢出属性
如果父容器或任一祖先设置了overflow: hidden/auto/scroll,sticky可能会失效(因为固定定位被限制在可滚动区域内)。通常建议不要在粘性元素的祖先上设置overflow非visible。 - 必须指定阈值
至少指定top、bottom、left或right中的一个,否则行为类似relative。 - 多个粘性元素
多个同向的粘性元素会依次堆叠,后一个会顶替前一个的位置(如实例二所示)。 - z-index
需要时可以通过z-index控制堆叠顺序,避免被其他元素覆盖。 - 表格表头
也可以用在<thead>上实现表头固定(但需注意浏览器兼容性)。
5. 浏览器兼容性
现代浏览器(Chrome、Firefox、Safari、Edge 较新版本)均支持 sticky。对于旧版浏览器(如 IE),可以使用 JavaScript 回退(例如用 position: fixed 结合滚动监听模拟),但通常 sticky 是渐进增强的特性,不强制支持。
6. 总结
position: sticky 让我们用纯 CSS 实现过去需要 JavaScript 才能完成的"滚动粘性"效果,代码简洁且性能更好。只需记住:一个粘性元素,一个阈值,一个不设溢出隐藏的父容器,就能轻松实现导航栏固定、分区标题、侧边栏跟随等常见交互。
如果这篇文章让你对CSS刮目相看,点个赞,转个发,收藏下,让更多朋友看到------CSS真的在吃掉前端。
#前端#CSS#干货