How to arrange items in css grid with auto heights - css

I want to make a fairy simple looking layout with css grid.
As, shown in above image, i want to place 3 items in a grid in the exact same order as shown in the image, I don't want to set specific height to any of the item, since each of the item have different height depending upon the content in it. I want to give 70% of grid horizontal space to item1 and 30% to item2 & item3, item3 should be placed beneath item2. Again, heights of items should be auto. I am trying to achieve this for many hours but failed to do so.
Markup of the problem:
<div class="container">
<div class="item1">some content in it...</div>
<div class="item2">some Content in it...</div>
<div class="item3">some Content in it...</div>
</div>

Solution as requested:
You could use grid-template-areas to span the first item across multiple rows. And use a spacer at the end of the right column to make the items just as big as needed.
We can use calc to account for the grip-gap.
.grid {
display: grid;
grid-gap: 20px;
grid-template-columns: calc(70% - 10px) calc(30% - 10px);
grid-template-areas: "item-1 item-2" "item-1 item-3" "item-1 spacer";
border: 1px dashed #000;
align-items: start;
}
.item {
display: flex;
justify-content: center;
align-items: center;
font-size: 32px;
font-weight: bold;
}
#media screen and (max-width: 600px) {
.grid {
grid-template-areas: "item-2" "item-1" "item-3";
grid-template-columns: 100%;
}
}
.item-1 {
grid-area: item-1;
}
.item-2 {
grid-area: item-2;
}
.item-3 {
grid-area: item-3;
}
.purple {
background-color: #5B00FF;
}
.red {
background-color: #FF0000;
}
.pink {
background-color: #FF00FD
}
.h-500 {
height: 500px;
}
.h-100 {
height: 100px;
}
.h-200 {
height: 200px;
}
<div class="grid">
<div class="item item-1 purple h-500">Item 1</div>
<div class="item item-2 red h-100">Item 2</div>
<div class="item item-3 pink h-200">Item 3</div>
</div>
Alternative solution with different columns:
You could use grid-gap along with grid-template-columns. You have to take the grid-gap into account for the width of template-column That's why there is this calc.
.grid {
display: grid;
grid-gap: 20px;
grid-template-columns: calc(70% - 10px) calc(30% - 10px);
border: 1px dashed #000;
}
.col--right {
display: flex;
flex-flow: column nowrap;
gap: 20px;
}
.item {
display: flex;
justify-content: center;
align-items: center;
font-size: 32px;
font-weight: bold;
}
.purple {
background-color: #5B00FF;
}
.red {
background-color: #FF0000;
}
.pink {
background-color: #FF00FD
}
.h-500 {
height: 500px;
}
.h-100 {
height: 100px;
}
.h-200 {
height: 200px;
}
<div class="grid">
<div class="col col--left">
<div class="item purple h-500">Item 1</div>
</div>
<div class="col col--right">
<div class="item red h-100">Item 2</div>
<div class="item pink h-200">Item 3</div>
</div>
</div>

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>

why does the height of the last item in my grid affect the width of the top level grid items?

https://jsfiddle.net/nqfzks6m/1/
above is the jsfiddle for my grid. As you can see, if you change the height of card-4-content to 50px, card 1 becomes slightly wider and card 2 becomes less wide. What is causing this? The grid template columns are set to "auto auto auto auto". I can't see why the height of the bottom row would affect the width of the top level row.
.base-card {
border: 1px solid black;
}
.card-1 {
grid-area: card-1;
background-color: red;
}
.card-2 {
grid-area: card-2;
background-color: blue;
}
.card-3 {
grid-area: card-3;
background-color: purple;
}
.card-4 {
grid-area: card-4;
background-color: pink;
}
.card-4-content {
height: 50px;
}
.container {
display: grid;
grid-template-columns: auto auto auto auto;
grid-gap: 25px;
grid-template-rows: 155px 160px auto auto;
grid-template-areas: "card-1 card-1 card-2 card-2" "card-1 card-1 card-2 card-2" "card-3 card-3 card-3 card-3" "card-4 card-4 card-4 card-4";
}
<div class="container">
<div class="card-1">
<div class="base-card">
card-1
</div>
</div>
<div class="card-2">
<div class="base-card">
card-2
</div>
</div>
<div class="card-3">
<div class="base-card">
card-3
</div>
</div>
<div class="card-4">
<div class="base-card card-4-content">
card-4
</div>
</div>
</div>

CSS Flex item spanning two rows without fixed height

I am trying to create a flex container layout whereby one of the flex items should span two rows. See image below for a better explanation:
Here is my markup:
<div class="container">
<div class="item item-1">ITEM 1</div>
<div class="item item-2">ITEM 2</div>
<div class="item item-3">ITEM 3</div>
</div>
I cannot seem to achieve this, I have tried using flex-wrap and different combinations of the flex property.
I was able to achieve this by putting ITEM 1 & ITEM 2 in a separate <div>, but this presents a problem on a smaller screen, whereby ITEM 3 needs to appear BETWEEN ITEM 1 & ITEM 2. So I would rather keep the markup as is and use the order property to move things around as necessary.
You can use display: contents on your extra div to achieve what you want:
* {
box-sizing: border-box;
}
.container {
display: flex;
width: 100%;
}
.holder {
width: 67%;
}
.item {
border: 1px solid black;
}
.item-1 {
margin-bottom: 40px;
}
.item-3 {
width: 33%;
}
#media screen and (max-width: 700px) {
.container {
flex-direction: column;
}
.item {
margin-bottom: 20px;
}
.item-1 {
order: 1;
}
.item-2 {
order: 3;
}
.item-3 {
order: 2;
width: 100%;
}
.holder {
width: 100%;
display: contents;
}
}
<div class="container">
<div class="holder">
<div class="item item-1">ITEM 1</div>
<div class="item item-2">ITEM 2</div>
</div>
<div class="item item-3">ITEM 3</div>
</div>
You can't achieve it using flexbox. Instead, you should have two parents which are better.
Use Css-grid. Actually, css-grid is the best option in this case.
Flex-Box
* {
color: #fff;
}
.flex {
display: flex;
justify-content: center;
align-items: center;
}
.child {
border-radius: 10px;
}
.container {
display: flex;
width: 500px;
height: 200px;
border: 1px solid #ff0000;
}
.container .first-item {
flex-direction: column;
justify-content: space-between;
align-items: start;
width: 50%;
height: 100%;
margin-right: 10px;
}
.first-item .child {
width: 100%;
height: 50%;
background-color: blue;
}
.first-item .child:first-child {
margin-bottom: 10px;
}
.container .second-item {
width: 50%;
height: 100%;
}
.second-item .child {
width: 100%;
height: 100%;
background-color: blue;
}
<div class="container">
<div class="first-item flex">
<div class="child flex">Item 1</div>
<div class="child flex">Item 2</div>
</div>
<div class="second-item flex">
<div class="child flex">Item 3</div>
</div>
</div>
Grid
.flex {
display: flex;
justify-content: center;
align-items: center;
}
.child {
background-color: blue;
border-radius: 10px;
}
.container {
display: grid;
grid-template-columns: 1fr 10px 1fr;
grid-template-rows: 1fr 10px 1fr;
grid-template-areas: "c1 . c3"
". . c3"
"c2 . c3";
width: 500px;
height: 300px;
border: 1px solid red;
}
.container .child {
border: 1px solid blue;
}
.child1 {
grid-area: c1;
}
.child2 {
grid-area: c2;
}
.child3 {
grid-area: c3;
}
<div class="container">
<div class="child child1 flex">Item 1</div>
<div class="child child3 flex">Item 3</div>
<div class="child child2 flex">Item 2</div>
</div>
i dont know if its a good solution but
put two item3 codes one in the individual div (item1&2) and one outside then put the one in the div to display none in non-small screens and switch between them with mediaquery
#media (max-width: 40rem) {
.item3 {
display: none;
}
.mobile-item3{
display: block;
}
}

Repeating CSS grid without defining more grid areas

I'm trying to use CSS grid to layout some content in the following constraints.
I have three divs - all should be 50% wide but div two and three should stack on top of each other next to div 1.
I've managed to achieve this using grid-template-areas, but I'm using PHP to dynamically populate this, so there's no guarantee that there will always be three divs, so if it goes over this amount, I simply want the grid to repeat.
I'm using the following code right now:
.container {
display: grid;
grid-template-columns: 50% 50% 50%;
gap: 0px 0px;
grid-auto-flow: row;
grid-template-areas:
"Grid-1 Grid-2 ."
"Grid-1 Grid-3 ."
". . .";
}
.Grid-2 { grid-area: Grid-2; }
.Grid-3 { grid-area: Grid-3; }
.Grid-1 { grid-area: Grid-1; }
html, body , .container {
height: 100%;
margin: 0;
}
.container * {
border: 1px solid red;
position: relative;
}
.container *:after {
content:attr(class);
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: grid;
align-items: center;
justify-content: center;
}
<div class="container">
<div class="Grid-1"></div>
<div class="Grid-2"></div>
<div class="Grid-3"></div>
</div>
It would also ne nice to not have to give each div that I'm generating a PHP the specific area class. Is this achievable using grid?
Simply like below:
.container {
display: grid;
grid-template-columns: 50% 50%; /* 2 columns */
grid-auto-rows:50vh; /* size of one row*/
}
/* for each 3 divs make the first one span 2 rows */
.container > :nth-child(3n + 1) { grid-row:span 2 }
.container * {
border: 1px solid red;
display: grid;
place-items: center;
}
.container *:after {
content:"some content";
}
body {
margin: 0;
}
<div class="container">
<div ></div>
<div ></div>
<div ></div>
<div ></div>
<div ></div>
<div ></div>
<div ></div>
<div ></div>
</div>

How can I reorder a grid of columns?

What I have is a two-column layout with several items inside:
.grid {
column-count: 2;
}
.grid-item {
break-inside: avoid;
height: 50px;
margin-bottom: 10px;
background-color: green;
text-align: center;
line-height: 50px;
color: white;
}
<div class="grid">
<div class="grid-item">1</div>
<div class="grid-item">2</div>
<div class="grid-item">3</div>
<div class="grid-item">4</div>
<div class="grid-item">5</div>
</div>
https://codepen.io/Deka87/pen/RgdLeZ
Now I need an ability to reorder those items inside the columns with CSS only (so they were in a different order on different screen resolutions), so I thought I can do this with:
.grid {
display: flex;
flex-direction: column;
column-count: 2;
}
.grid-item:nth-child(1) {
order: 5;
}
Obviously, this didn't work and broke the 2-column layout. Anybody tried to solve this before? Any chance I can get this working?
PS: Items on the same line should not be of the same height (I could have used simple floats in this case). Sorry for not specifying in the beginning.
Without a fixed height on the container, a column of flex items won't know where to wrap. There's nothing to cause a break, so items will continue expanding the single column.
Also, column-count and display: flex represent two different CSS technologies. column-count is not a valid property in a flex container.
CSS Grid Layout may be useful to you:
re-size the screen width to trigger the media query
revised codepen
.grid {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: repeat(3, auto);
grid-auto-rows: 50px;
grid-auto-flow: column;
grid-gap: 10px;
}
.grid-item {
background-color: green;
text-align: center;
line-height: 50px;
color: white;
}
#media ( max-width: 500px) {
.grid-item:nth-child(2) {
order: 1;
background-color: orange;
}
}
<div class="grid">
<div class="grid-item">1</div>
<div class="grid-item">2</div>
<div class="grid-item">3</div>
<div class="grid-item">4</div>
<div class="grid-item">5</div>
</div>
I tend to use flexbox for this
.grid {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: flex-start;
}
.grid-item {
box-sizing: border-box;
width: calc( 50% - 5px );
min-height: 50px;
margin-bottom: 10px;
background-color: green;
text-align: center;
line-height: 50px;
color: white;
}
.grid-item:nth-child(1) {
order: 5;
}
<div class="grid">
<div class="grid-item">1</div>
<div class="grid-item">2</div>
<div class="grid-item">3</div>
<div class="grid-item">4</div>
<div class="grid-item">5</div>
</div>
The flex syntax is widely supported and super flexible.

Resources