I recreated an issue that I am encountering in a template.
There is a nav that has position: relative;
. Inside the nav there is a div with two lists nested.
One of the lists is position absolutely to stick to the bottom of the nav.
The problem occurs when the div has a transformation applied to it.
When the div in between the absolutely and relatively positioned elements get's a transform property, the absolute list positions itself relatively to the div instead of the 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.
Does this mean a transformed element is a positioned element? Why does it do this? I tested in Edge, FF, and Chrome. They all act the same.
You can run the recreated snippet below. I am applying the transform on the div on hover of the nav.
*{
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>
The CSS spec states that 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.
And that (see spec):
In the absolute positioning model, a box is explicitly offset with respect to its containing block.
transform
property of an element to anything other thant none
, creates a new containing block; stacking contexts have nothing to do with the way the element is positioned.
See examples in the below snippet.
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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With