Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Building a Hexagonal Grid in CSS (ninjarockstar.dev)
242 points by indentit on June 19, 2020 | hide | past | favorite | 42 comments



This is a must read if you're working with hex grids: https://www.redblobgames.com/grids/hexagons/


Thanks for posting this, it was fascinating! I had to implement a hex grid recently, so when I started reading through this page and seeing some of the same things I had thought about, I thought I wouldn't find much that was new. I couldn't have been more wrong!


That site helped me to write a Plasma dynamic background.

https://invent.kde.org/vandenoever/tiles/


This helped me make my first hexagonal grid based game way back! Awesome site


Came here to post this, and saw that it's the very first comment... I am not disappointed, and instead very happy to be part of this knowledgeable community.


I see a lot of convoluted CSS things like this. Is there not much awareness of SVG in the webdev community, or is there some other reason people don't want to use it?


If you wanted arbitrary HTML content in the hexagons, would you be able to use SVG? I know you could hack together similar output since SVG supports images, links, text formatting, etc., but I can see people liking the idea of the hexagonal containers being plain divs that you can put whatever content you want into.


You can put arbitrary HTML elements inside an SVG element embedded in an HTML page:

https://developer.mozilla.org/en-US/docs/Web/SVG/Element/for...


I wonder what the accessibility for html in svg is like. But really, isn't this just an iframe with a different name?


No. An iframe is a separate browsing context which as a developer you can’t interact with perfectly, and is segregated from the rest as a user, which has implications on keyboard interactivity especially. Essentially, <iframe> is an accessibility headache. <foreignObject> is just the opposite of <svg>, so it’s no trouble at all.


Shameless plug. https://github.com/SpeciesFileGroup/waxy is coded based on Red Blob Games' incredible tutorials. We use it for visualizations in Rails.


Putting nice markup (or even OK formatted text) into SVG has been a pain for me.

I put an SVG background, then layer the HTML over it.

It works but, I'm not happy about it.


Check out the sibling answer above, you can embed HTML in svg and it generally works well: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/for...


I'm familiar with those docs. That method was a poor experience for my mobile users. SVG support on mobile is not that great. Sadly FF had the most issues so I'm stuck with my workaround for now.


This example doesn't even show how it would place content inside the grid... and I suspect any attempt to do so with anything more than trivial text excerpts would result in the layout shattering, or the content clipping. And attempting to fit hexagonally-shaped content into the exact elements of the grid seems even less likely, here.


SVG is not typically very responsive (mobile, desktop), and you end up digging yourself into a "no support" hole.

It seems the web community is dedicated to forcing things to work until they become fully supported features of HTML.

Also, in this case, CSS grid is a very good choice for layout, but the background could totally just be an svg.


To explain why that is: In SVG everything has x and y coordinates relative to the SVG view box. There is no fundamental declarative layout like in HTML/CSS where the browser will calculate where elements go for you.

SVG is great as something to embed in HTML, but not the other way around.


It's a different context than plain HTML content, so there's that...


Oooh, nice.

I have worked with hexes in little side project games, it was a difficult process and I went through a phase of trying to home-roll canvas drawing of hexes (and making some interesting looking bugs). I ended up using a js library (Konva / https://konvajs.org/) which was pretty easy to implement.

One completed (albeit ugly) project was an implementation of a minigame I played in Magnum Opus:

https://game.manfrincdn.com/#/

It's been a little project kicking around that I want to make a hex game engine of sorts in Vue. The difficult part I keep running in to is connecting the state of the engine (in vue) with the state of the canvas (outside). I've ended up often hitting lower level APIs to watch/update/rerender parts, but at that point I feel like I end up reimplementing parts of vue within itself, and that nagging 'you are missing an obvious solution' worm starts up.

A pure CSS approach would make this a lot simpler, because there'd be no need to do any manual wiring up of state to canvas state, you'd just let vue handle that cycle because that's its core competency.


Vue is pretty good at generating SVG (I use Vue+SVG on https://www.redblobgames.com/grids/hexagons/) but there's a trick for making it work with Canvas too. https://simblob.blogspot.com/2018/03/using-vue-with-canvas.h... — it will make the canvas drawing function depend on the right data in Vue, so that if any of that data changes, it re-draws the canvas automatically.


Oh excellent, thank you, I didn't know you had written about hexes + vue -- your site has been absolutely invaluable to me and is one of the primest examples of visualization done well.

One problem I remember running in to (drawing hexes) is that the redraw of one hex overwrote what had been drawn in another, causing corners of the bounding box of a hex to clear its neighbors. Did you run in to any issues like that, or was that likely just a quirk of how I coded it (I am amateur with canvas, so it's a likely cause).


There are some gotchas when using sprites/images for hexagons. 1. The bounding boxes overlap, so you'll want to make sure that the sprites have transparent corners so that they don't overwrite what's in the next hexagon. 2. The images won't be exactly regular (equal sided) hexagons because regular hexagons have an irrational side width or height. The image size will be rounded off to the nearest pixel. You'll need to adjust for this in your hexagon calculations, either shrinking or expanding one of the axes a tiny bit so that both axes are integer sized. For example if your hexagon spacing is 173.20508 x 150 then you'll change your spacing to be 173 x 150, or whatever matches your image size.


Sorry for the off-topic comment but I just want to thank you for your site (and in particular that article). I've been using your site for years and it's an invaluable resource to me.


Thank you! Glad to hear it!


Impressive! It's interesting for me if such grade CSS developers get same compensation as their JavaScript counterparts.


I think not, because despite the high quality of the pure CSS result, there's probably a js lib out there that will get the same result for a few hundred extra kilobytes in the bundle. But knowing CSS is still very useful as a skill, it's usually your "moat" that makes it hard for backend devs to do your work while you're on vacation.


They shouldn’t be doing frontend work. I’d argue frontend tooling and paradigms are more complicated than backend now.


Kind of a nostalgia thing to see this, as one of my earliest answers on gamedev stack was about creating a hex map (See https://gamedev.stackexchange.com/questions/6382/how-to-crea...)

I cheated and used hex-shaped png files but looking back using CSS to just auto-shape the PNG would be good.

That said, if you ARE using textures in the hexes and you'd like to actually tile them, you'll have to explicitly design an image that will tile. So you might as well just create hex shaped images like this and forget getting too fancy.


So there's one trick that's kind of cool using PNG images (with transparency) for your tiles. You can have parts of the image that actually extend out of the tile. So a tree can extend off the top of the tile in a pseudo-isometric style. Or a castle, or a mountain, or anything.


PSA: don't open this on Safari on a Mac book Pro, it'll either take a while to load or it'll freeze your computer if you have other heavy processes running. Chrome works fine.


I would like to see this where each edge is also uniquely addressable.



Why would you make this responsive? It doesn't make sense for any games to have the map/board be different based on window-size.


I ran into the problem too that CSS-counters are strings and not integers. Can anyone explain the reasoning? It's understandable that the displayed value is a string but the (sub)counters themselves could as well been done as integers imo.


Can anybody explain to me why I would use the CSS grid to accomplish this and not negative margins on inline divs? The latter is how I immediately guessed that this would be implemented. What would be the advantages of the grid method?


Maybe the responsiveness? In a real use case I think you'd want to have a set grid size so responsiveness seems like an odd goal.


I'm a bystander that ploughed through quite a lot of text regarding one case.

How do you do ngon grids in CSS?


I'm not sure if you are joking, but the answer is: you don't :-)

N-gon grids don't make sense for N other than 3, 4, and 6 [1]. N=4 is easy, N=6 is in the OP. I suspect one could find a similar "css trick" for N=3.

1: https://en.wikipedia.org/wiki/List_of_regular_polytopes_and_...


Don’t forget about the 15 pentagonal tilings! https://en.wikipedia.org/wiki/Pentagonal_tiling


Also cool: the last one wasn't discovered until 2015.


Sry noob here, but are there any spaces you have to use this hexagonal grid to solve things?


Accessibility for people with hexagonal monitors.




Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: