I created two sibling divs and applied negative margin on the last one, but when I added position: relative to the first one, it overlapped its next sibling:
.box {
width: 100px;
height: 100px;
}
.box-1 {
position: relative;
background: orange;
}
.box-2 {
margin-top: -50px;
background: yellowgreen;
}
<div class="box box-1">box-1</div>
<div class="box box-2">box-2</div>
However, MDN says that
positioned (absolutely or relatively) with a z-index value other than "auto" will create a new stacking context.
So I guess it isn't the stacking context that causes overlapping, any idea about how this happens?
Standard blocks in the normal flow, without any positioning property, are always rendered before positioned elements, and appear below them, even if they come later in the HTML hierarchy.
Example being
.absolute {
position: absolute;
background:purple;
left: 80px;
}
.relative {
position: relative;
left:50px;
background:yellow;
top:-50px;
}
div {
width:100px;
height:100px;
border: 1px dashed #999966;
background:blue;
}
<div class="absolute">absolute</div>
<div>normal</div>
<div class="relative">relative</div>
<div>normal</div>
Something cool about relative though, is that it's still considered to be in it's original location, even if it's been moved if you're using left, right, top, bottom. If you use margins to position the element the boundaries of the container are also moved with it. This can be seen using the same example above but changing the relative position to use margining. Reference to relative positioning
Non-positioned elements are always rendered before explicitly positioned elements. This means that by applying position: relative to 'box-1', it is rendered after 'box-2' and so appears on top of it.
The overlapping is caused by margin-top: -50px; in your CSS
Here is a decent explanation:
https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Understanding_z_index/Stacking_without_z-index
Standard blocks in the normal flow, without any positioning property, are always rendered before positioned elements, and appear below them, even if they come later in the HTML hierarchy.
Related
I need to give an element position fixed, but I can't position it relatively to the viewport, I need it to be positioned relatively to a container.
I managed to do so, but I wonder how and why it works, because actually I think position fixed is ALWAYS positioned relatively to the viewport and NOT to parent elements.
Here my (working) code:
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
body {
height: 2000px;
}
.container {
position: relative;
}
.sidebar {
width: 200px;
background-color: red;
height: 200px;
position: absolute;
left: 100px;
top: 100px;
}
.fixed {
width: 100px;
height: 100px;
background-color: green;
position: fixed;
/* top: 0;
left: 0; */
margin-left: 10px;
margin-top: 10px;
}
</style>
</head>
<body>
<div class="container">
<div class="sidebar">
<div class="fixed"></div>
</div>
</div>
</body>
</html>
Fiddle: https://jsfiddle.net/tnwLycao/
Element "fixed" can easily be positioned with margins (e.g. margin-left/margin-top). However, when I deactivate the margins and try to position "fixed" with top/left it positions itself relatively to the viewport again, not relatively to the parent container/element.
Can someone give me a hint how and why this works?
An element with position: fixed is indeed positioned relative to the viewport (or browser). However, because it is an absolutely positioned element, it is "positioned relative to the initial containing block established by the viewport".
This is laid out in the position documentation:
An absolutely positioned element is an element whose computed position value is absolute or fixed. The top, right, bottom, and left properties specify offsets from the edges of the element's containing block. (The containing block is the ancestor relative to which the element is positioned.) If the element has margins, they are added to the offset.
That is to say, when you specify margin-top and margin-left, these values are relative to the parent. And because the element is positioned relative to the parent, the default top and left are inherited from the parent. In your example, the .fixed element has a top value of 100px because it inherits the top value of 100px from .sidebar (the parent). When you set top: 0 on .fixed, you are overriding this value (going from top: 108px to top: 0):
Because of this, the element appears to be taken 'out of flow'. However, it is still always positioned relative to the viewport; it just had an initial offset (which it inherited from its parent).
I always hear that the main difference between relative and absolute that absolute can be placed out of its parent boundary!
if I can do same thing absolute does using relative, so what is the advantage of using absolute over relative>
An example
<style>
* {
margin: 0;
padding: 0;
}
.first_div {
width:300px;
height:300px;
background-color:red;
margin: 50px auto;
}
.second_div {
width:140px;
height:140px;
background-color:green;
position: relative;
top: 50px;
right: 80px;
}
</style>
<div class="first_div">
<div class="second_div"></div>
</div>
as you see I can place the green square anywhere in the page using relative same as absolute does
So what's the main advantage of using absolute over relative ?
The advantage of absolute is that you can easily position your div anywhere you want with "bottom:"";, top:"";, right:""; and left:""; - however this cause problems when you are making responsible websites - unless your absolute element is in a relative element.
I would avoid both if possible because mobile devices go haywire when you focus on an input, for example, that is positioned this way. The keyboard display pops up and you're input is now covered up and your UI is hosed.
Stick with margin.
I have a relative positioned div and I want to position its child using absolute positioning - easy. One question though: I was under the impression absolute positioned children dont take up any space, but if I position it right:5000px for example a huge gap appears to the right to accommodate that element.
How do I position an element as absolute say 5000px to the right from its parent without the parent expanding to take up the room to accomodate both.
Actually if you do it..the parent shouldn't get expanded.
Here's an example:
https://jsfiddle.net/0oofcd0x/1/
container{
position: relative;
background: black;
height:200px;
width: 500px;
}
.internal{
position: absolute;
background: green;
width:100px;
height:100px;
left: 800px;
}
I'm trying to override / ignore the stacking context for an element so it can be positioned on the z-axis relative to the page root.
However, according to the article What No One Told You About Z-Index:
If an element is contained in a stacking context at the bottom of the stacking order, there is no way to get it to appear in front of another element in a different stacking context that is higher in the stacking order, even with a z-index of a billion!
New stacking contexts can be formed on an element in one of three ways:
When an element is the root element of a document (the element)
When an element has a position value other than static and a z-index value other than auto
When an element has an opacity value less than 1
With the following example:
.red, .green, .blue { position: absolute; }
.red { background: red; }
.green { background: green; }
.blue { background: blue; }
<div><span class="red">Red</span></div>
<div><span class="green">Green</span></div>
<div><span class="blue">Blue</span></div>
If the first div is given opacity:.99;, (which creates a new stacking context on the first node) then even if .red has z-index:1, it will still be placed behind the other elements because it is just rendered as the highest element within that stack.
Working Demo in jsFiddle
Which looks like this:
Q: Is there a way for an element to ignore the stack context of any of it's parent elements and ask to be positioned relative to the original stack context of the page?
Q: Is there a way for an element to ignore the stack context of any of it's parent elements and ask to be positioned relative to the original stack context of the page?
No, it's not possible to transfer a positioned element between stacking contexts without repositioning the element in the DOM. You cannot even move an element to the root stacking context by using position: fixed or position: absolute (as you have observed, .red is being positioned relative to its parent, div:first-child because it creates a new stacking context).
That being said, given your HTML and CSS it should be trivial to just reassign the classes to the div elements instead, as shown in other answers and here so all your divs and spans participate in the root stacking context:
<div class="red"><span>Red</span></div>
<div class="green"><span>Green</span></div>
<div class="blue"><span>Blue</span></div>
But your situation probably isn't as simple as it seems.
We can do it using 3D transformation and we will be able to bring any element to the front even if it's trapped inside a stacking context:
.red,
.green,
.blue {
position: absolute;
width: 100px;
color: white;
line-height: 100px;
text-align: center;
}
body,
div:first-child {
transform-style: preserve-3d; /* this is important for the trick to work */
}
.red {
top: 20px;
left: 20px;
background: red;
/*z-index: 1; we no more need this */
transform:translateZ(1px); /* this will do the trick */
}
.green {
top: 60px;
left: 60px;
background: green;
}
.blue {
top: 100px;
left: 100px;
background: blue;
}
<div><span class="red">Red</span></div>
<div><span class="green">Green</span></div>
<div><span class="blue">Blue</span></div>
More details and examples here: Why can't an element with a z-index value cover its child?
As it stated in the The stacking context: "Using z-index, the rendering order of certain elements is influenced by their z-index value. This occurs because these elements have special properties which cause them to form a stacking context.
To partly overcome stacking content problem you can use css properties to display unwanted elements:
opacity: 0.1;
or
display: none;
Is there anyway for an absolute positioned child to expand to fill its relative positioned parent? (The height of parent is not fixed)
Here is what i did and it is working fine with Firefox and IE7 but not IE6. :(
<div id="parent">
<div id="child1"></div>
</div>
#parent { position: relative; width: 200px; height:100%; background:red }
#child1 { position: absolute; top: 0; left: 200px; height: 100%; background:blue }
That's easy. The trick is setting top: 0px and bottom: 0px at the same time
Here's the working code
html, body {
width: 100%;
height: 100%;
overflow: hidden;
}
#parent {
display: block;
background-color: #ff0;
border: 1px solid #f00;
position: relative;
width: 200px;
height: 100%;
}
#child1 {
background-color: #f00;
display: block;
border: 1px solid #ff0;
position: absolute;
left: 200px;
top: 0px;
bottom: 0px;
}
Check out a working example here http://jsfiddle.net/Qexhh/
If I remember correctly there is a bug with how IE6 handles div height. It will only create the div to the height needed to contain the content within it when height is set to 100%. I would recommend two approaches:
Don't worry about supporting IE6 as it is a dead browser anyway
If that doesn't work, use something like jQuery to get the height of the parent div and then set the child div to that height.
fake it by setting the backgrounds to be the same colour so no-one notices the difference
You can achieve this with setting both the top and bottom attributes of the child.
See how this is done
At the bottom of that article, there is a link to Dean Edwards' IE7 (and IE8) js library that you should include for IE6 visitors. It is a JS library that actually MAKES IE6 behave like IE7 (or 8) when you include it. Sweet!
Dean Edwars' IE7 and 8 JS libraries
As far as I know, there is no way of expanding a parent element around an absolutely positioned child element. By making the child element absolutely positioned your are removing it from the regular flow of page items.
I recently built a 2-column website where the right column was absolutely positioned but the left column was not. If the left column had less content and a smaller height than the right column, the page would cut off the right column since it was absolutely positioned.
In order to resolve this, I had to determine if the height of the right column was greater than the height of the left column and if so set the height of the parent div height to the greater of the two.
Here is my jQuery solution. I'm not much of a coder so feel free to tweak this:
jQuery(function(){
var rightColHeight = jQuery('div.right_column').height();
var leftColHeight = jQuery('div.left_column').height();
if (rightColHeight > leftColHeight){
jQuery('.content_wrap').height(rightColHeight+'px');
}
});