CSS Flexbox - Two columns with 'content wrap under' conundrum - css

Hugely frustrated that I've had to admit defeat on this one, just when I thought I had flexbox grokked! Apologies for the strange description but the issue is easier shown that described.
What I need:
All four labelled divs (title, left, right, under-left) must all reside within a common container. Left and Right cols take up half the space each, but UNDER-LEFT must tuck under LEFT regardless of the height of RIGHT.
What I've got: At present as I increase the height of RIGHT it is pushing UNDER-LEFT down with it :(
My Code So Far
<style>
#container {
display: flex;
flex-direction: row;
flex-wrap: wrap;
width: 580px;
background-color: rgb(240, 240, 240);
}
#heading {
display: inline-block;
height: 100px;
width: 100%;
background-color: rgb(200, 200, 200);
}
#left {
background-color: red;
height: 250px;
flex: 0 0 50%;
}
#right {
background-color: lightblue;
flex: 0 0 50%;
}
#under-left {
background-color: lightgreen;
flex: 0 0 50%;
}
</style>
<body>
<div id="container">
<div id="heading">
<p>title</p>
</div>
<div id="left">
<p>LEFT height 250, basis 50%</p>
</div>
<div id="right">
<p>RIGHT, basis 50%</p>
</div>
<div id="under-left">
<p>UNDER-LEFT</p>
</div>
</div>
</body>
What I've tried:
To be honest I'm at a total loss. I have tried floating elements but of course flex ignores floats. I don't know what else to try, it's not laziness as it took me about 25 minutes to create this post. I have searched for other answers on SO (such as CSS Flex Box Layout: full-width row and columns) but none feature the wrap-under element issue.
Please be kind!

Do like this to use flexbox (needed a markup change)
#container {
display: flex;
flex-direction: row;
flex-wrap: wrap;
width: 580px;
background-color: rgb(240, 240, 240);
}
#heading {
display: inline-block;
height: 100px;
width: 100%;
background-color: rgb(200, 200, 200);
}
#left {
flex: 1;
}
#right {
background-color: lightblue;
flex: 1;
padding: 20px;
}
#left-top {
background-color: red;
padding: 20px;
}
#left-bottom {
background-color: lightgreen;
padding: 20px;
}
<div id="container">
<div id="heading">
<p>title</p>
</div>
<div id="left">
<div id="left-top">
LEFT height 250, basis 50%
</div>
<div id="left-bottom">
UNDER-LEFT
</div>
</div>
<div id="right">
RIGHT, basis 50%
</div>
</div>
Update based on comment not being able to wrap the left div's
Note, this might be doable with flexbox and non wrapped divs, though I need to know how that layout should look like.
Here is a floated version, which can use flexbox on smaller screens using #media query to reorder the elements visually.
To make the under-left always stay under the left regardless of the right's height, you need to make them wider than the right (here 1px), have the left one's floated left, the right floated right
Sample, right lower
#container {
width: 580px;
background-color: rgb(240, 240, 240);
}
#heading {
display: inline-block;
height: 100px;
width: 100%;
background-color: rgb(200, 200, 200);
}
#left {
background-color: red;
height: 150px;
float: left;
width: calc(50% + 1px);
}
#right {
background-color: lightblue;
height: 100px;
float: right;
width: calc(50% - 1px);
}
#under-left {
background-color: lightgreen;
float: left;
width: calc(50% + 1px);
}
<div id="container">
<div id="heading">
<p>title</p>
</div>
<div id="right">
<p>RIGHT, basis 50%</p>
</div>
<div id="left">
<p>LEFT height 250, basis 50%</p>
</div>
<div id="under-left">
<p>UNDER-LEFT</p>
</div>
</div>
Sample, right higher
#container {
width: 580px;
background-color: rgb(240, 240, 240);
}
#heading {
display: inline-block;
height: 100px;
width: 100%;
background-color: rgb(200, 200, 200);
}
#left {
background-color: red;
height: 150px;
float: left;
width: calc(50% + 1px);
}
#right {
background-color: lightblue;
height: 250px;
float: right;
width: calc(50% - 1px);
}
#under-left {
background-color: lightgreen;
float: left;
width: calc(50% + 1px);
}
<div id="container">
<div id="heading">
<p>title</p>
</div>
<div id="right">
<p>RIGHT, basis 50%</p>
</div>
<div id="left">
<p>LEFT height 250, basis 50%</p>
</div>
<div id="under-left">
<p>UNDER-LEFT</p>
</div>
</div>
Update 2 based on yet another comment
Here is a floated version combined with flexbox and #media query, that will make them in the right order/size on smaller screens
#container {
width: 580px;
background-color: rgb(240, 240, 240);
}
#heading {
display: inline-block;
height: 100px;
width: 100%;
background-color: rgb(200, 200, 200);
}
#left {
background-color: red;
height: 150px;
float: left;
width: calc(50% + 1px);
}
#right {
background-color: lightblue;
height: 200px;
float: right;
width: calc(50% - 1px);
}
#under-left {
background-color: lightgreen;
float: left;
width: calc(50% + 1px);
}
#media screen and (max-width: 600px) {
#container {
display: flex;
flex-direction: column;
}
#left,
#under-left,
#right {
float: none;
width: auto;
}
#right {
order: 1;
}
}
<div id="container">
<div id="heading">
<p>title</p>
</div>
<div id="right">
<p>RIGHT, basis 50%</p>
</div>
<div id="left">
<p>LEFT height 250, basis 50%</p>
</div>
<div id="under-left">
<p>UNDER-LEFT</p>
</div>
</div>

Related

Dealing with cyclic dependencies of percentage sized boxes css (specifically how to get a max-height)

First shortly, this is a follow up question to Problem with max-height not working in css grid element where I misunderstood my problem and I would have had to completely rewrite it, so I'm starting a new one, I hope that is fine.
My goal in one sentence is, to have an overflow: auto in a box, which has its height governed by its content, but its max-height governed by its parent. A static representation would be:
#ctlsmall {
height: 50px;
}
#ctlbig {
height: 210px;
}
#contentsmall {
height: 50px;
}
#contentbig {
height: 350px;
}
.content {
background-image: linear-gradient(30deg, #005500 0%, #9922ee 100%);
width: 120px;
}
.overflowctl {
overflow-y: auto;
overflow-x: hidden;
}
.frame {
height: auto;
max-height: calc( 100% - 40px );
width: 120px;
border-radius: 15px;
padding: 20px;
background: #221100;
}
.canvas {
display: inline-block;
height: 250px;
width: 200px;
margin-right: 50px;
background: #ddccaa;
vertical-align: top;
}
<div class='canvas'>
<div class='frame'>
<div id='ctlbig' class='overflowctl'>
<div id='contentbig' class='content'>
</div>
</div>
</div>
</div>
<div class='canvas'>
<div class='frame'>
<div id='ctlsmall' class='overflowctl'>
<div id='contentsmall' class='content'>
</div>
</div>
</div>
</div>
The problems begin, when I don't want to use fix heights for my .overflowctl, because both, .content and .canvas have unknown sizes. (.content in reality is an iframe, and .canvas depends on the window size). My naive approach was to just use height: auto for .overflowctl and .frame, as usually the height should be governed by their content, and at the same time a percentage based max-height, as their max-height is set by the parents. This is logical in a natural understanding of those properties, but seemingly it does not work, because in css the combination between a parent-child combination, where the parent size relies on the child and vice versa is problematic and while solving this, the max-properties seem to be changed... It is described here and #onkar-ruikar who showed this to me as an answer to my previous question gave some explanation for it. I prepared a jsfiddle to illustrate the problem, with the adapted example from above:
.overflowctl {
height: auto;
max-height: 100%;
}
#contentsmall {
height: 50px;
}
#contentbig {
height: 350px;
}
.content {
background-image: linear-gradient(30deg, #005500 0%, #9922ee 100%);
width: 120px;
}
.overflowctl {
overflow-y: auto;
overflow-x: hidden;
}
.frame {
height: auto;
max-height: calc( 100% - 40px );
width: 120px;
border-radius: 15px;
padding: 20px;
background: #221100;
}
.canvas {
display: inline-block;
height: 250px;
width: 200px;
margin-right: 50px;
background: #ddccaa;
vertical-align: top;
}
<div class='canvas'>
<div class='frame'>
<div id='ctlbig' class='overflowctl'>
<div id='contentbig' class='content'>
</div>
</div>
</div>
</div>
<div class='canvas'>
<div class='frame'>
<div id='ctlsmall' class='overflowctl'>
<div id='contentsmall' class='content'>
</div>
</div>
</div>
</div>
In my previous question, I somehow had an example where height and max-height worked differently, but I think the above better shows what I actually want, and the problem boils down to the same thing. The ugly solution would be, to get rid of the .overflowctl, but then my nice .frame (in reality the colors are better...^^) doesn't work anymore with the padding and also the combination of scroll bar and border-radius. I will add it at the end, just to show it, anyways. I would be happy about any hints how I can achieve my goal! :)
#contentsmall {
height: 50px;
}
#contentbig {
height: 350px;
}
.content {
background-image: linear-gradient(30deg, #005500 0%, #9922ee 100%);
width: 120px;
}
.frame {
overflow-y: auto;
overflow-x: hidden;
}
.frame {
height: auto;
max-height: calc( 100% - 40px );
width: 120px;
border-radius: 15px;
padding: 20px;
background: #221100;
}
.canvas {
display: inline-block;
height: 250px;
width: 200px;
margin-right: 50px;
background: #ddccaa;
vertical-align: top;
}
<div class='canvas'>
<div class='frame'>
<div id='contentbig' class='content'>
</div>
</div>
</div>
<div class='canvas'>
<div class='frame'>
<div id='contentsmall' class='content'>
</div>
</div>
</div>
Simply add this
.frame {
display:grid;
grid-template-rows:1fr;
}
This will give a reference for your percentage height.
Full code
.overflowctl {
height: auto;
max-height: 100%;
}
#contentsmall {
height: 50px;
}
#contentbig {
height: 350px;
}
.content {
background-image: linear-gradient(30deg, #005500 0%, #9922ee 100%);
width: 120px;
}
.overflowctl {
overflow-y: auto;
overflow-x: hidden;
}
.frame {
height: auto;
max-height: calc( 100% - 40px );
width: 120px;
border-radius: 15px;
padding: 20px;
background: #221100;
display:grid;
grid-template-rows:1fr;
}
.canvas {
display: inline-block;
height: 250px;
width: 200px;
margin-right: 50px;
background: #ddccaa;
vertical-align: top;
}
<div class='canvas'>
<div class='frame'>
<div id='ctlbig' class='overflowctl'>
<div id='contentbig' class='content'>
</div>
</div>
</div>
</div>
<div class='canvas'>
<div class='frame'>
<div id='ctlsmall' class='overflowctl'>
<div id='contentsmall' class='content'>
</div>
</div>
</div>
</div>
CSS grid and Flexbox have some special behavior related to percentage height.
Related questions to get more details:
Why does `height: 100%` value 'work' for child tags of grid-items?
Percentage 'min-height' works only when element has indirect parent with 'display: flex'

CSS float right and then up?

I am trying to figure out if there's some way to accomplish a float (left or right) such that every new start from the border begins under the element above it. These are three elements:
#red-block {
background-color: red;
width: 70vw;
height: 15vh;
}
#blue-block {
background-color: blue;
width: 20vw;
height: 45vh;
}
#green-block {
background-color: green;
width: 60vw;
height: 15vh;
}
div {
float: right;
}
<div id="red-block">
red-block
</div>
<div id="blue-block">
blue-block
</div>
<div id="green-block">
green-block
</div>
In this case, the green block begins at the right end after the vertical end of the blue block. Is there some way to get it to begin at the bottom of the red block instead?
Thanks.
try flex.
HTML:
<div id="main-block">
<div id="blue-block">
</div>
<div>
<div id="red-block">
</div>
<div id="green-block">
</div>
</div>
</div>
CSS:
#main-block{
display: flex;
justify-content: flex-end;
}
#red-block {
background-color: red;
width: 70vw;
height: 15vh;
}
#second-block{
height: 30vh;
width: 70vh;
}
#blue-block {
background-color: blue;
width: 20vw;
height: 45vh;
}
#green-block {
background-color: green;
width: 60vw;
height: 15vh;
}

Make full-width without setting `width` [duplicate]

This question already has answers here:
Setting div width to 100% minus certain amount of px
(5 answers)
Expand a div to fill the remaining width
(21 answers)
Closed 6 years ago.
I will simulate what i need to achieve.
for example, i want that #2 took the whole space, remaining of 100% - 180px.. how to achieve that?
p.s. seems flexbox is more supported over devices than calc - http://css3clickchart.com/#flexbox
You can use flexbox model as shown below. Adding flex: auto; will allow the right content to use remaining width.
* {
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
}
#parent {
display: flex;
height: 100%;
}
#left {
width: 180px;
background-color: hotpink;
}
#right {
flex: auto;
background-color: dodgerblue;
}
<div id="parent">
<div id="left"></div>
<div id="right"></div>
</div>
Use css calc
Here with a example.. This might help:
.class {
width: -moz-calc(100% - 100px);
width: -webkit-calc(100% - 100px);
width: calc(100% - 100px);
}​
You can use float: left and overflow: hidden.
aside {
float: left;
width: 30%;
background: beige;
}
article {
overflow: hidden;
background: brown;
color: white;
}
<aside>
sidebar
</aside>
<article>
content
</article>
There are many ways to do this. One simple way is below.
1st way: Simple inline-block
.container {
width: 100%;
height: 600px;
background-color: #f2f2f2;
}
.sidebar {
background-color: red;
width: 180px;
height: 600px;
float: left;
}
.main-content {
display: inline-block;
background-color: green;
}
<div class="container">
<div class="main-content">Main Content</div>
<div class="sidebar">Sidebar</div>
</div>
Fair warning though: In this case the .main-content will only take the space it needs, and will not actually be full width. So If you want to set background to it, you should actually set the backround to .container.
2nd way: Use calc for width
.container {
width: 100%;
height: 600px;
background-color: #f2f2f2;
position: relative;
}
.sidebar {
background-color: red;
width: 180px;
height: 600px;
float: left;
}
.main-content {
float: right;
background-color: green;
width: calc(100% - 180px);
height: 600px;
}
<div class="container">
<div class="main-content">Main Content</div>
<div class="sidebar">Sidebar</div>
</div>
3rd way: use Flex
.container {
width: 100%;
height: 600px;
background-color: #f2f2f2;
display: flex;
}
.sidebar {
background-color: red;
width: 180px;
height: 600px;
}
.main-content {
background-color: green;
flex: auto;
}
<div class="container">
<div class="sidebar">Sidebar</div>
<div class="main-content">Main Content</div>
</div>
Flexbox is probably the nicest solution, but saidly old browsers don't support it.
4th way of doing this is the oldfasioned way with faking tables:
.container {
width: 100%;
height: 600px;
background-color: #f2f2f2;
display: table;
}
.sidebar {
background-color: red;
width: 180px;
display: table-cell;
}
.main-content {
display: table-cell;
background-color: green;
}
<div class="container">
<div class="sidebar">Sidebar</div>
<div class="main-content">Main Content</div>
</div>

Vertical divider line in a scrollable flexbox div element

I have a vertically central adaptable scrollable flexbox element, which itself should have two columns (I solved this with two child-divs). The central flexbox should have a frame and a central divider line.
I can't get the central divider line to run all the way to the bottom of the scrollable flexbox. I tried it with a third child div element but the line only appears for the vertical extent of the flexbox.
How can I make two columns in a scrollable flexbox with a frame and central divider line running all the way to the bottom?
Thank you for your help.
Here is the example:
https://jsfiddle.net/soliman/0d0tn22x/2/
<body>
<div class="wrapper">
<div class="header">
<h1>Header</h1>
</div>
<div class="content">
<div class="leftContent"> Column 1
With a lot of lines.
</div>
<div class="divider"></div>
<div class="rightContent"> Column 2
With fewer lines
</div>
</div>
<div class="footer">
Footer
</div>
</div>
</body>
CSS:
html,
body {
height: 100%;
margin: 0;
padding: 0;
background: black;
color: red;
}
.wrapper {
display: flex;
/* use the flex model */
height: 100%;
flex-direction: column;
}
.header {
margin: 1em 1em 0 1em;
}
.content {
flex: 1 1 auto;
display: flex;
overflow-y: auto;
position: relative;
min-height: 100px;
margin: 0 1em 0 1em;
border: 6px double red;
}
.content > div {
width: 50%;
padding: 3%;
}
.content > div:first-child {
margin-right: 10px;
}
.footer {
margin: 0 1em 1em 1em;
}
.divider {
position: absolute;
left: 50%;
top: 0%;
bottom: 0%;
border-left: 6px double red;
}
Try this mixed flexbox and CSS table layout. You can set the content area as a table, and the three columns as table cells, so they always be equal height.
There is one issue with the approach is - it only works properly if the content is taller than the container, otherwise the vertical line will stop in the middle. See the other approach at the bottom.
jsFiddle
html,
body {
height: 100%;
margin: 0;
}
.wrapper {
height: 100%;
display: flex;
flex-direction: column;
}
.content {
flex: 1;
overflow-y: auto;
min-height: 100px;
border: 1px solid;
}
.wrapContent {
display: table;
width: 100%;
}
.wrapContent > div {
display: table-cell;
}
.leftContent,
.rightContent {
width: 50%;
}
.divider {
border-left: 1px solid;
}
<div class="wrapper">
<div class="header">
<h1>Header</h1>
</div>
<div class="content">
<div class="wrapContent">
<div class="leftContent">
<div style="height:500px;">Left</div>
</div>
<div class="divider"></div>
<div class="rightContent">
<div style="height:auto;">Right</div>
</div>
</div>
</div>
<div class="footer">
<p>Footer</p>
</div>
</div>
Another way would be using background image for the vertical line, set that to the center of the content container, with repeat-y, the image can be just a square dot. It works well even if the content is shorter than the container.
jsFiddle
html,
body {
height: 100%;
margin: 0;
}
.wrapper {
height: 100%;
display: flex;
flex-direction: column;
}
.content {
flex: 1;
display: flex;
overflow-y: auto;
min-height: 100px;
border: 1px solid;
background: url("http://i.imgur.com/oyQ4xsL.png") center top repeat-y;
background-size: 1px;
}
.leftContent,
.rightContent {
width: 50%;
}
<div class="wrapper">
<div class="header">
<h1>Header</h1>
</div>
<div class="content">
<div class="leftContent">
<div style="height:500px;">left</div>
</div>
<div class="rightContent">
<div style="height:auto;">right</div>
</div>
</div>
<div class="footer">
<p>Footer</p>
</div>
</div>

Fixed DIV next to 5 fluid DIVs

I require a fairly complex layout. I've been trying for a few hours to figure this out but still no luck. I require a fixed div next to 5 fluid DIVs.
All the fluid DIVs need to be different percentages, but all 6 DIVs combined (1 fixed + 5 fluid) must equal to the width of the parent DIV. The height of the parent div will be fixed.
Here's what I want: http://i.imgur.com/u0L6hrz.png
But here's what I have right now: http://jsfiddle.net/mnNzR/
I need to eliminate the whitespace so all the DIVs combined fill the whole box. I'd prefer not to use JS, if possible. Any help will be appreciated, thanks.
<div class="parent">
<div class="s1"></div>
<div class="s2"></div>
<div class="s3"></div>
<div class="s4"></div>
<div class="s5"></div>
<div class="s6"></div>
</div>
You can achieve your layout with CSS by wrapping the fluid divs in a container with margin-left:150px;.
Then you must claculate so the sum of fluid divs width equals 100% :
FIDDLE
HTML :
<div class="parent">
<div class="s1"></div>
<div class="fluid_wrap">
<div class="s2"></div>
<div class="s3"></div>
<div class="s4"></div>
<div class="s5"></div>
<div class="s6"></div>
</div>
</div>
CSS :
.parent {
display:block;
width: 100%;
height: 150px;
background-color: white;
box-shadow: 0 0 5px 5px rgba(215, 44, 44, 0.9);
}
.s1 {
width: 150px;
height: 100%;
display: block;
background-color: #00baff;
float: left;
}
.fluid_wrap {
margin-left:150px;
height:100%;
}
.s2 {
width: 17.5%;
height: 100%;
display: block;
background-color: #0090c5;
float: left;
}
.s3 {
width:12.5%;
height: 100%;
display: block;
background-color: #006b93;
float: left;
}
.s4 {
width: 21%;
height: 100%;
display: block;
background-color: #004660;
float: left;
}
.s5 {
width: 21%;
height: 100%;
display: block;
background-color: #002939;
float: left;
}
.s6 {
width: 28%;
height: 100%;
display: block;
background-color: #001720;
float: left;
}

Resources