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.
We can even change the shape to something else:
Due to some rounding issue we may have to add/remove extra pixels to get the intended result. We may also need a height bigger than 100% for the float element
Discussion (30)
I’ve actually been wanting to set up a hexagon grid for a browser-based-game. One thing to consider is making the hexagons clickable or having content inside. I think either of those are the next big step to moving the approach from visually beautiful onwards to “functional” interactable content that people need.
That step is pretty easy using my code (like I detailed at the end). I am using empty divs so simply put any content you want inside and style it like you want ;) you can also catch hover and click events easily.
Usually with non-rectangular shapes on the web the problem becomes the clickability of the area. Circles, hexagons, diamonds, I’ve seen a lot of “click frustration” to them all where the visible shape does not map to the clickable link after using things like css ::before.
Far as a clickable demo, I’m on a phone, so it’s difficult to create a codepen example to see if the approach yields clickable links.
Visually arresting, regardless.
I am using clip-path, there is no pseudo element or complex trick and you will find no clickability issue. Try and see ;)
A trivial example is to add
.container div:hover {background:blue}
and you will see that the hover area fit the shape perfectlyYeah, made an attempt before on a fork, but not really able to do much via mobile codepen.io/tchalvak/pen/ZEByQad
Hi,
I already try to edit available code to make hexagon game board like the attached photo. However, I could not able to make it 100%.
dev-to-uploads.s3.amazonaws.com/up...
This is my code:
codepen.io/akeshma/pen/RwweNZG
I don't see my code in that codepen
Thanks for quick response. Oh, I'm sorry. I ment availave code in another place.
My question: is it possible to make Hexagon Game Board 5x5 using your code here?
dev-to-uploads.s3.amazonaws.com/up...
each Hexagon contains a letter and can be colored RED or GREEN depend on who is the winner.
of course, it should be pretty easy if you take my code as a starting point and add your content.
will try it and give you my feedback thanks.
Wow, just wow!
Great post Temani! Permission to use this code in a personal project? ☺
go ahead and use it ;) I am sharing tricks to be used :)
Thank you!
Hi Temani! I wanted to thank you so much for your help with responsive hexagons on Stackoverflow (since you´re not supposed to waste comments on such trivial things over there). And this post is just the best, could´ve really used it weeks ago! I think this resource will be a game changer for anyone trying their handshexagon tile board games. Keep up the good work :)
Thanks, more content is coming. Stay tunned ;)
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 ;)And hexagons, as you sure know, are the bestagons.
i love this!
Great post!
Wow cool
cool, can use for web page background?
what kind of background? only colored and repeated hexagon?
Very nice. Thanks for sharing :-)
Maybe this one? scispec.ca/index.php/blog/45-draw-...
Will tackle that one too, probably in another post. Stay tunned ;)
The funny thing about these flexible hexagons is that the more you shrink or expand the screen the more patterns you get in the arrangement of the hexagons on your screen.