Who Needs Squares and Rectangles? — How to Create a Diamond Grid Layout with CSS
Standard grids comprised of squares and rectangles is so old school wouldn’t you say? I recently had the opportunity to build a unique grid layout for a website, and boy, was it more than I bargained for. I approached the problem with a pretty good understanding of standard CSS Grid layouts, so why was I completely stumped on this one? The CSS Grid spec is great for creating many of the most common layouts on the web, but it quickly became apparent that it wasn’t going to work out for this project. So let’s stretch this idea of the “formal grid” in this article and see what’s possible without it.
The Problem
Here, we have the desired layout created by the awesome designers that I work with at Use All Five:
The idea seems simple, right? A standard grid comprised of 4 columns, 2 items per row. I know what you’re thinking: “Let’s just create a normal CSS grid and rotate each item using transform: rotate(45deg)
”. Well, you could do that, but the end result might not be what you’re imagining:
The items definitely rotate in the correct fashion, but how can we size and position the items in a way where the gaps are evenly spaced, while also trying to maintain responsiveness for the entire grid? You might think the golden ticket is Javascript in order to position each item individually? That could definitely work too, if you want to go the long road. I’d like to try a simpler, CSS way, with a little help from an old friend called — math.
The Solution
It became pretty clear to me at this point that a standard CSS grid layout or Flexbox wasn’t going to work here because it’s not possible to evenly line up the items or stagger them in any way. We’re going to need to use some Sass and come up with our own grid units to correctly calculate the distance between each item. The items inside the grid will also need to be position: absolute
, further enabling the use of vw
units to scale everything responsively based on browser size.
Upon rotating the items in the grid, it occurred to me that we’re not just looking at a square anymore, but rather two isosceles triangles! This should help immensely with the calculations in the next step.
Calculate Grid Units
Using some math you probably learned in 8th or 9th grade, we’re able to determine the correct width of each square that has been rotated. Since the adjacent and opposite sides of the triangle are equal, the width of each diamond would be the length of the hypotenuse (or the side of the square) divided by the square root of 2. Luckily for us, the √2 is a constant! So, no need to do those calculations with Sass, we can just hardcode it (even though we technically could calculate it using Sass functions). Here are the CSS variables I’ve used to create our grid units:
--sqrt: 1.41421356237; // Square root of 2
--grid-unit: calc(100vw / 5);
--transform-unit: calc(var(--grid-unit) / var(--sqrt));
--unit: calc(var(--transform-unit) * 2);
NOTE: I used CSS variables here so I can set different units for each media query in my project. This way you can change the amount of items per row depending on the screen size.
Create Markup
From there, it’s just a matter of using these units to position your diamonds into your preference for a grid layout. Our design needed two items per row, then the next row gets offset by exactly 2 more grid units to the right. I decided to markup my HTML like so:
<div class="grid">
<div class="layout">
<div class="item"></div>
<div class="item"></div>
</div>
...
</div>
Here, we chunk the array of grid items by 2 and insert a parent div, layout
. This way, we can have a consistant number of 2 diamond divs per parent div making it a little easier to read and understand when you add the styles in the next section.
Add Styles Using the Grid Units
Now, let’s use the grid units we calculated earlier and add them to our individual item
elements.
.item {
height: var(--unit);
left: 0;
position: absolute;
top: 0;
transform: rotate(45deg);
width: var(--unit);
}
Each item needs to use the --unit
variable for the width and height properties. This will size the diamonds accordingly based on the grid units that are calculated. Each item will then need to be rotated 45˚ and positioned absolutely.
Lastly, we need to add the styles for each row of diamonds. Each layout
div will then need to specify a height value since each item
is positioned absolutely. We can use height of 1 unit (or half a diamond). Then, we’ll just need to adjust our left position property for each diamond to our desired value in the grid:
.layout {
height: var(--grid-unit);
position: relative;
// Odd rows
&:nth-child(odd) {
.item {
&:first-child {
left: var(--grid-unit);
} &:last-child:not(:first-child) {
left: calc(var(--grid-unit) * 3);
}
}
} // Even rows
&:nth-child(even) {
.item {
&:first-child {
left: calc(var(--grid-unit) * 2);
} &:last-child {
left: calc(var(--grid-unit) * 4);
}
}
}
}
And there you have it! A fully responsive diamond grid made entirely with CSS. 🤠
But wait, what’s this? This doesn’t look like our design we had before.
Looks like we’re missing some gaps in between the diamond items. No worries there! All we need is a simple border on each item to create the illusion of a gap. border: 2vw solid white;
oughta do it. The important part here is that the border color must match the background color. So, if you have a background image or some gradient, it might be hard to replicate this behavior. I’m also using vw
here, so we can naturally scale the size of the border to the viewport along with the diamonds.
That’s more like it! Looks like we’re just about done. Right? Wrong. There’s just one more caveat to mention. Everything inside the diamonds is now off kilter! We’ll have to rotate everything inside the diamonds 45˚ counter-clockwise to correctly position all the interior content only. If you wanted to stretch an <img>
to the edges of the diamond (like in my case) you’ll need to use object-fit: cover;
and scale the image up a little bit to fill the space. Take a look at the end result to see what I’m talking about more in-depth.
The Result
Takeaways and Thoughts
I really enjoyed the journey to solve the diamond grid layout problem. The design for this project really pushed me to increase my knowledge and skills of CSS, but it also helped me rekindle an old flame for geometry that I forgot I had. If I could spend more time on it, I would have wanted to figure out a way to make it work within container divs rather than just using viewport units. In this current iteration, the grid has to be the full width of the viewport, which not ideal but in my case it worked out for the client.
Thank you for reading this far! I hope this helps someone out there struggling with the diamond grid layout like I was. Good luck!