how to move inner div behind surrounding div - html

My HTML:
<div class="outer">
<div class="inner">
Lorem Ipsum
<div class="innerest">
<!-- no content -->
</div>
</div>
<div class="inner">
Lorem Ipsum
<div class="innerest">
<!-- no content -->
</div>
</div>
</div>
My CSS:
.outer {
background: red;
padding: 6px 20px;
z-index: 10;
overflow: hidden;
}
.inner {
background: green;
z-index: 11;
float: left;
margin-left: 12px;
}
.innerest {
background: blue;
width: 30px;
height: 20px;
z-index: 9;
position: absolute;
}
Here's a fiddle: http://jsfiddle.net/jsnlry/ycJdy/
I want the blue boxes to be behind the red one. It seems, that z-index is ignored in this case. But why?
Any idea?

In this example z-index only works on the position:absolute element. Try putting a negative value like -9 and it should work.

Do you mean like this:
http://jsfiddle.net/audetwebdesign/WJzRY/
.innerest {
z-index: -1;
}
Why This Works...
By default, z-index is auto which computes to 0, all elements have the same stacking level.
In my fiddle, I set up a sequence of styles to show what is happening.
You start off with a parent div with two floated children which are out of flow, and the parent height collapses to 12px high because of the padding (Ex 1).
When you declare overflow: hidden, you start a new block formatting context and the floated child elements are retained in the context of the parent, which is why the red background fully covers the child elements (Ex 2).
Finally, you can add absolute positioning to the .innerest elements, and this takes them out of the flow and they project out of the .outer ancestor element. Note that the floated elements affect the computed height of the containing block, unlike absolutely positioned elements. On the right .innerest element, you add z-index: -1 which places this element below all the other elements in the stacking order (computed to 0), so you get the desired effect.
Reference
http://www.w3.org/TR/CSS2/visuren.html#layers

Please add z-index: -1 to innerest class. it will be work.
.innerest {
background: blue;
width: 30px;
height: 20px;
z-index: -1;
position: absolute;
}

Try adding a negative z-index (-1) to your .innerest class.

Now used to this code define your .outer class position relative and remove overflow hidden
.outer {
background: red;
padding: 6px 20px;
position:relative; //add this line
}
.outer:after{
content:"";
clear:both;
overflow:hidden;
display:table;
}
.innerest {
z-index: -1; // add this line
position: absolute;
}
Demo

Related

How to have a details container be the same size as its content if the latter has position absolute? [duplicate]

As you can see in the CSS below, I want child2 to position itself before child1. This is because the site I'm currently developing should also work on mobile devices, on which the child2 should be at the bottom, as it contains the navigation which I want below the content on the mobile devices. - Why not 2 masterpages? This is the only 2 divs which are repositioned in the entire HTML, so 2 masterpages for this minor change is an overkill.
HTML:
<div id="parent">
<div class="child1"></div>
<div class="child2"></div>
</div>
CSS:
parent { position: relative; width: 100%; }
child1 { width: auto; margin-left: 160px; }
child2 { width: 145px; position: absolute; top: 0px; bottom: 0px; }
child2 has dynamic height, as different subsites could have more or less navigation items.
I know that absolute positioned elements are removed from the flow, thus ignored by other elements.
I tried setting overflow:hidden; on the parent div, but that didn't help, neither does the clearfix.
My last resort will be JavaScript to reposition the two divs accordingly, but for now I'll try and see if there exist a non-JavaScript way of doing this.
You answered the question yourself:
I know that absolute positioned elements are removed from the flow, thus ignored by other elements.
So you can't set the parents height according to an absolutely positioned element.
You either use fixed heights or you need to involve JavaScript.
Nowadays one might use CSS flexbox or grid layout to reverse the visual order of HTML elements inside a parent container without using position: absolute;. See also Reverse order of columns in CSS Grid Layout
Although stretching to elements with position: absolute is not possible, there are often solutions where you can avoid the absolute positioning while obtaining the same effect. Look at this fiddle that solves the problem in your particular case http://jsfiddle.net/gS9q7/
The trick is to reverse element order by floating both elements, the first to the right, the second to the left, so the second appears first.
.child1 {
width: calc(100% - 160px);
float: right;
}
.child2 {
width: 145px;
float: left;
}
Finally, add a clearfix to the parent and you're done (see the fiddle for the complete solution).
Generally, as long as the element with absolute position is positioned at the top of the parent element, chances are good that you find a workaround by floating the element.
There is a quite simple way to solve this.
You just have to duplicate the content of child1 and child2 in relative divs with display:none in parent div. Say child1_1 and child2_2. Put child2_2 on top and child1_1 at the bottom.
When your jquery (or whatever) calls the absolute div, just set the according relative div (child1_1 or child2_2) with display:block AND visibility:hidden. The relative child will still be invisible but will make parent's div higher.
Feeela is right but you can get a parent div contracting or expanding to a child element if you reverse your div positioning like this:
.parent {
position: absolute;
/* position it in the browser using the `left`, `top` and `margin`
attributes */
}
.child {
position: relative;
height: 100%;
width: 100%;
overflow: hidden;
/* to pad or move it around using `left` and `top` inside the parent */
}
This should work for you.
This question was asked in 2012 before flexbox. The correct way to solve this problem using modern CSS is with a media query and a flex column reversal for mobile devices. No absolute positioning is needed.
https://jsfiddle.net/tnhsaesop/vjftq198/3/
HTML:
<div class="parent">
<div style="background-color:lightgrey;">
<p>
I stay on top on desktop and I'm on bottom on mobile
</p>
</div>
<div style="background-color:grey;">
<p>
I stay on bottom on desktop and I'm on top on mobile
</p>
</div>
</div>
CSS:
.parent {
display: flex;
flex-direction: column;
}
#media (max-width: 768px) {
.parent {
flex-direction: column-reverse;
}
}
With pure JavaScript, you just need to retrieve the height of your static position child element .child1 using the getComputedStyle() method then set that retrieve value as the padding-top for that same child using the HTMLElement.style property.
Check and run the following Code Snippet for a practical example of what I described above:
/* JavaScript */
var child1 = document.querySelector(".child1");
var parent = document.getElementById("parent");
var childHeight = parseInt(window.getComputedStyle(child1).height) + "px";
child1.style.paddingTop = childHeight;
/* CSS */
#parent { position: relative; width: 100%; }
.child1 { width: auto; }
.child2 { width: 145px; position: absolute; top: 0px; bottom: 0px; }
html, body { width: 100%;height: 100%; margin: 0; padding: 0; }
<!-- HTML -->
<div id="parent">
<div class="child1">STATIC</div>
<div class="child2">ABSOLUTE</div>
</div>
There's a very simple hack that fixes this issue
Here's a codesandbox that illustrates the solution: https://codesandbox.io/s/00w06z1n5l
HTML
<div id="parent">
<div class="hack">
<div class="child">
</div>
</div>
</div>
CSS
.parent { position: relative; width: 100%; }
.hack { position: absolute; left:0; right:0; top:0;}
.child { position: absolute; left: 0; right: 0; bottom:0; }
you can play with the positioning of the hack div to affect where the child positions itself.
Here's a snippet:
html {
font-family: sans-serif;
text-align: center;
}
.container {
border: 2px solid gray;
height: 400px;
display: flex;
flex-direction: column;
}
.stuff-the-middle {
background: papayawhip
url("https://camo.githubusercontent.com/6609e7239d46222bbcbd846155351a8ce06eb11f/687474703a2f2f692e696d6775722e636f6d2f4e577a764a6d6d2e706e67");
flex: 1;
}
.parent {
background: palevioletred;
position: relative;
}
.hack {
position: absolute;
left: 0;
top:0;
right: 0;
}
.child {
height: 40px;
background: rgba(0, 0, 0, 0.5);
position: absolute;
bottom: 0;
left: 0;
right: 0;
}
<div class="container">
<div class="stuff-the-middle">
I have stuff annoyingly in th emiddle
</div>
<div class="parent">
<div class="hack">
<div class="child">
I'm inside of my parent but absolutely on top
</div>
</div>
I'm the parent
<br /> You can modify my height
<br /> and my child is always on top
<br /> absolutely on top
<br /> try removing this text
</div>
</div>
I came up with another solution, which I don't love but gets the job done.
Basically duplicate the child elements in such a way that the duplicates are not visible.
<div id="parent">
<div class="width-calc">
<div class="child1"></div>
<div class="child2"></div>
</div>
<div class="child1"></div>
<div class="child2"></div>
</div>
CSS:
.width-calc {
height: 0;
overflow: hidden;
}
If those child elements contain little markup, then the impact will be small.
I had a similar problem.
To solve this (instead of calculate the iframe's height using the body, document or window) I created a div that wraps the whole page content (a div with an id="page" for example) and then I used its height.
"You either use fixed heights or you need to involve JS."
Here is the JS example:
---------- jQuery JS example--------------------
function findEnvelopSizeOfAbsolutelyPositionedChildren(containerSelector){
var maxX = $(containerSelector).width(), maxY = $(containerSelector).height();
$(containerSelector).children().each(function (i){
if (maxX < parseInt($(this).css('left')) + $(this).width()){
maxX = parseInt($(this).css('left')) + $(this).width();
}
if (maxY < parseInt($(this).css('top')) + $(this).height()){
maxY = parseInt($(this).css('top')) + $(this).height();
}
});
return {
'width': maxX,
'height': maxY
}
}
var specBodySize = findEnvelopSizeOfAbsolutelyPositionedSubDivs("#SpecBody");
$("#SpecBody").width(specBodySize.width);
$("#SpecBody").height(specBodySize.height);
There is a better way to do this now. You can use the bottom property.
.my-element {
position: absolute;
bottom: 30px;
}
This is very similar to what #ChrisC suggested. It is not using an absolute positioned element, but a relative one. Maybe could work for you
<div class="container">
<div class="my-child"></div>
</div>
And your css like this:
.container{
background-color: red;
position: relative;
border: 1px solid black;
width: 100%;
}
.my-child{
position: relative;
top: 0;
left: 100%;
height: 100px;
width: 100px;
margin-left: -100px;
background-color: blue;
}
https://jsfiddle.net/royriojas/dndjwa6t/
Also consider next approach:
CSS:
.parent {
height: 100%;
}
.parent:after {
content: '';
display: block;
}
Also since you are trying to reposition divs consider css grid
Absolute views position themselves against the nearest ancestor that isn't statically positioned (position: static), therefore if you want an absolute view positioned against a given parent, set the parent position to relative and the child to position to absolute
Try this, it was worked for me
.child {
width: 100%;
position: absolute;
top: 0px;
bottom: 0px;
z-index: 1;
}
It will set child height to parent height

How does negative margin on first child affect the position of the next elements?

if I have this dom structure
<div style="overflow:hidden;">
<div id="d1" style="margin-top:-50px; height:10px;"></div>
<div id="d2" style="height:30px;"></div>
<div id="d3" style="height:30px;"></div>
</div>
My question is how the elements d2 and d3 will be placed? just after the first element? even if d2 will be hidden, and d3 will be half-hidden (10px hidden). Or the two elements will be placed in the visible area of the parent?
My question here is about the exact CSS specifications.
How does negative margin on first child affect the position of the next elements?
No differently than how a zero or positive margin affects the position of the following elements, assuming everything is in the flow: a positive margin from the top pushes a box and following boxes downward, so it follows that a negative margin from the top pulls a box and following boxes upward. The value of the overflow property on the containing block is irrelevant in normal flow.
The spec does not mention this explicitly, simply because there are no special rules around negative margins in this specific scenario. It's just basic math. There are numerous other special rules around negative margins, but none of them apply in this scenario at all.
How does negative margin on first child affect the position of the
next elements?
Simply put, they follow, though it is a little more complicated than that, so I recommend read more here for the specifications.
https://developer.mozilla.org/en-US/docs/Web/CSS/margin
https://www.w3.org/TR/CSS2/box.html#margin-properties
body {
padding: 50px;
}
#d {
position: relative;
background: red;
border: 5px solid red;
}
#d1 {
background: green;
}
#d2 {
background: yellow;
}
#d3 {
background: blue;
}
/* these is for demo purpose only */
#d:before {
content: '';
background: red;
position: absolute;
width: 100%;
height: 5px;
top: -5px;
left: 0;
z-index: 1;
}
#d:after {
content: '';
background: white;
position: absolute;
width: 100%;
height: 45px;
top: -50px;
left: 0;
opacity: .7;
z-index: 1;
}
<div id="d">
<div id="d1" style="margin-top:-50px; height:10px;"></div>
<div id="d2" style="height:30px;"></div>
<div id="d3" style="height:30px;"></div>
</div>

Make child div in back of parent div with z-index?

No matter what I try, the child div is always in front of the parent. Is there a way to make the child div in back of the parent? z-index doesn't seem to work.
Notes :
I don't want to change the html
parent must have a z-index
duplicate "How to make child element upper than parent with z-index" doesn't make grammatical sense and is hard to read, and didn't really help me.
<div id='parent'>
<div id='child'>
</div>
</div>
#parent {
width:50px;
height:50px;
background:red;
position:absolute;
z-index:100;
}
#child {
width:50px;
height:50px;
background:blue;
position:absolute;
z-index:-100;
}
JSFiddle
Don't make the child div actually contained in the parent. Since the positions are absolute you can do this:
<div id='parent'>
</div>
<div id='child'>
</div>
Now if the z-index of parent is less than that of child it will appear on top.
You can't achieve that because they are part of the same stacking context. However a workaround could be set opacity: 0 to child
#parent {
width: 50px;
height: 50px;
background: red;
position: absolute;
z-index: 1;
}
#child {
width: 50px;
height: 50px;
background: blue;
position: absolute;
z-index: 2;
opacity: 0;
}
<div id='parent'>
<div id='child'></div>
</div>
AFAIK it's not possible to position a parent on top of a child. Without changing the HTML you can however use:before or :after to create a new element and position that on top of the child;
#parent:after {
background: red;
content: "ON TOP";
display: block;
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
z-index: 1;
}
http://jsfiddle.net/j6e9qho3/12/
Edit: Or seeing as the effect of the parent being on top of the child is that the child isn't visible at all, the easiest thing to do is probably #child {display: none}. But I assume that doesn't work for you for other reasons.
Perhaps if you explained what you want to accomplish we could be of more help.
I was able to achieve what I wanted by dealing with siblings inside the parent...
<div id='parent'>
<div id='child1'>
</div>
<div id='child2'>
</div>
</div>
where parent is a transparent container with its own z-index, but the children are the actual color squares that are drawn (each with their own z-index).

Why is an absolutely positioned element placed by its sibling instead of at the top corner of the page?

I don't understand why my absolutely positioned element appears after my child_static div. I always thought that absolutely positioned elements are taken out of the flow. So why doesn't child_absolute cover the child_static div?
.parent {
position: relative;
}
.child_static {
height: 20px;
background: blue;
}
.child_absolute {
position: absolute;
height: 20px;
width: 100%;
background: green;
}
<div class='parent'>
<div class='child_static'></div>
<div class='child_absolute'></div>
</div>
http://jsfiddle.net/4v4eLtp1/
I always thought that absolute positioned elements are out of the flow.
Yes, they are removed from normal flow.
I don't understand why absolute positioned element appeared after child_static div.
Just because absolute positioning removes elements from normal flow, it doesn't mean it does alter the position of the elements as well.
In other words, absolutely positioned elements would be at the same place as they are not positioned absolutely unless their top, left, ... offsets are set.
So what happens is that they would overlap next sibling elements, because they are not part of document flow anymore.
For instance have a look at the following example where the gold <div> element is covered by absolutely positioned element.
.parent {
position: relative;
}
.child_static {
height: 20px;
background: blue;
}
.child_absolute {
position: absolute;
height: 20px;
width: 100%;
background: green;
}
.child_static ~ .child_static {
background: gold;
}
<div class='parent'>
<div class='child_static'>Green</div>
<div class='child_absolute'>Blue</div>
<div class='child_static'>Gold</div>
</div>
You forgot to set from which sides your DIV is positioned.
Something like:
top: 0;
left: 0;
http://jsfiddle.net/Paf_Sebastien/uqprmkwo/
(I changed the 2nd DIV dimensions so you can see both.)

Make absolute positioned div expand parent div height

As you can see in the CSS below, I want child2 to position itself before child1. This is because the site I'm currently developing should also work on mobile devices, on which the child2 should be at the bottom, as it contains the navigation which I want below the content on the mobile devices. - Why not 2 masterpages? This is the only 2 divs which are repositioned in the entire HTML, so 2 masterpages for this minor change is an overkill.
HTML:
<div id="parent">
<div class="child1"></div>
<div class="child2"></div>
</div>
CSS:
parent { position: relative; width: 100%; }
child1 { width: auto; margin-left: 160px; }
child2 { width: 145px; position: absolute; top: 0px; bottom: 0px; }
child2 has dynamic height, as different subsites could have more or less navigation items.
I know that absolute positioned elements are removed from the flow, thus ignored by other elements.
I tried setting overflow:hidden; on the parent div, but that didn't help, neither does the clearfix.
My last resort will be JavaScript to reposition the two divs accordingly, but for now I'll try and see if there exist a non-JavaScript way of doing this.
You answered the question yourself:
I know that absolute positioned elements are removed from the flow, thus ignored by other elements.
So you can't set the parents height according to an absolutely positioned element.
You either use fixed heights or you need to involve JavaScript.
Nowadays one might use CSS flexbox or grid layout to reverse the visual order of HTML elements inside a parent container without using position: absolute;. See also Reverse order of columns in CSS Grid Layout
Although stretching to elements with position: absolute is not possible, there are often solutions where you can avoid the absolute positioning while obtaining the same effect. Look at this fiddle that solves the problem in your particular case http://jsfiddle.net/gS9q7/
The trick is to reverse element order by floating both elements, the first to the right, the second to the left, so the second appears first.
.child1 {
width: calc(100% - 160px);
float: right;
}
.child2 {
width: 145px;
float: left;
}
Finally, add a clearfix to the parent and you're done (see the fiddle for the complete solution).
Generally, as long as the element with absolute position is positioned at the top of the parent element, chances are good that you find a workaround by floating the element.
There is a quite simple way to solve this.
You just have to duplicate the content of child1 and child2 in relative divs with display:none in parent div. Say child1_1 and child2_2. Put child2_2 on top and child1_1 at the bottom.
When your jquery (or whatever) calls the absolute div, just set the according relative div (child1_1 or child2_2) with display:block AND visibility:hidden. The relative child will still be invisible but will make parent's div higher.
Feeela is right but you can get a parent div contracting or expanding to a child element if you reverse your div positioning like this:
.parent {
position: absolute;
/* position it in the browser using the `left`, `top` and `margin`
attributes */
}
.child {
position: relative;
height: 100%;
width: 100%;
overflow: hidden;
/* to pad or move it around using `left` and `top` inside the parent */
}
This should work for you.
This question was asked in 2012 before flexbox. The correct way to solve this problem using modern CSS is with a media query and a flex column reversal for mobile devices. No absolute positioning is needed.
https://jsfiddle.net/tnhsaesop/vjftq198/3/
HTML:
<div class="parent">
<div style="background-color:lightgrey;">
<p>
I stay on top on desktop and I'm on bottom on mobile
</p>
</div>
<div style="background-color:grey;">
<p>
I stay on bottom on desktop and I'm on top on mobile
</p>
</div>
</div>
CSS:
.parent {
display: flex;
flex-direction: column;
}
#media (max-width: 768px) {
.parent {
flex-direction: column-reverse;
}
}
With pure JavaScript, you just need to retrieve the height of your static position child element .child1 using the getComputedStyle() method then set that retrieve value as the padding-top for that same child using the HTMLElement.style property.
Check and run the following Code Snippet for a practical example of what I described above:
/* JavaScript */
var child1 = document.querySelector(".child1");
var parent = document.getElementById("parent");
var childHeight = parseInt(window.getComputedStyle(child1).height) + "px";
child1.style.paddingTop = childHeight;
/* CSS */
#parent { position: relative; width: 100%; }
.child1 { width: auto; }
.child2 { width: 145px; position: absolute; top: 0px; bottom: 0px; }
html, body { width: 100%;height: 100%; margin: 0; padding: 0; }
<!-- HTML -->
<div id="parent">
<div class="child1">STATIC</div>
<div class="child2">ABSOLUTE</div>
</div>
There's a very simple hack that fixes this issue
Here's a codesandbox that illustrates the solution: https://codesandbox.io/s/00w06z1n5l
HTML
<div id="parent">
<div class="hack">
<div class="child">
</div>
</div>
</div>
CSS
.parent { position: relative; width: 100%; }
.hack { position: absolute; left:0; right:0; top:0;}
.child { position: absolute; left: 0; right: 0; bottom:0; }
you can play with the positioning of the hack div to affect where the child positions itself.
Here's a snippet:
html {
font-family: sans-serif;
text-align: center;
}
.container {
border: 2px solid gray;
height: 400px;
display: flex;
flex-direction: column;
}
.stuff-the-middle {
background: papayawhip
url("https://camo.githubusercontent.com/6609e7239d46222bbcbd846155351a8ce06eb11f/687474703a2f2f692e696d6775722e636f6d2f4e577a764a6d6d2e706e67");
flex: 1;
}
.parent {
background: palevioletred;
position: relative;
}
.hack {
position: absolute;
left: 0;
top:0;
right: 0;
}
.child {
height: 40px;
background: rgba(0, 0, 0, 0.5);
position: absolute;
bottom: 0;
left: 0;
right: 0;
}
<div class="container">
<div class="stuff-the-middle">
I have stuff annoyingly in th emiddle
</div>
<div class="parent">
<div class="hack">
<div class="child">
I'm inside of my parent but absolutely on top
</div>
</div>
I'm the parent
<br /> You can modify my height
<br /> and my child is always on top
<br /> absolutely on top
<br /> try removing this text
</div>
</div>
I came up with another solution, which I don't love but gets the job done.
Basically duplicate the child elements in such a way that the duplicates are not visible.
<div id="parent">
<div class="width-calc">
<div class="child1"></div>
<div class="child2"></div>
</div>
<div class="child1"></div>
<div class="child2"></div>
</div>
CSS:
.width-calc {
height: 0;
overflow: hidden;
}
If those child elements contain little markup, then the impact will be small.
I had a similar problem.
To solve this (instead of calculate the iframe's height using the body, document or window) I created a div that wraps the whole page content (a div with an id="page" for example) and then I used its height.
"You either use fixed heights or you need to involve JS."
Here is the JS example:
---------- jQuery JS example--------------------
function findEnvelopSizeOfAbsolutelyPositionedChildren(containerSelector){
var maxX = $(containerSelector).width(), maxY = $(containerSelector).height();
$(containerSelector).children().each(function (i){
if (maxX < parseInt($(this).css('left')) + $(this).width()){
maxX = parseInt($(this).css('left')) + $(this).width();
}
if (maxY < parseInt($(this).css('top')) + $(this).height()){
maxY = parseInt($(this).css('top')) + $(this).height();
}
});
return {
'width': maxX,
'height': maxY
}
}
var specBodySize = findEnvelopSizeOfAbsolutelyPositionedSubDivs("#SpecBody");
$("#SpecBody").width(specBodySize.width);
$("#SpecBody").height(specBodySize.height);
There is a better way to do this now. You can use the bottom property.
.my-element {
position: absolute;
bottom: 30px;
}
This is very similar to what #ChrisC suggested. It is not using an absolute positioned element, but a relative one. Maybe could work for you
<div class="container">
<div class="my-child"></div>
</div>
And your css like this:
.container{
background-color: red;
position: relative;
border: 1px solid black;
width: 100%;
}
.my-child{
position: relative;
top: 0;
left: 100%;
height: 100px;
width: 100px;
margin-left: -100px;
background-color: blue;
}
https://jsfiddle.net/royriojas/dndjwa6t/
Also consider next approach:
CSS:
.parent {
height: 100%;
}
.parent:after {
content: '';
display: block;
}
Also since you are trying to reposition divs consider css grid
Absolute views position themselves against the nearest ancestor that isn't statically positioned (position: static), therefore if you want an absolute view positioned against a given parent, set the parent position to relative and the child to position to absolute
Try this, it was worked for me
.child {
width: 100%;
position: absolute;
top: 0px;
bottom: 0px;
z-index: 1;
}
It will set child height to parent height