How To Create Pure CSS Hexagonal Grids

This article will show you how I created the responsive, honeycomb grid used in my free portfolio template Hexa.



I will also explain in detail several CSS selectors and techniques used to reduce code duplication, and some tricks that can be used to achieve a fluid height property on a CSS element.

SETTING UP THE BASIC LAYOUT

First set up a basic HTML markup and link to a stylesheet to contain the CSS styles that we will be applying throughout this article:

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="x-ua-compatible" content="ie=edge"> <title>Hexagonal Grid by Codin @ Codesmite.com</title> <meta name="description" content="Hexagonal Grid by Codin @ Codesmite.com"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" type="text/css" href="styles/styles.css"> </head> <body> </body> </html>

Add a background colour to the page body:

body { background: #282828; }

Next we will create an unordered list with the id #grid, the list defines the size of the hexagon grid. I have used a width of 60% and positioned the grid in the centre of the page using an automatic left and right margin; you can adjust the value to any size you wish as the hexagonal grid will be fully responsive.

<body> <ul id="grid" class="clear"></ul> </body>

#grid { position: relative; width: 60%; margin: 0 auto; padding: 0; /* Clears unordered list default of 40px */ } .clear:after { content: ""; display: block; clear: both; }

We have also applied a clearfix to the unordered list as we will be adding side-by-side, block-level elements using float. Float is similar to positioning an element with an absolute value; it does not affect the height and width of the element’s container. Content positioned around a floated element will wrap around the element, first beside it and then below. Clearfix prevents elements after the container from also wrapping around the floated elements.

HOW TO CREATE A HEXAGONAL SHAPE WITH SIMPLE CSS

There are several methods you can use to create hexagonal shapes in CSS; the one shown in this article is my personal favourite as it is backwards compatible with many older browsers and also scales well for responsive design. We will create a simple parallelogram using CSS 2D Transforms which will utilise the CSS property overflow and act as a mask to create our hexagonal shape.

Start by adding a <li> element as a child of the unordered list: #grid; this <li> element will become the parallelogram mask:

<body> <ul id="grid" class="clear"> <li></li> </ul> </body>

We then turn the <li> element into the shape of a parallelogram using CSS styles:

#grid li { list-style-type: none; position: relative; float: left; width: 27.85714285714286%; padding: 0 0 32.16760145166612% 0; -o-transform: rotate(-60deg) skewY(30deg); -moz-transform: rotate(-60deg) skewY(30deg); -webkit-transform: rotate(-60deg) skewY(30deg); -ms-transform: rotate(-60deg) skewY(30deg); transform: rotate(-60deg) skewY(30deg); background: #fd005f; }

list-style-type: none;

Removes the bullet point marker from the list item.

Removes the bullet point marker from the list item. Padding bottom instead of height

This is a common trick used in responsive design to generate a fluid height value based on the containers width (this works due to how padding calculates percentage values).

This is a common trick used in responsive design to generate a fluid height value based on the containers width (this works due to how padding calculates percentage values). -o-, -moz-, -webkit-, -ms-

We have declared our transform property 5 times, 4 times using the above prefixes. These are browser prefixes that are required on some older browsers for newer CSS properties to be understood by the browser. I highly recommend checking out www.caniuse.com, this website is a great resource for checking if a CSS property or selector is compatible or requires prefixes for older browsers.

You should now have a parallelogram similar to the example below. The parallelogram should also maintain its aspect ratio and scale in a fluid manner based on the width of its parent container.

This parallelogram will be the parent container for the basic shape we will now create in order to form the resulting hexagon.

Add a <div> element with the class hexagon as a child element of the <li> element:

<body> <ul id="grid" class="clear"> <li> <div class="hexagon"></div> </li> </ul> </body>

Add the following styles to the hexagon class:

#grid li .hexagon { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: #fdbf00; -o-transform: skewY(-30deg) rotate(60deg); -moz-transform: skewY(-30deg) rotate(60deg); -webkit-transform: skewY(-30deg) rotate(60deg); -ms-transform: skewY(-30deg) rotate(60deg); transform: skewY(-30deg) rotate(60deg); }

position: absolute; top: 0; left: 0;

The height value of the <li> element is 0 because we have used the responsive padding trick to generate a fluid height instead of setting a static height value. This stops any child elements of the <li> element that are positioned as relative from displaying. To stop this from happening to our <div> element we set the position property as absolute, this removes the hexagon shape from the flow of the page layout, meaning it will not be affected by the 0 height value of its parent. The top and left properties determine the position of the absolute element.

The height value of the element is 0 because we have used the responsive padding trick to generate a fluid height instead of setting a static height value. This stops any child elements of the element that are positioned as relative from displaying. To stop this from happening to our element we set the position property as absolute, this removes the hexagon shape from the flow of the page layout, meaning it will not be affected by the 0 height value of its parent. The top and left properties determine the position of the absolute element. The actual shape explained The height and width are both set to 100% to ensure that the final shape has the same height and width of the <li> element before transformations were applied. The 2D transforms applied to the <li> element also apply to its child elements; reversing the transformation so that the final shape is not rotated or skewed.

You should now have something that looks similar to this:

It doesn’t look anything like a hexagon yet, but it will do very soon.



Now we are going to use the CSS property overflow to turn the above shape into a hexagon.



The overflow property can be used to specify what happens if content overflows an element’s box. There are several possible values for the overflow property:

Visible

The overflow is not clipped and renders outside the element’s box. This is the default value.

The overflow is not clipped and renders outside the element’s box. This is the default value. Hidden

The overflow is clipped and will not be visible.

The overflow is clipped and will not be visible. Scroll

The overflow is clipped and a scroll-bar is added to view the overflowing content. The scroll-bar will be added regardless of whether there is overflowing content or not.

The overflow is clipped and a scroll-bar is added to view the overflowing content. The scroll-bar will be added regardless of whether there is overflowing content or not. Auto

The overflow is clipped and a scroll-bar is added to view the overflowing content. The scroll-bar is only added if there is overflowing content.

The overflow is clipped and a scroll-bar is added to view the overflowing content. The scroll-bar is only added if there is overflowing content. Initial

The overflow is clipped and a scroll-bar is added to view the overflowing content. The scroll-bar is only added if there is overflowing content.

The overflow is clipped and a scroll-bar is added to view the overflowing content. The scroll-bar is only added if there is overflowing content. Inherit

Sets the property to its default value. Inherits the value of this property from its parent element.

The final shape is currently overflowing its parent element’s box (the <li> element).

Next we add overflow: hidden to the <li> element in order to clip the overflowing shape.

#grid li { list-style-type: none; position: relative; float: left; width: 27.85714285714286%; padding: 0 0 32.16760145166612% 0; -o-transform: rotate(-60deg) skewY(30deg); -moz-transform: rotate(-60deg) skewY(30deg); -webkit-transform: rotate(-60deg) skewY(30deg); -ms-transform: rotate(-60deg) skewY(30deg); transform: rotate(-60deg) skewY(30deg); background: fd005f; overflow: hidden; }

The final shape has now been clipped by its parent element’s box and should look similar to the image below.

Now all that is left to do is to hide the <li> element so that we are left with only the hexagon.

To do this we will add the property visibility with the value hidden; to our <li> element, this will make our <li> element invisible. We will also remove the background property as we do not need a background on an element that is not visible.

#grid li { list-style-type: none; position: relative; float: left; width: 27.85714285714286%; padding: 0 0 32.16760145166612% 0; -o-transform: rotate(-60deg) skewY(30deg); -moz-transform: rotate(-60deg) skewY(30deg); -webkit-transform: rotate(-60deg) skewY(30deg); -ms-transform: rotate(-60deg) skewY(30deg); transform: rotate(-60deg) skewY(30deg); overflow: hidden; visibility: hidden; }

The <li> element is no longer visible, but its child elements have also inherited its visibility properties and we can no longer see the hexagon shape.

We could resolve this by adding the visibility property to the hexagon class with the value of visible, making the hexagon visible again.

But instead let’s create a new selector:

#grid li * { visibility: visible; }

Asterisk Wild Card Selector

The asterisk selector used above will select all child elements contained in the <li> element and will apply the visibility property with the value specified: visible. By using the asterisk wildcard selector we do not have to re-declare the visibility property on every child element we create inside the <li> element, for example if an image element or a text header is later added to the hexagon shape.



You should now have a hexagon shape similar to the one below, the hexagon should also be responsive, try changing the size of the browser window to see how the hexagon scales to fit the page.

Lastly we add the overflow property to the hexagon class; this clips any child elements of the hexagon class. For example, if we were to add an image element to the hexagon we would want it to clip to the shape of the hexagon and not overflow.

#grid li .hexagon { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: #fdbf00; -o-transform: skewY(-30deg) rotate(60deg); -moz-transform: skewY(-30deg) rotate(60deg); -webkit-transform: skewY(-30deg) rotate(60deg); -ms-transform: skewY(-30deg) rotate(60deg); transform: skewY(-30deg) rotate(60deg); overflow: hidden; }

Experiment with this technique!

This technique is not confined to just creating hexagons, by using different shapes as masks with the overflow property you can create all manner of shapes.



Please feel free to share in the comments any shapes you create using this technique, we would love to see them.

CREATING A RESPONSIVE GRID OF HEXAGONS

Let’s now take a look at how to create a responsive grid of hexagons as seen in our free portfolio template Hexa



Firstly we are going to need more hexagons to create the grid! Add another 11 <li> elements containing the div element with hexagon class as children of the unordered list #grid;.

<body> <ul id="grid" class="clear"> <li> <div class="hexagon"></div> </li> <li> <div class="hexagon"></div> </li> <li> <div class="hexagon"></div> </li> <li> <div class="hexagon"></div> </li> <li> <div class="hexagon"></div> </li> <li> <div class="hexagon"></div> </li> <li> <div class="hexagon"></div> </li> <li> <div class="hexagon"></div> </li> <li> <div class="hexagon"></div> </li> <li> <div class="hexagon"></div> </li> <li> <div class="hexagon"></div> </li> <li> <div class="hexagon"></div> </li> </ul> </body>

You should now have a total of 12 hexagons.

This is essentially a grid of hexagons; it is responsive and functional but not very visually appealing. A responsive honeycomb shaped grid would have far more appeal, whilst still being capable of adding more or less hexagons.



Before we start moving the hexagons into a honeycomb shape we should add a left and right margin to the hexagon located in the centre of each line of the grid. This will add some horizontal spacing between the hexagons.



To achieve this we could add a class to the second, fifth, eighth, and eleventh hexagon with a margin property, but that would require a lot of duplicate work, especially if we plan to add more hexagons to the grid in the future.



Fortunately CSS has a very useful selector called nth-child; this selector will allow us to easily add margins to the central column of hexagons, and will also let us add as many hexagons as desired without having to add classes to each new hexagon.



Start by adding the following CSS selector and styles:

#grid li:nth-child(2) { margin: 0 1%; }

This selects the second <li> element child of the unordered list element with id #grid. As you can see the second hexagon now has a fluid left and right margin of 1%.

We could now create selectors :nth-child(5), :nth-child(8), :nth-child(11) to target the second hexagon of each row in the grid, but this also is repetitive work that should be avoided.



Instead we use the formula (an+b), a represents the cycle size, n represents a counter, b represents the offset value. The counter n starts at 0 and increments by 1 each cycle. Here is an example using (5n+7):



Cycle 1: (5 x 0) + 7 = 7

Cycle 2: (5 x 1) + 7 = 12

Cycle 3: (5 x 2) + 7 = 17

Cycle 4: (5 x 3) + 7 = 22

etc



The cycle begins on the offset of 7 and increments by 5 each cycle.



We can use the formula (3n+2) to select the second hexagon in every row in the grid.



Cycle 1: (3 x 0) + 2 = 2

Cycle 2: (3 x 1) + 2 = 5

Cycle 3: (3 x 2) + 2 = 8

Cycle 4: (3 x 3) + 2 = 11

etc



Now we can add as many hexagons as we like without needing to make any further changes to the CSS as the formula will automatically cycle the second hexagon of each row in the grid.



Remove the (2) from the selector and add the formula (3n+2) in its place.

#grid li:nth-child(3n+2) { margin: 0 1%; }

Now every second hexagon of each row in the grid has a fluid left and right margin with the value of 1%.

Using the nth-child selector we can also shift every other row to the right to achieve the honeycomb effect we are aiming for, at the same time we will also add a top and bottom margin for vertical spacing between each row.

#grid li:nth-child(6n+4), #grid li:nth-child(6n+5), #grid li:nth-child(6n+6) { margin-top: -6.9285714285%; margin-bottom: -6.9285714285%; -o-transform: translateX(50%) rotate(-60deg) skewY(30deg); -moz-transform: translateX(50%) rotate(-60deg) skewY(30deg); -webkit-transform: translateX(50%) rotate(-60deg) skewY(30deg); -ms-transform: translateX(50%) rotate(-60deg) skewY(30deg); transform: translateX(50%) rotate(-60deg) skewY(30deg); }

The formulas used in our nth-child selectors are: (6n+4), (6n+5) and (6n+6).



(6n+4)

Cycle 1: (6 x 0) + 4 = 4

Cycle 2: (6 x 1) + 4 = 10

Cycle 3: (6 x 2) + 4 = 16

Cycle 4: (6 x 3) + 4 = 22

etc



(6n+5)

Cycle 1: (6 x 0) + 5 = 5

Cycle 2: (6 x 1) + 5 = 11

Cycle 3: (6 x 2) + 5 = 17

Cycle 4: (6 x 3) + 5 = 23

etc



(6n+6)

Cycle 1: (6 x 0) + 6 = 6

Cycle 2: (6 x 1) + 6 = 12

Cycle 3: (6 x 2) + 6 = 18

Cycle 4: (6 x 3) + 6 = 24

etc

The translateX value has been declared to transform the position of the property, and the rotate and skew values have also been declared again. This is due to the cascading rules of CSS, if we were to only declare the translateX value on the transform property this would overwrite the previous rule that rotates and skews the selected <li> elements to create the parallelogram. We need to declare our previous transforms again to avoid this happening.



We need to add one final rule that selects the first hexagon of every other row and slightly nudges the entire row to the right leaving us with equal spaces around each hexagon. This could be achieved by increasing the translateX value by 0.5% in the previous CSS rule, however, using translate with decimal values can have very undesired effects in some browsers.



Instead, we use the nth-child selector again to apply a left margin for the adjustment we need.

#grid li:nth-child(6n+4) { margin-left: 0.5%; }

With a very minimal amount of code and repetition, thanks to the nth-child CSS selector, we have accomplished a fully responsive hexagonal grid with fluid height and width.

We would love to see your creations using this grid technique, so feel free to post a link in the comments!