I have a parent div and two divs inside. I want to keep specific sizes (columns) for those child divs. Is this possible in flexbox? I'm strugling with this.
<div class="parent">
<div class="child"></div>
<div class="child"></div>
</div>
First child should have width of 1 column, second child width of 2 columns. On right side I want to have empty space in width of 1 column (so parent div should behave like it has 4 columns).
Here's a method using flex-basis to set flex items to specific percentage widths.
In this example, the two flex items can neither shrink nor grow. Splitting 100% width into four columns, each column needs to be 25% of the parent width. The first item is 25% and the second is 50% (two columns wide), leaving 25% space on the right.
.parent {
display: flex;
min-height: 10em;
border: 1px solid #CCC;
}
.child {
outline: 1px solid black;
background-color: lightgray;
}
.child:nth-child(1) {
flex: 0 0 25%
}
.child:nth-child(2) {
flex: 0 0 50%;
}
<div class="parent">
<div class="child"></div>
<div class="child"></div>
</div>
EDIT
I notice you'd like some space between each column. One way is to add some right margin percentage to flex items and subtract that percentage from each item's flex-basis.
.parent {
display: flex;
min-height: 10em;
border: 1px solid #CCC;
}
.child {
outline: 1px solid black;
background-color: lightgray;
margin-right: 3%;
}
.child:nth-child(1) {
flex: 0 0 22%;
}
.child:nth-child(2) {
flex: 0 0 47%;
}
<div class="parent">
<div class="child"></div>
<div class="child"></div>
</div>
If you'd rather that the space between columns not be a percentage, you can use calc() to calculate the appropriate flex-basis. However, note that this is not supported in IE or Edge at the time of this post.
IE & Edge are reported to not support calc inside a 'flex'. (Not tested on older versions)
This example does not work: flex: 1 1 calc(50% - 20px);
caniuse.com
.parent {
display: flex;
min-height: 10em;
border: 1px solid #CCC;
}
.child {
outline: 1px solid black;
background-color: lightgray;
margin-right: 0.5em;
}
.child:nth-child(1) {
flex: 0 0 calc(25% - 0.5em);
}
.child:nth-child(2) {
flex: 0 0 calc(50% - 0.5em);
}
<div class="parent">
<div class="child"></div>
<div class="child"></div>
</div>
You can achieve this using flexbox by using a pseudo element that occupies the fourth column:
add flex: 1 to the first child and the pseudo element,
add flex: 2 to the second child.
See demo below:
.parent {
display: flex;
height: 100px;
border: 1px solid #ddd;
}
.child {
border: 1px solid cadetblue;
background: lightblue;
flex: 1;
}
.child + .child {
flex: 2;
}
.parent:after {
content: '';
flex: 1;
}
<div class="parent">
<div class="child"></div>
<div class="child"></div>
</div>
And the easier solution using CSS Grid layout - establish a 4-column layout and span the second child element over two columns:
.parent {
display: grid;
grid-template-columns: repeat(4, 1fr);
height: 100px;
border: 1px solid #ddd;
}
.child {
border: 1px solid cadetblue;
background: lightblue;
}
.child + .child {
grid-column: span 2;
}
<div class="parent">
<div class="child"></div>
<div class="child"></div>
</div>
Nobody seems to have suggested you could just set the width of the parent:
.parent {
width: 75%;
display: flex;
}
.child {
flex: 150;
height: 2rem;
border: 1px solid #000;
}
.child:first-child {
flex: 75;
}
<div class="parent">
<div class="child"></div>
<div class="child"></div>
</div>
EDIT:
And to add, you want your second child to be twice as big as your first, so give your second child a flex value of something that's twice as big as your first - I used 1 and 2, but you could've used flex: 75 and flex: 150 to achieve the same effect.
Related
This question already has answers here:
Is it possible to prevent wrapping of child elements in HTML?
(3 answers)
Stop flex children wrapping
(2 answers)
Prevent wrapping in flex items
(1 answer)
Closed 11 months ago.
I'm trying to make a very simple list of cards, there should be 3 cards in each row with a 20 pixels gap between them. Thus, each card should occupy 1/3 of the parent container. But for some reason, when I decrease the size of the browser window, the 3rd card moves to the second row. How can I prevent this?
.parent{
border: solid green 1px;
display: flex;
flex-wrap: wrap;
width: 1000px;
height: 100px;
gap: 20px;
}
.child{
width: 32.2%;
border: solid blue 1px;
background-color: blue;
}
<div class="parent">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>
flex-wrap: nowrap; should do the trick for you. You can set the width for the children by doing calc(100% / 3);. For this to work, remove the fixed width of 1000px on the parent.
.parent{
border: solid green 1px;
display: flex;
flex-wrap: nowrap;
height: 100px;
gap: 10px;
}
.child{
width: calc(100% / 3);
border: solid blue 1px;
background-color: blue;
}
<div class="parent">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>
Using ul:
.parent {
border: solid green 1px;
display: flex;
flex-wrap: wrap;
width: 1000px;
height: 100px;
gap: 10px;
list-style-type: none;
padding-inline-start: 0;
}
.child {
border: solid blue 1px;
background-color: blue;
flex-basis: 31%;
}
<ul class="parent">
<li class="child"></li>
<li class="child"></li>
<li class="child"></li>
<li class="child"></li>
<li class="child"></li>
<li class="child"></li>
</ul>
You can change in your parent container flex-wrap: nowrap; And the item width you can change to 100%;
.parent{
border: solid green 1px;
display: flex;
flex-wrap: nowrap;
width: 1000px;
height: 100px;
gap: 20px;
box-sizing: border-box;
}
.child{
width: 100%;
border: solid blue 1px;
background-color: blue;
}
<div class="parent">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>
UPDATE
With flex-basis
.parent{
border: solid green 1px;
display: flex;
flex-wrap: wrap;
width: 1000px;
height: 100px;
gap: 20px;
box-sizing: border-box;
justify-content: space-between;
}
.child{
flex-basis: 30%;
border: solid blue 1px;
background-color: blue;
}
<div class="parent">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>
This question already has answers here:
Is there a CSS selector for the first direct child only?
(8 answers)
Closed 1 year ago.
Assuming that the parent has width 100%, it is wanted to make child 1 with width 25%, child 2 with width 75%.
Those two children are some custom components that cannot have their own class so the changes must be done in the parent class.
What I've tried:
.parent {
display: flex;
}
.parent:first-child {
width: 25%;
background: #ddd;
}
<div class="parent">
<div>child 1</div>
<div>child 2</div>
</div>
This one makes both of them having 25% of the parent in total.
Any ideas?
Try to use css grid
.parent {
display: grid;
grid-template-columns: 25% 75%;
}
.parent > div {
border: 1px solid blue;
}
<div class="parent">
<div>child 1</div>
<div>child 2</div>
</div>
Your pseudo-selector is faulty. It's looking for an element with class parent which is a first child. You want .parent :first-child, which is a descendant selector.
.parent {
display: flex;
justify-content: stretch;
}
.parent :first-child {
width: 25%;
background: #ddd;
}
.parent :last-child {
flex: auto;
background: pink;
}
<div class="parent">
<div>child 1</div>
<div>child 2</div>
</div>
Seems simple enough:
.parent {
display: flex;
gap: 15px;
margin: 15px;
}
.parent > div:first-child {
flex-basis: 25%;
outline: 1px dotted red;
background: #ddd;
}
.parent > div:nth-child(2) {
flex-basis: 75%;
outline: 1px dotted green;
}
<div class="parent">
<div>child 1</div>
<div>child 2</div>
</div>
By setting the flex-basis property on both child elements, you can make them take up the full width of the container.
The other option would be to set the flex-basis of the first child, and tell the second child to grow to fill the remaining space.
.parent {
display: flex;
gap: 15px;
margin: 15px;
}
.parent > div:first-child {
flex-basis: 25%;
outline: 1px dotted red;
background: #ddd;
}
.parent > div:nth-child(2) {
flex-grow: 1;
outline: 1px dotted green;
}
<div class="parent">
<div>child 1</div>
<div>child 2</div>
</div>
CSS Flexible Box Layout - CSS: Cascading Style Sheets | MDN
A Complete Guide to Flexbox - CSS-Tricks
You need to update the selectors to target the child elements properly, something like :
.parent {
width: 500px;
height: 200px;
display: flex;
border: 1px solid black;
}
.parent div:first-child {
background-color: red;
width: 25%;
height: 200px;
}
.parent div:nth-child(2) {
background-color: yellow;
width: 75%;
height: 200px;
}
<div class="parent">
<div> child1 </div>
<div> child2 </div>
</div>
There seems to be a lot of questions regarding the same issue but can't seem to find a satisfactory answer ... I have:
1 container (flex) (green)
2 columns (block) -> left: red, right: orange
in the left column, I have two divs (green) who follow each other 'menu1''menu2'
These two menus are themselves wrapped in a div (black) so that when I rotate it, the two menus are vertical rather than horizontal (rotation by 90 deg)
The goal is to have the top wrapper/container (green) to take on the height of the vertical black wrapper, and the left column wrapper to be no larger than the 'width' of the rotated black wrapper.
What I get is illustrated in the following example:
https://jsfiddle.net/pg373473/
<div id='container' style='display: flex; border: 3px solid green; flex-direction=row'>
<div id='leftbox' style='position: relative; display: block; border: 3px solid red'>
<div id='textwrapper' style='transform-origin: bottom left; transform: translateY(-100%) rotate(90deg); border: 2px solid black;'>
<div style='border: 3px solid green; display: inline-block'>menu 1</div>
<div style='border: 3px solid green; display: inline-block'>menu 2</div>
</div>
</div>
<div id='rightbox' style='position: relative; display: flex; flex: 1 1 auto; border: 3px solid orange';>
xx
</div>
</div>
Is this possible at all?
By default, the rotation seems to be applied after all the width/height for all divs have been calculated. I personally find this behavior to be against what anybody would expect, but maybe someone who knows the specs very well can explain why this is so? But in the end, I am more interested to know if there is a solution to what I try to achieve (thx).
EDIT
Rotate elements in CSS that affect their parents... is asking something about rotations but the explanation is not satisfactory and the problem slightly different since it's only about being sure that the div of the rotated child take into account the height of the rotated child. The questions asked in this post has 3 constraints:
you have 2 divs in a row that are rotated by 90 degrees (or more than 2)
the wrapper container needs to take on:
the width
and the height of children rotated elements
The aforementioned question is only asking about the height and does not solve the width problem. Additionally, the jsfiddle doesn't work either.
The only good part about this other question is the mentioned in the comments of the writing-mode but I haven't managed to make it work with this either. I tried this option and while I can fix the height issue, I can't make it work to fix the width problem...
<div id='container' style='display: flex; border: 3px solid green; flex-direction: row'>
<div style='display: flex; flex-direction: column; border: 3px solid red; flex: 1 1 auto;'>
<div style='flex: 0 0 auto; display: inline-block; flex-direction: row; writing-mode: vertical-rl; border: 3px solid black;'>
<div style='flex: 0 0 auto; border: 1px solid green; display: inline-block'>menu 1</div>
<div style='flex: 0 0 auto; border: 1px solid green; display: inline-block'>menu 2</div>
</div>
</div>
<div id='rightbox' style='display: flex; flex: 1 1 auto; border: 3px solid orange';>
Right Box
</div>
</div>
https://jsfiddle.net/dyae4xru/
For clarity here is what I want:
ANSWER / EDIT 2
There is no solution to this problem at this point in time. CSS/HTML/Browsers doesn't support that out of the box. I fixed the problem by writing a small JS function that gives me the exact width and height of the div when horizontal and used the values to set the width of the div once rotated by 90 degrees (using writing-mode: vertical-rl).
There may be hacky solutions, yet I'd say CSS transforms are not built for something like this.
If the property has a value different than none, a stacking context
will be created. In that case the object will act as a containing
block for position: fixed elements that it contains.
Source: MDN
(See this post for a scaling transform question.)
CSS Writing Mode
I suggest you use the newer CSS writing mode - see here for browser support:
The writing-mode CSS property defines whether lines of text are laid
out horizontally or vertically and the direction in which blocks
progress.
Use writing-mode: vertical-lr on the div - see demo below that works in Chrome:
#container {
display: flex;
border: 1px solid green;
flex-direction: row;
}
#container>div:first-child {
position: relative;
display: block;
border: 1px solid red;
writing-mode: vertical-lr; /* ADDED */
-webkit-writing-mode: vertical-lr;
}
#container>div>div {
/*transform-origin: bottom left;
transform: translateY(-100%) rotate(90deg);*/
border: 2px solid black;
}
#container>div>div>div {
border: 1px solid green;
display: inline-block;
}
#rightbox {
position: relative;
display: flex;
flex: 1 1 auto;
border: 1px solid orange;
}
<div id='container'>
<div>
<div>
<div>menu 1</div>
<div>menu 2</div>
</div>
</div>
<div id='rightbox'>
xx
</div>
</div>
Issue in Firefox
Note that this doesn't work in Firefox, as flex items do not behave well for vertical writing mode - there are open issues:
Writing-mode: vertical; breaks flexbox layout in Firefox
Flex + vertical writing-mode: flex items / text disappear
The above issue for vertical mode in flexboxes was fixed in Firefox 60, and now you can see that the above demo works in both Chrome & Firefox.
I doubt that this task can be solved without JavaScript because transformed elements are drawn on separate "layers" and their visual appearance doesn't affect DOM properties. However since your transformation is fixed - you can calculate resulted visual size of element and update size of parent element accordingly. Moreover you can use mutation observers to update size of your container in a case if its contents will be changed in runtime. This example displays correct container size and reacts on runtime mutations of menu items. Tested into Firefox and Chrome
document.addEventListener('DOMContentLoaded', function () {
const container = document.querySelector('#container .menu-container');
const menu = document.querySelector('#container .menu-items');
let items = [];
const updateItems = () => {
const nodes = document.querySelectorAll('#container .menu-item');
for (let node of nodes) {
if (items.indexOf(node) === -1) {
items.push(node);
new MutationObserver(updateSize).observe(node, {attributes: true, characterData: true, subtree: true});
}
}
updateSize();
}
const updateSize = () => {
container.style.width = menu.offsetHeight + 'px';
container.style.height = menu.offsetWidth + 'px';
}
new MutationObserver(updateSize).observe(menu, {attributes: true, characterData: true});
new MutationObserver(updateItems).observe(menu, {childList: true});
updateItems();
updateSize();
});
#container {
display: flex;
border: 1px solid green;
flex-direction: row;
}
.menu-container {
position: relative;
display: block;
border: 1px solid red;
}
.menu-items {
transform-origin: bottom left;
transform: translateY(-100%) rotate(90deg);
border: 2px solid black;
display: flex;
position: absolute;
}
.menu-item {
border: 1px solid green;
display: inline-block;
white-space: nowrap;
}
#rightbox {
position: relative;
display: flex;
flex: 1 1 auto;
border: 1px solid orange;
}
<div id="container">
<div class="menu-container">
<div class="menu-items">
<div class="menu-item">menu 1</div>
<div class="menu-item">menu 2</div>
</div>
</div>
<div id="rightbox">
xx
</div>
</div>
Here is my approach to the solution:
I use flex on the container as well as the LEFT BOX, then user writing-mode vertical left to right and finally flex direction column so they stack.
*,
*:before,
*:after {
/* So 100% means 100% */
box-sizing: border-box;
margin: 0;
padding: 0;
}
.container {
display: flex;
border: 2px solid tomato;
}
.box-left {
flex: 0 2.5%; // change % value for the size you want it!
}
.box-right {
flex: 1 auto;
border: 2px solid green;
}
.box-left ul {
display: flex;
flex-direction: column;
border: 2px solid blue;
}
.box-left ul li {
list-style: none;
writing-mode: vertical-lr;
margin-bottom: 0.5em;
}
<div class="container">
<div class="box-left">
<ul>
<li>menu01</li>
<li>menu02</li>
</ul>
</div>
<div class="box-right">
box right
</div>
</div>
I modified your code and below is the out of CSS and HTML snippet.
*,
*:before,
*:after {box-sizing: border-box;margin: 0;padding: 0;}
.container {display: flex;border: 2px solid green;}
.left-box {flex: 0 2.5%;}
.right-box {flex: 1 auto;border: 2px solid orange;}
.left-box {flex: 0 5.5%;border: 2px solid red;}
.menu {border: 1.5px solid green;}
.inner-left-box ul {display: flex;flex-direction: column;border: 2px solid black;}
.inner-left-box ul li {list-style: none;writing-mode: vertical-lr;}
<div class="container">
<div class="left-box">
<div class="inner-left-box">
<ul>
<li class="menu">menu 1</li>
<li class="menu">menu 2</li>
</ul>
</div>
</div>
<div class="right-box">Right Box</div>
</div>
The answer is in the question's edited answer for the writing-mode solution actually. The only problem was the flex: 1 1 auto style on the red-border div, removing it solves the width problem.
HTML w/ Style Tag Variant
<div id='container' style='display: flex; border: 3px solid green; flex-direction: row'>
<div style='display: flex; flex-direction: column; border: 3px solid red;'>
<div style='flex: 0 0 auto; display: inline-block; flex-direction: row; writing-mode: vertical-rl; border: 3px solid black;'>
<div style='flex: 0 0 auto; border: 1px solid green; display: inline-block'>
menu 1
</div>
<div style='flex: 0 0 auto; border: 1px solid green; display: inline-block'>
menu 2
</div>
</div>
</div>
<div id='rightbox' style='display: flex; flex: 1 1 auto; border: 3px solid orange';>
Right Box
</div>
</div>
CSS Classes Variant
#container
{
display: flex;
flex-direction: row;
border: 3px solid green;
}
#leftbox
{
display: flex;
flex-direction: column;
border: 3px solid red;
}
#inner-leftbox
{
display: inline-block;
flex-direction: row;
flex: 0 0 auto;
writing-mode: vertical-rl;
border: 3px solid black;
}
#rightbox
{
display: flex;
flex: 1 1 auto;
border: 3px solid orange;
}
.menu
{
display: inline-block;
flex: 0 0 auto;
border: 1px solid green;
}
<div id="container">
<div id="leftbox">
<div id="inner-leftbox">
<div class="menu">menu 1</div>
<div class="menu">menu 2</div>
</div>
</div>
<div id="rightbox">
Right Box
</div>
</div>
I've got four div's in a flexbox grid. I want them to wrap two at a time, like this:
+-----------------------+
| 1 | 2 | 3 | 4 |
+-----------------------+
+-----------+
| 1 | 2 |
+-----------+ THIS IS WHAT I WANT
| 3 | 4 |
+-----------+
+-----+
| 1 |
+-----+
| 2 |
+-----+
| 3 |
+-----+
| 4 |
+-----+
Now, this seems easy enough, just nest them inside new flex containers and apply flex-wrap, and give the cells some min-widths. However, this has the side-effect of making the middle view look like this:
+-----------+
| 1 | 3 |
+-----------+ NOT WHAT I WANT
| 2 | 4 |
+-----------+
Apparently, flexbox wants to first wrap the inner div's instead of considering them rows. In order to keep all of the other wrapping working, setting flex-basis (to e.g. 100%) for the nested div's is not an option. In order to keep everything dynamic (for instance adding a third cell to one of the rows), setting %-widths on the cells is not an option. And in order to avoid hard breakpoints and base wrapping on (dynamic) content width, I'd really like to avoid media queries.
Can this be achieved with flexbox and without media queries?
JSFiddle
div {
box-sizing: border-box;
margin: 2px;
}
.grid {
display: flex;
flex-flow: row wrap;
border: 2px solid blue;
flex: 1;
}
.cell {
flex: 1;
min-width: 100px;
border: 2px solid red;
background: white;
height: 100px;
}
<div class="grid">
<div class="grid">
<div class="cell">1</div>
<div class="cell">2</div>
</div>
<div class="grid">
<div class="cell">3</div>
<div class="cell">4</div>
</div>
</div>
EDIT: I know I can make the inner .grid not wrap at all, but what I really want is for all the cells to wrap below each other if space is super tight. (As in the first illustration.)
You need to tell the children-elements of .grid .grid to flow in a row:
div {
box-sizing: border-box;
margin: 2px;
}
.grid {
display: flex;
flex-flow: row wrap;
border: 2px solid blue;
flex: 1;
}
.grid .grid {
flex-flow: row; /* this is your fix */
}
.cell {
flex: 1;
min-width: 100px;
border: 2px solid red;
background: white;
height: 100px;
}
<div class="grid">
<div class="grid">
<div class="cell">1</div>
<div class="cell">2</div>
</div>
<div class="grid">
<div class="cell">3</div>
<div class="cell">4</div>
</div>
</div>
Note, there is no specific Flexbox property that replace a media query, and no need either as media queries is perfect for this, better than any other available method or property.
The trick here is to make the inner grid's to wrap before the cell's does. For that to happen they also need a minimum width, which is wider than the sum of the 2 cell's.
The downside with that extra min-width is it will also affect the cell's width on narrower screens
Fiddle demo 1
Stack snippet
div {
box-sizing: border-box;
margin: 2px;
}
.grid-outer {
display: flex;
flex-wrap: wrap;
border: 2px solid blue;
}
.grid-inner {
flex: 1;
display: inline-flex;
flex-wrap: wrap;
border: 2px solid blue;
min-width: 210px;
}
.cell {
flex: 1;
min-width: 100px;
border: 2px solid red;
background: white;
height: 100px;
}
<div class="grid-outer">
<div class="grid-inner">
<div class="cell">1</div>
<div class="cell">2</div>
</div>
<div class="grid-inner">
<div class="cell">3</div>
<div class="cell">4</div>
</div>
</div>
An option is to drop the Flexbox properties on the outer grid and set the inner grid's to inline-flex and let the cells grow with their content.
The downside with this is that the cell's won't fill their parents width
Fiddle demo 2
Stack snippet
div {
box-sizing: border-box;
margin: 2px;
}
.grid-outer {
display: inline-block;
}
.grid-inner {
display: inline-flex;
flex-wrap: wrap;
border: 2px solid blue;
}
.cell {
flex: 1;
min-width: 100px;
border: 2px solid red;
background: white;
height: 100px;
}
<div class="grid-outer">
<div class="grid-inner">
<div class="cell">1</div>
<div class="cell">2</div>
</div>
<div class="grid-inner">
<div class="cell">3</div>
<div class="cell">4</div>
</div>
</div>
The absolute best solution here is a combination of Flexbox and a media query, where one use the query to alter the outer grid's flex direction to column...
Fiddle demo
Stack snippet
div {
box-sizing: border-box;
margin: 2px;
}
.grid-outer {
display: flex;
border: 2px solid blue;
}
.grid-inner {
flex: 1;
display: flex;
border: 2px solid blue;
}
.cell {
flex: 1;
min-width: 100px;
border: 2px solid red;
background: white;
height: 100px;
}
#media (max-width: 600px) {
.grid-outer {
flex-direction: column;
}
}
<div class="grid-outer">
<div class="grid-inner">
<div class="cell">1</div>
<div class="cell">2</div>
</div>
<div class="grid-inner">
<div class="cell">3</div>
<div class="cell">4</div>
</div>
</div>
...or drop the inner grid's all together and change the cell's flex basis
Fiddle demo
Stack snippet
div {
box-sizing: border-box;
margin: 2px;
}
.grid-outer {
display: flex;
flex-wrap: wrap;
border: 2px solid blue;
}
.cell {
flex: 1;
min-width: 100px;
border: 2px solid red;
background: white;
height: 100px;
}
#media (max-width: 600px) {
.cell {
flex-basis: calc(50% - 4px);
}
}
<div class="grid-outer">
<div class="cell">1</div>
<div class="cell">2</div>
<div class="cell">3</div>
<div class="cell">4</div>
</div>
Having different definitions for the grids does the job. I redefined them as outer and inner grid.
EDIT: Added wrap for .grid-inner to cover width < 200px
div {
box-sizing: border-box;
margin: 2px;
}
.grid-outer {
display: flex;
flex-flow: row wrap;
border: 2px solid blue;
flex: 1;
width: 230px; /* for demo purposes */
}
.grid-inner {
display: flex;
border: 2px solid green;
flex-wrap: wrap;
}
.cell {
flex: 1;
min-width: 100px;
border: 2px solid red;
background: white;
height: 100px;
}
<div class="grid-outer">
<div class="grid-inner">
<div class="cell">1</div>
<div class="cell">2</div>
</div>
<div class="grid-inner">
<div class="cell">3</div>
<div class="cell">4</div>
</div>
</div>
I'm using a flex box to display 8 items that will dynamically resize with my page. How do I force it to split the items into two rows? (4 per row)?
Here is a relevant snip:
(Or if you prefer jsfiddle - http://jsfiddle.net/vivmaha/oq6prk1p/2/)
.parent-wrapper {
height: 100%;
width: 100%;
border: 1px solid black;
}
.parent {
display: flex;
font-size: 0;
flex-wrap: wrap;
margin: -10px 0 0 -10px;
}
.child {
display: inline-block;
background: blue;
margin: 10px 0 0 10px;
flex-grow: 1;
height: 100px;
}
<body>
<div class="parent-wrapper">
<div class="parent">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>
</div>
</body>
You've got flex-wrap: wrap on the container. That's good, because it overrides the default value, which is nowrap (source). This is the reason items don't wrap to form a grid in some cases.
In this case, the main problem is flex-grow: 1 on the flex items.
The flex-grow property doesn't actually size flex items. Its task is to distribute free space in the container (source). So no matter how small the screen size, each item will receive a proportional part of the free space on the line.
More specifically, there are eight flex items in your container. With flex-grow: 1, each one receives 1/8 of the free space on the line. Since there's no content in your items, they can shrink to zero width and will never wrap.
The solution is to define a width on the items. Try this:
.parent {
display: flex;
flex-wrap: wrap;
}
.child {
flex: 1 0 21%; /* explanation below */
margin: 5px;
height: 100px;
background-color: blue;
}
<div class="parent">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>
With flex-grow: 1 defined in the flex shorthand, there's no need for flex-basis to be 25%, which would actually result in three items per row due to the margins.
Since flex-grow will consume free space on the row, flex-basis only needs to be large enough to enforce a wrap. In this case, with flex-basis: 21%, there's plenty of space for the margins, but never enough space for a fifth item.
Add a width to the .child elements. I personally would use percentages on the margin-left if you want to have it always 4 per row.
DEMO
.child {
display: inline-block;
background: blue;
margin: 10px 0 0 2%;
flex-grow: 1;
height: 100px;
width: calc(100% * (1/4) - 10px - 1px);
}
Here is another apporach.
You can accomplish it in this way too:
.parent{
display: flex;
flex-wrap: wrap;
}
.child{
width: 25%;
box-sizing: border-box;
}
Sample:
https://codepen.io/capynet/pen/WOPBBm
And a more complete sample:
https://codepen.io/capynet/pen/JyYaba
I would do it like this using negative margins and calc for the gutters:
.parent {
display: flex;
flex-wrap: wrap;
margin-top: -10px;
margin-left: -10px;
}
.child {
width: calc(25% - 10px);
margin-left: 10px;
margin-top: 10px;
}
Demo: https://jsfiddle.net/9j2rvom4/
Alternative CSS Grid Method:
.parent {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-column-gap: 10px;
grid-row-gap: 10px;
}
Demo: https://jsfiddle.net/jc2utfs3/
For more detail you can follow this Link
.parent{
display: flex;
flex-wrap: wrap;
}
.parent .child{
flex: 1 1 25%;
/*Start Run Code Snippet output CSS*/
padding: 5px;
box-sizing: border-box;
text-align: center;
border: 1px solid #000;
/*End Run Code Snippet output CSS*/
}
<div class="parent">
<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>
I believe this example is more barebones and easier to understand then #dowomenfart.
.child {
display: inline-block;
margin: 0 1em;
flex-grow: 1;
width: calc(25% - 2em);
}
This accomplishes the same width calculations while cutting straight to the meat. The math is way easier and em is the new standard due to its scalability and mobile-friendliness.
.parent-wrapper {
height: 100%;
width: 100%;
border: 1px solid black;
}
.parent {
display: flex;
font-size: 0;
flex-wrap: wrap;
margin-right: -10px;
margin-bottom: -10px;
}
.child {
background: blue;
height: 100px;
flex-grow: 1;
flex-shrink: 0;
flex-basis: calc(25% - 10px);
}
.child:nth-child(even) {
margin: 0 10px 10px 10px;
background-color: lime;
}
.child:nth-child(odd) {
background-color: orange;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
</style>
</head>
<body>
<div class="parent-wrapper">
<div class="parent">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>
</div>
</body>
</html>
;)
Flex wrap + negative margin
Why flex vs. display: inline-block?
Flex gives more flexibility with elements sizing
Built-in white spacing collapsing (see 3 inline-block divs with exactly 33% width not fitting in parent)
Why negative margin?
Either you use SCSS or CSS-in-JS for the edge cases (i.e. first element in column), or you set a default margin and get rid of the outer margin later.
Implementation
https://codepen.io/zurfyx/pen/BaBWpja
<div class="outerContainer">
<div class="container">
<div class="elementContainer">
<div class="element">
</div>
</div>
...
</div>
</div>
:root {
--columns: 2;
--betweenColumns: 20px; /* This value is doubled when no margin collapsing */
}
.outerContainer {
overflow: hidden; /* Hide the negative margin */
}
.container {
background-color: grey;
display: flex;
flex-wrap: wrap;
margin: calc(-1 * var(--betweenColumns));
}
.elementContainer {
display: flex; /* To prevent margin collapsing */
width: calc(1/var(--columns) * 100% - 2 * var(--betweenColumns));
margin: var(--betweenColumns);
}
.element {
display: flex;
border: 1px solid red;
background-color: yellow;
width: 100%;
height: 42px;
}
you can try this
.parent-wrapper {
height:100%;
width:100%;
border: 1px solid black;
}
.parent {
display: grid;
font-size: 0;
grid-template-columns: 25% 25% 25% 25%;
}
.child {
background:blue;
flex-grow: 1;
height:100px;
margin: 10px;
margin-bottom: 0;
}
.child:last-child {
margin-bottom: 10px;
}
<body>
<div class="parent-wrapper">
<div class="parent">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>
</div>
</body>
https://jsfiddle.net/samet19/gdntwLhb/
Here's another way without using calc().
// 4 PER ROW
// 100 divided by 4 is 25. Let's use 21% for width, and the remainder 4% for left & right margins...
.child {
margin: 0 2% 0 2%;
width: 21%;
}
// 3 PER ROW
// 100 divided by 3 is 33.3333... Let's use 30% for width, and remaining 3.3333% for sides (hint: 3.3333 / 2 = 1.66666)
.child {
margin: 0 1.66666% 0 1.66666%;
width: 30%;
}
// and so on!
That's all there is to it. You can get fancy with the dimensions to get a more aesthetic sizes but this is the idea.