CSS Grid - wrap top items to the right - css

I am attempting to create a specific dynamic grid layout. There's two main components, a larger banner-type component (orange) and a component that is composed of several smaller components (green). On larger screens the smaller components should wrap on the side of the larger component, if not they should remain on top.
Currently I am using CSS grid to create the layout, but the larger item is essentially hardcoded to the second row. I can use media queries to change the row-start of the larger item, but the assumption is that the number of smaller items is potentially going to change. I am looking for a pure CSS solution.
.body {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 1.5rem;
}
.small-item {
width: 200px;
height: 100px;
background-color: green;
}
.large-item {
grid-column-start: 1;
grid-column-end: span 3;
grid-row-start: 2;
grid-row-end: span 2;
background-color: orange;
}
<div class='body'>
<div class='small-item'>Small item</div>
<div class='small-item'>Small item</div>
<div class='small-item'>Small item</div>
<div class='small-item'>Small item</div>
<div class='small-item'>Small item</div>
<div class='small-item'>Small item</div>
<div class='small-item'>Small item</div>
<div class='small-item'>Small item</div>
<div class='small-item'>Small item</div>
<div class='small-item'>Small item</div>
<div class='small-item'>Small item</div>
<div class='small-item'>Small item</div>
<div class='large-item'>Large item</div>
</div>

Related

Alternating rows using css grids and nth-child

I am working on a product grid with an alternating row pattern like this.
The color containers represent what I think the rows should look like.
Basically there are two products on the first row, and one product on the second row, repeating infinitely. I've been trying to do it with css grids + nth child, but I can't seem to get it right. Here's what I have so far:
.container {
display: grid;
grid-template-columns: 1fr 2fr;
grid-column-gap: 0;
width: 70vw;
margin: 0 auto;
}
.item:nth-child(3n+3) {
grid-column: auto / span 2;
background-color: #e2a7de;
}
/*just for debugging*/
.container{grid-gap:5px;}
.item{background-color: #ffa900;padding: 10px;text-align:center;}
<div class="container">
<div class="item">
X
</div>
<div class="item">
X
</div>
<div class="item">
X
</div>
<div class="item">
X
</div>
<div class="item">
X
</div>
</div>
My brain can't wrap around combining grids and nth-child to create this layout. I'm also open to a better way of creating this 2-1-2 pattern if anyone has other suggestions. Thank you!
You can simplify your code like below:
.container {
display: grid;
grid-auto-columns: 1fr; /* all columns equal */
width: 70vw;
margin: 0 auto;
}
.item:nth-child(3n) {
grid-column: span 2; /* span and create two columns*/
background-color: #e2a7de;
}
/*just for debugging*/
.container{grid-gap:5px;}
.item{background-color: #ffa900;padding: 10px;text-align:center;}
<div class="container">
<div class="item">
X
</div>
<div class="item">
X
</div>
<div class="item">
X
</div>
<div class="item">
X
</div>
<div class="item">
X
</div>
</div>
Update the grid-template-columns to be 1fr 1fr
.container {
display: grid;
grid-template-columns: 1fr 1fr;
grid-column-gap: 0;
width: 70vw;
margin: 0 auto;
}
.item:nth-child(3n+3) {
grid-column: auto / span 2;
background-color: #e2a7de;
}
/*just for debugging*/
.container{grid-gap: 5px;}.item {background-color: #ffa900;padding: 10px;text-align: center;}
<div class="container">
<div class="item">
X
</div>
<div class="item">
X
</div>
<div class="item">
X
</div>
<div class="item">
X
</div>
<div class="item">
X
</div>
</div>

Automatic offset / alignment in CSS grid?

I've a five column grid, which has in some cases only content in three columns. The content should be right aligned, so that there will be an offset of two columns. Is there a possibility to do this automatically? Actually I'm doing it with grid-column-start: 3, grid-column-start: 4, grid-column-start: 5:
.grid {
display: grid;
grid-template-columns: repeat(5, minmax(0, 1fr));
gap: 1rem;
margin: 2rem 0;
}
.col {
text-align: center;
padding: 2rem;
background-color: lightblue;
}
<div class="grid">
<div class="col">1</div>
<div class="col">2</div>
<div class="col">3</div>
<div class="col">4</div>
<div class="col">5</div>
</div>
<p>Actual syntax / layout:</p>
<div class="grid">
<div class="col">1</div>
<div class="col">2</div>
<div class="col">3</div>
</div>
<p>Should behave like this:</p>
<div class="grid">
<div class="col" style="grid-column-start: 3;">1</div>
<div class="col" style="grid-column-start: 4;">2</div>
<div class="col" style="grid-column-start: 5;">3</div>
</div>
Thought about something like justify-items: end but thats for the alignment of the content inside the column. For me I'm looking like even more a solution as it's behaviour in flexbox (justify-content), but I don't want to use flexbox ;)
Regards,
Markus
You can handle each case alone since they aren't a lot:
.grid {
display: grid;
grid-template-columns: repeat(5, minmax(0, 1fr));
gap: 1rem;
margin: 2rem 0;
}
.col {
text-align: center;
padding: 2rem;
background-color: lightblue;
}
.col:nth-last-child(1):first-child {
grid-column-end: -1;
}
.col:nth-last-child(2):first-child {
grid-column-end: -2;
}
.col:nth-last-child(3):first-child {
grid-column-end: -3;
}
.col:nth-last-child(4):first-child {
grid-column-end: -4;
}
<div class="grid">
<div class="col">1</div>
</div>
<div class="grid">
<div class="col">1</div>
<div class="col">2</div>
</div>
<div class="grid">
<div class="col">1</div>
<div class="col">2</div>
<div class="col">3</div>
</div>
<div class="grid">
<div class="col" >1</div>
<div class="col" >2</div>
<div class="col" >3</div>
<div class="col" >4</div>
</div>
<div class="grid">
<div class="col">1</div>
<div class="col">2</div>
<div class="col">3</div>
<div class="col">4</div>
<div class="col">5</div>
</div>

2 columns on desktop one column on mobile with flexbox

I´m trying to generate a list of users (2 per row on desktop and 1 per row in mobile)
this is my markup
<div class="users">
<div>user 1</div>
<div>user 2</div>
<div>user 3</div>
<div>user 4</div>
</div>
this is my SCSS
.users {
display: flex;
#media (min-width: 1025px) {
column-count: 2;
}
}
I´m not sure if column-count is meant to be used like this.
you can use Bootstrap grid system like this .
<div class="users row">
<div class="col-lg-6 col-12" >user 1</div>
<div class="col-lg-6 col-12">user 2</div>
<div class="col-lg-6 col-12">user 3</div>
<div class="col-lg-6 col-12">user 4</div>
</div>
did You mean something like that?
HTML:
<div class="users">
<div>user 1</div>
<div>user 2</div>
<div>user 3</div>
<div>user 4</div>
</div>
CSS
.users {
display: flex;
flex-wrap: wrap;
max-width: 900px;
}
.users div {
background-color: teal;
margin-right: 10px;
width: 400px;
}
demo here -> https://codepen.io/AdamKniec/pen/PoPxXvJ

Grid slices the content

I am trying to work a little with the css grids. Until now I have managed to stack these contents on top of each other, and when the screen gets smaller, I want to display them in 2 rows with 2 columns each.
The problem is that when doing so, the grid is slicing up the content? How can I prevent this from happening?
Here is the code I used:
#top-story {
grid-template-columns: repeat(auto-fit, minmax(450px, 1fr));
column-count: 4;
}
#top-story .top-news {
grid-row-start: 1;
grid-column-start: 1;
grid-column-end: 4;
}
#top-story .news-rows {
grid-row-start: 2;
column-count: 2;
}
Here is the HTML:
<div id="top-story">
<a href="#">
<div class="top-news">
<img src="images/test.jpg" />
<div id="gradient">
<div id="headline">
<div id="category">
Galleri
</div>
Forårstopscorer Jung: Fortjener ikke at blive sammenlignet med Kamil – endnu
</div>
</div>
</div>
</a>
<div class="news-rows">
Nyheder
<div style="width: 100%; height: 10px;"> </div>
<a href="#">
<div id="story">
<img src="images/test.jpg" />
<div id="seperator"> </div>
<div id="info">
<div id="inside-content">
<div id="category">
Galleri
</div>
Forårstopscorer Jung: Fortjener ikke at blive sammenlignet med Kamil – endnu
</div>
</div>
</div>
</a>
<br />
<a href="#">
<div id="story">
<img src="images/test.jpg" />
<div id="seperator"> </div>
<div id="info">
<div id="inside-content">
<div id="category">
Galleri
</div>
Forårstopscorer Jung: Fortjener ikke at blive sammenlignet med Kamil – endnu
</div>
</div>
</div>
</a>
<br />
<a href="#">
<div id="story">
<img src="images/test.jpg" />
<div id="seperator"> </div>
<div id="info">
<div id="inside-content">
<div id="category">
Galleri
</div>
Forårstopscorer Jung: Fortjener ikke at blive sammenlignet med Kamil – endnu
</div>
</div>
</div>
</a>
<br />
<a href="#">
<div id="story">
<img src="images/test.jpg" />
<div id="seperator"> </div>
<div id="info">
<div id="inside-content">
<div id="category">
Galleri
</div>
Forårstopscorer Jung: Fortjener ikke at blive sammenlignet med Kamil – endnu
</div>
</div>
</div>
</a>
</div>
</div>
top-news is the large image and news-rows is the one with the four contents.
See image of the issue here:
You have to design for Mobile first, then Desktop. You will use CSS3 #media but min-width i.e.: #media (min-width: 1024px){}. Remove column-count from your code. You have to design infinity column. You have to transfer the column where you want using grid-column-start and grid-row-start. Also you should use a CSS prefixer for browser support. Use classes instead of ids.
Here is the snippet.
.main-container{
display: grid;
grid-template-columns: repeat(1fr);
grid-row-gap: 30px;
margin-left: auto;
margin-right: auto;
max-width: 1024px;
width: 100%;
}
#media (min-width: 1024px){
.main-container{
grid-column-gap: 30px;
grid-template-columns: repeat(2, 1fr);
}
}
.child-item{
background-color: green;
border: 2px solid black;
border-radius: 3px;
color: white;
height: 100px;
padding: 15px;
text-transform: uppercase;
}
#media (min-width: 1024px){
.box-3{
grid-column-start: 2;
grid-row-start: 1;
}
.box-4{
grid-column-start: 2;
grid-row-start: 2;
}
}
<div class="main-container">
<div class="child-item box-1">Box 1</div>
<div class="child-item box-2">Box 2</div>
<div class="child-item box-3">Box 3</div>
<div class="child-item box-4">Box 4</div>
</div>
Explanation of the code:
First .main-container creates grid for Mobile view where use grid-template-columns: repeat(1fr);. No grid column-count property. Instead of margin-bottom I use grid-row-gap: 30px; for space between column in bottom. If browser window is more than or equal to 1024px, grid-template-columns: repeat(2, 1fr); /* Create two column in side by side */ and use grid-column-gap: 30px; for separated from side by side column.
At this point in Desktop your box will be look like this.
Second, if you want to transfer box-3 where is box-2 in Desktop view in #media box-3 will be grid-column-start: 2;, grid-row-start: 1; and box-4 grid-column-start: 2;, grid-row-start: 2;. Box 4 will be auto resize when you set column 3 specific CSS.
Now Desktop view change like this.
Please read about CSS Grid here.

CSS3 grid layouts: New row after specific element - possible?

I've got a list of items, sorted by date.
Some of the items are in the future (green items), thus more interesting, some are in the past (brown items). I want the second group of items to start in a new row.
.grid{
width: 120px;
display:grid;
grid-template-columns: repeat(3,1fr);
grid-gap: 10px;
}
.item{
border:1px solid black;
height:50px;
width:50px;
}
.green{
background:green;
}
.brown{
background:brown;
}
<div class="grid">
<div class="item green"></div>
<div class="item green"></div>
<div class="item green"></div>
<div class="item green"></div>
<div class="item green"></div>
<div class="item brown"></div>
<div class="item brown"></div>
<div class="item brown"></div>
<div class="item brown"></div>
</div>
The number of overall items / items per category is constantly changing, the number of Items per row depends on screen size - that might eliminate some possible solutions to this.
I could of course split the array containing all items at a certain point and organize the output into two separate grids, like so:
.grid{
width: 120px;
display:grid;
grid-template-columns: repeat(3,1fr);
grid-gap: 10px;
margin-bottom:10px;
}
.item{
border:1px solid black;
height:50px;
width:50px;
}
.green{
background:green;
}
.brown{
background:brown;
}
<div class="grid">
<div class="item green"></div>
<div class="item green"></div>
<div class="item green"></div>
<div class="item green"></div>
<div class="item green"></div>
</div>
<div class="grid">
<div class="item brown"></div>
<div class="item brown"></div>
<div class="item brown"></div>
<div class="item brown"></div>
</div>
Probably that's the easiest option. Looks like what I want to achieve & isn't too difficult to do. But anyway, I'm curious: Is there a more elegant approach to this? I was thinking something like:
.item.green + .item.brown:before {
/* force new row */
}
You could target the first .brown after .green and set grid-column-start to 1.
.grid {
width: 120px;
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 10px;
}
.item {
border: 1px solid black;
height: 50px;
width: 50px;
}
.green {
background: green;
}
.brown {
background: brown;
}
.green + .brown {
grid-column-start: 1;
}
<div class="grid">
<div class="item green"></div>
<div class="item green"></div>
<div class="item green"></div>
<div class="item green"></div>
<div class="item green"></div>
<div class="item brown"></div>
<div class="item brown"></div>
<div class="item brown"></div>
<div class="item brown"></div>
</div>
Since you are using grid-template-columns, you won't be able to acheive this with before or after, you would need to set the grid-column-start to 1 with the item.green + .item.brown selection:
.grid{
width: 120px;
display:grid;
grid-template-columns: repeat(3,1fr);
grid-gap: 10px;
}
.item{
border:1px solid black;
height:50px;
width:50px;
}
.green{
background:green;
}
.brown{
background:brown;
}
.item.green + .item.brown {
grid-column-start: 1;
}
<div class="grid">
<div class="item green"></div>
<div class="item green"></div>
<div class="item green"></div>
<div class="item green"></div>
<div class="item green"></div>
<div class="item brown"></div>
<div class="item brown"></div>
<div class="item brown"></div>
<div class="item brown"></div>
</div>
The approach that I came up with is definitely the longest one, but if for what ever reason you need to have a modular design I think this way would save you time in the end. Added grid-areas and added individual class for all your tiles.
.grid{
width: 120px;
display:grid;
grid-template-columns: repeat(3,1fr);
grid-template-areas: "green1 green2 green3"
"green4 green5 green6"
"green7 green8 green9"
"brown1 brown2 brown3"
"brown4 brown5 brown6";
grid-gap: 10px;
}
.item{
border:1px solid black;
height:50px;
width:50px;
}
.green1 {
background:green;
grid-area: green1;
}
.green2 {
background:green;
grid-area: green2;
}
.green3 {
background:green;
grid-area: green3;
}
.green4 {
background:green;
grid-area: green4;
}
.green5 {
background:green;
grid-area: green5;
}
.brown1{
grid-area: brown1;
background:brown;
}
.brown2{
grid-area: brown2;
background:brown;
}
.brown3{
grid-area: brown3;
background:brown;
}
.brown4{
grid-area: brown4;
background:brown;
}
<div class="grid">
<div class="item green1"></div>
<div class="item green2"></div>
<div class="item green3"></div>
<div class="item green4"></div>
<div class="item green5"></div>
<div class="item brown1"></div>
<div class="item brown2"></div>
<div class="item brown3"></div>
<div class="item brown4"></div>
</div>

Resources