Absolute DIV taking all remaining height - html

I'm stacked with CSS, trying to give to an absolute positioned <div> the remaining height from where it starts.. Let me explain better with this snippet:
#main {
background-color: yellow;
}
#container {
display: grid;
position: relative;
grid-template-rows: auto auto;
}
#child_1 {
background-color: red;
grid-row: 1 / 2;
height: 100px; // this can vary
}
#child_2 {
background-color: green;
grid-row: 2 / 3;
height: 77px; // this can vary
}
#child_3 {
width: 100%;
position: absolute;
top: 100%;
background: lightblue;
}
<div id="main">
<div id="container">
<div id="child_1">CHILD 1</div>
<div id="child_2">CHILD 2</div>
<div id="child_3">CHILD 3<br /> CHILD 3</div>
</div>
<div id="something-else">
Something that is <br />
behind <br />
the absoolute <br />
div <br />
</div>
</div>
As you can see, div#child_3 starts right after div#child_2 (this is a constraint, I do want this), and I also want it to be position: absolute because it must cover anything else that may be on the screen (basically, I will have a JS handler that show/hide div#child_3, and when it is shown, it should cover #something-else).
What I would like to achieve is that div#child_3 takes all the height, from where it starts, to the end of the viewport.. To make it clearer, look at this image:
The difficult part is that.. I would like to achieve this only with CSS!
Because the only solution I've found so far is to set a fixed height to div#child_3, by granting him (100vh - div#child_3.getBoundingBoundRect().Top), and setting a ResizeObserver to cover the case in case in which the window got resized.
By the way, notice I cannot set a fixed height: calc(100vh - 177px) because, as written in CSS code, the div#child_1 and div#child_2 heights may vary.
Moreover, the div#main should not be touched: I can only work on div#container and its children, because they are part of a separate component (this example is simplified).

If there is no reason for any of the children to have their position set to absolute then this layout could be achieved with flexbox. Please see the snippet below for an example:
.parent {
height: 100vh;
/* Important styles below */
display: flex;
flex-flow: column wrap;
}
.child {
background: blue;
}
.child:nth-of-type(even) {
background: red;
}
.child--large {
/* Important styles below */
flex: 1;
}
<div class="parent">
<div class="child">
1
</div>
<div class="child">
2
</div>
<div class="child">
3
</div>
<div class="child child--large">
4
</div>
</div>

Use CSS flex-box. It's much more flexible and responsive than grid.
#main {
background-color: yellow;
}
#container {
display: flex;
flex-direction: column;
height: 100vh;
}
#child_1 {
background-color: red;
flex-grow: 1;
}
#child_2 {
background-color: green;
flex-grow: 1;
}
#child_3 {
background-color: lightBlue;
flex-grow: 2;
}
<div id="main">
<div id="container">
<div id="child_1">CHILD 1</div>
<div id="child_2">CHILD 2</div>
<div id="child_3">CHILD 3<br /> CHILD 3</div>
</div>
<div id="something-else">
More<br>elements<br>down<br>here...
</div>
</div>

Edited: It seems the original answer I deliver below is not what you want. The another idea I come up with when try on my own local machine (instead of Stackoverflow's the snippet editor) is to wrap the #child_3 inside another div called #child_3_wrapper and then position #child_3 relative to #child_3_wrapper instead of #container.
Here is the full code:
#main {
background-color: yellow;
}
#container {
display: grid;
height: 100vh; /*added this, try 100%, 98vh(or *padding:0;margin:0,...etc) to get the result desired*/
grid-template-rows: auto auto 1fr; /*added 1fr*/
}
#child_1 {
background-color: red;
grid-row: 1 / 2;
height: 100px;
}
#child_2 {
background-color: green;
grid-row: 2 / 3;
height: 77px;
}
/* changed the code below */
#child_3_wrapper {
position: relative;
}
#child_3 {
position: absolute;
top: 0; /* change top to 0 - relative to the wrapper, not the grid any more*/
width: 100%;
height: 100%;
background: lightblue;
}
<div id="main">
<div id="container">
<div id="child_1">CHILD 1</div>
<div id="child_2">CHILD 2</div>
<div id="child_3_wrapper">
<div id="child_3">CHILD 3<br /> CHILD 3</div>
</div>
</div>
<div id="something-else">
Something that is <br />
behind <br />
the absoolute <br />
div <br />
</div>
</div>
The old answer
Is this what you want? I tried tweaking around with it to get the result.
Added height: 100%; to #container and #child_3
#main {
background-color: yellow;
}
#container {
display: grid;
height: 100%; /* add this */
position: relative;
grid-template-rows: auto auto;
}
#child_1 {
background-color: red;
grid-row: 1 / 2;
height: 100px; // this can vary
}
#child_2 {
background-color: green;
grid-row: 2 / 3;
height: 77px; // this can vary
}
#child_3 {
width: 100%;
position: absolute;
top: 100%;
height: 100%; /* add this */
background: lightblue;
}
<div id="main">
<div id="container">
<div id="child_1">CHILD 1</div>
<div id="child_2">CHILD 2</div>
<div id="child_3">CHILD 3<br /> CHILD 3</div>
</div>
<div id="something-else">
Something that is <br />
behind <br />
the absoolute <br />
div <br />
</div>
</div>

Related

Flexbox with flex:1 child and grandchild with 100%

Imagine having this situation: a simple 3 rows layout made with flexbox, with the central row filling all the space available. Pretty standard stuff.
<body>
<div class="container">
<div class="flex-container">
<div>header</div>
<div class="content">
<div class="item red">asdasd</div>
<div class="item yellow">asdasd</div>
<div class="item green">asdasd</div>
</div>
<div>footer</div>
</div>
<div>
<body>
Here the CSS:
html,
body,
.container {
height: 100%;
}
.flex-container {
height: 100%;
display: flex;
flex-direction: column;
}
.flex-container .content {
flex: 1;
}
.flex-container .content .item {
height: 100%;
}
(omitting css for background colors, you can guess it).
The problem is that the "content" div does not push down the footer div, keeping it at the bottom of the page, like is position:fixed with bottom: 0.
Scrolling the page show, except for this problem, the correct behavior, with 3 div with different color all sizing 100% the browser window.
What I'm missing?
EDIT: look at this jsfiddle
https://jsfiddle.net/rq1xywng/
I am not sure about what you are looking for. May be it will be help for you.
html,
body {
margin: 0;
padding: 0;
box-sizing: border-box;
height: 100vh;
min-height: 100vh;
}
.container {
height: 100vh;
min-height: 100vh;
background-color: fuchsia;
}
.header, .footer {
height: 30px;
}
.flex-container .content {
display: flex;
height: 100%;
height: calc(100vh - 60px);
}
.flex-container .content .item {
width: 100%;
height: 100%;
}
.red {
background-color: red;
}
.yellow {
background-color: yellow;
}
.green {
background-color: green;
}
<div class="container">
<div class="flex-container">
<div class="header">header</div>
<div class="content">
<div class="item red">asdasd</div>
<div class="item yellow">asdasd</div>
<div class="item green">asdasd</div>
</div>
<div class="footer">footer</div>
</div>
<div>
So you have couple of errors here:
you set EVERY ITEM IN THE CONTAINER to be 100% - this amounts to 300% :)
their parent is "only" 100%
footer will be hidden unless given height
you used vh and % combined in an unhealthy way.
you should have 2 flex components:
.flex-container - to match to screen size
.flex-container .content - to be able to stretch the items
You should set .item to flex: 1;
Here is a working version: https://jsfiddle.net/oj0thmv7/5/
Here is a working example with scroll: https://jsfiddle.net/oyLbxsrc/
If you change the 100% to 100vh this works
.flex-container .content .item {
height: 100vh;
}
Or have I misunderstood the issue?

How can i place two divs side by side and a third div aligning with the second

I have two divs (div1 and div2) side by side and I would like to place a third div (div3) under div2.
I've tried adding a margin to div3 to try and line it up, but div1 width is dynamic. I've also tried floating div3 to the right but then the content is too far and doesn't line up with the start of div2 like in the image above
.row {
display: flex;
}
.div1 {
margin-right: 1em;
}
<div class="row">
<div class="div1">
<p> some content with unknown width</p>
</div>
<div class="div2">
<p> some content </p>
</div>
</div>
<div class="div3">
<p> some content that should be under div2 </p>
</div>
The default behaviour is div3 being under div1. I am trying to put div3 below div 2
You can do this with below:
.wrapper {
display: flex;
flex-wrap: wrap;
justify-content: flex-end;
}
.div {
flex-basis: 50%;
min-height: 100px;
}
.div1 {
background: red;
}
.div2 {
background: blue;
}
.div3 {
background: aqua;
}
<div class="wrapper">
<div class="div div1">div1</div>
<div class="div div2">div2</div>
<div class="div div3">div3</div>
</div>
And here is a codepan
Use float and inline-block:
[class*="div"] {
display:inline-block;
border:2px solid;
}
.div1 {
float:left;
margin-right: 1em;
margin-bottom:10px; /*mandatory margin to push the div3*/
}
<div class="row">
<div class="div1">
<p> some content with unknown width</p>
</div>
<div class="div2">
<p> some content </p>
</div>
</div>
<div class="div3">
<p> some content that should be under div2 </p>
</div>
You can make use of the CSS Grid structure. In this way you can have all child elements inside a single parent container.
.row {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-template-rows: repeat(2, 1fr);
grid-column-gap: 5px;
grid-row-gap: 5px;
}
.div1 {
grid-area: 1 / 1 / 2 / 2;
}
.div2 {
grid-area: 1 / 2 / 2 / 3;
}
.div3 {
grid-area: 2 / 2 / 3 / 3;
}
/* Snippet styling */
.row > div {
background: #6A67CE;
color: white;
text-align: center;
text-transform: capitalize;
font-family: sans-serif;
}
<div class="row">
<div class="div1">
<p> some content with unknown width</p>
</div>
<div class="div2">
<p> some content </p>
</div>
<div class="div3">
<p> some content under div2 </p>
</div>
</div>
Here is a flex solution, you can use the slider to change the width of the left box to see that the width doesn't matter.
In case you are not familiar with flex, here is what happens.
display: flex; tells the container to act as a flex container, flex is just another display behavior just like float.
flex-flow: row wrap;, now that the container is flex, tells the children to display in a row, and wrap if necessary, not in this case.
That is all, after adding two boxes in the right div, and set some demo width and height, we are done.
window.addEventListener('DOMContentLoaded', e => {
let left = document.querySelector('.left')
let range = document.querySelector('.range')
range.addEventListener('input', e => {
left.style.width = e.target.value + 'px'
})
})
div {
border: 3px solid green;
}
.container,
.right {
border: none;
}
.container {
display: flex;
flex-flow: row wrap;
}
.left,
.one,
.two {
min-width: 50px;
min-height: 50px;
}
.left {
margin-right: 1em;
}
.one {
min-width: 80px;
}
.two {
margin-top: 1em;
}
<div class="container">
<div class="left"></div>
<div class="right">
<div class="one"></div>
<div class="two"></div>
</div>
</div>
<input class="range" type="range" min="50" max="300"></input>
Since div do not share the same parent , you could use display:contents and set a grid-layout one level upper , unfortunately, display:contents is not yet supported every where .
here is an example (body is the wrapper and .row not seen anymore)
body {
display: grid;
grid-template-columns: auto 1fr;
grid-gap: 10px;
}
.row {
display: contents;
/* removed from the tree */
}
div {
border: solid;
/* show me */
grid-column: 2;
/* make it the defaut column position */
width: max-content;
}
.div1 {
grid-column: 1;
/*a single reset enough here */
}
#supports (display:grid) {
.disclaimer {
display: none;
}
}
<div class="row">
<div class="div1">
<p> some content with unknown width</p>
</div>
<div class="div2">
<p> some content </p>
</div>
</div>
<div class="div3">
<p> some content that should be under div2 </p>
</div>
<p class="disclaimer">Your browser do not support <code>display:contents</code>.</p>
Another possibility is the table-layout algorythm
example with display:table (widely supported) , but every cell of each columns are of the same width.
body {
display: table;
border-spacing: 10px;
}
.div3,
.row {
display: table-row;
}
.row>div,
.div3>p,
.div3::before {
display: table-cell;
border: solid;
}
.div3::before {/* it stands in column 1 */
content: '';
border: none;
}
<div class="row">
<div class="div1">
<p> some content with unknown width</p>
</div>
<div class="div2">
<p> some content </p>
</div>
</div>
<div class="div3">
<p> some content that should be under div2 </p>
</div>
Nothing is perfect ;)
hi i coded this if that helps
.first-container {
display: flex;
flex-direction: row;
}
.first-container div{
margin: 10px;
}
.container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
<div class="container">
<div class="first-container">
<div class="first">first</div>
<div class="second">second</div>
</div>
<div class="third">third</div>
</div>

Force next div to go to next row

I have some structure like this:
.divParent{
height: 100px;
}
.div1 {
height: 40px;
background: blue;
}
.div2{
height: 150px;
background: yellow
}
<div class="divParent">
<div class="div1">Div 1</div>
<div class="div2">Div 2</div>
</div>
<div class="divNew">
<span>Hello</span>
</div>
I want divNew to go to next line and not get overlapped by content of divParent. I tried so many things but nothing is working out.
I know, I can use <br /> tag to do this but I don't want to use that. Is there any other solution.
Use flex
.divParent{
clear:both;
height: 100px;
}
.div1 {
height: 40px;
background: blue;
}
.div2{
height: 150px;
background: yellow
}
.divParent, .divNew {
display: flex;
flex: 1;
flex-direction: column;
}
.divNew {
background:red;
}
<div class="divParent">
<div class="div1">Div 1</div>
<div class="div2">Div 2</div>
</div>
<div class="divNew">
<span>Hello</span>
</div>
You don't need to remove the height, your second div is actually causing an issue. It's bigger than parent. So either increase the parent or decrease div2.

FlexBox Filling blank spaces

So in the image below, I created a flexbox for a sidebar, a main area, and then a small area up to the right as a login area.
The first sidebar on the left has a fixed height of 600px, the mainarea in the middle has a height of 100vh, and the right sidebar has a fixed height of 200px.
My questions is if it is possible to fill in the blank space on the right, underneath the green with the main area content with flexbox. Is this possible, or is flexbox not the way to go with this layout?
I essentially want the content my main area red content to flow beneath the green area.
.main {
display: flex;
flex-wrap: wrap;
border: 0px solid black;
height: 100vh;
}
.sidebar {
background: #F1F1F9;
flex: 1;
height: 600px;
}
.mainArea {
flex: 3;
background: red;
}
.rightSidebarSmall {
flex: 1;
background: green;
height: 200px;
}
<link href="//fonts.googleapis.com/css?family=Raleway:300,400,600,700" rel="stylesheet">
<div class="main">
<div class="sidebar">
<div class="logo">
<img src="img/sound-wave-icon.png" height="100px" width="140px">
</div>
<div class="selectorBar">
</div>
<div class="menu">
<ul class="menuOptions">
<li>Recent Files</li>
<li>Projects</li>
<li>Teams</li>
<li>Archives</li>
</ul>
</div>
<div class="addButton">
plus icon button
</div>
<div class="progressBar">
uploading 5 files <br> progressBar <br> 9.8mbps 36 secs remaining
</div>
</div>
<div class="mainArea"></div>
<div class="rightSidebarSmall"></div>
</div>
Using CSS Grid is the easiest way to go about this, since the layout you are going for is very unorthodox. With that said, I was able to get a layout that I think fits your description that I put in a Pen.
https://codepen.io/anon/pen/bLjNRO
The gist of it adds:
.main {
display: grid;
grid-template-columns: repeat(5, 1fr);
}
.mainArea {
grid-column: 1 / 6;
grid-row: 1;
}
.rightSidebarSmall {
grid-column: 5 / 6;
grid-row: 1;
}
I think it is better if you can make the right sidebar to position absolute. with this your main (red arean) will be cover full with and green area will be overlap on the red area
.main {
display: flex;
flex-wrap: wrap;
border: 0px solid black;
height: 100vh;
position:relative;
}
.sidebar {
background: #F1F1F9;
flex: 1;
height: 600px;
}
.mainArea {
flex: 3;
background: red;
}
.rightSidebarSmall {
position:absolute;
right:0;
top:0;
z-index: 10;
min-width:100px;
height:200px;
background:green;
}
<div class="main">
<div class="sidebar"></div>
<div class="mainArea"></div>
<div class="rightSidebarSmall"></div>
</div>
Hope it will help you :)
Sure, just use float: right Just make sure the floating div is before the rest of your text.
.main {
width: 50vw;
height: 50vh;
position: relative;
}
.inner {
background-color: red;
float: left;
width: 100%;
height: 100%;
word-break: break-all;
}
.other {
background-color: green;
float: right;
max-width: 150px;
}
<div class="main">
<div class="inner">
<div class="other">
another text asdfsdf asdf asdf
</div>
<div>
The quick brown fox The quick brown fox The quick brown fox
</div>
</div>
</div>

How can I make the left div expand and the right div have constant width?

So as the title says, I want to put two divs right next to each other, and have the left one expand if the window is expanded, while the right one stays at a constant width.
Here is what I've got so far:
<body>
<div id="content" style="background-color: red">
<div id="left" style="margin-right: 100px; background-color: blue">
This</br>is</br>left.
</div>
<div id="right" style="float: right; width: 100px; height: 100px; background-color: green">
This</br>is</br>right.
</div>
<div style="clear:both"></div>
</div>
</bod>
Which produces this:
Ideally, the green square and blue square should have their tops aligned with each other. One solution I found was putting a negative margin-top setting on the green div, which works... but only as long as the blue div never changes in height. Unfortunately, the blue div can in fact change height in my situation.
Any ideas on how I'd fix this? I'm having some difficulty understanding the intricacies of CSS positioning :(
If you can use position:absolute, you can do something like this:
<div class="left">This is the left box.</div>
<div class="right">This is the right box.</div>
And the CSS:
.left {
position: absolute;
left: 0px;
right: 100px;
}
.right {
position: absolute;
right: 0px;
width: 100px;
}
http://jsfiddle.net/Q2TKU/
Have you considered nesting them ?
http://jsfiddle.net/bonatoc/N3xWn/
<div id="content" style="background-color: red">
<div id="left" style=" background-color: blue">
<div id="right" style="display:inline-block; float: right; width: 100px; height: 100px; background-color: green">
This</br>is</br>right.
</div>
This</br>is</br>left.
</div>
<div style="clear:both"></div>
You could do it this way.
If this is your HTML:
<div id="content">
<div id="left">This</br>is</br>left.</div>
<div id="right">This</br>is</br>right.</div>
</div>
Try the following CSS:
#content {
background-color: red;
position: relative;
min-height: 100px;
}
#left {
margin-right: 100px;
background-color: blue;
width: auto;
}
#right {
position: absolute;
top: 0;
right: 0;
width: 100px;
height: 100px;
background-color: green;
}
See demo at: http://jsfiddle.net/audetwebdesign/GfpyL/
Your logo in the #right element has specific dimensions, so position it absolutely to the top right of the parent #content element which has position: relative to set the point of reference for the absolute positioning.
Add a min-height to the parent block to prevent it from collapsing for those cases where the #left block is less than 100px in height.
How about using flexbox? flexbox help you control these width flexibility.
If you set left content as a 100px, right box width is flexibility.
HTML below :
<div id="content" >
<div id="left">
This<br>is<br>left.
</div>
<div id="right">
This<br>is</br>right.
</div>
</div>
CSS below:
#content {
/* old*/
display: -webkit-box;
display: -moz-box;
display: -ms-box;
display: box;
/* New */
display: -webkit-flexbox;
display: -moz-flexbox;
display: -ms-flexbox;
display: flexbox;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
-ms-box-sizing: border-box;
box-sizing: border-box;
}
#left {
/* old */
-webkit-box-ordinal-group: 1;
-moz-box-ordinal-group: 1;
-ms-box-ordinal-group: 1;
box-ordinal-group: 1;
/* New */
-webkit-flex-order: 1;
-moz-flex-order: 1;
-ms-flex-order: 1;
flex-order: 1;
/* Old */
-webkit-box-flex: 1;
-moz-box-flex: 1;
-ms-box-flex: 1;
box-flex: 1;
/* New */
width: -webkit-flex(1);
width: -moz-flex(1);
width: -ms-flex(1);
width: flex(1);
}
#right {
width: 100px;
/* Old */
-webkit-box-ordinal-group: 2;
-moz-box-ordinal-group: 2;
-ms-box-ordinal-group: 2;
box-ordinal-group: 2;
/* New */
-webkit-flex-order: 2;
-moz-flex-order: 2;
-ms-flex-order: 2;
flex-order: 2;
}
Here is jsfiddle code below :
http://jsfiddle.net/sota0805/kykU7/
I hope it help you.
You could use make use of block formatting contexts to fill remaining width.
1) Float the first child of a div
2) Set overflow:auto (or hidden) on the second child to fill remaining width
So this would work too:
FIDDLE
Markup:
<div class="wpr">
<div class="rFloat"></div>
<div class="blue overflow" contenteditable>this is left</div>
<div class="rFloat green">This is right</div>
<div class="overflow"></div>
</div>
CSS
.wpr {
background: red;
min-width: 200px;
}
div {
min-height: 20px;
}
.rFloat {
width: 100px;
float:right;
}
.blue {
background: blue;
}
.green {
background: green;
}
.overflow {
overflow: auto;
}
Notice that in the fiddle I have set the contenteditable attribute to true on the blue div - so you can type in the blue area and see that it expands as required.