How to show only three items per row? - css

I want to created a wrapper component in React, which take a children items, and the wrapper should only show three items per row (inputs, checkboxes, whatever).
And also for bigger screens the cells should not stretch, and items have to be grouped tightly. But when the screen shrinks, items have to wrap and change number of columns.
That's how it should be for bigger screens:
I thought css grid perfectly fits, but I can't find the proper way to do so.

Since you don't have any code shared, this is difficult to answer because we have no reference/starting point of where you are at.
Here is a blitz I put together for you showing a few ways to achieve what I think you need.
EDIT: Here is a snippet of the three options I included.
Option 1: Limit the number of children per parent. Then you can add a flexbox to the parent to control wrapping. Repeat this for how ever many you need.
<div class="parent">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div> //repeat
Option 2: Flex Basis
<div class="parent2">
<div class="child2">
<div class="grandchild"></div>
</div>
<div class="child2">
<div class="grandchild"></div>
</div>
</div> // Put your data inside the grandchild component and add a flex basis to the child component
Option 3: Flex and Position
<div class="parent3">
<div class="child3">
<h2>1 </h2>
</div>
<div class="child3">
<h2>2</h2>
</div>
<div class="child3">
<h2>3</h2>
</div>
<div class="spacing"></div>
<div class="child3">
<h2>4 </h2>
</div>
<div class="child3">
<h2>5</h2>
</div>
<div class="child3">
<h2>6</h2>
</div>
</div>
Here are all the styles I used
.parent {
display: flex;
font-size: 0;
flex-wrap: wrap;
margin: 10px;
}
.child {
background: blue;
margin: 10px 0 0 10px;
height: 100px;
width: 100px;
}
/* ....................................... */
.parent2 {
display: flex;
font-size: 0;
flex-wrap: wrap;
margin: 10px;
}
.child2 {
flex-basis: 30%;
background: lightblue;
margin: 10px 0 0 10px;
height: 100px;
width: 100px;
}
.grandchild {
border: 3px solid red;
height: 50px;
width: 50px;
}
/* ....................................... */
.parent3 {
width: 100%;
min-height: 100px;
height: auto;
display: flex;
justify-content: flex-start;
flex-wrap: wrap;
}
.child3 {
width: 100px;
height: 100px;
background-color: lightgreen;
margin: 10px;
position: relative;
}
.spacing {
width: 100%;
height: 5%;
}

Related

Grid layout but avoid space distribute equally

I'm trying to use the grid layout for two columns in one row which can be easily achieved by flex. I have to create one more div for flex but the grid doesn't need one more div.
The problem with the grid is that it will divide the width space by 2 (cannot align to start/left) and that's not what I want, please refer to the first example below and you will understand.
Is there any way to use the grid in this situation but we can align the items to the left like in the second example?
#main-1 {
display: grid;
gap: 30px;
grid-teplate-column: repeat(2, minmax(0, 1fr));
}
.test-1 {
background-color: orange;
grid-area: span 1 / span 2;
}
.test-2 {
background-color: gray;
width: 150px;
}
#main-2 {
display: flex;
gap: 30px;
margin-top: 30px;
}
.test-3 {
background-color: orange;
width: 100%;
}
.test-4 {
background-color: gray;
width: 150px;
}
.test-1,
.test-2,
.test-3,
.test-4 {
height: 60px;
}
<h1>Grid</h1>
<div id="main-1">
<div class="test-1"></div>
<div class="test-2"></div>
<div class="test-2"></div>
</div>
<h1 style="margin:30px 0 0 0;padding-top:15px;border-top: 3px solid #000;">Flex</h1>
<p style="margin:0 0 30px 0;">This is the desired layout but with one more extra div</p>
<div>
<div class="test-3"></div>
<div id="main-2">
<div class="test-4"></div>
<div class="test-4"></div>
</div>
</div>
Edited
Inline-block might work but we cannot control how many items should be on each row. Imagine the width of the first div .first is dynamic and we do not know how wide it would be(but I will make it 30px for illustration). Now the desired layout should be only one .first and one .second on each row.
By inline-block it would appear that now each row is one .first, one .second, and one .first. Check out the example below. Because we cannot control the amount like grid on each row.
#main {
width: 120px;
}
.first,
.second {
display: inline-block;
height: 60px;
}
.first {
background-color: orange;
width: 30px;
}
<div id="main">
<div class="first"></div>
<p class="second">hhhhhh</p>
<div class="first"></div>
<p class="second">hhhhhh</p>
<div class="first"></div>
<p class="second">hhhhhh</p>
</div>
Define the columns as auto and keep only one at 1fr then you can align to the left.
#main-1 {
display: grid;
gap: 30px;
/* update "5" based on your needs */
grid-template-columns: repeat(5,auto) 1fr;
justify-content: left; /* align to left */
}
.test-1 {
background-color: orange;
grid-column: 1/-1; /* take all the columns */
}
.test-2 {
background-color: gray;
width: 150px;
}
#main-2 {
display: flex;
gap: 30px;
margin-top: 30px;
}
.test-3 {
background-color: orange;
width: 100%;
}
.test-4 {
background-color: gray;
width: 150px;
}
.test-1,
.test-2,
.test-3,
.test-4 {
height: 60px;
}
<h1>Grid</h1>
<div id="main-1">
<div class="test-1"></div>
<div class="test-2"></div>
<div class="test-2"></div>
</div>
<h1 style="margin:30px 0 0 0;padding-top:15px;border-top: 3px solid #000;">Flex</h1>
<p style="margin:0 0 30px 0;">This is the desired layout but with one more extra div</p>
<div>
<div class="test-3"></div>
<div id="main-2">
<div class="test-4"></div>
<div class="test-4"></div>
</div>
</div>

How to horizontally align list item child elements with dynamic data with CSS

I'm wondering if its possible using CSS to horizontally align each child-element within a collection of items (<section>in code snippet) when the title (<h1> in code snippet) and description (<p> in code snippet) can have dynamic lengths.
For this to work, each parent elements height would have to adjust to be the same height as the largest parent element on the same line.
I don't want to explicitly set the height of each item (<section>), to keep items dynamically as small as possible.
The end result should have the first line of all item child-elements aligned horizontally to all its neighbouring item child-elements.
html, body {
margin: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100%;
transform: scale(0.8);
}
section {
width: 272px;
height: 321px;
background-color: whitesmoke;
display: flex;
flex-direction: column;
justify-content: space-between;
margin: 0 50px;
}
.img {
width: 64px;
height: 64px;
background-color: grey;
min-height: 64px;
}
div, h1, p {
border: solid 1px;
margin: 0;
}
.wrapper {
display: flex;
flex-direction: column;
height: 100%;
margin: 10px 0;
}
h1 {
flex: 1;
font-size: 1.5rem;
}
p {
flex: 1;
margin-top: 10px;
font-size: 22px;
}
<section>
<div class="img"></div>
<div class="wrapper">
<h1>This is a short title</h1>
<p>This is a short description</p>
</div>
<div class="download">Download</div>
</section>
<section>
<div class="img"></div>
<div class="wrapper">
<h1>This is a much longer title that will push the description element down too far, so that it is no longer aligned with the first section desc</h1>
<p>This is a short description</p>
</div>
<div class="download">Download</div>
</section>
<section>
<div class="img"></div>
<div class="wrapper">
<h1>This is a short title </h1>
<p>This is an extra long description that will push upwards so that the text can fit, but again is no longer aligned horizontally to first</p>
</div>
<div class="download">Download</div>
</section>

CSS Flex dynamic grid with multiple sizes

I have a problem with flex.
I have a wrapper where a minimum of 1 and maximum of 9 squares can be shown. Squares can have multiple sizes, based on the number of squares in grid.
I've got all required cases working except for one, as seen in this picture:
My styles are:
.grid {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
align-content: space-between;
width: 300px;
height: 300px;
position: relative;
}
Plus. the images have sized based on the overall number of them and their position in a list.
So the problem is in situation when I have 1 big square (takes position of 4 small squares) and 5 small squares around him from right and bottom.
The big one is first as he should be.
Next to him (top right corner) is second one, that's also correct.
The third one is in bottom left corner, and it should be in the second line and on the far right. Because of this one, all the others are in wrong position, so the last one is overflowing.
I've tried a lot of value combinations for justify-content, align-content, align-items and align-self but nothing have worked.
I'll go back to ton of classes and position absolute solution, if there is no flex solution for this. But I don't like it. It's too much styles and it doesn't look good.
Any advice would be greatly appreciated.
I think float is a better option for you, check out this snippet:
.grid {
width: 300px;
}
.box {
background: orange;
width: 90px;
height: 90px;
margin: 5px;
float: left;
}
.wide {
width: 190px;
}
.tall {
height: 190px;
}
.empty {
background: transparent
}
/* you can ignore everything after this comment - it's all for illustration */
body {
background: #334;
color: white;
font-family: sans-serif;
}
.example {
display: inline-block;
margin: 5px;
border: 1px solid #445;
padding: 10px;
width: 300px;
}
h3 {
margin: 0 0 5px 0;
}
<div class="example">
<h3>Example 1</h3>
<div class="grid">
<div class="box wide tall"></div>
<div class="box tall empty"></div>
<div class="box wide empty"></div>
<div class="box"></div>
</div>
</div>
<div class="example">
<h3>Example 2</h3>
<div class="grid">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
</div>
<div class="example">
<h3>Example 4</h3>
<div class="grid">
<div class="box wide tall"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
</div>
Flex is still trying to make complete rows of elements, so your big square and your little square are part of one row; there's no support for stacking beyond that.
Float on the other hand tries to stuff elements wherever it can fit them.
EDIT
I've updated this answer with examples on how to reproduce most of the images above (I've purposefully left out the 2 by 2 example - didn't want to cloud the answer with classes for boxes of 1.5 height/width).
Use of an empty class to remove color from blocks, as well as classes tall and wide to fill in spots of all sizes should help you customize your layout however you see fit. One note - here empty sets the background color to transparent. Your empty class may do more or less than this. You may not even need an empty class if all it is is a div without content.
There is no way to handle this layout with flex in a single container.
You need to do a little trick to achieve it.
The easier one would be to take the third item out of the flex layout, positioning it absolute:
.grid {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
align-content: space-between;
width: 300px;
height: 300px;
position: relative;
}
.item {
background-color: lightblue;
width: 100px;
height: 100px;
margin: 0px;
border: transparent solid 5px;
box-sizing: border-box;
background-clip: content-box;
}
.item:first-child {
width: 200px;
height: 200px;
}
.item:nth-child(2) {
background-color: blue;
position: absolute;
top: 100px;
right: 0px;
}
<div class="grid">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
Another posibility, may be more in the flex idea, but also tricky
Set the big element with a margin-bottom negative, that makes it occupy only 1 row (being the height of a row the size of the small boxes).
Now be have a layout with 3 rows. The problem will be that the 3rd box will be under the first, big box. To solve this, we are setting a pseudo element (I have styled the snippet to make it visible, in production just set it to height 0 and it will disappear) with the same properties of width and margin of the first element.
.grid {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
align-content: space-between;
width: 300px;
height: 300px;
position: relative;
}
.grid:after {
content: "";
order: 3;
background-color: red;
width: 190px;
height: 10px;
margin: 5px;
}
.item {
background-color: lightblue;
width: 90px;
height: 90px;
margin: 5px;
}
.item:first-child {
width: 190px;
height: 190px;
margin-bottom: -100px;
order: 1;
opacity: 0.5;
}
.item:nth-child(2) {
order: 2;
}
.item:nth-child(n+3) {
order: 4;
}
<div class="grid">
<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>

Flex item override max-width property

I am trying to make a flex container of divs in which all the divs will have the same width (two divs per line, 50% width of the container each of them).
I have set the divs inside the container with max-width: 50%; because I want them to be equals but it does not seem to respect this max-width when there is only one item in this line.
HTML:
<div id="container">
<div id="left" class="block">Left</div>
<div id="center" class="block">
<div class="flexContainer">
<div class="flexDiv"></div>
</div>
<div class="flexContainer">
<div class="flexDiv"></div>
</div>
<div class="flexContainer">
<div class="flexDiv"></div>
</div>
</div>
<div id="right" class="block">Right</div>
</div>
CSS:
html, body{
width: 100%;
height: 100%;
}
#container{
display: flex;
height: 100%;
background-color: blue;
}
.block{
flex: 1;
}
#left{
background-color: green;
}
#center{
display: flex;
flex: 1;
flex-wrap: wrap;
align-content: flex-start;
}
#right{
background-color: orange;
}
.flexContainer{
flex: 1;
min-width: 100px;
max-width: 50%;
height: 150px;
background-color: red;
padding: 10px;
}
.flexDiv{
width: 100%;
height: 100%;
background-color: yellow;
}
JSFiddle in which you can see how the width of the third element is bigger than the others.
Why the flex divs inside the container are not respecting max-width property?
Thanks in advance!
you can reset or switch box model to include padding within width calculation:
https://developer.mozilla.org/en-US/docs/Web/CSS/box-sizing
https://www.w3.org/TR/css-ui-3/#box-sizing
.flexContainer{
flex: 1;
min-width: 100px;
max-width: 50%;
height: 150px;
background-color: red;
padding: 10px;
box-sizing:border-box;/* includes borders & padding within width calculation
}
https://jsfiddle.net/b5h9rjcd/1/

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