CSS属性 position 用于指定一个元素在文档中的定位方式。
top, right, bottom和 left 属性则决定了该元素的最终位置。
定位在页面布局中应用很多,比较常用的几个值有relative、absolute、fixed。
今天就来好好扒一下定位的各种值以及相应的效果。
语法
position: static|relative|absolute|fixed|sticky
默认值: static
适用于:除display属性定义为table-column-group|table-coumn之外的所有元素
取值
static: 指定元素使用正常的布局行为,即元素在文档常规流中当前的布局位置。此时 top, right, bottom, left 和 z-index 属性无效。
relative:也是常规流,并且参照自身在常规六中的位置通过top,right,bottom,left这四个偏移属性进行偏移,且不会影响其他元素。
absolute: 对象脱离常规流,此时偏移属性参照的是里自身最近的定位最先元素,如果没有定位的祖先元素,则一直回溯到body元素。盒子的偏移位置不影响常规流中的任何元素,其margin不与其他任何margin折叠。
fixed: 通过指定元素相对于屏幕视口(viewport)的位置来指定元素位置。元素的位置在屏幕滚动时不会改变。fixed 属性会创建新的层叠上下文。当元素祖先的 transform 属性非 none 时,容器由视口改为该祖先。
sticky:像是relative和fixed的合体,元素在跨越特定阈值前为相对定位,之后为固定定位。该属性的表现是现实中你见到的吸附效果。(CSS3)
兼容
不受控空的fixed
大家都知道,position:fixed 在日常的页面布局中非常常用,在许多布局中起到了关键的作用。它的作用是:
position:fixed 的元素将相对于屏幕视口(viewport)的位置来指定其位置。并且元素的位置在屏幕滚动时不会改变。
但是,在许多特定的场合,指定了 position:fixed 的元素却无法相对于屏幕视口进行定位。这是为何呢?
失效的 position:fixed
在许多情况下,position:fixed
将会失效。MDN 用一句话概括了这种情况
当元素祖先的 transform 属性非 none 时,定位容器由视口改为该祖先。
通俗的讲就是指定了 position:fixed 的元素,如果其祖先元素存在非 none 的 transform 值 ,那么该元素将相对于设定了 transform 的祖先元素进行定位。
那么,为什么会发生这种情况呢?说好的相对视口(Viewport)定位呢?
这个问题,就牵涉到了 Stacking Context ,也就是堆叠上下文的概念了。解释上面的问题分为两步:
任何非 none 的 transform 值都会导致一个堆叠上下文(Stacking Context)和包含块(Containing Block)的创建。
由于堆叠上下文的创建,该元素会影响其子元素的固定定位。设置了 position:fixed 的子元素将不会基于 viewport 定位,而是基于这个父元素。
Stacking Context -- 堆叠上下文
堆叠上下文(Stacking Context):堆叠上下文是 HTML 元素的三维概念,这些 HTML 元素在一条假想的相对于面向(电脑屏幕的)视窗或者网页的用户的 z 轴上延伸,HTML 元素依据其自身属性按照优先级顺序占用层叠上下文的空间。
概念比较抽象,简单理解,记住 生成了 Stacking Context 的元素会影响该元素的层叠关系与定位关系。
创建堆叠上下文的方式
为此,首先要找到所有能够使元素生成堆叠上下文的方法。
So,如何触发一个元素形成 堆叠上下文
?方法如下(参考自 MDN):
- 根元素 (HTML),
- z-index 值不为 "auto"的 绝对/相对定位,
- 一个 z-index 值不为 "auto"的 flex 项目 (flex item),即:父元素 display: flex|inline-flex,
- opacity 属性值小于 1 的元素(参考 the specification for opacity),
- transform 属性值不为 "none"的元素,
- mix-blend-mode 属性值不为 "normal"的元素,
- filter值不为“none”的元素,
- perspective值不为“none”的元素,
- isolation 属性被设置为 "isolate"的元素,
- position: fixed
- 在 will-change 中指定了任意 CSS 属性,即便你没有直接指定这些属性的值
- -webkit-overflow-scrolling 属性被设置 "touch"的元素
一探 position:fixed 失效的最终原因
并不是所有能够生成层叠上下文的元素都会使得 position:fixed 失效,但也不止 transform 会使 position:fixed 失效。
所以,MDN 关于 position:fixed 的补充描述不够完善。下述 3 种方式目前都会使得 position:fixed 定位的基准元素改变(本文重点):
- transform 属性值不为 none 的元素
- perspective 值不为 none 的元素
- 在 will-change 中指定了任意 CSS 属性
上述结论是在最新的 Chrome 浏览器下(Blink内核),经过测试发现,在 MAC 下的 Safari 浏览器(WebKit内核,Version 9.1.2 (11601.7.7))和 IE Trident/ 内核及 Edge 浏览器下,上述三种方式都不会改变 position: fixed 的表现!
绝对定位元素的定位值发生冲突时的解决方法:
- 如果同时指定 top 和 bottom(非 auto),优先采用 top。
- 如果同时指定 left和 right,若 direction为 ltr(英语、汉语等),则优先采用 left;若 direction为 rtl(阿拉伯语、希伯来语等),则优先采用 right。