需求
需求是在一个子容器的右上方放一个菜单栏,且要求在容器滚动时,这个菜单栏始终在顶部出现,效果如图。

一开始的想法是,使用绝对定义 postition: absolute 让菜单栏位于右上方,然后再用粘性定位 position: sticky 进行粘性布局。结果发现这两种设置不能同时应用在一个元素上,于是思考其他的方案。
最终实现的在线 demo:https://codepen.io/F-star/pen/PomddPm
方案选择
因为是要定位到右上方,于是我就想,用 float: right 或许也能实现效果,也这样做了。但我忘了一个很重要的 float: right 的副作用,就是它会造成 文字环绕,直到测试人员测试时才发现了这个问题。如下图:

直接使用元素浮动的方案不可行,我就想或许可以多加一个父元素。父元素使用绝对定位,然后子元素(菜单栏)使用粘性定位。试了下发现是可行的,作为最终的方案。
实现原理
需要给菜单栏 .bar 提供一个父元素 .bar-wrap,这个父元素需要将元素的宽高设置为和容器一样大。对父元素设置绝对定位 position: absolute;,然后通过 width: 100%; height:100% 或 top: 0; left:0; right: 0; bottom: 0; 的方式,让父元素的宽高和容器元素的宽高相同。
宽度要和容器高度相同,是为了让子元素使用右浮动能够正确定位到右上角;高度要和容器相同,是因为使用粘性定位的元素只能在它的父元素内发生粘性效果,无法在父元素的外部出现。高度如果只是和菜单栏的高度相同,是无法出现粘性效果的。
最后我们需要使用 pointer-events: none; 让父元素不可点击,就像不存在一样,实现 点击穿透。否则容器下的其他内容将无法点击。
|
|
然后就是给菜单栏元素设置 右浮动 和 粘性定位,实现需求的效果。因为菜单栏元素的父元素设置的点击穿透会影响子元素,所以这里需要设置 pointer-events: auto; 来取消点击穿透。
|
|
结尾
实现上并不复杂,简而言之,就是在容器上加一个可以点击穿透的透明遮罩,遮罩下的菜单元素设置 右浮动 和 粘性,并设置为不可点击穿透,最终实现了想要的效果。
在线 demo:https://codepen.io/F-star/pen/PomddPm