Complex grid with bootstrap - css

I would like to make a design like this in CSS, but without the blank below blue div and with a margin between each.
I tried different things and impossible to do that, my divs always go to a new line...
Thank you very much !
Here is my code (simplified)
.row > div { border: 1px solid black;}
.A {height:420px;}
.D {height:200px;}
.E {height:200px;}
.B {height:300px;}
.C {height:300px;}
<div class="container">
<div class="row">
<div class="col-md-8 col-lg-6 A">
<div>
A
</div>
</div>
<div class="col-md-12 col-lg-6 B">
<div>
B
</div>
</div>
<div class="col-md-12 col-lg-6 C">
<div>
C
</div>
</div>
<div class="col-md-4 col-lg-3 D">
<div>
D
</div>
</div>
<div class="col-md-4 col-lg-3 E">
<div>
E
</div>
</div>
</div>
</div>

With Flexbox there, no need to use bootstrap or grid!
.topmost-wrapper {
height: 100vh;
width: 65%;
margin: 0 auto;
display: flex;
flex-direction: row;
}
.sub-wrap-1 {
display: flex;
flex-direction: column;
flex: 0.5 1 0;
height: 100%;
margin-right: 0.125rem;
}
.inner-1 {
flex: 0.7 1 0;
background: lightblue;
margin-bottom: 0.0925rem;
border-radius: 0.1825rem;
}
.inner-2 {
flex: 0.3 1 0;
display: flex;
flex-direction: row;
margin-top: 0.0925rem;
}
.in-inner-1 {
flex: 0.7 1 0;
background: lightgreen;
margin-right: 0.0825rem;
border-radius: 0.1825rem;
}
.in-inner-2 {
flex: 0.3 1 0;
background: lightsalmon;
margin-left: 0.0825rem;
border-radius: 0.1825rem;
}
.sub-wrap-2 {
display: flex;
flex-direction: column;
flex: 0.5 1 0;
height: 100%;
margin-left: 0.125rem;
}
.inner-3 {
flex: 0.5 1 0;
background: grey;
margin-bottom: 0.0925rem;
border-radius: 0.25rem;
}
.inner-4 {
flex: 0.5 1 0;
background: #3e3e3e;
margin-top: 0.0925rem;
border-radius: 0.25rem;
}
<div class='topmost-wrapper'>
<div class="sub-wrap-1">
<div class="inner-1"></div>
<div class="inner-2">
<div class="in-inner-1"></div>
<div class="in-inner-2"></div>
</div>
</div>
<div class='sub-wrap-2'>
<div class="inner-3"></div>
<div class="inner-4"></div>
</div>
</div>

Related

Account for gap when calculating flex-basis

I'm trying to use gap to specify gaps between flexed items within my grid system, but running in to a major drawback. It seems that when you're using flex-grow: 0;/flex-shrink: 0; in conjunction with gap and flex-basis values that fill the entire available width (i.e. three columns with flex: 0 0 33.3333%;), the columns overflow their parent container as the gap doesn't account for the fixed width as specified with flex: 0 0 33.3333%.
Similar to box-sizing: border-box;, is there some way to instruct the rendering engine that the gap should be subtracted when determining the width of these columns?
Demonstration:
.row {
display: flex;
gap: 30px;
border: 2px solid red;
}
.col {
flex: 0 0 33.3333%;
background: teal;
border: 2px solid #004D4D;
color: white;
font-weight: 700;
padding: 50px;
text-align: center;
}
:root {
font-family: sans-serif;
}
* {
box-sizing: border-box;
}
<h2>With gap:</h2>
<div class="row">
<div class="col">
1
</div>
<div class="col">
2
</div>
<div class="col">
3
</div>
</div>
<h2>Without gap:</h2>
<div class="row" style="gap:0;">
<div class="col">
1
</div>
<div class="col">
2
</div>
<div class="col">
3
</div>
</div>
Note: I could account for this with a formula like flex-basis: calc($width - ($gap / ($number-of-columns / 2));, but as this is for a reusable grid system, I can't practically account for every possible scenario.
Here is another not very elegant quick way to hack your way forward. Similar to the answer by UPinar it alters the outer flex container. Here with negative margin on the right (this might cause other layout problems!). This "solution" is using shrink 0. Also it works with a wrapping flex.
I agree that this should not be so complicated and hacky. Maybe we are missing something? I am also under the impression that this is not the really the desired box-sizing border-box behavior which I hoped to find in combination with the gap property.
flex and gap should be hack free like: Draw three containers each consuming a third of the width and have some space between em. AFAIK gap works that way with CSS grid and CSS columns.
.flex {
display: flex;
flex-grow: 0;
flex-shrink: 0;
flex-wrap: wrap;
}
.flex.gap {
gap: var(--space-s);
margin-right: calc(-1 * var(--space-s));
}
.col {
flex-basis: 33.3333%;
background: teal;
border: 2px solid #004D4D;
color: white;
font-weight: 700;
padding: 50px;
text-align: center;
}
.flex.gap .col {
flex-basis: calc(33.3333% - var(--space-s));
background: teal;
border: 2px solid #004D4D;
color: white;
font-weight: 700;
padding: 50px;
text-align: center;
}
:root {
font-family: sans-serif;
--space-s: 1rem;
}
* {
box-sizing: border-box;
}
<h2>With gap</h2>
<div class="flex gap">
<div class="col">
1
</div>
<div class="col">
2
</div>
<div class="col">
3
</div>
<div class="col">
4
</div>
<div class="col">
5
</div>
<div class="col">
6
</div>
</div>
<h2>Without gap</h2>
<div class="flex">
<div class="col">
1
</div>
<div class="col">
2
</div>
<div class="col">
3
</div>
<div class="col">
4
</div>
<div class="col">
5
</div>
<div class="col">
6
</div>
</div>
The formula you mentioned works... you can use CSS variables to make a reuseable grid system. A buddy and I came up with this:
.flex{
--columns:3;
--gap:30px;
--gap-count:calc( var(--columns) - 1 );
display:flex;
gap:var(--gap);
}
.flex-child {
flex-basis: calc( calc( 100% / var(--columns) ) - calc( var(--gap) / var(--columns) * var(--gap-count) ) );
}
#media (max-width: 992px) {
.flex{
--columns:2;
}
}
#media (max-width: 767px) {
.flex{
--columns:1;
}
}
So then all you need to change are the variables --columns and --gap
https://codepen.io/pyledigital/pen/mdWmjQb
When you add a padding-right: calc(var(--gap-space) * 2); to parent container. Parent container width will calculte before child containers use 100% which is parent container width. You need to change parent containers width before using its width inside child container.
*,
*::before,
*::after {
box-sizing: border-box;
}
body {
min-height: 100vh;
text-rendering: optimizeSpeed;
line-height: 1.5;
margin: 0;
background-color: bisque;
display: grid;
place-content: center;
}
:root{
--gap-space:30px;
font-family: sans-serif;
}
.row-1 {
display: flex;
gap: var(--gap-space);
border: 2px solid red;
padding-right: calc(var(--gap-space) * 2);
}
.row-1 .col{
background: teal;
border: 2px solid #004D4D;
color: white;
font-weight: 700;
padding: 50px;
text-align: center;
flex: 0 0 calc(100% / 3);
}
.row-2{
display: flex;
flex-direction: row;
border: 2px solid red;
}
.row-2 .col{
background: teal;
border: 2px solid #004D4D;
color: white;
font-weight: 700;
padding: 50px;
text-align: center;
flex: 0 0 calc(100% / 3);
}
<h2>With gap:</h2>
<div class="row-1">
<div class="col">1</div>
<div class="col">2</div>
<div class="col">3</div>
</div>
<h2>Without gap:</h2>
<div class="row-2" style="gap: 0">
<div class="col">1</div>
<div class="col">2</div>
<div class="col">3</div>
</div>
What's wrong with using only width?
.col {
width: 33.3333%;
...
}
.row {
display: flex;
gap: 30px;
border: 2px solid red;
}
.col {
width: 33.3333%;
background: teal;
border: 2px solid #004D4D;
color: white;
font-weight: 700;
padding: 50px;
text-align: center;
}
:root {
font-family: sans-serif;
}
* {
box-sizing: border-box;
}
<h2>With gap:</h2>
<div class="row">
<div class="col">
1
</div>
<div class="col">
2
</div>
<div class="col">
3
</div>
</div>
<h2>Without gap:</h2>
<div class="row" style="gap:0;">
<div class="col">
1
</div>
<div class="col">
2
</div>
<div class="col">
3
</div>
</div>

Flexbox: row with inline-flex + fixed item width (fixing flex-basis bug): not working inside column layout

I want to get a table in CSS with a sticky header (only body scrolls) on Y, and whole table scrolls on X.
According to Michael_B comment on my previous question here there is a flexbox bug and I have to use inline-flex on row + width on cells to make sure my row grows correctly.
This leads me to this result:
html, body {
width: 100%;
min-height: 100vh;
margin: 0;
padding: 0;
}
body {
display: flex;
align-items: center;
justify-content: center;
}
.table {
border: solid black;
width: 60vw;
height: 80vh;
overflow-x: auto;
display: flex;
flex-direction: column;
}
.header {
border: solid cyan;
flex: 0;
}
.body {
flex: 1;
overflow-y: auto;
border: solid yellow;
display: inline-block;
}
.row {
border: solid red;
display: inline-flex;
flex-direction: row;
align-items: center;
}
.cell {
border: solid green;
width: 400px;
height: 50px;
}
<div class="table">
<div class="header">
<div class="row">
<div class="cell">
cell 1
</div>
<div class="cell">
cell 2
</div>
<div class="cell">
cell 3
</div>
</div>
</div>
<div class="body">
<div class="row">
<div class="cell">
cell 1
</div>
<div class="cell">
cell 2
</div>
<div class="cell">
cell 3
</div>
</div>
<div class="row">
<div class="cell">
cell 1
</div>
<div class="cell">
cell 2
</div>
<div class="cell">
cell 3
</div>
</div>
<div class="row">
<div class="cell">
cell 1
</div>
<div class="cell">
cell 2
</div>
<div class="cell">
cell 3
</div>
</div>
</div>
</div>
JsFiddle
As you can see it's not exactly what I want. It seems my rows do not grow according to their content size even with inline-flex, and this happens only when using a flex column layout on the table.
html, body {
width: 100%;
min-height: 100vh;
margin: 0;
padding: 0;
}
body {
display: flex;
align-items: center;
justify-content: center;
}
.table {
border: solid black;
width: 60vw;
height: 80vh;
overflow-x: auto;
}
.header {
border: solid cyan;
flex: 0;
display: inline-block;
height: 50px;
}
.body {
flex: 1;
overflow-y: auto;
border: solid yellow;
display: inline-block;
height: calc(100% - 50px - 16px);
}
.row {
border: solid red;
display: inline-flex;
flex-direction: row;
align-items: center;
}
.cell {
border: solid green;
width: 400px;
height: 50px;
}
By removing flex column, using inline-block and calc computations, I almost get the behavior I want, except I'd like the scrollY scrollbar to always stay visible
<div class="table">
<div class="header">
<div class="row">
<div class="cell">
cell 1
</div>
<div class="cell">
cell 2
</div>
<div class="cell">
cell 3
</div>
</div>
</div>
<div class="body">
<div class="row">
<div class="cell">
cell 1
</div>
<div class="cell">
cell 2
</div>
<div class="cell">
cell 3
</div>
</div>
<div class="row">
<div class="cell">
cell 1
</div>
<div class="cell">
cell 2
</div>
<div class="cell">
cell 3
</div>
</div>
<div class="row">
<div class="cell">
cell 1
</div>
<div class="cell">
cell 2
</div>
<div class="cell">
cell 3
</div>
</div>
</div>
</div>
JsFiddle
Anyone knows how I could achieve the table layout I want? I'm open for no flexbox solution but I don't want a JS based solution for now.

Centering form with flex rows

I have a form where every single row has display: flex. Each row has a label box with a fixed width and a field box which fit to his content. Now it looks like this:
What I want to achive is to shrink every row to the minimum content width and centering the form horizontally. Something like this:
I tried using inline-flex for rows but seems like parent becomes smaller than the total width of children.
Is there a way to achive it keeping flexbox for each row and without using transform: translate to align form horizontally?
Here is the code of the first image:
.form-container {
background-color: black;
padding: 5px;
color: white;
}
.form {
background-color: yellow;
padding: 5px;
}
.form-row {
display: flex;
background-color: silver;
padding: 5px 0;
margin: 5px 0;
}
.form-row-label {
flex: 0 0 200px;
background-color: cornflowerblue;
}
.form-row-field {
flex: 0 1 0;
background-color: orangered;
white-space: nowrap;
}
<div class="form-container">
<div class="form">
<div class="form-row">
<div class="form-row-label">
label 1
</div>
<div class="form-row-field">
field 1 xxxxxxxxxxxxxxxxx
</div>
</div>
<div class="form-row">
<div class="form-row-label">
label 2
</div>
<div class="form-row-field">
field 2 xxxx
</div>
</div>
<div class="form-row">
<div class="form-row-label">
label 3
</div>
<div class="form-row-field">
field 3 xxxxxxxxxx
</div>
</div>
</div>
</div>
And here is the jsfiddle.
Thanks
Here is an idea:
.form-container {
background-color: black;
padding: 5px;
color: white;
text-align:center; /* Center the inline-block*/
}
.form {
background-color: yellow;
padding: 5px;
display:inline-block; /* Use this to fit content */
}
.form-row {
display: flex;
background-color: silver;
padding: 5px 0;
margin: 5px 0;
}
.form-row-label {
width: 200px;
flex-shrink:0; /* Avoid the content to shrink*/
background-color: cornflowerblue;
text-align:left;
}
.form-row-field {
flex-shrink:0;
background-color: orangered;
}
<div class="form-container">
<div class="form">
<div class="form-row">
<div class="form-row-label">
label 1
</div>
<div class="form-row-field">
field 1 xxxxxxxxxxxxxxxxx
</div>
</div>
<div class="form-row">
<div class="form-row-label">
label 2
</div>
<div class="form-row-field">
field 2 xxxx
</div>
</div>
<div class="form-row">
<div class="form-row-label">
label 333
</div>
<div class="form-row-field">
field 3 xxxxxxxxxx
</div>
</div>
</div>
</div>
Here is an idea using display:inline-flex and flex-direction:column in the .form class with text-align: center in the parent class. Also you will need to use width: 200px in label instead of flex-basis:200px
.form-container {
background-color: black;
padding: 5px;
color: white;
text-align: center;
}
.form {
background-color: yellow;
padding: 5px;
display: inline-flex;
flex-direction: column;
justify-content: center;
}
.form-row {
display: flex;
background-color: silver;
padding: 5px 0;
margin: 5px 0;
}
.form-row-label {
width: 200px;
background-color: cornflowerblue;
}
.form-row-field {
flex: 0 1 0;
background-color: orangered;
white-space: nowrap;
}
<div class="form-container">
<div class="form">
<div class="form-row">
<div class="form-row-label">
label 1
</div>
<div class="form-row-field">
field 1 xxxxxxxxxxxxxxxxx
</div>
</div>
<div class="form-row">
<div class="form-row-label">
label 2
</div>
<div class="form-row-field">
field 2 xxxx
</div>
</div>
<div class="form-row">
<div class="form-row-label">
label 3
</div>
<div class="form-row-field">
field 3 xxxxxxxxxx
</div>
</div>
</div>
</div>
If you want to center the yellow box within the black box, you should only add below code to your code:
.form {
background-color: yellow;
padding: 5px;
display: flex;
width: 650px;
max-width: 650px;
flex-direction: column;
margin: 0 auto;
}
.form-row-label {
flex: 0 0 60%;
background-color: cornflowerblue;
}
I think it will help you a little bit.

First-child full-width in Flexbox

How can I set the first-child of flexbox in full-width and all of the other childs set to flex:1(for split space)?
Like this:
You can set the :first-child to a width of 100%, and the rest of the childs :not(:first-child) to flex: 1.
To put them on multiple lines, use flex-wrap: wrap on the container:
.container {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
background: #e2eaf4;
padding: 10px;
}
.child {
display: inline-block;
font-family: "Open Sans", Arial;
font-size: 20px;
color: #FFF;
text-align: center;
background: #3794fe;
border-radius: 6px;
padding: 20px;
margin: 12px;
}
.child:first-child {
width: 100%;
}
.child:not(:first-child) {
flex: 1;
}
<div class="container">
<div class="child">Child</div>
<div class="child">Child</div>
<div class="child">Child</div>
</div>
Add width: 100%; for your first item. And flex: 1; for others.
.flex {
display: flex;
flex-wrap: wrap;
}
.flex-item:not(:first-child) {
flex: 1;
}
.flex-item:nth-child(1) {
width: 100%;
}
/* Styles just for demo */
.flex-item {
background-color: #3794fe;
margin: 10px;
color: #fff;
padding: 20px;
border-radius: 5px;
}
<div class="flex">
<div class="flex-item">
Child
</div>
<div class="flex-item">
Child
</div>
<div class="flex-item">
Child
</div>
</div>
Another solution which utilises the flex-basis option (the third value when using this format flex: 1 1 100%).
MDN link for flex-basis
.flexContainer {
display: flex;
flex-wrap: wrap;
}
.item:first-child {
flex: 1 1 100%;
margin-bottom: 20px;
}
.item {
flex: 1 1 40%;
height: 50px;
background-color: red;
margin: 0 20px;
}
<div class="flexContainer">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
I find this solution simple. Just set desired child item height.
<div style={{ display: 'flex', flexWrap: 'wrap', gap:'32px'}}>
<div style={{ flex: '0 0 100%' }}>Some content</div>
<div style={{ flexGrow: 1 }}>Some content</div>
<div style={{ flexGrow: 1 }}>Some content</div>
</div>

Reorder columns in reverse order

I have a list of flex items within a flexbox. The order of the items matter, and for accessibility purposes, the items need to show up in the correct order in the dom.
[[itema][itemb][itemc]]
When the flexbox shrinks I would like to have the items wrap in reverse order, e.g. itema wraps first, etc. Is there any way to have the itema wrap first? Thanks!
Edit:
Here is the code
<div class="flex">
<div class="container">
<div class="item">item1</div>
<div class="item orange">item2</div>
<div class="item blue">item3</div>
</div>
<div class="last-item green">menu</div>
</div>
.flex {
display: flex;
background-color: yellow;
height: 80px;
overflow: hidden;
color: #fff;
}
.container {
display: flex;
flex: 1 1 auto;
flex-wrap: wrap;
}
.item {
flex: 0 0 auto;
background-color: red;
height: 80px;
padding: 0 40px;
}
.last-item {
width: 40px;
flex: 0 0 auto;
height: 80px;
}
JSFiddle
All the behavior is as desired except I want the first item to wrap first. Any ideas? Thanks!
You can use the flex-direction: column-reverse to get your solution.
#media (max-width: 768px) {
.flex-box {
display: flex;
flex-direction: column-reverse;
}
}
.first,
.second,
.third {
display: inline-block;
}
<div class="flex-box">
<div class="first">
<p>First Box</p>
<img src="http://placehold.it/300x300" />
</div>
<div class="second">
<p>Second Box</p>
<img src="http://placehold.it/300x300" />
</div>
<div class="third">
<p>Third Box</p>
<img src="http://placehold.it/300x300" />
</div>
</div>
JSfiddle Demo
To make item1 wrap first, you can use flex-wrap: wrap-reverse on your flex container.
Try this simplified version of you code:
<div class="container">
<div class="item">item1</div>
<div class="item orange">item2</div>
<div class="item blue">item3</div>
</div>
.container {
display: flex;
flex: 0 1 auto;
flex-wrap: wrap-reverse;
}
.item {
background-color: red;
height: 80px;
padding: 0 40px;
}
.orange {
background-color: orange;
}
.blue {
background-color: blue
}
See the MDN reference for browser support.

Resources