Find out more CSS tricks at css-tip.com
I know there is a ton of articles detailing how to create hexagon grid but how many of them are responsive? Only few of them and they rely on a lot of media query or JS.
Here is a CSS only solution to have a responsive hexagon grid that fit nicely into all the sreen sizes. No JS, no media query and no complex html code. Only few lines of CSS.
Here you go
Explanation
<div class="main">
<div class="container">
<div></div>
<div></div>
...
</div>
</div>
.main {
--s: 100px; /* size of a hexagon */
--m: 4px; /* space between each heaxgon */
--r: calc(var(--s)*3*1.1547/2 + 4*var(--m));
display:flex;
}
.container div {
width: var(--s);
height: calc(var(--s)*1.1547);
margin: var(--m);
display: inline-block;
clip-path: polygon(0% 25%, 0% 75%, 50% 100%, 100% 75%, 100% 25%, 50% 0%);
margin-bottom: calc(var(--m) - var(--s)*0.2885);
}
.container::before {
content: "";
width: calc(var(--s)/2 + var(--m));
float: left;
height: 100%;
shape-outside: repeating-linear-gradient(
transparent 0 calc(var(--r) - 3px),
#fff 0 var(--r));
}
[main]
Nothing special here. A basic div
where I am defining some CSS variables and it need to be a flexbox container.
[container]
No CSS here, this is our flex item that will allow us to use the height:100%
.
[div]
Our hexagon item. The width/height are defined with the variable s
(1.15 ~ 1/cos(30deg)
). We use clip-path
to create the hexagon shape ref. Finally we apply a margin-bottom
to create the overlap with the next line ( 0.2885 ~ tan(30deg)/2
).
Until now nothing complex. Let's move to the intresting part!
[container::before]
A floated pseudo element where I will apply shape-outside
to allow the hexagon items to wrap around a particular shape creating the perfect indentation between lines.
A figure to illustrate:
It's trivial that our float element need to fill all the container thus the use of height:100%
. Each "even" line of our grid need an indentation equal to half the width of an hexagon item plus a margin which will give us width:calc(var(--s)/2 + var(--m))
.
We need to repeat the logic for each 2 lines and the height of 2 lines is 2 height of hexagon + 4 margin + 2 negative margin-bottom = 2xS/cos(30deg) + 4xM - 2xSxtan(30deg)/2
After some simplification we get (3xS)/(2xcos(30deg)) + 4xM
and this is our r
variable. The shape-outside
will create a repeating gradient having transparent within [0, r - x]
and non-transparent within [r - x, r]
.
The non-transparent part (illustrated by the blue rectangle) will push the elements of the second line creating our beautiful responsive behavior.
x
can have any value but not too big to avoid pushing the first line too (1px
should do the trick but to avoid rounding issue we use a bigger value).
That's It!
In addition to this being responsive, we can easily adjust the size of the hexagon items, the margin between them and since we are dealing with empty divs we can add any content inside.
Check the below post for more shapes:


Latest comments (47)
Anyone got this to run on Mac, iPad? I'm using Sadfari 18.3
Apparently the shape-outside trick doesn't work.
Otherwise its quite beautifuly simple, hats off.
....I know I'm rather late to this party.
Oh man, having the offset be a transparent ::before shape with the right height spacing between lines is a great idea! I was puzzling over that one. Thanks, this works great and is so much simpler than all the js/media-query ones!
What if I wanted the hexagons to be horizontal? Is it possible with this code or it would completely change? I am trying to make a game but I am very new to frontend and this is the best tutorial I have seen so far.
Hey Temani, this article is awesome, thanks for sharing!
Do you know if we can do that with circles too? As a workaround, I'm thinking to put circles into these hexagons for now. Also, I tried using your example to fix the horizontal alignment but it's not working from Safari, do you have any example?
Thanks for your help! <3
I made this example for circles: codepen.io/t_afif/pen/xxXVBMB
For Safari, I cannot help because I don't have any apple device to test but I know there are a lot of bugs with Safari
Wow Temani, this is really awesome, thanks for all your help, so impressive!! <3
Happy Friday!
Juan
Hi Temani Afif,
In the safari browser the hexagons don't show in the same structure. Is there a fix?
Hi, I encountered a problem with content below the hexagons.
In some cases, the hexagons leak out of the main div and the content below will overlap with the hexagons.
For a few rows of hexagons everything is fine, but when the number of rows increases the problem becomes more severe. You can check it with your codepen example by adding a div below with some dummy content and then resizing the browser window to get more rows of hexagons
Is there a fix for this, so the main div will always have the same height as it's contents (the hexagons)?
Hi, very nice script.
I'd like to have the indentation beginning on the first row. Can you help me?
in the shape-outside use this
repeating-linear-gradient(
#000 0 3px,
#0000 0 var(--f))
and in the
--f
you will find- 1px
, replace it with+ 1px
Thanks for your help :)
I encountered a problem.
You can also test it with your example on codepen.
When you put the size to 200px (--s: 200px;) and look at it from a mobile device or resize your browser to mobile dimensions, then the last hexagon misbehaves.
This also occurs with the original code/indentation.
Can you help me again?
I found a solution, but maybe you have a better one.
I just added a couple of extra hexagons and made them invisible.
visibility: hidden;
This way all the visible hexagons have the correct indentation, the last (visible) ones aswel.
The invisible hexagons will still be out of place, but it doesn't matter because nobody sees them.
Really cool. Any idea how to implement this in React Native?
I am not familiar with react native so I don't really know the limitation you be facing and if shape-outside is supported there or not. You can try using a basic example to test the shape-outside. It should be the only property that would potentially give you troubles.
@afif Thank's for this post! I've noticed an small error when it comes to responsive Design - see dev-to-uploads.s3.amazonaws.com/up.... If only one hexagon will be shown in a row there's a large gap between the hexagons. Any idea/hint how to fix that?
it's not really an error, it's meant to work that way. In that case, you can simply remove the float element (using media query when the screen size is very small)
Hi. Any ways to use this with percentual values for width/height? If pixels are used (or any other unit), then in some cases there is space left on the right side of the viewport.
Quite brilliant btw, really nice work (i am amazed everytime what can be achieved with css these days).
Thanks in advance.
So you want a fixed number of hexagon per row that fit all the width, right?
Yeah, that would be ideal as that would prevent the case i mentioned above. Unfortunately my css skills are not so good so i couldnt figure it out :)
In this case, the easiest solution is to replaced
px
withvw
which is the viewport unit that behave as percentage based on the screen size. To use%
we need to change the logic, I will probably write another post about it ;)That would be awesome
Some comments may only be visible to logged-in visitors. Sign in to view all comments.