❌ 纠错:fixed 定位并不止相对于视口

发布于:2024-05-09 ⋅ 阅读:(25) ⋅ 点赞:(0)

本文为稀土掘金技术社区首发签约文章,30天内禁止转载,30天后未获授权禁止转载,侵权必究!

前言

在很多weber的思维里,认为 fixed 定位就是相对于窗口左上角定位的。这其实是错误的认知,导致这个误解的原因我猜测是因为大家在前端入门时,很多教程为了便于理解,则直接拿最常见的例子来说fixed定位是相对于窗口的。

但这很显然是错误的,来看 MDN 对fixed定位的解释:

该元素被排除在文档的正常流程之外,并且在页面布局中不会为其创建空间。元素相对于第一个 containing block包含块(或视觉媒体元素的视口)定位。最终位置由top、right、bottom、left 的值决定。

可以看到,影响 fixed 元素位置的因素有两个:

  • containing block包含块
  • left、right、bottom、top属性值

所以下文我们就基于这两个因素,看看 fixed 定位如何不相对于窗口,而是相对于父级元素。

方法

总结下来,其实有 种方法可以实现 fixed 定位相对于父级元素。

1. 嵌套定位

给一个元素设置 fixed 固定定位,而不设置其 top、bottom、left、right 值,该元素就会从原本该在的位置从文档流中脱离,并且位置不变,只是周围元素会顶上来。

效果如下:

为什么位置不会变呢?因为其 top、bottom、left、right 值已经默认根据其在文档流中的位置计算出来了。所以设置fixed,元素只是脱离了文档流,而其位置不会变化。

所以说这些有什么用呢?因为我们可以利用这种特性使用障眼法使某个元素相对于另一个元素固定(其实还是相对于视口的)。如下:

无标题-2024-02-23-1141.png

当然了,这种情况用absolute或者sticky定位也是可以实现的,但是略有区别,如下:

  • absolute定位和fixed定位都可以固定到障眼法父元素的左侧,但是其大小的相对值不同,设置absolute后的100%是障眼法的父元素宽度,而fixed的100%是视口宽度;
  • 如果障眼法父元素内部被撑开可以滚动,那么absolute和fixed都会随着一起滚动,而sticky可以固定在左上角不动

所以具体采用哪种就需要根据实际情况取舍了。

2. 新建复合图层

根据前言所说,fixed定位是相对于其包含块的,那如何确定其包含块呢?元素的包含块默认是距离元素最近的块级祖先。那 fixed 定位的元素的包含块是指向谁呢?总结为以下三种:

  1. 视口
  2. 距离最近的复合图层元素(就是设置了transform、filter、will-change等属性的父级元素)
  3. contain隔离内容

相对于视口就不说了,这一节说说相对于复合涂层的 fixed 定位。

大家都知道,利用css的一些属性可以启用 GPU 硬件加速。例如以下属性:

  • opacity
  • transform
  • perspective
  • filter
  • backdrop-filter
  • will-change

GPU 硬件加速的原理有两个原因:

  • 使用某些css属性后,渲染引擎会把该把元素单独分层交给 GPU 渲染,GPU处理图形计算更快;
  • 分层渲染不会造成页面的回流重绘;

想了解浏览器渲染原理,可以阅读我的往期文章

而这些可以新建复合图层的属性,可以影响 fixed元素 的包含块,从而使设置了fixed定位的元素相对于距离最近的设置这些属性的祖先元素定位。

注意:以上列举的css属性中,opacity不能影响包含块

简单来说就是,当 fixed 元素的某个祖先元素设置了这些新建复合图层的属性之后,这个祖先元素将会成为 fixed 元素的包含块,即fixed 元素的位置和大小都将相对于此元素。

3. contain属性

第三种方法就是利用css的 contain 属性。该属性可以隔离某个 DOM 元素,即将布局、样式、绘制、大小或任何组合的计算限制为 某个DOM 子树而不是整个页面。

可以看到,contain 主要可以隔离某个元素的布局、样式、绘制、大小,分别是layoutstylesizepaint。当然也可以使用其组合值,只需要用空格隔开:

contain: layout style size paint;
可以简写为: contain: strict;

显而易见,只要我们将某个元素的布局 layout 隔离,就能使其中的子元素的fixed定位相对于这个隔离元素。

contain 隔离属性除了遏制布局以外,最大的好处就是改善性能,例如在以下几种情况可以使用其优化性能:

  • 隔离动画:如果某个元素内部元素有大量的动画或者频繁的样式变化,可以使用 contain 属性来隔离这个元素,使得这个元素内部的变化不会影响到外部的元素,减少不必要的重绘和重排;

  • 防止样式的泄露:在使用Shadow DOM或者Web Components时,你可能想要防止样式的泄露。此时,你可以使用contain: style来防止元素内部的样式影响到外部的元素;

  • 隔离计数器:如果一个页面有多个 css 计数器 counter-increment,可以使用 contain 属性隔离这几个计数器,以免混在一起计数;

  • 页面小饰件:如果你想在网页上添加一个第三方小饰件,可以使用 contain: strict 将它和页面主体内容隔离开;

🎁 最后

学如逆水行舟,不进则退~👊👊👊

先看后赞,养成习惯👍
收藏吃灰,不如学会🍗
点个关注,不要迷路🪤

image.png