技术知识文章集合TECHNICAL ARCHIVE · 457 DOCUMENTS

显示模式

登录
ARCHIVE DOCUMENTCSS

说说 position: sticky

所属馆藏
CSS
文件格式
Markdown
原始路径
CSS/28-说说position sticky
本文目录11 个章节
  1. 参考文章
  2. 一、基本用法
  3. 二、sticky 的工作方式
  4. 三、滚动容器与 overflow
  5. 四、必须设置粘滞阈值
  6. 五、常见应用场景
  7. 六、Flex 和 Grid 中的注意事项
  8. 七、sticky 与其他定位方式的区别
  9. 八、为什么 sticky 不生效?
  10. 九、可访问性与交互注意事项
  11. 十、总结

说说 position: sticky

Category(分类): CSS Status: 未知

position: sticky 通常被称为粘性定位,常用于吸顶标题、侧边栏导航、表格表头和分组列表标题。

它保留普通流中的布局空间,在滚动过程中根据设定的阈值调整元素的位置。当滚动位置达到阈值时,元素会在允许的范围内保持相对固定;当它到达所属包含块的边界时,则不能继续粘滞。

sticky 不是简单地在 relativefixed 之间切换。元素的计算值仍然是 sticky,浏览器会结合滚动容器、粘滞阈值和包含块边界计算它的最终位置。

参考文章

一、基本用法

最简单的吸顶效果是:

<header class="site-header">
  页面标题
</header>

<main>
  <p>页面内容……</p>
  <p>页面内容……</p>
  <p>页面内容……</p>
</main>
.site-header {
  position: sticky;
  top: 0;
  z-index: 10;
  background: #fff;
  border-bottom: 1px solid #e5e7eb;
}

当页面向下滚动并且标题到达视口顶部时,标题会在允许的范围内保持在 top: 0 的位置。它仍然会占据原来的布局空间,因此不会像 fixed 那样直接从普通流中移除。

使用逻辑属性

如果需要适配不同书写模式,可以使用逻辑方向属性:

.site-header {
  position: sticky;
  inset-block-start: 0;
}

常见对应关系:

  • top 对应 inset-block-start
  • bottom 对应 inset-block-end
  • leftright 对应行方向的逻辑 inset。

二、sticky 的工作方式

1. 初始状态保留普通流空间

sticky 元素在没有达到滚动阈值前,表现得类似普通流中的元素。它不会像 absolutefixed 一样立即脱离普通流。

.title {
  position: sticky;
  top: 0;
}

此时标题原来的空间仍然存在,后面的内容不会因为标题“消失”而向上移动。

2. 达到阈值后保持粘滞

如果设置了 top: 0,当元素的顶部到达滚动容器顶部时,浏览器会尝试让它保持在该位置:

.title {
  position: sticky;
  top: 0;
}

如果设置了 top: 1rem,元素会与滚动容器顶部保持 1rem 的距离:

.title {
  position: sticky;
  top: 1rem;
}

3. 受到包含块边界限制

粘性元素不能无限脱离自己的父级区域。当它到达所属包含块的边界时,会停止继续移动。也就是说,sticky 元素通常只会在自己的父级内容范围内粘滞。

下面的示例中,每个章节标题只会在对应的 section 区域中吸顶:

<div class="article">
  <section class="chapter">
    <h2 class="chapter-title">第一章</h2>
    <p>第一章内容……</p>
    <p>第一章内容……</p>
    <p>第一章内容……</p>
  </section>

  <section class="chapter">
    <h2 class="chapter-title">第二章</h2>
    <p>第二章内容……</p>
    <p>第二章内容……</p>
    <p>第二章内容……</p>
  </section>
</div>
.chapter {
  min-height: 600px;
}

.chapter-title {
  position: sticky;
  top: 0;
  z-index: 1;
  margin: 0;
  padding: 0.75rem 1rem;
  background: #fff;
  border-bottom: 1px solid #e5e7eb;
}

当第二章标题进入顶部时,第一章标题会随着第一章的包含区域离开而停止粘滞。它不是简单地变成了 fixed,而是受到了章节边界的约束。

三、滚动容器与 overflow

sticky 会参考最近的滚动容器。很多“sticky 不生效”的问题,实际上是因为某个祖先设置了 overflow,改变了滚动参考系。

例如:

.sidebar-wrapper {
  height: 100vh;
  overflow: auto;
}

.sidebar {
  position: sticky;
  top: 1rem;
}

此时 .sidebar 会在 .sidebar-wrapper 这个滚动容器中粘滞,而不是直接参考整个页面视口。

overflow: hidden 的影响

祖先元素设置 overflow: hiddenautoscroll 后,可能建立滚动机制或改变 sticky 的粘滞边界。overflow: hidden 不一定让 sticky 彻底失效,但如果该祖先没有实际的滚动空间,效果可能看起来像没有生效。

排查时应检查:

  1. 哪个元素真正发生滚动;
  2. sticky 元素最近的滚动祖先是谁;
  3. 祖先是否设置了 overflow-xoverflow-y
  4. 滚动容器是否有明确高度;
  5. 父级是否有足够内容让元素产生粘滞过程。

常见问题代码:

.wrapper {
  overflow: hidden;
}

.sticky {
  position: sticky;
  top: 0;
}

如果 .wrapper 没有足够高度或滚动内容,.sticky 可能没有明显的滚动空间。可以根据需求移除不必要的 overflow,或者明确设置滚动容器:

.wrapper {
  max-height: 100vh;
  overflow-y: auto;
}

overflow: clipoverflow: hidden 的滚动容器行为并不完全相同。涉及复杂裁剪和粘性定位时,应在目标浏览器中实际测试。

四、必须设置粘滞阈值

垂直方向的 sticky 通常需要设置 topbottom,水平方向则需要设置 leftright

.vertical-sticky {
  position: sticky;
  top: 0;
}

.horizontal-sticky {
  position: sticky;
  left: 0;
}

如果没有设置对应滚动方向的 inset,元素通常不会表现出明显的粘滞效果:

/* 缺少阈值,通常看不到粘滞效果 */
.sticky {
  position: sticky;
}

同时设置多个方向时,最终结果还会受到元素尺寸、书写模式和粘滞视图范围影响。常规吸顶场景只设置 top,通常最容易理解和维护。

五、常见应用场景

1. 吸顶导航

.navbar {
  position: sticky;
  top: 0;
  z-index: 100;
  min-height: 3rem;
  background: #fff;
  box-shadow: 0 1px 4px rgb(0 0 0 / 12%);
}

2. 侧边栏目录

<div class="layout">
  <main class="content">
    <p>正文内容……</p>
    <p>正文内容……</p>
    <p>正文内容……</p>
  </main>

  <aside class="toc">
    <nav aria-label="文章目录">
      <a href="#intro">简介</a>
      <a href="#usage">用法</a>
      <a href="#notes">注意事项</a>
    </nav>
  </aside>
</div>
.layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 240px;
  gap: 2rem;
  align-items: start;
}

.toc {
  position: sticky;
  top: 1rem;
  max-height: calc(100vh - 2rem);
  overflow: auto;
}

侧边栏需要注意:

  • Grid 或 Flex 容器不要把侧边栏强制拉伸到过高;
  • 使用 align-self: start 可以避免某些拉伸场景;
  • 目录内容过多时,应该给目录设置最大高度和内部滚动;
  • 如果页面有固定头部,top 应预留头部高度。

3. 表格表头

.table-wrapper {
  overflow: auto;
}

thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: #f8fafc;
}

表格场景还要注意:

  • 外层横向滚动容器会影响 sticky 的参考系;
  • 表头背景不能透明,否则下面的内容会穿透;
  • 不同浏览器对表格内部元素的粘性定位支持细节可能不同;
  • 如果同时固定首列,需要分别设置 lefttop 和合适的 z-index

4. 横向滚动列表

.tabs {
  display: flex;
  gap: 1rem;
  overflow-x: auto;
}

.tabs__active {
  position: sticky;
  left: 0;
  flex: 0 0 auto;
  background: #fff;
}

横向 sticky 需要横向滚动空间,并且应结合书写方向测试 leftright 或逻辑 inset 的效果。

六、Flex 和 Grid 中的注意事项

Flex 拉伸导致没有滚动空间

在 Flex 容器中,默认的 align-items: stretch 可能使子项被拉伸到与容器一样高,从而没有明显的粘滞空间:

.layout {
  display: flex;
  align-items: flex-start;
}

.sidebar {
  position: sticky;
  top: 1rem;
  align-self: flex-start;
}

Grid 项目设置起始对齐

.layout {
  display: grid;
  grid-template-columns: 1fr 240px;
  align-items: start;
}

.sidebar {
  position: sticky;
  top: 1rem;
}

这不是所有布局中必需的配置,但当 sticky 看起来不生效时,align-itemsalign-self、父级高度和滚动容器是值得优先检查的项目。

七、sticky 与其他定位方式的区别

定位方式是否保留普通流空间是否跟随滚动常见参考系常见用途
static普通流默认布局
relative元素自身原始位置建立包含块、轻微偏移
absolute通常随包含块滚动定位包含块角标、浮层、覆盖元素
fixed通常不随页面滚动通常是视口固定导航、浮动按钮、遮罩
sticky在阈值范围内粘滞最近滚动容器和包含块吸顶标题、侧边栏、表头

stickyfixed 的主要区别是:

  • fixed 脱离普通流,通常相对于视口定位;
  • sticky 保留普通流空间,并受到滚动容器和父级边界限制;
  • fixed 可能遮挡页面内容,需要额外给正文预留空间;
  • sticky 通常只在所属容器的范围内保持粘滞。

八、为什么 sticky 不生效?

可以按照以下顺序排查:

1. 是否设置了阈值

.sticky {
  position: sticky;
  top: 0;
}

2. 是否真的发生了滚动

如果页面没有足够内容,或者滚动发生在另一个祖先元素中,sticky 可能没有机会触发。

3. 是否被祖先的 overflow 改变了滚动容器

重点检查祖先的:

overflow
overflow-x
overflow-y

4. 父级是否有足够高度

父级高度过小,sticky 没有可粘滞的范围。

5. Flex/Grid 是否产生了拉伸

尝试添加:

align-items: start;
align-self: start;

6. 是否被其他元素遮挡

为 sticky 元素设置背景和适当的 z-index

.sticky {
  z-index: 10;
  background: #fff;
}

7. 是否有布局或浏览器实现差异

旧版 Safari 曾经需要使用:

position: -webkit-sticky;
position: sticky;

现代项目通常可以优先使用标准写法,但如果项目需要支持旧版浏览器,应根据实际目标环境测试,而不是无条件添加前缀。

九、可访问性与交互注意事项

粘性元素可能遮挡锚点跳转后的内容。例如页面有固定或粘性头部时,标题可能被头部覆盖,可以使用:

[id] {
  scroll-margin-top: 4rem;
}

如果粘性头部高度会变化,可以使用 CSS 自定义属性统一维护:

:root {
  --header-height: 4rem;
}

.header {
  position: sticky;
  top: 0;
  min-height: var(--header-height);
}

[id] {
  scroll-margin-top: var(--header-height);
}

还应注意:

  • sticky 元素不能遮挡键盘焦点;
  • 颜色和背景应保证文字对比度;
  • 表格和目录固定后仍应保持合理的阅读顺序;
  • 不要仅依靠视觉位置变化传递重要状态;
  • 在移动端测试地址栏展开、收起和横竖屏切换的效果。

十、总结

  1. position: sticky 是一种带滚动约束的粘性定位方式;
  2. 它保留普通流空间,不是简单地切换为 fixed
  3. 垂直吸顶通常需要设置 top,水平粘滞通常需要设置 left 或对应逻辑 inset;
  4. sticky 会受到最近滚动容器、祖先 overflow、父级高度和包含块边界影响;
  5. overflow: hidden 不一定让 sticky 直接失效,但可能改变滚动参考系并让效果不明显;
  6. Flex/Grid 中需要重点检查 align-itemsalign-self 和可用滚动空间;
  7. 粘性元素通常需要背景色和合适的 z-index
  8. 表头、侧边栏、导航栏和分组标题是常见应用场景;
  9. 遇到 sticky 不生效时,应先检查阈值、滚动容器、父级高度和祖先 overflow;
  10. 使用 sticky 时还要考虑锚点滚动、键盘焦点和移动端视口变化。
457 DOCUMENTS · 10 COLLECTIONS
ARCHIVE SEARCH457 篇文章

SEARCH GUIDE

输入关键词开始搜索

支持搜索文章标题、所属分类和原始文档路径。

按分类浏览

10 COLLECTIONS