holy grial layout with flex - css

I just use flex for layout, the markup like this:
<div class="grid">
<div class="grid-cell"></div>
<div class="grid-cell"></div>
<div class="grid-cell"></div>
</div>
and the normal view like this:
layout structure - default
when in a breakpoint, view like this:
layout structure - responsive
the problem is, do not change the markup and just use flex, how can I make this?

With flex, you may use min-width to set a breaking-point.
example with 2 childs at:
min-width:200px;
margin:10px;
padding:10px;
flex:1
makes a first break point at 200px + 40px margin + 40px padding = ~ 480px (mind borders too or reset box-sizing properties)inside the flex container .
Example with your structure breaking at average 750px
.grid {
display: flex;
flex-wrap: wrap;
border: solid;
}
.grid div {
padding: 10px;
margin: 10px;
flex: 1;
border: solid;
min-width: 200px;
/* from 3 childs: avearge breaking points */
/* first breaking-point at 200 x 3 + padding/margin = 730px within flex-container */
/*second breaking-point at 200 x 2 + padding/margin = 480px within flex-container */
}
<div class="grid">
<div class="grid-cell"></div>
<div class="grid-cell"></div>
<div class="grid-cell"></div>
</div>

Related

CSS - spaces between items on multiple lines [duplicate]

This question already has answers here:
Targeting flex items on the last or specific row
(10 answers)
Closed 1 year ago.
I have a container with a dynamic number of items.
Each line can contain up to 4 items. If there are more than 4 items, the next item will start a new line (image 1). If there are less than 4 items it's OK, they just won't fill the whole line (image 2).
But I'm having troubles with the spaces between them:
I tried to use margin-right but it affects the last items in the lines (e.g.: item #4).
I tried to use justify-content: space-between but it looks good only for 4 items and up. For 3 and bellow, it creates a big space between them and I want them to look as in image 2.
Any other elegant / easy solutions?
.container {
display: flex;
flex-wrap: wrap;
/* justify-content: space-between; */
}
.item {
display: inline-block;
width: calc(25% - 12px);
/* margin-right: 12px; */
}
<div class="container">
<div class="item">
#1
</div>
<div class="item">
#2
</div>
<div class="item">
#3
</div>
<div class="item">
#4
</div>
</div>
You can use css grid, you have to use display: grid;, use grid-template-columns to set the amount of columns that you want (1fr = 1 parent container fraction) and finally use grid-gap to set the space between your items.
.container {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
grid-gap: 12px;
}
.item {
display: inline-block;
border: 1px solid red;
color: red;
}
<div class="container">
<div class="item">
#1
</div>
<div class="item">
#2
</div>
<div class="item">
#3
</div>
<div class="item">
#4
</div>
</div>
.container {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
grid-gap: 12px;
}
.item {
display: inline-block;
border: 1px solid red;
color: red;
}
<div class="container">
<div class="item">
#1
</div>
<div class="item">
#2
</div>
<div class="item">
#3
</div>
<div class="item">
#4
</div>
<div class="item">
#5
</div>
<div class="item">
#6
</div>
</div>
More info about Css grid Here!
In class .item, is defined width with calc(25% - 12px). Remember, 25% is just 4 items in each line. 20% is 5 items in each line.
So, change the width to calc(20% - 12px)
While CSS Grid is possibly the better solution for the problem, it's entirely possible to solve the problem with CSS flex-box layout, using the gap property and taking advantage – as did your original code – of the calc() function:
// this is to allow you to dynamically add more .item elements
// so you see that it should meet your needs containing more
// elements.
// we use document.querySelector() to retrieve the first element
// that matches the selector (if any exist, otherwise null):
const button = document.querySelector('button'),
// defining a named function to handle addition of new .item
// elements:
addMore = () => {
// finding the first .item element on the page:
let base = document.querySelector('.item');
// finding the .container element, and using
// .append() to attach a cloned copy of the first
// .item:
document.querySelector('.container').append(base.cloneNode(true));
}
// binding the named - addMore() - function as the event-handler
// for the 'click' event:
button.addEventListener('click', addMore);
*,
::before,
::after {
/* selecting all elements, and the pseudo-elements ::before
and ::after, setting their box-sizing model to border-box
in order that their widths include their border and padding
*/
box-sizing: border-box;
/* removing margin and padding: */
margin: 0;
padding: 0;
}
.container {
display: flex;
flex-wrap: wrap;
/* using the gap property to place a 0.5em 'gutter'
between adjacent elements, both horizontally and
vertically: */
gap: 0.5em;
}
.item {
/* setting the flex-grow: to 1, flex-shrink to 0,
and flex-basis to the result of 20% of the parent-
width minus 0.5em (the gap-space): */
flex: 1 0 calc(20% - 0.5em);
}
/* irrelevant, purely for aesthetics */
*,
::before,
::after {
line-height: 2em;
}
.container {
border: 1px solid #000;
counter-reset: itemCount;
width: 90vw;
margin-inline: auto;
}
.item {
background-color: lightblue;
flex: 1 0 calc(20% - 0.5em);
}
.item:nth-child(odd) {
background-color: palegreen;
}
.item::before {
content: counter(itemCount, decimal-leading-zero);
counter-increment: itemCount;
}
<button type="button">Add another item</button>
<div class="container">
<div class="item">
</div>
<div class="item">
</div>
<div class="item">
</div>
<div class="item">
</div>
</div>
JS Fiddle demo.
References:
box-sizing.
calc().
gap.
margin-inline.

how to make columns the same width with css flex

hello I need to basicaly display a table but with flex (only because I need to adjust the look for mobile)
.container {
display: flex
}
<div class="container">
<div class="row">
<div>1000</div>
<div>mary</div>
</div>
<div class="row">
<div>1</div>
<div>john</div>
</div>
<div class="row">
<div>11</div>
<div>mike</div>
</div>
</div>
how can I make each column have the same width? or at least the width of the largest item.
If you apply flex-grow: 1 to each div in the .row then it will expand accordingly. Note that the .row divs need the display flex (flex only apply to the DIRECT children of the flexed element.
The width can be set by using flex-basis and calc() and dividing the full-width by the number of columns you want (2 in this case). I added a border to demonstrate.
I would be remiss if I didn't suggest that the best tool to display a table structure - is a ... table... then you can work out how to modifiy for responsive layout - but the semantic structure of a table is correct for tabulr content.
.container {
width: 100%;
}
.row {
display: flex;
width: 100%;
}
.row div {
flex-grow: 1;
flex-basis: calc(100% / 2);
padding: 4px 8px;
border: solid 1px red;
}
<div class="container">
<div class="row">
<div>1000</div>
<div>mary</div>
</div>
<div class="row">
<div>1</div>
<div>john</div>
</div>
<div class="row">
<div>11</div>
<div>mike</div>
</div>
</div>
Use flex-basis to set the 'default' width first.
Use flex-grow and/or flex-shrink to allow it to grow /shrink
Use max-width' and min-width` to define by how much it can grow/shrink
.container{ #Stack the div inside the conainer
display:flex;
flex-flow: columns nowrap;
}
.row{ # Set div as cell in the row.
display:flex;
flex-flow: row nowrap;
flex-basis: 33%; # Calculate width from there.
flex-grow:1; #Allow resizing bigger
flex-shrink:1; #Allow resize smaller.
max-width:50%; #Adjust to your liking
min-width:25%; #Adjust o your liking
}
Please consider this ressource https://css-tricks.com/snippets/css/a-guide-to-flexbox/
You can add a flex-basis to the .row items by doing this:
.row {
flex-basis:calc(100% / 3);
}
.container {
width: 100%;
}
.row {
display: flex;
width: 100%;
}
.row div {
flex-grow: 1;
flex-basis: calc(100% / 2);
padding:10px;
margin: 5px;
background: #eee;
}
<div class="container">
<div class="row">
<div>1000</div>
<div>mary</div>
</div>
<div class="row">
<div>1</div>
<div>john</div>
</div>
<div class="row">
<div>11</div>
<div>mike</div>
</div>
</div>

CSS Grid - unnecessary word break

I have a problem with CSS grid.
In the following snippet extracted from the codebase, I have a very simple HTML structure with grid layout. Content is set to break-word to prevent text from overflowing. Event though there is enough space for the text to NOT get broken, it does create a line break just before the last letter.
My understanding was that in grid layout, by default, items are calculated to fit the content as much as possible, which is somehow not the case in this example.
Removing padding from content or margins from grid item does solve the issue, but margin is there for centering and padding is also needed.
Is there any property I have to or can use to solve this problem?
P.S. To my knowledge, the bug is not present in Firefox, I have found it in Chrome and Safari so far.
.grid {
display: grid;
grid-template-columns: auto;
}
.item {
margin: 0 auto;
}
p {
word-break: break-word;
padding: 0 4%;
}
<div class="grid">
<div class="item">
<p>HOTEL</p>
<p>GRAND</p>
</div>
</div>
It's not a bug but a complex calculation.
There is a kind of cycle to calculate the final width of the element which create the issue. The width is first calculated considering the content (a shrink-to-fit behavior based on the properties you used) then using percentage value with padding will consider the calculated width1. At the end, we will reduce the calculated padding from the width creating the word break.
This will happen with the smallest value since in all the cases the width will always be less than the needed width to contain the longest word:
.grid {
display: grid;
grid-template-columns: auto;
}
.item {
margin:auto;
border:1px solid;
}
.pad p {
word-break: break-word;
padding: 0 1%;
}
<div class="grid">
<div class="item">
<p>HOTEL</p>
<p>I_WILL_FOR_SURE_BREAK</p>
</div>
</div>
<div class="grid">
<div class="item pad">
<p>HOTEL</p>
<p>I_WILL_FOR_SURE_BREAK</p>
</div>
</div>
As you can see, the first grid with padding is shrinked to its content and the second grid is having exactly the same width and the padding is creating the line break.
An easy fix is to use pixel value instead of percentage in case you know the value you want:
.grid {
display: grid;
grid-template-columns: auto;
justify-content:center;
}
.item {
margin:auto;
border:1px solid;
}
.pad p {
word-break: break-word;
padding: 0 20px;
}
<div class="grid">
<div class="item">
<p>HOTEL</p>
<p>I_WILL_NOT_BREAK</p>
</div>
</div>
<div class="grid">
<div class="item pad">
<p>HOTEL</p>
<p>I_WILL_NOT_BREAK</p>
</div>
</div>
Why you don't see this on firefox?
Simply because break-word is not supported there (https://developer.mozilla.org/en-US/docs/Web/CSS/word-break)
So you will have an overflow instead of a word break. You may notice this behavior on firefox if you use break-all:
.grid {
display: grid;
grid-template-columns: auto;
}
.item {
margin:auto;
border:1px solid;
}
p {
word-break: break-all;
padding: 0 1%;
}
<div class="grid">
<div class="item">
<p>HOTEL</p>
<p>I_WILL_FOR_SURE_BREAK</p>
</div>
</div>
1: The size of the padding as a percentage, relative to the width of the containing block.ref

Using calc() with a dynamic value?

I am wondering if this is possible: I have a header that can contain a variable amount of text. Below that I have another element which I want to take up the remaining height of the page.
<div class="header row">
<div class="title column large-5">Potentially very long text</div>
<div class="menu column large-7">Menu items</div>
</div>
<div class="content">
</div>
<div class="footer">
</div>
Normally I would do this using calc, eg:
.content {
height: calc(100vh - 75px);
}
Where 75px is the set height of .header.
But in this example, the .header element is dynamic and does not have a set height. Only a padding and font-size are set.
To complicate things, this also uses the Foundation Grid layout, which makes me nervous about using display: table (.title and .menu sit side by side on desktop, but stacked on mobile) .
Is there anyway to get the height of the dynamic header element (without resorting to JQuery)?
You can use flexbox and set .content to flex-grow: 1 so that it will fill to grow the available space.
body {
display: flex;
flex-direction: column;
min-height: 100vh;
margin: 0;
}
.content {
flex-grow: 1;
background: #eee;
}
<div class="header row">
<div class="title column large-5">Potentially very long text</div>
<div class="menu column large-7">Menu items</div>
</div>
<div class="content">
</div>
<div class="footer">
</div>
I made a small pen to show the way to do this using flex box, it involved changing your markup a bit:
css:
.container {
display: flex;
flex-direction: column;
height: 250px; // whatever you want here
}
.header {
width: 100%;
background: red;
padding: 10px;
}
.content {
background: yellow;
width: 100%;
flex-grow: 1;
}
So the content will always take the available space inside the content div.
check the whole pen: http://codepen.io/anshul119/pen/yMYeLa
hope this helps.

Bootstrap - center inner div

I have this : http://www.bootply.com/apUgehnGLq
Why width of red box is so big ? I want it to finish immediately after last box, which is a box with tag CCC and then center the whole red box.
Since you're working with % in the inner div you are going to have to make the percentages bigger and the div smaller till you have the size you prefer, like so:
http://www.bootply.com/juFV1xgpNY
Just play around with the withs of the .inner and the divs inside of it.
The border adds pixels to the width of the box, so the last box goes on a new line. You can set box-sizing: border-box; on the body and a padding on the .border instead of a margin to achieve what you want.
I updated your code: http://www.bootply.com/1s5ESfKlod
Read more about what the box-sizing property can do at Mozilla Developer Network.
Update
See code here: http://www.bootply.com/ASWCuTHrZy
You can control the items in this example using flex-basis, where the X items is 3.
flex-basis: calc(100% * 1/3);
So 100 divided by 1/3 makes 33.333..%, that's the width of the AAA, BBB, CCC containers. DDD will go to the next line.
All used CSS:
body * {
box-sizing: border-box;
}
.border {
padding: 5px;
border: 2px solid black;
}
#inner {
border: 2px solid red;
width: 80%;
}
.container-fluid {
display: flex;
flex-flow: row wrap;
align-content: flex-start;
}
.border {
flex-basis: calc(100% * 1/3);
}
The issues you are having with the 4 columns not lining up is due to the margin you have set in the .border class, as well as the class for #inner id. So, if you remove the border margin we should be able to resolve all the issues. Like so:
<div id="center" class="col-lg-7">
<div class="col-md-4 border">AAA</div>
<div class="col-md-4 border">BBB</div>
<div class="col-md-4 border">CCC</div>
<div class="clearfix"></div>
<div class="col-md-12 border">DDD</div>
</div>
Alternatively, if you would like to have all the 4 columns to line up, you can just code it like so:
<div id="center" class="col-lg-7">
<div class="col-md-3 border">AAA</div>
<div class="col-md-3 border">BBB</div>
<div class="col-md-3 border">CCC</div>
<div class="col-md-3 border">DDD</div>
</div>
You can view the sample code here: http://www.bootply.com/GZJwteX6yT
I hope this helps you!

Resources