创建页面内容,使其在滚动时固定在视口中,例如跳转到锚点菜单或章节标题,从未如此简单。在您的 CSS 规则集中添加一个 position: sticky
,设置方向偏移量(例如 top: 0
),您就可以毫不费力地给您的团队留下深刻印象。查看 这篇 CSS-Tricks 文章,了解一些真正花哨的固定定位用例。
但是固定定位可能会有点棘手,尤其是在涉及高度以及隐藏无法滚动到的位置中的内容的危险情况下。让我设置场景,向您展示问题以及我如何解决它。
我最近在一个我们都熟悉的桌面布局上工作:一个主要内容区域,旁边有一个侧边栏。此侧边栏包含与主要内容相关的操作项和筛选器。当页面部分滚动时,此组件保持固定在视口中,并且可以上下文访问。
布局样式的实现就像我之前提到的那样简单。但有一个问题:组件的高度会根据其内容而变化。我可以使用 max-height
对其进行限制,并设置 overflow-y: auto
使组件内容可滚动。这在我的笔记本电脑屏幕和我的典型视口高度上运行良好,但在垂直空间较小的较小视口中,侧边栏的高度会超出视口。
事情变得棘手了。
思考解决方案
我最初考虑使用媒体查询。也许我可以使用媒体查询删除固定定位,并让组件相对于侧边栏容器的顶部放置。这将允许访问其所有内容。否则,当滚动页面时,固定组件的内容会在视口底部被截断,直到我到达其父部分的末尾。
然后我记起固定组件的高度是动态的。
我可以在媒体查询中使用什么神奇的值来处理这样的事情?也许我可以编写一个 JavaScript 函数来检查组件在页面加载时是否超出视口边界?然后我可以更新组件的高度……
这是一种可能性。
但是如果用户调整窗口大小呢?我应该在调整大小事件处理程序中使用相同的函数吗?这感觉不对。一定有更好的方法来构建它。
事实证明有,它涉及一些 CSS 技巧来完成这项工作!
设置页面部分
我从主元素上的 flex
显示开始。为侧边栏设置了一个 flex-basis
值,用于固定桌面宽度。然后文章元素填充了剩余的可用水平视口空间。
如果您好奇我如何在没有媒体查询的情况下让这两个容器在较小的视口中堆叠,请查看 Flexbox 神圣信天翁 技巧。
我向侧边栏添加了 align-self: start
,以便其高度不会随着主要文章(stretch
是默认值)而拉伸。这使我的定位属性能够发挥其魔力
.sidebar {
--offset: var(--space);
/* ... */
position: sticky;
top: var(--offset);
}
看看!使用这两个 CSS 属性,侧边栏元素会固定在视口顶部,并带有一个偏移量以提供一些呼吸空间。请注意,top
值设置为 作用域 CSS 自定义属性。现在,--offset
变量可以在侧边栏内的任何子元素上重复使用。这在稍后设置固定侧边栏组件的最大高度时会派上用场。
您可以在 CodePen 演示中找到全局 CSS 变量声明的列表,包括在 :root
规则集中用于偏移值的 --space
变量。
固定侧边栏
请记住,组件本身不是固定的;是侧边栏本身固定。通用布局和定位通常应由父级处理。这使组件更具灵活性,并使其更易于在应用程序的其他区域中使用。
让我们深入了解此组件的结构。在 演示中,我已删除了以下装饰性属性,以专注于布局样式
.component {
display: grid;
grid-template-rows: auto 1fr auto;
}
.component .content {
max-height: 500px;
overflow-y: auto;
}
- 此组件使用 CSS Grid 和来自 1-Line Layouts的 煎饼堆栈理念来配置此模板的行。标题和页脚(
auto
)都调整为其子元素的高度,而内容(1fr
,或一个 分数单位)填充剩余的开放垂直空间。 - 内容上的
max-height
限制了组件在较大屏幕尺寸上的增长。如果希望组件拉伸以填充视口高度,则无需此操作。 overflow-y: auto
允许在必要时滚动内容。
当组件在侧边栏中使用时,需要 max-height
以使其不超过视口高度。之前作用域到 .sidebar
类的 --offset
加倍以在元素底部创建与固定侧边栏顶部偏移量匹配的边距
.sidebar .component {
max-height: calc(100vh - var(--offset) * 2);
}
至此,这个固定侧边栏组件的组装就完成了!应用了一些装饰性样式后,此原型便可以进行测试和审查。试一试!在 CodePen 中打开演示,然后点击网格项将其添加到侧边栏。调整浏览器窗口大小以查看组件如何在视口中灵活变化,同时在您滚动主要内容部分时保持可见。
此布局可能在桌面浏览器上运行良好,但对于较小的设备或视口宽度并不完全理想。但是,此处的代码提供了一个坚实的基础,可以轻松地对 UI 进行改进。
一个简单的想法:一个按钮可以固定到视口窗口,单击时,页面会跳转到侧边栏内容。另一个想法:侧边栏可以隐藏在屏幕外,一个切换按钮可以将其从左侧或右侧滑入。迭代和用户测试将帮助将此体验引导到正确的方向。
它应该在手机上固定吗?
如果是这样,它可能无法按预期工作 - 刚在 Chrome/Pixel 3a 上尝试过 :/
我的完美时机!这正是我昨天想到的问题的解决方案。
而且我确实希望在文章中提出的手机上有一个切换功能。感谢这篇文章!
所以是的,这在手机上效果很好;)
只是它仅在桌面布局中有效(如您在 CodePen 中直接看到的横向手机)。
不错不错 :)
我分叉并在 gist 中保存,以便可以在我的项目中实现它!
我不明白使用
align-selft: start
、在侧边栏上偏移顶部,然后计算组件高度的原因。为什么不在组件上设置max-height: 100%
,然后在侧边栏上设置max-height: 100vh
并使用--space
进行顶部和底部填充?这两种方法是否都有效,或者您的方法有什么特别之处?使用
top
属性而不是在侧边栏上应用填充或边距将正确地将组件的顶部与主要文章的顶部对齐。如果您要在 CodePen 上分叉此演示并添加您建议的更改,您还会注意到,当视口高度变得非常高时,组件会在到达主要部分底部之前停止。我认为在尝试此布局时,我经历过类似的迭代。很棒的文章,Ryan!非常喜欢那个视频演示。
您能否在文章中添加 Facebook 案例?例如,在桌面的 Facebook 个人资料页面中。
很棒且简单的解决方案,Ryan!感谢分享。
还有一种方法可以解决动态大小侧边栏的问题,而无需创建内部滚动区域,但它将使用 JavaScript。
https://github.com/vursen/FloatSidebar.js(我的库,gzip 后大小为 2kb)
https://abouolia.github.io/sticky-sidebar/
非常棒的文章和布局!但是有个快速的问题:如果有一个可以改变高度的固定头部(基于用户输入,所以不能使用 margin),是否有办法在 CSS 中实现相同的功能?
我似乎找不到不使用 js 的解决方案……
谢谢
谢谢!!这篇文章真的让我开心了一天..解释得很好,直中要害!! :)