Responsive checkerboard grid in CSS? - css

This snippet contains a responsive grid. As you change the screen width the number of columns varies automatically. Sometimes there is an even number of columns, sometimes there is an odd number. When there is an odd number of columns, the cells alternate colours like a checkerboard, but when there is an even number of columns, they do not. Is there any way to achieve the checkerboard effect for even numbers of columns as well as odd numbers? Does it require Javascript, or can it be done using CSS alone?
body {
margin: 0;
}
.checkers {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(8em, 1fr));
padding: 1em;
gap: 1em;
}
.checkers>div {
background-color: red;
aspect-ratio: 1/1;
}
.checkers>div:nth-child(even) {
background-color: blue;
}
<div class="checkers">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>

If you can omit the use of 1fr and consider fixed width elements, you can do this using some background trick:
.checkers {
display: grid;
grid-template-columns: repeat(auto-fit, 8em);
padding: 1em;
gap: 1em;
position: relative; /* Relative on the main container */
z-index:0;
}
.checkers > div {
aspect-ratio: 1;
clip-path: inset(0); /* clip the pseudo element to element*/
}
.checkers > div:before {
content:"";
position: absolute;
z-index:-1;
inset: 1em; /* same as padding */
/* create a checkboard pattern using gradient
18em = (8em + 1em[gap])*2
*/
background: repeating-conic-gradient(red 0 25%,blue 0 50%) 0 0/18em 18em;
}
body {
margin: 0;
background: pink;
counter-reset: num;
}
.checkers div:after {
content: counter(num);
counter-increment: num;
color:#fff;
font-weight:900;
font-size: 25px;
}
<div class="checkers">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>

As far as I can tell, this cannot be done for an even number of columns. What you can do is ensure there is always an odd number of columns. You will need to explicitly set an odd number of columns for grid-template-columns, which can be adjusted with media queries.
In this snippet I have borrowed the breakpoints from Bootstrap as a starting point. I have initially set the grid to have 3 columns minimum (grid-template-columns: repeat(3, 1fr);), then increment by 2 (next odd number) at each breakpoint up to 13 columns:
body {
margin: 0;
}
.checkers {
display: grid;
grid-template-columns: repeat(3, 1fr);
padding: 1em;
gap: 1em;
overflow: hidden;
}
.checkers>div {
background-color: red;
aspect-ratio: 1/1;
}
.checkers>div:nth-child(even) {
background-color: blue;
}
#media (min-width: 576px) {
.checkers {
grid-template-columns: repeat(5, 1fr);
}
}
#media (min-width: 768px) {
.checkers {
grid-template-columns: repeat(7, 1fr);
}
}
#media (min-width: 992px) {
.checkers {
grid-template-columns: repeat(9, 1fr);
}
}
#media (min-width: 1200px) {
.checkers {
grid-template-columns: repeat(11, 1fr);
}
}
#media (min-width: 1400px) {
.checkers {
grid-template-columns: repeat(13, 1fr);
}
}
<div class="checkers">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
You can adjust the breakpoint sizes to be multiples of your grid square sizes to get it dialed in to your liking.

Related

CSS Grid Margin Top for entire columns

Is it possible to shift all 2nd/even grid colums as a whole like in the image using CSS grid?
My current css code situation is very simple, it looks like this:
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 24px;
I am trying to achive something that looks like the following image:
You can use the :nth-child() pseudo class to achieve this. This is how I approached it:
<div class="container">
<div class="cards">
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
</div>
</div>
.container{
max-width: 900px;
margin: 0 auto;
height: auto;
}
.cards{
display: grid;
place-items: center;
grid-template-columns: repeat(4,1fr);
gap: 5px;
}
.card{
width: 200px;
height: 250px;
border: 3px solid black;
}
.card:nth-child(2n-2){
position: relative;
top: 100px;
}
/* or use margin */
/*
.card:nth-child(2n-2){
margin-top: 100px;
}
*/
Here is the codepen link: https://codepen.io/glenhug/pen/QWrWXJY
Also this is post had a nice explanation: How to target a specific column or row in CSS Grid Layout?
This might do the trick.
.grid-container {
width: min-content;
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-gap: 10px;
}
.grid-container > div {
width: 50px;
height: 50px;
border: 1px solid black;
}
.grid-container div:nth-child(2n) {
position: relative;
top: 15px;
}
<div class='grid-container'>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
Not with CSS grid but combining inline-block, float and shape-outside you can do it and it will be responsive and works with any element.
Find all the details in my article: https://css-tricks.com/hexagons-and-beyond-flexible-responsive-grid-patterns-sans-media-queries/
Here is a demo:
.main {
display:flex;
--s: 100px; /* size */
--r: 1; /* ratio */
--mv: 4px; /* margin */
--vc: calc(var(--s) * var(--r) * .5);
--mh: calc(var(--mv) + var(--s)/2);
--f: calc(2*var(--s)*var(--r) + 4*var(--mv) - 2*var(--vc) - 2px);
}
.container {
font-size: 0; /*disable white space between inline block element */
}
.container div {
width: var(--s);
margin: var(--mv) var(--mh);
height: calc(var(--s)*var(--r));
display: inline-block;
font-size: initial;
background: red;
margin-bottom: calc(var(--mv) - var(--vc));
}
.container div:nth-child(odd) {
background: green;
}
.container::before {
content: "";
width: calc(var(--s)/2 + var(--mh));
float: left;
height: 135%;
shape-outside: repeating-linear-gradient(
#0000 0 calc(var(--f) - 2px),
#000 0 var(--f));
}
<div class="main">
<div class="container">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</div>

How do you (dynamically) justify cells to the right with CSS Grid?

I have a 2 col 2 row grid with 3 of the items/cells occupied.
I would like it to appear like:
A
B
C
I know I can use grid-column: 2; on the 3rd item but that doesn't really help me if I have a dynamic number of rows and items.
I'm also aware of direction: rtl; on the wrapping element, but this obviously reverses the order which is not idea, eg:
B
A
C
I've tried justify-content: right/end/flex-end but no luck there either.
I am aware I can achieve the above with flex-box but was just curious if there was a way with CSS grid?
Since you only have two columns you can write a specific selector and target the last item
.box {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 5px;
border: 1px solid;
margin: 10px;
}
.box div {
height: 50px;
background: red;
}
/* place the last item at last column */
.box div:last-child {
grid-column-end: -1;
}
<div class="box">
<div></div>
<div></div>
</div>
<div class="box">
<div></div>
<div></div>
<div></div>
</div>
<div class="box">
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div class="box">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>

Elements with rounded corners - how to detect specific elements to give them a special style?

I have kind of a strange layout - the boxes should have rounded corners as if they were one big element (see image with 4 examples). Problem is the boxes are made dynamically so the rows and columns can vary. And so the fun starts. I started with giving the first and the last box a rounded corner, after this counting (nth) - but I can't wrap my head around how to do this with different rows. Tried everything like "tnh-last-child(3)" (does not work if last "row" has only 2 boxes) or "nth-child(3n+1)" but then there is a problem when i have more than 2 "rows" (I mean there are no "rows" [would be great] - only columns). Any idea?
// First and last
&:first-of-type {
border-top-left-radius: 30px;
}
&:last-of-type {
border-bottom-right-radius: 30px;
}
&:nth-of-type(3) {
border-top-right-radius: 30px;
}
Here is a fiddle: https://codepen.io/herrfischer/pen/eYEyRQp
section {
display: flex;
flex-wrap: wrap;
justify-content: left;
width: 400px;
}
section div {
width: 30%;
margin: 5px;
height: 100px;
background-color: grey;
}
section div:first-of-type {
border-top-left-radius: 30px;
}
section div:last-of-type {
border-bottom-right-radius: 30px;
}
section div:nth-of-type(3) {
border-top-right-radius: 30px;
}
.red {
background-color: red;
}
<h1>Red box should always have a rounded corner in the bottom left.</h1>
<h2>Example A</h2>
<section class="a">
<div></div>
<div></div>
<div></div>
<div class="red"></div>
<div></div>
<div></div>
</section>
<h2>Example B</h2>
<section class="b">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div class="red"></div>
<div></div>
</section>
<h2>Example C</h2>
<section class="b">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div class="red"></div>
</section>
<h2>Example D</h2>
<section class="b">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div class="red"></div>
<div></div>
<div></div>
</section>
You can combine nth-child selectors. This will match with only one item.
&:nth-child(3n + 1):nth-last-child(3),
&:nth-child(3n + 1):nth-last-child(2),
&:nth-child(3n + 1):last-child {
border-bottom-left-radius: 30px;
}
section {
display: flex;
flex-wrap: wrap;
justify-content: left;
width: 400px;
}
section div {
width: 30%;
margin: 5px;
height: 100px;
background-color: grey;
}
section div:first-child {
border-top-left-radius: 30px;
}
section div:last-child {
border-bottom-right-radius: 30px;
}
section div:nth-child(3) {
border-top-right-radius: 30px;
}
section div:nth-child(3n+1):nth-last-child(3),
section div:nth-child(3n+1):nth-last-child(2),
section div:nth-child(3n+1):last-child {
border-bottom-left-radius: 30px;
}
.red {
background-color: red;
}
<h1>Red box should always have a rounded corner in the bottom left.</h1>
<h2>Example A</h2>
<section class="a">
<div></div>
<div></div>
<div></div>
<div class="red"></div>
<div></div>
<div></div>
</section>
<h2>Example B</h2>
<section class="b">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div class="red"></div>
<div></div>
</section>
<h2>Example C</h2>
<section class="b">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div class="red"></div>
</section>
<h2>Example D</h2>
<section class="b">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div class="red"></div>
<div></div>
<div></div>
</section>

CSS Flex columns layout with overflow

Using pure CSS, is it possible to make the data flow in columns (like flex-direction: column) and also overflow the entire column layout? Like here:
Examples seem to focus on specifying the number of columns upfront, or, using media queries to achieve this - but with the caveat that it hinges on page width and not on the size of the content (so you have to set the content to be e.g. 33% width when 3 columns).
I think your best option is columns
.container {
background:lightblue;
padding:10px;
column-count:3;
column-gap:10px;
}
#media (max-width:800px) {
.container {column-count:2}
}
#media (max-width:400px) {
.container {column-count:1}
}
.container div {
padding:10px;
margin:5px 0;
display:inline-block;
width:100%;
box-sizing:border-box;
background:grey;
}
/* irrelevant CSS*/
.container {
counter-reset:num;
}
.container div:before {
content:counter(num);
counter-increment:num;
}
<div class="container">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
Like below if you want to control the width:
.container {
background:lightblue;
padding:10px;
column-width:max(200px,100vw/4);
column-gap:10px;
}
.container div {
padding:10px;
margin:5px 0;
display:inline-block;
width:100%;
box-sizing:border-box;
background:grey;
}
/* irrelevant CSS*/
.container {
counter-reset:num;
}
.container div:before {
content:counter(num);
counter-increment:num;
}
<div class="container">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
The max(200px,100vw/4) will get you a maximum number of columns equal to 3 and the 200px will control when we fall to 2 columns then 1.

CSS: How to style last grid row of a dynamic number of items?

I have my first row as 22px and using grid-auto-rows to make the subsequent rows 70px. Is there a way to make the last row also 22px without using template since I won't know how many div's are in it at the time?
.cont {
background: grey;
height: 600px;
display: grid;
grid-template-rows: 22px;
grid-auto-rows: 70px;
grid-template-columns: 1fr 1fr 1fr;
grid-gap: 3px;
}
.cont div {
background: red;
}
<div class="cont">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
If you will always have 3 columns keep the template row auto and define the height on the elements. All should have 70px except the first 3 and the last 3 under certain conditions.
.cont {
background: grey;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-gap: 3px;
margin:10px;
}
.cont div {
background: red;
height:70px;
}
.cont div:nth-child(1), /* 1st */
.cont div:nth-child(2), /* 2nd */
.cont div:nth-child(3), /* 3rd */
.cont div:nth-last-child(1), /* last one */
.cont div:nth-last-child(2):not(:nth-child(3n + 3)), /* before the last if not the last one of a row*/
.cont div:nth-last-child(3):nth-child(3n + 1){ /* before the two last only if the fisrt one of a row*/
height:22px;
}
<div class="cont">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div class="cont">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div class="cont">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
If you know how many columns your layout is going to have (in my example, it has 3 like yours), you can use the :nth-child() and :last-child() psuedo-class CSS selectors and do something like this:
.cont > div:nth-child(3n+1):nth-last-child(-n+3),
.cont > div:nth-child(3n+1):nth-last-child(-n+3) ~ div {
height:22px;
}
This CSS will always target the individual divs in the last row of your 3 column grid.
Good article on this technique here: https://keithclark.co.uk/articles/targeting-first-and-last-rows-in-css-grid-layouts/

Resources