绝对定位元素相对于转换元素的位置
Absolutely positioned element positions relatively to transformed element
我重现了我在模板中遇到的问题。
有一个 nav 有 position: relative;
。在 nav 中有一个 div 嵌套了两个列表。
其中一个列表的位置绝对固定在 nav 的底部。
当 div 应用了转换时会出现问题。
当绝对和相对定位元素之间的 div 得到变换 属性 时,绝对列表相对于 [=48 定位自身=] 而不是 nav.
MDN Docs state the following about position:absolute
Do not leave space for the element. Instead, position it at a
specified position relative to its closest positioned ancestor if any,
or otherwise relative to the containing block. Absolutely positioned
boxes can have margins, and they do not collapse with any other
margins.
这是否意味着转换后的元素是定位元素?
为什么要这样做?我在 Edge、FF 和 Chrome 中进行了测试。他们的行为都一样。
您可以 运行 下面重新创建的代码段。我在导航悬停时对 div 应用变换。
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body{
min-height: 100%;
height: 100%;
}
nav{
background: #000;
height: 100%;
width: 50%;
position: relative;
}
nav:hover > div{
transform: translateX(50px) translateY(0) translateZ(0);
}
a{
color: #fff;
}
ul{
padding: 16px;
}
ul.main{
background: blue;
}
ul.lower{
position: absolute;
background: red;
bottom: 0;
width: 100%;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<nav>
<div>
<ul class="main">
<li><a href="">link</a></li>
<li><a href="">link</a></li>
<li><a href="">link</a></li>
<li><a href="">link</a></li>
</ul>
<ul class="lower">
<li><a href="">link</a></li>
<li><a href="">link</a></li>
<li><a href="">link</a></li>
<li><a href="">link</a></li>
</ul>
</div>
</nav>
</body>
</html>
如果您将转换应用于 .main
而不是 div
,它似乎可以按预期工作。
基本上是因为应用了变换 属性 的任何元素都会自动触发新的堆叠顺序:https://developer.mozilla.org/en-US/docs/Web/CSS/transform
"If the property has a value different than none, a stacking context will be created. In that case the object will act as a containing block for position: fixed elements that it contains."
这里有一些关于堆叠上下文的额外信息:https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context
CSS 规范指出 defining a transform
on an element creates a containing block:
For elements whose layout is governed by the CSS box model, any value other than none for the transform results in the creation of both a stacking context and a containing block.
还有那个 (see spec):
In the absolute positioning model, a box is explicitly offset with respect to its containing block.
这里的关键是将元素的 transform
属性 设置为 none
以外的任何值,创建一个新的 包含块 ; 堆叠上下文与元素的定位方式无关。
请参阅以下代码段中的示例。
body {
padding-top: 100px;
}
.containing-block,
.stacking-context {
height: 50px;
padding-top: 50px;
}
.containing-block {
background-color: hotpink;
/* transform with a value other than none defines both a containing block and a stacking context. */
transform: scale(1);
}
.stacking-context {
background-color: orange;
/* opacity with a value other than 1 defines a stacking context but no containing block. */
opacity: .99;
}
.abs{
position: absolute;
top: 0;
padding: 10px;
background-color: dodgerblue;
}
<body>
<div class="containing-block">1: transform: scale(1);
<div class="abs">1: Containing block example</div>
</div>
<div class="stacking-context">2: opacity: .99
<div class="abs">2: Stacking context example</div>
</div>
</body>
我重现了我在模板中遇到的问题。
有一个 nav 有 position: relative;
。在 nav 中有一个 div 嵌套了两个列表。
其中一个列表的位置绝对固定在 nav 的底部。
当 div 应用了转换时会出现问题。
当绝对和相对定位元素之间的 div 得到变换 属性 时,绝对列表相对于 [=48 定位自身=] 而不是 nav.
MDN Docs state the following about position:absolute
Do not leave space for the element. Instead, position it at a specified position relative to its closest positioned ancestor if any, or otherwise relative to the containing block. Absolutely positioned boxes can have margins, and they do not collapse with any other margins.
这是否意味着转换后的元素是定位元素? 为什么要这样做?我在 Edge、FF 和 Chrome 中进行了测试。他们的行为都一样。
您可以 运行 下面重新创建的代码段。我在导航悬停时对 div 应用变换。
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body{
min-height: 100%;
height: 100%;
}
nav{
background: #000;
height: 100%;
width: 50%;
position: relative;
}
nav:hover > div{
transform: translateX(50px) translateY(0) translateZ(0);
}
a{
color: #fff;
}
ul{
padding: 16px;
}
ul.main{
background: blue;
}
ul.lower{
position: absolute;
background: red;
bottom: 0;
width: 100%;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<nav>
<div>
<ul class="main">
<li><a href="">link</a></li>
<li><a href="">link</a></li>
<li><a href="">link</a></li>
<li><a href="">link</a></li>
</ul>
<ul class="lower">
<li><a href="">link</a></li>
<li><a href="">link</a></li>
<li><a href="">link</a></li>
<li><a href="">link</a></li>
</ul>
</div>
</nav>
</body>
</html>
如果您将转换应用于 .main
而不是 div
,它似乎可以按预期工作。
基本上是因为应用了变换 属性 的任何元素都会自动触发新的堆叠顺序:https://developer.mozilla.org/en-US/docs/Web/CSS/transform
"If the property has a value different than none, a stacking context will be created. In that case the object will act as a containing block for position: fixed elements that it contains."
这里有一些关于堆叠上下文的额外信息:https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context
CSS 规范指出 defining a transform
on an element creates a containing block:
For elements whose layout is governed by the CSS box model, any value other than none for the transform results in the creation of both a stacking context and a containing block.
还有那个 (see spec):
In the absolute positioning model, a box is explicitly offset with respect to its containing block.
这里的关键是将元素的
transform
属性 设置为 none
以外的任何值,创建一个新的 包含块 ; 堆叠上下文与元素的定位方式无关。
请参阅以下代码段中的示例。
body {
padding-top: 100px;
}
.containing-block,
.stacking-context {
height: 50px;
padding-top: 50px;
}
.containing-block {
background-color: hotpink;
/* transform with a value other than none defines both a containing block and a stacking context. */
transform: scale(1);
}
.stacking-context {
background-color: orange;
/* opacity with a value other than 1 defines a stacking context but no containing block. */
opacity: .99;
}
.abs{
position: absolute;
top: 0;
padding: 10px;
background-color: dodgerblue;
}
<body>
<div class="containing-block">1: transform: scale(1);
<div class="abs">1: Containing block example</div>
</div>
<div class="stacking-context">2: opacity: .99
<div class="abs">2: Stacking context example</div>
</div>
</body>