Is there a way of making a DIV expand to fill the space left in it's parent container without having to use Javascript to calculate the necessary heights?
<div class="parent" style="height: 100%">
<div class="child-top">
</div>
<div class="child-bottom" style="position: relative;">
</div>
</div>
.parent is a sidebar that takes up the whole screen, .child-top height may vary depending on the content, and I would like .child-bottom to just take up the rest of the space with position relative so that I can correctly position other elements inside.
UPDATE: I can't use fixed heights in any of the elements. .child-top for obvious reasons, and .child-bottom will have an element with a scrollbar when its height outgrows the parent.
If you're just looking to fill it up, you can use overflow:hidden on the parent to fake it. This comes with some caveats. Anything within the child bottom with a height greater than the child will be hidden, so take it as you will.
http://jsfiddle.net/hBLQR/
Your HTML:
<div class="parent">
<div class="child-top">
Hi there
</div>
<div class="child-bottom">
Hi back
</div>
</div>
And the CSS:
.parent {
position: absolute;
left: 0;
right: 200px;
top: 0;
bottom: 0;
overflow: hidden;
}
.child-top {
background: green;
height: 100px;
width: 200px;
}
.child-bottom {
background: red;
height: 100%;
width: 200px;
}
Related
Is it possible with only CSS to have the following effect:
I have two divs. One follows the other.
Now, if the user starts scrolling down the page (to see other content, more divs if you want..) the second div should "go up" (could also stay fixed and the first div goes down, I mean it would look the same) and overlap the first.
But only overlap for let's say 50px. After that, the behaviour is normal again, meaning that if you scroll further, those divs move out of the browser window eventually.
Have I made myself clear? I can add two coloured boxed to showcase if that helps. I played around a bit and tried parallex/position fixed/sticky mixes, but none seem to work with a given height restriction. I just wonder if this is possible without javascript.
You can get this effect by using position: sticky on both elements. There are a few things that can stop this from taking place, like having overflow: hidden or not having a height set on the parent element.
HTML
<div class="container">
<div class="red-box">This is the red box</div>
<div class="blue-box">this is the blue box</div>
</div>
<!-- needs space to be able to actually scroll on the page -->
<div class="container">
<div class=""></div>
<div class=""></div>
</div>
CSS
/* set the height of the container so that the sticky elements know how far they are meant to scroll */
.container{
min-height: 400px;
}
/* set your position sticky and a attribute that tells it when it should become sticky, in this case right at the top */
.red-box{
height: 400px;
background-color: red;
position: sticky;
top: 0px;
}
.blue-box{
height: 400px;
background-color: blue;
position: sticky;
top: 0px;
}
I have done a quick codepen example so that you can see this working. hope that helps.
https://codepen.io/Domnewmarch/pen/NWzqBde
Solution: I used a combination of negative margin, z-index and position: sticky.
Added margin to the 2nd container to make it more visible.
.sticky-wrapper {
height: 310px;
margin-bottom: -60px;
}
.content {
z-index: -1;
position: sticky;
top: 0;
padding: 0 3%;
height: 250px;
background-color: green;
}
.foo {
margin: 0 50px;
background-color: red;
height: 200px;
}
.next-content {
height: 1000px;
background-color: khaki;
}
<div class="sticky-wrapper">
<div class="content"></div>
</div>
<div class="foo"></div>
<div class="next-content"></div>
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
It is a common question, but I still have not found any solution for my issue.
The .parent is a slider and the .child are images.
I need pass .child height (which is an absolute-positioned element) to .parent.
.parent has 0px height. Any ideas?
Thanks in advance.
<div class="parent">
<img class="child"></div>
</div>
.child {
position: absolute; //It must be absolute , because slider works with this
width: 100%;
top: 0;
left: 0;
right: 0;
}
As I mentioned in the comments, you could perhaps add two <img> elements. One with position: absolute - as your application requires, and another one with visibility: hidden but with position: relative.
If you don't want to mess about with the markup, you could do something similar with pseudo-elements, such as :after or :before. But the idea is the same.
The parent now takes up the full height of your image. This solution may or may not work depending on your application, which isn't very clear in your question, but perhaps it's worth a try.
.parent {
background: #AAA;
}
.child {
position: absolute;
}
.child-hidden {
visibility: hidden;
}
<div class="parent">
<img class="child" src="http://www.extremekitcars.com/wp-content/uploads/2016/01/Sports-Cars.png">
<img class="child-hidden" src="http://www.extremekitcars.com/wp-content/uploads/2016/01/Sports-Cars.png">
</div>
Since you know the image dimensions, you can divide the height by the width and get the aspect ratio. Then apply that as a vertical padding percentage to the parent and that will make the parent match the image dimensions responsively.
.child {
position: absolute;
width: 100%;
top: 0;
left: 0;
right: 0;
}
.parent {
border: 1px solid red;
position: relative;
padding-bottom: 39.86451277%; /* (765 / 1919) * 100 */
}
<div>some content</div>
<div class="parent">
<img class="child" src="http://via.placeholder.com/1919x765">
</div>
<div>more content</div>
what could be the solution if the child is not an image rather the child is a div with unknown(auto) height because it needs accomodate for dynamic content ?
I am trying to put a position:fixed div inside an another div. I want a fixed div which has a width:100%; so it will be great for mobile and desktop at the same time.
Here is my JSfiddle
SF wants some code:
<div id="container">
<div id="item">This div is good div</div>
<div id="fixed">Right side of this div overflow its parent!!! </div>
</div>
An element with position: fixed; ignores the parent size because it is relative only to the viewport:
MDN:
Fixed positioning is similar to absolute positioning, with the exception that the element's containing block is the viewport.
You can:
Try giving it position: absolute; and set the container to position: relative;.
Use position: fixed; and set the size explicitly.
You can use the calc() method to adapt the viewport size. Just subtract right and left margin from the 100%:
Edit: I added a min-height to the body to see the "fixed-effect" on scrolling
body {
margin: 0;
min-height: 1000px;
}
#container {
margin: 10px;
background: black;
color: white;
}
#item {
height: 50px;
width: 100%;
}
#item {
background: blue;
}
#fixed {
height: 50px;
width: calc(100% - 20px);
background: green;
position: fixed;
}
<div id="container">
<div id="item">Normal div</div>
<div id="fixed">Fixed div</div>
</div>
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