CSS - relative positioned parent div not stretching to absolute child div height - html

I've been googling this all morning and can't seem to get it to work:
I have a parent DIV with Relative positioning and a two column child DIV setup inside of it, both positioned Absolute.
I need the parent DIV's height to stretch with the content of the inner DIV's.
I have tried putting a .clearfix type bit before the closing tags for #content but I'm not floating anything. I've also tried adding a float attribute to the #content div to no avail. Can anyone point me to the right direction here. Clearly I'm missing something with how the nested displays affect each other.
CSS:
#content {
width: 780px;
padding: 10px;
position: relative;
background: #8b847d;
}
#leftcol {
width: 500px;
position: absolute;
}
#rightcol {
width: 270px;
position: absolute;
left: 500px;
margin-left: 10px;
text-align: center;
}
HTML:
<div id="content">
<div id="leftcol">
<p>Lorem Ipsum</p>
</div><!-- /leftcol -->
<div id="rightcol">
<img src="images/thumb1.jpg">
<img src="images/thumb2.jpg">
</div><!-- /rightcol -->
<br style="clear:both;">
</div><!-- /content -->

Dark side of the force is a pathway to many abilities some consider to be unnatural.
$(document).ready(function()
{
var objHeight = 0;
$.each($('#content').children(), function(){
objHeight += $(this).height();
});
$('#content').height(objHeight);
});​

clearing works but ive had weird results. then i found a post that makes it much easier and perfect in all browsers.
Set your child divs to float:left/right. Then put "overflow:hidden" on the parent. Because you haven't specified a height, it will just wrap to teh child elements perfectly. I haven't use'd clearing for ages now.

Your column divs won't effect their containing div while they have absolute positions as they're removed from the normal page flow.
Instead, try floating them then have a div with clear: both; after them.

I have just been struggling with that for a while and found a real solution CSS-only is to change positioning of 'absolute' divs to 'relative'. This really works!!!
Tested on a Mac, using Safari 5.1.5 and Chrome 21.0....
Hope this will help someone else.

You do not need position: absolute for this task.
#content {
width: 780px;
padding: 10px;
position: relative;
background: #8b847d;
}
#leftcol {
width: 500px;
float: left;
}
#rightcol {
width: 270px;
position: relative;
margin-left: 510px;
text-align: center;
}

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

Absolute div goes behind other elements

I have a structure like this:
#article {
position: relative;
height: 100%;
}
#special {
position: absolute;
bottom: 0%!important;
top: 100%!important;
width: 100%;
}
<section>
<div id="article">
<div>...</div>
<div id="special">...</div>
<div>...</div>
</div>
</section>
<section>
<div></div>
</section>
I place article div as position:relative and special div as position:absolute and top:100%. It goes at the end of article div but it seems that it has no height at all and shows below the below section. I added height attribute to special div and height:100% to article div with no success.
How can I force section div to occupy actual space? I tried to place an after element to special div to clear:both but no success.
When using absolute positioning, you don't need to include both top and bottom usally.
#article {
position: relative;
height: 100px; // Example just to show you a bit clearer.
}
#special {
position: absolute;
bottom: 0;
/* top: 100%!important; */ // Don't need this line
width: 100%;
}
I finally did this with jquery like this:
jQuery("#jc").insertAfter(".openSocialShareHorizontalSharing");
where #jc the div that i move below div with class openSocialShareHorizontalSharing
Although, if anyone could post a valid answer using CSS, please check the link from the comment from first post

Relative Parent div same height as absolute child div [duplicate]

I've been googling this all morning and can't seem to get it to work:
I have a parent DIV with Relative positioning and a two column child DIV setup inside of it, both positioned Absolute.
I need the parent DIV's height to stretch with the content of the inner DIV's.
I have tried putting a .clearfix type bit before the closing tags for #content but I'm not floating anything. I've also tried adding a float attribute to the #content div to no avail. Can anyone point me to the right direction here. Clearly I'm missing something with how the nested displays affect each other.
CSS:
#content {
width: 780px;
padding: 10px;
position: relative;
background: #8b847d;
}
#leftcol {
width: 500px;
position: absolute;
}
#rightcol {
width: 270px;
position: absolute;
left: 500px;
margin-left: 10px;
text-align: center;
}
HTML:
<div id="content">
<div id="leftcol">
<p>Lorem Ipsum</p>
</div><!-- /leftcol -->
<div id="rightcol">
<img src="images/thumb1.jpg">
<img src="images/thumb2.jpg">
</div><!-- /rightcol -->
<br style="clear:both;">
</div><!-- /content -->
Dark side of the force is a pathway to many abilities some consider to be unnatural.
$(document).ready(function()
{
var objHeight = 0;
$.each($('#content').children(), function(){
objHeight += $(this).height();
});
$('#content').height(objHeight);
});​
clearing works but ive had weird results. then i found a post that makes it much easier and perfect in all browsers.
Set your child divs to float:left/right. Then put "overflow:hidden" on the parent. Because you haven't specified a height, it will just wrap to teh child elements perfectly. I haven't use'd clearing for ages now.
Your column divs won't effect their containing div while they have absolute positions as they're removed from the normal page flow.
Instead, try floating them then have a div with clear: both; after them.
I have just been struggling with that for a while and found a real solution CSS-only is to change positioning of 'absolute' divs to 'relative'. This really works!!!
Tested on a Mac, using Safari 5.1.5 and Chrome 21.0....
Hope this will help someone else.
You do not need position: absolute for this task.
#content {
width: 780px;
padding: 10px;
position: relative;
background: #8b847d;
}
#leftcol {
width: 500px;
float: left;
}
#rightcol {
width: 270px;
position: relative;
margin-left: 510px;
text-align: center;
}

Centering <div> without using "margin: auto;"

I'm looking for a way to center a div horizontally in the page on Google Chrome.
I tried using margin: auto; but I've read that this function is not supported in Google Chrome. As a result my div stays aligned to the left side of the screen.
If I use, for example, margin-left: 100px; the div does move toward the center of the page, but I don't want to center it manually.
HTML:
<body>
<div id="header">
<p>John Doe</p>
<p>email</p>
</div>
</body>
CSS:
body
{
background-color: #f0f0f0;
}
div
{
border-radius: 5px;
}
#header
{
position: fixed;
background-color: #3399ff;
color: white;
width: 60%;
margin: auto;
}
#header p
{
display: inline;
}
margin: auto will not work on a fixed (or absolute) position div. Instead you need to set left: 50% and the left margin to negative half of the element width.
#header
{
position: fixed;
width: 60%;
left: 50%;
margin-left: -30%;
}
http://jsfiddle.net/ZAqJM/
UPDATE: as of now most browsers will support transfrom: translate so you can comfortably do:
{
position: fixed;
left: 50%;
transform: translateX(-50%);
}
I know this is quite old but I think is worth mentioning that the following works like magic:
#header {
left: 50%;
transform: translateX(-50%);
}
For future references.
Centering a <div> using margin: auto; works cross browsers. You need to make sure the div that you're trying to center is contained in a block-level element.
<div class="headerContainer">
<div id="header">
<p>John Doe</p>
<p>email</p>
</div>
</div>
To properly center, your div#header needs to be block-level and must have a width and is a child element of a block-level element. (Technically <body> is block-level but you might want to maintain your header's "containership")
Therefore, remove the position: fixed from #header { ... }. Please see working example: http://jsfiddle.net/amyamy86/2sXdC/
margin:auto is for the object that has width and set the left-right margin equally.
Div is basically BLOCK with FULL-WIDTH (100%) so set margin:auto is doesn't get anything since the width is full to the parent.
To make it work, you can did that by 2 ways,
use text-align:center for div -> this will align text inside div center
include width property in div (i.e. width:200px) and it will work fine.

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