I would like to create a vertical layout with flexbox.
Here is the structure :
.container {
display: flex;
flex-direction: column;
}
<div class="container">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
<div class="child">5</div>
<div class="child">6</div>
<div class="child">7</div>
<div class="child">8</div>
</div>
And it should display 6 items per column
1 7
2 8
3
4
5
6
For the structure to break into a new column, it needs to know the limit to which it can fit its contents.
To make it clear, think of a simple paragraph tag with some text. Once the text exceeds the width of the page (or the container), the excess text wraps to the next line. So, in case of rows, width can be set as the limit, which is by default 100% of the viewport width or 100% of the container's width.
But here as we are dealing with columns and it takes height as the limit, the challenge here arises as the height is limitless in a HTML document. Because the height of a page increases to any extend when the content increases along with the vertical scroll bar. (Note that the same can be made possible in case of width with overflow a horizontal scroll bar, but here we are talking about the default behaviour).
Therefore, in this situation, to break the contents into a new column is only possible (exception with CSS grid) if we specify a height to the container.
It can either be specified in pixels or rem as mentioned in other answers.
Or if you are looking for a behaviour equivalent to the rows' as mentioned above, you can resort to viewport-height similar to viewport-width in case of rows. PEN
body {
margin: 0;
}
.container {
display: flex;
flex-direction: column;
flex-wrap: wrap;
height: 100vh;
}
.child {
height: 16.667vh;
}
Please note that this is not a perfect solution as it could cause misalignment when the content exceeds the height and also have browser compatibility issues. Also you may consider CSS grid or try Javascript solutions to perfectly tackle this scenario.
Hope this helps.
Try this style:
.container {
display: flex;
flex-direction: column;
height: 112px;
flex-wrap: wrap;
}
What I did here is set height to the container div so that the flex items wrap to the next column when it overflows. For this you need to set flex-wrap: wrap; too. In this case, height: 112px caused the overflow. You can change it as per your requirements.
The height is dynamic, base on the number of items you want to control vertically (in this case 6), I have calculated the height base on a 1rem font-size:
Example for 6 items:
.container {
display: flex;
flex-flow: column wrap;
font-size: 1rem;
max-height: calc(6 * 1.2em);
}
<div class="container">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
<div class="child">5</div>
<div class="child">6</div>
<div class="child">7</div>
<div class="child">8</div>
</div>
Example for 7 items:
.container {
display: flex;
flex-flow: column wrap;
font-size: 1rem;
max-height: calc(7 * 1.2em);
}
<div class="container">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
<div class="child">5</div>
<div class="child">6</div>
<div class="child">7</div>
<div class="child">8</div>
</div>
As the OP agreed to accept a CSS Grid solution, here is one:
.container {
display: grid;
}
.child:nth-child(6n + 2) {
grid-row-start: 2;
}
.child:nth-child(6n + 3) {
grid-row-start: 3;
}
.child:nth-child(6n + 4) {
grid-row-start: 4;
}
.child:nth-child(6n + 5) {
grid-row-start: 5;
}
.child:nth-child(6n) {
grid-row-start: 6;
}
PEN - Hope this helps.
Related
I am having a problem regarding elements inside a flex box. I am using flex: 1 1 auto with flex-flow: column wrap. I want to show a number of divs whose size increases along with that of the screen.
Using media queries would be so confusing and the code would be so large. I am searching for a way to achieve it without using media queries because the size of each div in the flex is about 200px each, I would need to make a lot of media queries incrementing from low to high resolutions.
The min-width property is rather useful here. I put fifteen divs to show the effect on multiple screen sizes.
.flex-parent {
display: flex;
flex-wrap: wrap; /* this makes the divs wrap */
}
.flex-child {
margin: 3px;
background-color: lightblue;
min-width: 200px; /*prevents the flex-child from shrinking more than 200px */
height: 50px;
flex: auto; /* this auto-adjusts the width */
/* Everything after this is just to align everything to the center */
padding-top: 20px;
text-align: center;
}
<div class='flex-parent'>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
</div>
Use flex-flow: row wrap.
If you want to show more div elements as the screen gets wider, you’ll want to use row for flex-direction, not column. With flex-direction: row, the flex items will be put into each line from left to right, like a line of text. And the bigger the screen, the more items will fit.
If you want your flex items to grow and fill all the available space, use flex: auto. This might mean the items end up with different sizes, because you can have a different number of items in each flex line. If you want all of them to be the same size, you could set something like flex: 200px.
.flex-container {
display: flex;
flex-flow: row wrap;
gap: 8px;
}
.flex-item {
flex: auto;
padding: 32px;
background-color: bisque;
}
<div class="flex-container">
<div class="flex-item">One</div>
<div class="flex-item">Two</div>
<div class="flex-item">Three</div>
<div class="flex-item">Four</div>
<div class="flex-item">Five</div>
<div class="flex-item">Six</div>
<div class="flex-item">Seven</div>
<div class="flex-item">Eight</div>
<div class="flex-item">Nine</div>
<div class="flex-item">Ten</div>
<div class="flex-item">Eleven</div>
<div class="flex-item">Twelve</div>
</div>
If you want to arrange the div elements as columns (top to bottom), then your flex container needs to have a height set on it, for example height: 500px. This is so that the flex container can calculate how many flex items can fit into each column.
.flex-container {
display: flex;
flex-flow: column wrap;
height: 100vh;
gap: 8px;
}
.flex-item {
flex: auto;
padding: 32px;
background-color: bisque;
}
<div class="flex-container">
<div class="flex-item">One</div>
<div class="flex-item">Two</div>
<div class="flex-item">Three</div>
<div class="flex-item">Four</div>
<div class="flex-item">Five</div>
<div class="flex-item">Six</div>
<div class="flex-item">Seven</div>
<div class="flex-item">Eight</div>
<div class="flex-item">Nine</div>
<div class="flex-item">Ten</div>
<div class="flex-item">Eleven</div>
<div class="flex-item">Twelve</div>
</div>
I am learning Flex Box and I have troubles with the property align-content. The property shouldn't have result when there is a single line, but in my case it does and I can't understand why.
The result is that my single line of divs is at the end of my container.
I will be glad for some help.
.conteiner {
border: solid red;
display: flex;
flex-direction: row;
flex-wrap: wrap;
min-height: 500px;
justify-content: flex-start;
align-items: flex-start;
align-content:flex-end
}
.child {
min-height: 100px;
min-width: 100px;
background-color: lightblue;
margin: 10px;
}
<body>
<section class="conteiner">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
<div class="child">5</div>
<div class="child">6</div>
</section>
</body>
try this:
.container{
justify-content: flex-end;
}
Likely, the reason your code is not working as intended... The result is that my single line of divs is at the end of my container. I will be glad for some help.
Is because of this line of code:
align-content:flex-end
Also, in your code, you did not close the css function with a semicolon either.
this means the content in your div that is defined as flex, will have its content placed at the end of the parent element. Likely simply changing this to one of the other definitions for align-content will be the outcome you are looking for.
The following article should assist you in understanding flex-box alignment better:
Aligning Items in a Flex Container
From my comment :
if you read the specification, you'find out that it doesn't work when flex-wrap is set to no wrap. you did set flex-wrap:wrap, so if you have a single line, it does work and send the content all the way down. You probably need javascript to reset the wrap property when your flex children stands on a single row.
https://developer.mozilla.org/en-US/docs/Web/CSS/align-content
The CSS align-content property sets the distribution of space between and around content items along a flexbox's cross-axis or a grid's block axis.
This property has no effect on single line flex containers (i.e. ones with flex-wrap: nowrap).
here is a possible javascript workaround, not on flex-wrap but align-content value to get the expected result for both case (a single line or many) : resize the window to wrap an unwrap your flex children
window.onload = check;
window.onresize = check;
let flexbox = document.querySelector(".conteiner");
function check() {
flexbox.style.alignContent = "flex-start";
var child = document.querySelector(".conteiner > :last-child");
var childPos = child.offsetTop;
child.style.color="red";
var parentPos = flexbox.offsetTop;
var childOffset = childPos - parentPos;
console.log( parentPos + ' - ' + childPos)
if (childOffset > 20) {
flexbox.style.alignContent = "flex-end";
}
}
.conteiner {
border: solid red;
display: flex;
flex-direction: row;
flex-wrap: wrap;
min-height: 500px;
justify-content: flex-start;
align-items: flex-start;
align-content:flex-end
}
.child {
min-height: 100px;
min-width: 100px;
background-color: lightblue;
margin: 10px;
}
<section class="conteiner">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
<div class="child">5</div>
<div class="child">6</div>
</section>
This question already has answers here:
CSS when inline-block elements line-break, parent wrapper does not fit new width
(2 answers)
How to remove the space between inline/inline-block elements?
(41 answers)
Closed 4 years ago.
I have a container div that has child divs with fixed widths and wraps. What I realised is that the container's width doesn't fit tightly to the content after it wraps, usually leaving a 'ghost' space on the right. Is there a way to force it to readjust the width according to its content?
.container {
max-width: 12em;
background-color: black;
}
.child {
display: inline-block;
width: 5em;
background-color: red;
}
<div class="container">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
<div class="child">5</div>
<div class="child">6</div>
</div>
So in this case when the child wraps after 2 of them add up to 10em, the container instead of being 10em, it is still 12em. And if the window size forces it down to a single div wrapping, the container rather than being 5em, could be 6em, 7em, 8em, etc depending on window width.
Is there a way to get rid of the 'ghost' space and make the container fit exactly to how the child is wrapping and it's total width?
Note: I am not talking about the extra space in between each child element. I'm referring to the giant gap left in the container, which causes the container to not accurately reflect the size of its child content. I understand that I can simply count how many child can fit in 12em and change the container width to be 10em to fit 2 childs perfectly. But I want that to be flexible. Is that possible?
The extra space after each child element is a result of the display: inline-block property and is due to the literal whitespace between each div in your HTML. You may verify this by removing the linebreaks between child divs so that their open and close tags are back-to-back:
<div class="container">
<div class="child">1</div><div class="child">2</div><div class="child">3</div>/*...*/
</div>
Although this will eliminate the pesky whitespace, it comes at the expense of code clarity/readability and is surely an irritating way to write HTML.
In my experience, often the best solution to this issue is to set the parent container to display: flex:
.container {
display: flex;
flex-wrap: wrap;
max-width: 10em;
background-color: black;
}
.child {
display: inline-block;
width: 5em;
background-color: red;
}
<div class="container">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div><div class="child">5</div>
<div class="child">6</div>
</div>
In this case you will also need to provide the flex-wrap: wrap property to inform the flex container to wrap its contents. Presumably you can now update the container's max-width property to 10em to fit exactly the width of two child elements so I've taken the liberty of this change in the code snippet.
Looks like you want to render a table. So you may want to use:
<table>
<tr>
<td>Col1</td>
<td>Col2</td>
</tr>
...
</table>
In case im wrong:
You can do this with flex or grid
Helpful link Flexbox, Grid
.container {
max-width: 12em;
background-color: black;
display: flex;
}
.child {
display: block;
min-width: 5em;
background-color: red;
border: 1px dashed blue;
}
/* FLEX */
.container-flex {
/* new row if next element doesnt fit */
flex-wrap: wrap;
}
.container-flex .child {
/* makes children grow evenly after wrapping */
flex-grow: 1;
}
/* GRID */
.container-grid {
display: grid;
/* 2 auto-horizontally sized colums */
grid-template-columns: auto auto;
}
.container-grid .child {
/* noting to do here */
}
<div style='float: left; margin-right: 10px;'>
Flex<br>
<small>extend elements to 6em</small><br>
<hr>
<div class="container container-flex">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
<div class="child">5</div>
<div class="child">6</div>
</div>
</div>
<div style='float: left; margin-right: 10px;'>
Grid<br/>
<small>collapse container to 10em</small><br>
<hr>
<div class="container container-grid">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
<div class="child">5</div>
<div class="child">6</div>
</div>
</div>
You can do it like this
.container { max-width: 4.5em;background-color: black; }
.child { display: inline-block; width:cover; background-color: red; }
<!DOCTYPE html>
<html>
<head>
<title>Answer</title>
</head>
<body>
<div class="container">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
<div class="child">5</div>
<div class="child">6</div>
</div>
With the width set to 'cover' it covers the complete area leaving no space.In order to fix the black background (of container which is more or less acting like border), you can manually adjust it's size.
I am trying to better understand flex box css and have a main layout for all pages. It is 3 columns where the first column is fixed width and the others can be any size so long as all 3 take up 100% width.
I believe the problem is in .col class but unsure how to set the 1st column and let the other grow. Thank you.
.wrapper {
display: flex;
flex-direction: row;
}
.col {
flex-basis: 25%;
align-items: stretch;
}
<div class="wrapper">
<div class="col">1</div>
<div class="col">2</div>
<div class="col">3</div>
</div>
You simply need to specify a fixed width to the first one and then set flex:1 to the other so they take the remaining space and fill 100% of the container space:
.wrapper {
display: flex;
flex-direction: row;
}
.col {
flex: 1;
background: red;
}
.col:first-child {
width: 100px; /* Or a percentage value */
flex:initial;
background: green;
}
<div class="wrapper">
<div class="col">1</div>
<div class="col">2</div>
<div class="col">3</div>
</div>
I'm currently working on responsiveness on my website and I hit the wall. On smaller resolutions I changed the flex-direction to column from row, changed the ordering of flex elements, changed the main textbox width to 100% and sideboxes to 50%.
Code looks like this:
<section class="about" id="ABOUT">
<div class="about-sidebox l">
</div>
<div class="about-mainbox">
</div>
<div class="about-sidebox r">
</div>
</section>
As you can see the sideboxes are not within the container. Putting them in container helps but completely ruins my previous layout.
CSS for wanted resolution is:
.about {
flex-direction: column;
}
.about-mainbox {
order: 1;
}
.about-sidebox {
order: 2;
width: 50%;
flex-wrap: wrap;
}
Effect is like this:
As you can see I want the sideboxes to be next to each other. Any solution I can't think of without adding additional container?
I hope I've understood you correctly. You could remove the flex-direction property from .about
Add flex-wrap. Then just give .about-mainbox a width of 100%
.about {
display: flex;
flex-wrap: wrap;
}
.about-mainbox {
order: 1;
width: 100%;
}
.about-sidebox {
order: 2;
width: 50%;
}
<section class="about" id="ABOUT">
<div class="about-sidebox l">demo left
</div>
<div class="about-mainbox">demo
</div>
<div class="about-sidebox r">demo right
</div>
</section>
The simplest possible is to do this;
Set the about to flex-wrap: wrap so its flex items can wrap, skip flex-direction so it uses its default row
Set the mainbox to order: -1 (default is 0), which will position it before the sidebox's, and flex-basis: 100%, which will make it take full width and by doing that, it pushes the sidebox's to a new line
Give the sidebox's flex-basis: 50% to be equally wide, and min-width: 0; so they stay side-by-side (if you wan't them to wrap and stack vertical when their content force's them to, drop this, or control it with a set width, i.e. min-width: 150px;)
I also recommend you use Flexbox's own properties, i.e. in this case flex-basis instead of width
.about {
display: flex;
flex-wrap: wrap;
}
.about-mainbox {
flex-basis: 100%;
order: -1;
}
.about-sidebox {
flex-basis: 50%;
min-width: 0;
}
<section class="about" id="ABOUT">
<div class="about-sidebox l">Left
</div>
<div class="about-mainbox">Main
</div>
<div class="about-sidebox r">Right
</div>
</section>