FlexBox - How to display one column 100% and two others 50% - css

Looking at the bellow code, I'm trying to have the 3 child columns as follow:
The first column should be 100% wide and above two other columns.
Two other columns should be bellow the first column and each 50% wide.
Like this:
.flex-container {
width: 80%;
min-height: 300px;
margin: 0 auto;
display: flex;
}
.flex-container .column {
padding: 10px;
background: #dbdfe5;
flex: 1;
}
.column.first {
background: blueviolet;
}
.column.third {
background: #b4bac0;
}
<div class="flex-container">
<div class="column first">Column 1</div>
<div class="column second">Column 2</div>
<div class="column third">Column 3</div>
</div>
But whatever I try it doesn't work that way.
Is it possible or I'm trying an impossible layout?

Flexbox version
You can use flex-wrap: wrap on the container to make children that overflow go below, and use flex-basis: 100% on the first child and flex-basis: 50% on the 2 others.
I have also added box-sizing: border-box on the children, to avoid border or padding count in the percentage.
.flex-container {
width: 80%;
min-height: 300px;
margin: 0 auto;
display: flex;
flex-wrap: wrap;
}
.flex-container .column {
padding: 10px;
background: #dbdfe5;
box-sizing: border-box;
}
.column.first {
background: blueviolet;
flex-basis: 100%;
}
.column.second {
flex-basis: 50%;
}
.column.third {
background: #b4bac0;
flex-basis: 50%;
}
<div class="flex-container">
<div class="column first">Column 1</div>
<div class="column second">Column 2</div>
<div class="column third">Column 3</div>
</div>
Grid version
The grid version is even simpler, you only need display: grid on the container, and grid-column: 1 / 3 on the first child.
.flex-container {
width: 80%;
min-height: 300px;
margin: 0 auto;
display: grid;
}
.flex-container .column {
padding: 10px;
background: #dbdfe5;
}
.column.first {
background: blueviolet;
grid-column: 1 / 3;
}
.column.third {
background: #b4bac0;
}
<div class="flex-container">
<div class="column first">Column 1</div>
<div class="column second">Column 2</div>
<div class="column third">Column 3</div>
</div>

Related

CSS Flex item spanning two rows without fixed height

I am trying to create a flex container layout whereby one of the flex items should span two rows. See image below for a better explanation:
Here is my markup:
<div class="container">
<div class="item item-1">ITEM 1</div>
<div class="item item-2">ITEM 2</div>
<div class="item item-3">ITEM 3</div>
</div>
I cannot seem to achieve this, I have tried using flex-wrap and different combinations of the flex property.
I was able to achieve this by putting ITEM 1 & ITEM 2 in a separate <div>, but this presents a problem on a smaller screen, whereby ITEM 3 needs to appear BETWEEN ITEM 1 & ITEM 2. So I would rather keep the markup as is and use the order property to move things around as necessary.
You can use display: contents on your extra div to achieve what you want:
* {
box-sizing: border-box;
}
.container {
display: flex;
width: 100%;
}
.holder {
width: 67%;
}
.item {
border: 1px solid black;
}
.item-1 {
margin-bottom: 40px;
}
.item-3 {
width: 33%;
}
#media screen and (max-width: 700px) {
.container {
flex-direction: column;
}
.item {
margin-bottom: 20px;
}
.item-1 {
order: 1;
}
.item-2 {
order: 3;
}
.item-3 {
order: 2;
width: 100%;
}
.holder {
width: 100%;
display: contents;
}
}
<div class="container">
<div class="holder">
<div class="item item-1">ITEM 1</div>
<div class="item item-2">ITEM 2</div>
</div>
<div class="item item-3">ITEM 3</div>
</div>
You can't achieve it using flexbox. Instead, you should have two parents which are better.
Use Css-grid. Actually, css-grid is the best option in this case.
Flex-Box
* {
color: #fff;
}
.flex {
display: flex;
justify-content: center;
align-items: center;
}
.child {
border-radius: 10px;
}
.container {
display: flex;
width: 500px;
height: 200px;
border: 1px solid #ff0000;
}
.container .first-item {
flex-direction: column;
justify-content: space-between;
align-items: start;
width: 50%;
height: 100%;
margin-right: 10px;
}
.first-item .child {
width: 100%;
height: 50%;
background-color: blue;
}
.first-item .child:first-child {
margin-bottom: 10px;
}
.container .second-item {
width: 50%;
height: 100%;
}
.second-item .child {
width: 100%;
height: 100%;
background-color: blue;
}
<div class="container">
<div class="first-item flex">
<div class="child flex">Item 1</div>
<div class="child flex">Item 2</div>
</div>
<div class="second-item flex">
<div class="child flex">Item 3</div>
</div>
</div>
Grid
.flex {
display: flex;
justify-content: center;
align-items: center;
}
.child {
background-color: blue;
border-radius: 10px;
}
.container {
display: grid;
grid-template-columns: 1fr 10px 1fr;
grid-template-rows: 1fr 10px 1fr;
grid-template-areas: "c1 . c3"
". . c3"
"c2 . c3";
width: 500px;
height: 300px;
border: 1px solid red;
}
.container .child {
border: 1px solid blue;
}
.child1 {
grid-area: c1;
}
.child2 {
grid-area: c2;
}
.child3 {
grid-area: c3;
}
<div class="container">
<div class="child child1 flex">Item 1</div>
<div class="child child3 flex">Item 3</div>
<div class="child child2 flex">Item 2</div>
</div>
i dont know if its a good solution but
put two item3 codes one in the individual div (item1&2) and one outside then put the one in the div to display none in non-small screens and switch between them with mediaquery
#media (max-width: 40rem) {
.item3 {
display: none;
}
.mobile-item3{
display: block;
}
}

flexbox makes content disappear

I'm playing around with flexbox to get the hang of it but I am running into some issues. My goal is to have the window separated by four background colors where the first is just a header row and then the rest of the page is filled by 3 columns each a different background color. But for some reason if I write display: flex it doesn't show anything. Can someone explain to me how to get this desired effect?
.container {
width: 100%;
height: 100%;
}
.header {
height: 150px;
background-color: red;
}
.col-container {
widows: auto;
height: auto;
display: flex;
flex-direction: row;
}
.col {
flex: 1;
}
.col-container:nth-child(1) {
background: green;
}
.col-container:nth-child(2) {
background: blue;
}
.col-container:nth-child(3) {
background: yellow;
}
<body>
<div class="container">
<div class="header"></div>
<div class="col-container">
<div class="col"></div>
<div class="col"></div>
<div class="col"></div>
</div>
</div>
</body>
Here is a working example:
.container {
width: 100%;
height: 100%;
}
.header {
height: 150px;
background-color: red;
}
.col-container {
widows: auto;
height: auto;
display: flex;
flex-direction: row;
}
.col-1 {
flex: 1 1 33.333%;
background-color: green;
}
.col-2 {
flex: 1 1 33.333%;
background-color: blue;
}
.col-3 {
flex: 1 1 33.333%;
background-color: yellow;
}
<body>
<div class="container">
<div class="header"></div>
<div class="col-container">
<div class="col-1">ts</div>
<div class="col-2">dtd</div>
<div class="col-3">dt</div>
</div>
</div>
</body>
Here's what you needed to fix:
Set flex-direction to row. You most likely want the columns next to each other.
Add the classes to your HTML for the col-1, col-2 and col-3.
You need content in those col classes, or you won't see anything anyway.
I set a flex-basis (the third parameter in the flex shorthand) to 33.333%. You don't necessarily need this, but it's nice to see how much space a particular element will fill or change it.
EDIT For the comments:
body {
margin: 0;
padding: 0;
}
.container {
width: 100%;
height: 100%;
}
.header {
height: 150px;
background-color: red;
}
.col-container {
widows: auto;
height: auto;
display: flex;
flex-direction: row;
height: calc(100vh - 150px);
}
.col-1 {
flex: 1 1 33.333%;
background-color: green;
}
.col-2 {
flex: 1 1 33.3333%;
background-color: blue;
}
.col-3 {
flex: 1 1 33.3333%;
background-color: yellow;
}
<body>
<div class="container">
<div class="header"></div>
<div class="col-container">
<div class="col-1"></div>
<div class="col-2"></div>
<div class="col-3"></div>
</div>
</div>
</body>
Basically, you need to give the col-container a height. To achieve this, I used vh units in the calc statement. It subtracts your header height from the viewport height and gives the remainder. This also removes the necessity for filler content.

responsive separator between divs in flex row container

I have a flex container, and some divs inside of it. Each div has some content inside of it, that set the width of this div. between each of the divs, I want to put a responsive separator-div.
I've tried to give the max-width property for each of the responsive class in the code below, but it not rendering.
I cannot give the inner-wrapper's a fixed width, because it depends on the width of the inner{#}.
<div class='main'>
<div class='item-wrapper'>
<div class='inner1'></div>
<div class='responsive'></div>
</div>
<div class='item-wrapper'>
<div class='inner2'></div>
<div class='responsive'></div>
</div>
<div class='item-wrapper'>
<div class='inner3'></div>
<div class='responsive'></div>
</div>
</div>
.main{
width:100%;
display:flex;
height:40px;
background:yellow;
}
.responsive{
max-width:200px;
}
.item-wrapper{
display:flex;
height:100%;
background:green;
}
to summarize, i expect:
div1 -------------- div2 --------------- div3
such that only the width of the '------' will increase/decrease if i resizing my screen
You can do it like this by adding a rule to your flexbox container:
myContainer{
//other properties
justify-content:space-between;
}
You do need that much of markup
example
.main {
width: 100%;
display: flex;
height: 40px;
background: yellow;
justify-content: space-between;
/* new */
}
.responsive {
flex: 1;
/* new */
max-width: 200px;
margin: auto;
/* new */
border-top: dotted;
/* new */
}
.main>div:not([class]) {
background: green;
display: flex;
align-items: center;
/* new */
}
<div class='main'>
<div>inner 1</div>
<div class='responsive'></div>
<div>inner 2</div>
<div class='responsive'></div>
<div>inner 3</div>
</div>
If you have a only 3 elements, then 2 pseudos can become the seperator via order:
.main {
width: 100%;
display: flex;
height: 40px;
background: yellow;
justify-content: space-between;
}
.main::before,
.main::after {
content: '';
flex: 1;
max-width: 200px;
margin: auto;
border-top: dotted;
}
.main>div:not([class]) {
background: green;
display: flex;
align-items: center;
}
.main>div:first-child {
order: -1
}
.main>div:last-child {
order: 1
}
<div class='main'>
<div>inner 1</div>
<div>inner 2</div>
<div>inner 3</div>
</div>
more about flex : https://css-tricks.com/snippets/css/a-guide-to-flexbox/

Flex-Basis for Wrapping Columns

I have a pretty basic grid setup in flex, but I recently came across an oversight I made.
I have columns that have a margin-right: 3em and flex-basis: calc(33% - 3em).
My problem is that the 4th and 5th of these don't line up until there is a full "row" of 3.
Any insights as to why this is happening? I imagine I may be over-complicating things as per usual.
section {
width: 1170px;
margin: 0 auto;
padding: 4em;
background-color: lightgray;
}
.flex {
display: flex;
}
.wrap {
flex-wrap: wrap;
}
.column {
flex: 1;
flex-direction: column;
margin-right: 3em;
}
.column:last-child {
margin-right: 0;
}
.three {
max-width: 33%;
flex-basis: calc(33% - 3em);
}
.three:nth-child(3n) {
margin-right: 0;
}
.debug {
margin-bottom: 3em;
background-color: #ebf5fb;
height: 3em;
border: 1px dashed red;
text-align: center;
}
<section>
<div class="flex wrap">
<div class="column three debug">3 Columns</div>
<div class="column three debug">3 Columns</div>
<div class="column three debug">3 Columns</div>
<div class="column three debug">3 Columns</div>
<div class="column three debug">3 Columns</div>
</div>
</section>
Codepen
Since you use flex: 1, it will make the element take all available space, what's left after the flex-basis been retracted.
What stop the 2 last items from filling the entire row is the max-width, and since that its value is wider than the flex-basis, they will expand to it.
Either remove flex: 1 from column, or use the same calc for max-width as used for flex-basis
Stack snippet
section {
width: 1170px;
margin: 0 auto;
padding: 4em;
background-color: lightgray;
}
.flex {
display: flex;
}
.wrap {
flex-wrap: wrap;
}
.column {
flex: 1;
flex-direction: column;
margin-right: 3em;
}
.column:last-child {
margin-right: 0;
}
.three {
max-width: calc(33% - 3em); /* changed */
flex-basis: calc(33% - 3em);
}
.three:nth-child(3n) {
margin-right: 0;
}
.debug {
margin-bottom: 3em;
background-color: #ebf5fb;
height: 3em;
border: 1px dashed red;
text-align: center;
}
<section>
<div class="flex wrap">
<div class="column three debug">3 Columns</div>
<div class="column three debug">3 Columns</div>
<div class="column three debug">3 Columns</div>
<div class="column three debug">3 Columns</div>
<div class="column three debug">3 Columns</div>
</div>
</section>
Updated based on a comment
If to also make the items spread equally inside its parent, one need to divide the sum of the actual margin/gutter/gap space with the amount of items.
So in this case it would be (2 gaps * 3em) / 3 items = 2em
Also, one need the closest possible to a 1/3, which can be either e.g. 33.33333% or (100% / 3)
Stack snippet
section {
width: 1170px;
margin: 0 auto;
padding: 4em;
background-color: lightgray;
}
.flex {
display: flex;
}
.wrap {
flex-wrap: wrap;
}
.column {
flex: 1;
flex-direction: column;
margin-right: 3em;
}
.column:last-child {
margin-right: 0;
}
.three {
max-width: calc(33.33333% - 2em); /* changed */
flex-basis: calc(33.33333% - 2em); /* changed */
}
.three:nth-child(3n) {
margin-right: 0;
}
.debug {
margin-bottom: 3em;
background-color: #ebf5fb;
height: 3em;
border: 1px dashed red;
box-sizing: border-box; /* added */
text-align: center;
}
.debug2 {
border: 1px dashed red; /* added */
box-sizing: border-box; /* added */
}
<section>
<div class="flex wrap debug2">
<div class="column three debug">3 Columns</div>
<div class="column three debug">3 Columns</div>
<div class="column three debug">3 Columns</div>
<div class="column three debug">3 Columns</div>
<div class="column three debug">3 Columns</div>
</div>
</section>
Thank you LGson for pointing me in the right direction.
My math was incorrect.
I needed to take 100% - the total margins in the row.
Instead of flex-basis: calc(33% - 3em); it needed to be flex-basis: calc( (100% - 6em) / 3);
Updated Snippet
*,
::before,
::after {
background-repeat: no-repeat; /* 1 */
box-sizing: inherit; /* 2 */
}
html {
box-sizing: border-box; /* 1 */
cursor: default; /* 2 */
-ms-text-size-adjust: 100%; /* 3 */
-webkit-text-size-adjust: 100%; /* 3 */
}
section {
width: 1170px;
margin: 0 auto;
padding: 4em;
background-color: lightgray;
}
.flex {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
}
.wrap {
-ms-flex-wrap: wrap;
flex-wrap: wrap;
}
.column {
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
-webkit-box-flex: 1;
-ms-flex: 1;
flex: 1;
margin-right: 3em;
/*overflow: hidden;*/
}
.column:last-child {
margin-right: 0;
}
.three {
max-width: calc( (100% - 6em) / 3);
-ms-flex-preferred-size: calc( (100% - 6em) / 3);
flex-basis: calc( (100% - 6em) / 3);
}
.three:nth-child(3n) {
margin-right: 0;
}
.debug {
background-color: #EBF5FB;
margin-top: 1em;
padding: .75em;
text-align: center;
border: 1px dashed #E8DAEF;
}
<section>
<h2>Layout for 2 Dimensions</h2>
<h3>Specific Widths (or not)</h3>
<div class="flex wrap">
<div class="column three debug">1/3 Columns</div>
<div class="column three debug">1/3 Columns</div>
<div class="column three debug">1/3 Columns</div>
<div class="column three debug">1/3 Columns</div>
<div class="column three debug">1/3 Columns</div>
</div>
</section>

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>

Resources