Absolute-positioned div within a div that takes all remaining space - html

I'm trying to make a layout that seems simple. Despite looking at lots of examples, I can't crack it.
SideBar| .......MapContainer......
SideBar| ..........Map............
SideBar| .......MapContainer......
Both SideBar and MapContainer should be 100% height.
The tricky bit: Map must have a defined height and width, because the mapbox-gl-js library uses its dimensions to populate it. (Rather than adding content which then sizes it).
MapContainer exists because there will be other absolutely positioned overlay elements within it.
I'm trying to avoid having the sidebar width coded into the definition of MapContainer so I can hide/show the sidebar in JS, and have the MapContainer automatically fill the space.
This gets really, really close:
* {
box-sizing: border-box;
}
.sidebar, .mapcontainer, .container {
height: 200px;
}
.container {
width:100%;
border:1px solid;
display: flex
}
.sidebar {
width:200px;
background:lightblue;
}
.mapcontainer {
width:auto;
background:lightgreen;
position:relative;
flex-grow: 1;
}
.map {
width: 100%;
height: 100%;
position:absolute;
border: 20px dashed grey;
}
<div class="container">
<div class="sidebar"></div>
<div class="mapcontainer">
<div class="map">
</div>
</div>
</div>
But as soon as I change the "height: 200px" to "height: 100%", it collapses to nothing. What do I need to do?

Use viewport units vh instead in the .sidebar, .mapcontainer, .container rule
* {
box-sizing: border-box;
}
html, body {
margin: 0;
}
.sidebar, .mapcontainer, .container {
height: 100vh;
}
.container {
border: 1px solid;
display: flex
}
.sidebar {
width: 200px;
background:lightblue;
}
.mapcontainer {
background:lightgreen;
position:relative;
flex-grow: 1;
}
.map {
width: 100%;
height: 100%;
position:absolute;
border: 20px dashed grey;
}
<div class="container">
<div class="sidebar"></div>
<div class="mapcontainer">
<div class="map">
</div>
</div>
</div>

I just need to add height: 100%; to html and body:
* {
box-sizing: border-box;
}
html, body {
height: 100%;
margin: 0;
}
.sidebar, .mapcontainer, .container {
height: 100%;
}
.container {
width:100%;
border:1px solid;
display: flex
}
.sidebar {
width:200px;
background:lightblue;
}
.mapcontainer {
width:auto;
background:lightgreen;
position:relative;
flex-grow: 1;
}
.map {
width: 100%;
height: 100%;
position:absolute;
border: 20px dashed grey;
}
<div class="container">
<div class="sidebar"></div>
<div class="mapcontainer">
<div class="map">
</div>
</div>
</div>

Related

How to have image fill remaining space within a div? [duplicate]

This question already has answers here:
Why don't flex items shrink past content size?
(5 answers)
Fill remaining vertical space with CSS using display:flex
(6 answers)
Closed 3 years ago.
I have a <div> that takes up 60% of the window space, and it contains two things:
a narrow header line
an image that I want to take up the remainder of the div.
How can I do this with pure CSS (no Javascript)? I've been trying a bunch of things, no luck.
This is the closest I can get; the image sneaks outside of the green border of the div.container
html, body {
height: 100%;
overflow: hidden;
margin: 0px;
}
div.container {
height: 60%;
border: 2px solid green;
box-sizing: border-box;
}
div.rest {
height: 40%;
border: 2px solid red;
box-sizing: border-box;
}
div.img-container {
height: 100%; /* this is wrong, but what do I do? */
}
div.img-container img {
max-height: 100%;
max-width: 100%;
height: auto;
width: auto;
opacity: 0.5;
}
<html>
<body>
<div class="container">
<div class="header">hieronymus bosch last judgement</div>
<div class="img-container"><img src="https://i.imgur.com/TT6drhn.jpg"></div>
</div>
<div class="rest">
<h1>blah blah blah</h1>
</div>
</body>
</html>
Here's my attempt at using flex but that fails.
html, body {
height: 100%;
overflow: hidden;
margin: 0px;
}
div.container {
height: 60%;
border: 2px solid green;
box-sizing: border-box;
display: flex;
flex-direction: column
}
div.rest {
height: 40%;
border: 2px solid red;
box-sizing: border-box;
}
div.img-container {
flex: 1;
}
div.header {
flex: 0;
}
div.img-container img {
max-height: 100%;
max-width: 100%;
height: auto;
width: auto;
opacity: 0.5;
}
<html>
<body>
<div class="container">
<div class="header">hieronymus bosch last judgement</div>
<div class="img-container"><img src="https://i.imgur.com/TT6drhn.jpg"></div>
</div>
<div class="rest">
<h1>blah blah blah</h1>
</div>
</body>
</html>
#Christian's approach works if you know the height of the header element, however alternatively you could use flex.
This allows the element to grow to fill the remaining space dynamically, so your header can be any height.
html,
body {
height: 100%;
overflow: hidden;
margin: 0px;
}
div.container {
height: 60%;
border: 2px solid green;
box-sizing: border-box;
display: flex;
flex-direction: column;
}
div.rest {
height: 40%;
border: 2px solid red;
box-sizing: border-box;
}
div.img-container {
flex: 1;
position: relative;
}
div.img-container img {
opacity: 0.5;
height: 100%;
position: absolute;
}
<html>
<body>
<div class="container">
<div class="header">hieronymus bosch last judgement</div>
<div class="img-container"><img src="https://i.imgur.com/TT6drhn.jpg"></div>
</div>
<div class="rest">
<h1>blah blah blah</h1>
</div>
</body>
</html>
If you look at div.img-container in Chrome Inspector, you can see what the issue is - the img element is doing its job and filling its container, but the container itself is overflowing.
This is happening because it is set to height: 100% - what this says is "make my height 100% of my parent's height", but this does not mean "fill the remaining space." The browser just reads the computed height of the element's parent, and then multiplies it by your % value - basically, it's all in absolute terms. You can see that the blue box is 100% as tall as the box outlined in green, but because it sits below a line of text, it overflows by the height of that text.
flex could be used to solve this problem, but you can patch this pretty quickly by using calc to subtract out the height of that text. In your example, it's 19px, and I would recommend manually setting the height of that text element container just to be sure nothing will break in edge cases. Then, the .img-container gets height: calc(100% - 19px) and it works as expected.
html, body {
height: 100%;
overflow: hidden;
margin: 0px;
}
div.container {
height: 60%;
border: 2px solid green;
box-sizing: border-box;
}
div.rest {
height: 40%;
border: 2px solid red;
box-sizing: border-box;
}
div.img-container {
height: 100%; /* this is wrong, but what do I do? */
}
div.img-container img {
max-height: 100%;
max-width: 100%;
height: auto;
width: auto;
opacity: 0.5;
}
/*
ADDED CODE BELOW
*/
/* optional, just to be safe */
.header {
height: 19px;
}
/* overrides .img-container from above */
.img-container {
height: calc(100% - 19px) !important;
}
<html>
<body>
<div class="container">
<div class="header">hieronymus bosch last judgement</div>
<div class="img-container"><img src="https://i.imgur.com/TT6drhn.jpg"></div>
</div>
<div class="rest">
<h1>blah blah blah</h1>
</div>
</body>
</html>
With Flex, you may use the flex property and overflow (or min-height). Example:
html, body {
height: 100vh;
margin: 0px;
display:flex;
flex-direction:column;
}
div.container {
flex:6;/* instead height:xx% */
border: 2px solid green;
box-sizing: border-box;
display: flex;
flex-direction: column;
overflow:hidden; /* or min-height:0 if scroll is needed */
}
div.rest {
flex:4;/* instead height:xx% */
border: 2px solid red;
box-sizing: border-box;
}
div.img-container {
flex: 1;
min-height:0; /* or overflow:hidden; */
}
div.header {
min-height:1.6em; /* if you need something alike ?? */
}
div.img-container img {
max-height: 100%;
opacity:0.5;
}
<html>
<body>
<div class="container">
<div class="header">hieronymus bosch last judgement</div>
<div class="img-container"><img src="https://i.imgur.com/TT6drhn.jpg"></div>
</div>
<div class="rest">
<h1>blah blah blah</h1>
</div>
</body>
</html>

Dynamic grid system with different widths css3?

I need to perform a dynamic grid system like this:
Each section is an article that contains an image, a title and a link/button to that article.
The problem is that each section is loaded dynamically and i only have the html of the section so i need to put each section on the correct position dynamically from the CSS. The one i know is that there are 5 sections.
The html code of each section and the container of all the sections is this:
<section class="scroll">
<!-- ARTICLES -->
<!-- ARTICLE -->
<div class="article-content">
<img class="article-image" src="${item.imgPath}" />
<div class="article-texts">
<h1 class="article-title">${item.title}</h1>
<a class="article-button" href="${item.link}.html" role="button">Read Article ></a>
</div>
</div>
<div class="clear"></div>
<!-- END ARTICLE -->
<!-- END ARTICLES -->
</section>
If you have control over the dimensions of your sections, you can use a fixed width container and float the sections inside that. Clear the float on the fourth section.
Example Fiddle: http://jsfiddle.net/abhitalks/mbuf9957/3/
Example Snippet:
* { box-sizing: border-box; padding: 0; margin:0; }
div { width: 380px; overflow: hidden; }
section { border: 1px solid #666; float: left; }
section:nth-child(1) { width: 240px; height: 240px; }
section:nth-child(2) { width: 120px; height: 120px; }
section:nth-child(3) { width: 120px; height: 120px; }
section:nth-child(4) { width: 120px; height: 120px; clear: left; }
section:nth-child(5) { width: 240px; height: 120px; }
<div>
<section>1</section>
<section>2</section>
<section>3</section>
<section>4</section>
<section>5</section>
</div>
Since you have tagged this as CSS3, I think Flexbox would be an option. You could set display:flex on the parent and then have percentage widths for each box's flex-basis and set the flex-grow property to the amount of space, relative to other boxes, you want them to take up in the container and set flex-shrink to 0 since you don't need them to shrink.
CSS/HTML:
.grid-system {
/* Uncomment the next line to see the container */
/* border:1px solid black; */
}
.grid-system .box-width-2 {
border:1px solid black;
-webkit-flex:2 0 65%;
flex: 2 0 65%;
}
.grid-system .box-width-1 {
border:1px solid black;
-webkit-flex:1 0 32%;
flex: 1 0 32%;
}
.grid-system .box-height-2 {
-webkit-flex-grow:2;
flex-grow:2;
}
.grid-system .box-height-1 {
-webkit-flex-grow:1;
flex-grow:1;
}
.grid-system .flex-row {
display:-webkit-flex;
display:flex;
-webkit-flex-flow:row nowrap;
flex-flow:row nowrap;
-webkit-justify-content:flext-start;
justify-content:flex-start;
}
.grid-system .flex-column {
display:-webkit-flex;
display:flex;
-webkit-flex-flow:column nowrap;
flex-flow:column nowrap;
width:32%;
}
.grid-system .flex-row > div {
margin:0.5%
}
.grid-system .box-width-1.box-height-1 {
margin-bottom:0.5%;
-webkit-flex-grow:1;
flex-grow:1;
}
.grid-system .box-width-1.box-height-1.end {
margin-bottom:0px;
}
<div class="grid-system">
<div class="flex-row">
<div class="box-width-2 box-height-2">1</div>
<div class="flex-column">
<div class="box-width-1 box-height-1">2</div>
<div class="box-width-1 box-height-1 end">3</div>
</div>
</div>
<div class="flex-row">
<div class="box-width-1">4</div>
<div class="box-width-2">5</div>
</div>
</div>
jsFiddle
A solution only involving floats can reproduce your layout. Compatibility IE8+ (and even below but nobody cares). Pseudo-class :nth-child() (compat. IE9+) is used here to give an arbitrary width and height for demo, you'll have your own layout in real conditions.
* { box-sizing: border-box; }
div { width: 360px; }
section { border: 1px solid #666; }
.left { float: left; }
.right { float: right; }
.clear { clear: both; }
section:nth-child(1) { width: 240px; height: 240px; }
section:nth-child(2) { width: 120px; height: 100px; }
section:nth-child(3) { width: 120px; height: 80px; }
section:nth-child(4) { width: 200px; height: 120px; }
section:nth-child(5) { width: 160px; height: 100px; }
<div>
<section class="left">1</section>
<section class="right">2</section>
<section class="right">3</section>
<section class="left clear">4</section>
<section class="right">5</section>
</div>

How to style five rows with alternating fixed/variable width?

Example:
<div class="container">
<div>variable</div>
<div>fixed</div>
<div>variable with min-width</div>
<div>fixed</div>
<div>variable</div>
</div>
I want the whole thing to be as wide as the viewport.
I know how to do that for three columns, but I am completely lost with the five column version. I do not even have a concept of how that could work. The usual three column style involves absolute positioning of the fixed columns, but that would not work since the outermost columns are of variable width. I am lost.
Any ideas?
This is what I tried:
HTML:
<div class="container">
<div class="left">var</div>
<div class="inner_container">
<div class="inner_left">fix</div>
<div class="middle">var</div>
<div class="inner_right">fix</div>
</div>
<div class="right">var</div>
</div>
CSS:
.container {
position:relative;
}
.container div {
background: yellow;
}
.container .left,
.container .right {
background: orange;
width: 15%;
}
.inner_container {
position:relative;
}
.inner_container div {
margin:0 50px;
background:lightgreen;
}
.inner_container .inner_left,
.inner_container .inner_right {
background:lightblue;
position:absolute;
top:0;
width:50px;
}
.inner_container .inner_left {
left:-50px;
}
.inner_container .inner_right {
right:-50px;
}
The "inner_container" is basically the usual three column solution. If I set the inner_container to "left: 15%" the whole inner container is moved to the right, but still on its own "line".
flexbox can do that.
* {
box-sizing: border-box;
}
.container div {
height: 75px;
border:1px solid grey;
}
.container {
display: flex;
}
.variable {
background: lightgreen;
flex: 1 0 auto
}
.fixed {
background: lightblue;
flex: 0 0 150px;
}
.min-width {
flex-basis:250px;
min-width:250px;
background: pink;
}
<div class="container">
<div class="variable">variable</div>
<div class="fixed">fixed</div>
<div class="variable min-width">variable with min-width</div>
<div class="fixed">fixed</div>
<div class="variable">variable</div>
</div>
Codepen Demo

One column static width while other colum is dynamic width

<div class="table">
<div class="sidebar"></div>
<div class="content"></div>
</div>
* {
margin:0; padding:0;
}
html, body {
width:100%;
height:100%;
}
.table {
display:table;
width:100%;
height:100%;
}
.sidebar {
width:200px;
height:100%;
background:red;
display:table-cell;
white-space:nowrap;
vertical-align: top;
}
.content {
width:100%;
height:100%;
background:orange;
display:table-cell;
vertical-align: top;
}
What am I missing exactly? :), trying to replicate this structure:
http://dev.brigademarketing.com/brigade/old-content/site1/
fiddle:
http://jsfiddle.net/8o50f0cf/
Remove the width:100% from the dynamic column, so it can calculate its width automatically.
Updated Fiddle
A display: table-cell element acts like a <td>, meaning that it takes the remaining space of its table parent if no width is define.
Here's a solution that uses calc() function and floating: http://jsfiddle.net/jyx9orLy/.
HTML:
<div class="container">
<div class="sidebar"></div>
<div class="content"></div>
</div>
CSS:
* {
margin: 0;
padding: 0;
}
html, body, .container {
height: 100%;
}
.container .sidebar {
height: 100%;
background-color: red;
width: 200px;
float: left;
}
.container .content {
float: left;
height: 100%;
width: calc(100% - 200px);
background-color: orange;
}
A second solution is to use a table, which you are doing, and to make it work you do what #LcSalazar mentioned.
A third solution uses flexbox specification and requires a modern browser: http://jsfiddle.net/yp49uqay/.
CSS:
* {
margin: 0;
padding: 0;
}
html, body, .container {
height: 100%;
}
.container {
display: flex;
flex-direction: row;
}
.container > .sidebar {
flex: 0 0 200px;
background-color: red;
}
.container > .content {
flex: 1 1 auto;
background-color: orange;
}
And, a fourth solution that uses floating in a different way: http://jsfiddle.net/079sr0fu/.
HTML:
<div class="container">
<div class="sidebar"></div>
<div class = "contentWrapper">
<div class="content">Content...</div>
</div>
</div>
CSS:
* {
margin: 0;
padding: 0;
}
html, body, .container,
.container > .sidebar,
.container > .contentWrapper,
.container > .contentWrapper > .content {
height: 100%;
}
.container > .sidebar {
width: 200px;
background-color: red;
float: left;
}
.container > .contentWrapper {
overflow: hidden;
}
.container .content {
float: left;
width: 100%;
background-color: orange;
}

3 div's middle div take up remaining width

Alright guys, I've been busting my balls over this one.
I've got three divs; left, middle, right. All 100% height. The left and right div have a fixed width of 150px. Now I want the middle div to take up the remaining space.
Example: Here
CSS:
#left {
height:100%;
width:150px;
float:left;
background:red;
z-index:999;
}
#middle {
height:100%;
width:100%;
background:yellow;
margin-left:-150px;
margin-right:-150px;
}
#right {
float:right;
height:100%;
width:150px;
background:red;
z-index:998;
}
Use display: table:
#container {
display: table;
width: 100%;
}
#left, #middle, #right {
display: table-cell;
}
#left, #right {
width: 150px;
}
Where the #container is your parent element like in
<div id="container">
<div id="left"></div>
<div id="middle"></div>
<div id="right"></div>
</div>
Here is a Fiddle.
Okay using flex and based this answer
#parent {
display: flex;
}
#left {
width:150px;
background-color:#ff0000;
}
#middle {
flex: 1 1 auto;
background-color:#00ff00;
}
#right {
width: 150px;
background-color:#0000ff;
}
<div id="parent">
<div id="left">left</div>
<div id="middle">middle</div>
<div id="right">right</div>
</div>
This actually works if the left and right divs has variable width also.
Check this similar answer
HTML
<div class = "container">
<div class = "fixed">
I'm 150px wide! Glee is awesome!
</div>
<div class = "fluid">
I'm fluid! Glee is awesome!
</div>
<div class = "fixed">
I'm 150px wide! Glee is awesome!
</div>
</div>
CSS
html, body {
height: 100%;
font-family: 'Arial', 'Helvetica', Sans-Serif;
}
.container {
display: table;
width: 100%;
height: 100%;
}
.container > div {
display: table-cell;
text-align: center;
}
.fixed {
width: 150px;
background: rgb(34, 177, 77);
color: white;
}
.fluid {
background: rgb(0, 162, 232);
}
DEMO
If you don't want to use table cells and don't want to give your outer boxes a fixed width (instead let their width be determined by their content, you can use the overflow-hidden and float method)
The bad thing about this method is you have to adhere to having overflow hidden on your divs and also you have to arrange your divs in a backwards way (see below)
DEMO
HTML
<div class='container'>
<div class='third-box'>Third</div>
<div class='first-second'>
<div class='first-box'>First</div>
<div class='second-box'>Second</div>
</div>
</div>
CSS
.container {
width: 400px;
}
.first-second {
overflow: hidden;
}
.first-box {
float: left;
background-color: coral;
}
.second-box {
overflow: hidden;
background-color: aquamarine;
}
.third-box {
float: right;
background-color: salmon;
}
I used this to set a flexible width for the items to the side. Used it in a listed item to get a progress bar with 2 buttons on the side.
ul {
display: table;
width: 100%;
}
ul > li {
display: table-cell;
}
ul > li:nth-child(2) {
min-width: 100%;
}