position
属性非常重要,它有五个可选值。“这五个选项是哪些?它们的作用如何?”是我非常喜欢的面试题。以我的经验,凡是这道题答得好的,后面多半没啥问题;这道题答不出或者错漏的,后面能翻盘的概率很低。
属性及释义大家请看 MDN,本文不再赘述。
position: sticky
比较复杂,简单来说,它包含以下特性:
- 当它的位置让它可以正常呈现的时候,它的定位等同于
position: static
,随着正常的文档流滚动 - 当它的位置不足以让它正常显示,但它的父元素有足够多让它显示的空间,它的定位等同于
position: fixed
- 当它的父元素的空间不够让它显示,它的定位等同于
position:absolute
言说太复杂,大家可以看下这个演示,基本上就能明白了:
最近我想用这个样式完成一个侧边栏导航的需求,如下图所示:
很简单,这是一个文档页面,屏幕分成两列,左侧是侧边栏导航,右侧是文档内容。文档内容很长,用户需要滚动阅读。滚动过程中,左侧的导航栏固定不动,方便用户跳走或选择章节。因为有一个顶部通栏,所以我需要导航滚动大约70px后再固定,那么这里很合适用 position:sticky
。
然而事与愿违,我给侧边栏导航加上 position:sticky
之后,它的表现和开始并无二致,看起来似乎是属性没有生效。我把 CSS 放在这里,大家可以看看能不能猜到问题在哪里:
.doc-list
display flex
#sidebar
position sticky
top 0
.doc-container
flex 1
padding-top 1rem
.container
max-width 720px
margin 0 auto
这个问题困扰了我很长时间,直到我看到这篇文章:CSS Position Sticky – How It Really Works! 它并没有直接解答我的疑问,不过它给了我一些启示:刚才说的行为特征,翻译过来,其实隐含着一条规则:
position:sticky
对象的父元素的尺寸必须比它大很多。
我用开发者工具一看,果然,因为我只设置了 display:flex
,没有定义 align-items
,所以它取默认值 stretch
也就是拉伸,所以我的侧边栏和右边文档容器的高度一样,所以滚动的时候,整个侧边栏都跟着一起滚,自然不会有任何效果。
于是我在第三行增加了 align-items: flex-start
,立刻就获得了令人满意的效果。
.doc-list
display flex
+ align-items flex-start
欢迎吐槽,共同进步