Hexagons and Past: Versatile, Responsive Grid Patterns, Sans Media Queries

No Comments

A short while again, Chris shared this good hexagonal grid. And true to its title, it’s utilizing —await it — CSS Grid to type that format. It’s a neat trick! Combining grid columns, grid gaps, and inventive clipping churns out the ultimate outcome.

The same factor might be completed with flexbox, too. However I’m right here to resurrect our outdated buddy float to create the identical type of advanced and responsive format — however with much less complexity and and not using a single media question.

I do know, it’s laborious to imagine. So let’s begin with a working demo:

CodePen Embed Fallback

It is a totally responsive hexagon grid made with out media queries, JavaScript, or a ton of hacky CSS. Resize the demo display and see the magic. Along with being responsive, the grid additionally scales. For instance, we will chuck extra hexagons in there by including extra divs, and management each the sizing and spacing utilizing CSS variables.

Cool, proper? And this is just one instance amongst many grids we are going to construct in the identical method.

Making a grid of hexagons

First, we create our hexagon form. This process is pretty simple utilizing clip-path. We’ll contemplate a variable S that may outline the dimension of our aspect. Bennett Feely’s Clippy is a superb on-line generator for clip paths.

Making a hexagonal form utilizing clip-path

Every hexagon is an inline-block aspect. The markup can go one thing like this:

<div class=”major”>
<div class=”container”>
<div></div>
<div></div>
<div></div>
<!–etc. –>
</div>
</div>

…and the CSS:

.major {
show: flex; /* we are going to discuss this later … */
–s: 100px; /* measurement */
–m: 4px; /* margin */
}

.container {
font-size: 0; /* disable white house between inline block aspect */
}

.container div {
width: var(–s);
margin: var(–m);
top: calc(var(–s) * 1.1547);
show: inline-block;
font-size: preliminary; /* we reset the font-size if we need to add some content material */
clip-path: polygon(0% 25%, 0% 75%, 50% 100%, 100% 75%, 100% 25%, 50% 0%);
}

Nothing advanced up to now. We now have a major aspect that holds a container which, in flip, holds the hexagons. Since we’re coping with inline-block, we have to battle the frequent white house difficulty (utilizing the font-size trick) and we contemplate some margin (outlined with the variable M) to manage the house.

Toggling the font-size of the primary demo for instance the white house difficulty

Right here’s the outcome up to now:

Each different row wants some unfavorable offset so the rows overlap somewhat than stack instantly on prime of one another. That offset will probably be equal to 25% of the aspect top (see Determine 1). We apply that offset to margin-bottom to get the next:

.container div {
width: var(–s);
margin: var(–m);
top: calc(var(–s) * 1.1547);
show: inline-block;
font-size: preliminary;
clip-path: polygon(0% 25%, 0% 75%, 50% 100%, 100% 75%, 100% 25%, 50% 0%);
margin-bottom: calc(var(–m) – var(–s) * 0.2886); /* some unfavorable margin to create overlap */
}

…and the outcome turns into:

Now the true trick is how we will shift the second row to get an ideal hexagon grid. We’ve already scrunched issues to the purpose the place the rows overlap one another vertically, however what we want is to push each different row towards the fitting so the hexagons stagger somewhat than overlap. Right here’s the place float and shape-outside come into play.

Did you surprise why we’ve a .major aspect wrapping our container and having show: flex ? That div can be part of the trick. In a earlier article, I used float and I wanted that flexbox container so as to have the ability to use top: 100%. I will probably be doing the identical factor right here.

.container::earlier than {
content material: “”;
width: calc(var(–s)/2 + var(–m));
float: left;
top: 100%;
}

I’m utilizing the container::earlier than pseudo-element to create a float aspect that take up all the peak on the left of the grid, and that has a width equal to half a hexagon (plus its margin). We get the next outcome:

The yellow space is our.container::earlier than pseudo-element.

Now, we will attain for shape-outside. Let’s take a fast refresher on what it does. Robin defines it properly within the CSS-Methods Almanac. MDN describes it properly as nicely:

The form-outside CSS property defines a form—which can be non-rectangular—round which adjoining inline content material ought to wrap. By default, inline content material wraps round its margin field; shape-outside gives a solution to customise this wrapping, making it doable to wrap textual content round advanced objects somewhat than easy packing containers.

Emphasis mine

Discover “inline content material” within the definition. This explains precisely why the hexagons have to be inline-block components. However to grasp what sort of form we want, let’s zoom into the sample.

What’s cool about shape-inside is that it truly works with gradients. However what sort of gradient suits our scenario?

If, for instance, we’ve 10 rows of hexagons, we solely must shift means each even row. Seen in another way, we have to shift each second row so we want a sort of repetition — excellent for a repeating gradient!

We’ll create a gradient with two colours:

A clear one to create the “free house” whereas permitting the primary row to remain in place (illustrated by the blue arrow above).An opaque coloration to shift the second row to the fitting so the hexagons aren’t instantly stacked on prime of each other (illustrated by the inexperienced arrow).

Our shape-outside worth will appear like this:

shape-outside: repeating-linear-gradient(#0000 0 A, #000 0 B); /* #0000 = clear */

Now, let’s discover the worth of A and B. B will merely be equal to the peak of two rows since our logic must repeat every two rows.

The peak of two rows is the same as the peak of two hexagons (together with their margins), minus twice the overlap (2*Top + 4*M – 2*Top*25% = 1.5*Top + 4*M ). Or, expressed in CSS with calc():

calc(1.732 * var(–s) + 4 * var(–m))

That’s loads! So, let’s maintain all of this in a CSS customized property, F.

The worth of A (outlined by the blue arrow within the earlier determine) must be a minimum of equal to the scale of 1 hexagon, nevertheless it may also be larger. In an effort to push the second row over to the fitting, we want few pixel of opaque coloration so A can merely be equal to B – Xpx, the place X is a small worth.

We find yourself with one thing like this:

shape-outside: repeating-linear-gradient(#0000 0 calc(var(–f) – 3px),#000 0 var(–f));

And the next outcome:

shape-outside is utilized to the floated aspect, making a floated space with a predating linear gradient.

See that? Our repeating linear gradient’s form is pushing each different row to the fitting by one half the width of a hexagon to offset the sample.

Let’s put that every one collectively:

.major {
show:flex;
–s: 100px; /* measurement */
–m: 4px; /* margin */
–f: calc(var(–s) * 1.732 + 4 * var(–m) – 1px);
}

.container {
font-size: 0; /* disable white house between inline block aspect */
}

.container div {
width: var(–s);
margin: var(–m);
top: calc(var(–s) * 1.1547);
show: inline-block;
font-size:preliminary;
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::earlier than {
content material: “”;
width: calc(var(–s) / 2 + var(–m));
float: left;
top: 120%;
shape-outside: repeating-linear-gradient(#0000 0 calc(var(–f) – 3px), #000 0 var(–f));
}

That’s it! With not more than 15 CSS declarations, we’ve a responsive grid that match properly into all of the display sizes and we will simply modify issues by merely controling two variables.

You might have seen that I’m including -1px to the variable F. Since we’re coping with calculation that contain decimals, the rounding could give us unhealthy outcomes. To keep away from this we add or take away few pixels. I’m additionally utilizing 120% as a substitute of 100% for the peak of the floated aspect for related causes. There isn’t any specific logic with theses values; we merely modify them to verify to cowl a lot of the circumstances with none misaligning our shapes.

Need extra shapes?

We are able to do greater than hexagons with this strategy! Let’s create a “rhombus” grid as a substitute. Once more, we begin with our clip-path to create the form:

Rhombus form utilizing clip-path

The code is principally the identical. What’s altering are the calculations and values. Discover beneath a desk that may illustrate the modifications.

Hexagon gridRhombus gridheightcalc(var(–s)*1.1547)var(–s)clip-pathpolygon(0% 25%, 0% 75%, 50% 100%, 100% 75%, 100% 25%, 50% 0%)polygon(50% 0, 100% 50%, 50% 100%, 0 50%)margin-bottomcalc(var(–m) – var(–s)*0.2885)calc(var(–m) – var(–s)*0.5)–fcalc(var(–s)*1.7324 + 4*var(–m))calc(var(–s) + 4*var(–m))

And we’re performed! A mere 4 modifications to our code will get us a totally new grid however with a distinct form.

CodePen Embed Fallback

Simply how versatile is that this?

We noticed how we have been capable of make the hexagon and rhombus grids utilizing the very same code construction, however totally different variables. Let me blow your thoughts with one other concept: What about making that calculation a variable in order that we will simply change between totally different grids with out altering the code? We are able to definitely do this!

We’ll use an octagonal form as a result of it’s extra of a generic form from that we will use to create different shapes (a hexagon, a rhombus, a rectangle, and so forth.) just by altering a number of values.

The factors on this octagon form are outlined within the clip-path property.

Our octagon is outlined with 4 variables:

S: the width.R: the ratio that may assist us defines the peak based mostly on the width.hc and vc : each of those will management our clip-path values and the form we need to get. hc will probably be based mostly on the width whereas vc on the peak

I do know it appears hefty, however the clip-path is outlined utilizing eight factors (like proven within the determine). Including some CSS variables, we get this:

clip-path: polygon(
var(–hc) 0, calc(100% – var(–hc)) 0, /* 2 factors on the prime */
100% var(–vc),100% calc(100% – var(–vc)), /* 2 factors on the proper */
calc(100% – var(–hc)) 100%, var(–hc) 100%, /* 2 factors on the backside */
0 calc(100% – var(–vc)),0 var(–vc) /* 2 factors on the left */
);

That is what we’re aiming for:

Let’s zoom in to determine the totally different values:

The overlap between every row (illustrated by the crimson arrow) could be expressed utilizing the vc variable which supplies us a margin-bottom equal to M – vc (the place M is our margin).

Along with the margin we utilized between our aspect, we additionally want a further horizontal margin (illustrated by the yellow arrow) equal to S – 2*hc. Let’s outline one other variable for the horizontal margin (MH) that is the same as M + (S – 2*hc)/2.

The peak of two rows is the same as twice the scale of a form (plus the margin), minus twice the overlap, or 2*(S + 2*M) – 2*vc.

Let’s replace our desk of values to see how we’re calculating issues between the totally different grids:

Hexagon gridRhombus gridOctagon gridheightcalc(var(–s)*1.1547)var(–s)calc(var(–s)*var(–r)))clip-pathpolygon(0% 25%, 0% 75%, 50% 100%, 100% 75%, 100% 25%, 50% 0%)polygon(50% 0, 100% 50%, 50% 100%, 0 50%)polygon(var(–hc) 0, calc(100% – var(–hc)) 0,100% var(–vc),100% calc(100% – var(–vc)), calc(100% – var(–hc)) 100%,var(–hc) 100%,0 calc(100% – var(–vc)),0 var(–vc))–mh––calc(var(–m) + (var(–s) – 2*var(–hc))/2)marginvar(–m)var(–m)var(–m) var(–mh)margin-bottomcalc(var(–m) – var(–s)*0.2885)calc(var(–m) – var(–s)*0.5)calc(var(–m) – var(–vc))–fcalc(var(–s)*1.7324 + 4*var(–m))calc(var(–s) + 4*var(–m))calc(2*var(–s) + 4*var(–m) – 2*var(–vc))

Alright, let’s replace our CSS with these changes:

.major {
show: flex;
–s: 100px; /* measurement */
–r: 1; /* ratio */

/* clip-path parameter */
–hc: 20px;
–vc: 30px;

–m: 4px; /* vertical margin */
–mh: calc(var(–m) + (var(–s) – 2*var(–hc))/2); /* horizontal margin */
–f: calc(2*var(–s) + 4*var(–m) – 2*var(–vc) – 2px);
}

.container {
font-size: 0; /* disable white house between inline block aspect */
}

.container div {
width: var(–s);
margin: var(–m) var(–mh);
top: calc(var(–s)*var(–r));
show: inline-block;
font-size: preliminary;
clip-path: polygon( … );
margin-bottom: calc(var(–m) – var(–vc));
}

.container::earlier than {
content material: “”;
width: calc(var(–s)/2 + var(–mh));
float: left;
top: 120%;
shape-outside: repeating-linear-gradient(#0000 0 calc(var(–f) – 3px),#000 0 var(–f));
}

As we will see, the code construction is identical. We merely added extra variable to manage the form and prolong the margin property.

And beneath a working instance. Alter the totally different variables to manage the form whereas having a completely responsive grid:

CodePen Embed Fallback

An interactive demo, you say? You guess!

CodePen Embed Fallback

To make issues simpler, I’m expressing the vc and hc as percetange of the width and top so we will simply scale our components with out breaking the clip-path

From the above we will simply get the preliminary hexagonal grid:

The rhombus grid:

And one more hexagon grid:

A masonry-like grid:

And a checkerboard whereas we’re at it:

A number of prospects to create a responsive grid with any sort of form! All we’ve to do is modify few variables.

Fixing the alignment

Let’s attempt to management the alignment of our shapes. Since we’re coping with inline-block components, we’re coping with default left alignment and a few empty house on the finish, relying on viewport width.

Discover that we alternate between two sort of grids based mostly on the display width:

Grid #1: A totally different variety of gadgets per row (N, N-1,N, N-1, and so forth.)
Grid #2: The identical variety of gadgets per row (N, N, N, N, and so forth.)

It could be good to at all times have one of many grid on a regular basis (both #1 or #2) and heart every part in order that the free house is equally divided on either side.

In an effort to get the primary grid within the determine above, the container width must be a multiplier of the scale of 1 form, plus its margin, or N*(S + 2*MH), the place N is an integer worth.

This may increasingly sound unimaginable with CSS, nevertheless it’s certainly doable. I made it utilizing CSS grid:

.major {
show: grid;
grid-template-columns: repeat(auto-fit, calc(var(–s) + 2*var(–mh)));
justify-content: heart;
}

.container {
grid-column: 1/-1;
}

.major is now a grid container. Utilizing grid-template-columns, I outline the column width (as beforehand defined) and use the auto-fit worth to get as many columns as doable into the accessible house. Then, the .container spans all the grid columns utilizing 1/-1 — which signifies that the width of our container will probably be a mutiplier of 1 column measurement.

All it takes to heart issues is justify-content: heart.

Sure, CSS is magic!

CodePen Embed Fallback

Resize the demo and see that not solely do we’ve the primary grid from the determine, however every part is completely centered as nicely.

However wait, we eliminated show: flex and swapped in show: grid… so how is the percentage-based top of the float nonetheless working? I had stated that utilizing a flex container was the important thing for that, no?

Nicely, seems CSS grid sports activities that function too. From the specification:

As soon as the scale of every grid space is thus established, the grid gadgets are laid out into their respective containing blocks. The grid space’s width and top are thought of particular for this goal.

Be aware: Since formulation calculated utilizing solely particular sizes, such because the stretch match system, are additionally particular, the scale of a grid merchandise which is stretched can be thought of particular.

A grid merchandise has a stretch alignment by default, so its top is particular, that means utilizing a share as a top inside it’s completely legitimate.

Let’s say we as a substitute need the second grid within the determine — we merely add an additional column with a width equal to half the width of the opposite columns:

.major {
show: grid;
grid-template-columns: repeat(auto-fit,calc(var(–s) + 2*var(–mh))) calc(var(–s)/2 + var(–mh));
justify-content :heart;
}

CodePen Embed Fallback

Now, along with a completely responsive grid that’s versatile sufficient to take customized shapes, every part is completely centred!

Preventing the overflow

The usage of unfavorable margin-bottom on the final gadgets and the float aspect pushing our gadgets will create some undesirable overflow which will have an effect on the content material positioned after our grid.

CodePen Embed Fallback

Should you resize the demo, you’ll discover an overflow equal to the unfavorable offset and generally it’s larger. The repair is so as to add some padding-bottom to our container. I’ll make the padding equal to the peak of 1 form:

CodePen Embed Fallback

I’ve to confess that there isn’t an ideal answer to battle that overflow and to manage the house beneath our grid. That house will depend on loads of components and we could have to make use of a distinct padding worth for every case. The most secure answer is to think about a giant worth that covers a lot of the circumstances.

Wait, another: a pyramidal grid

Let’s take every part we’ve realized and construct one other wonderful grid. This time, we’ll rework the grid we simply made right into a pyramidal one.

Take into account that, not like the grid we’ve made up to now, the variety of components is essential particularly for the responsive half. It’s required to know the variety of components and extra precesily the variety of rows.

Completely different pyramidal grid based mostly on the variety of gadgets

It doesn’t imply we want a bunch of hardcoded values; somewhat we use an additional variable to regulate issues based mostly on the variety of rows.

The logic relies on the variety of rows as a result of totally different numbers of components could give us the identical variety of rows. For instance, there are 5 rows when we’ve between 11 and 15 components, even when the final row is just not totally occupied. Having between 16 and 21 components provides us six rows, and so forth. The variety of rows is our new variable.

Earlier than digging into the geometry and the mathematics here’s a working demo:

CodePen Embed Fallback

Discover that a lot of the code is identical as what we’ve performed within the earlier examples. So let’s give attention to the brand new properties that we’ve added:

.major {
–nr: 5; /* variety of rows */
}

.container {
max-width: calc(var(–nr)*(var(–s) + 2*var(–mh)));
margin: 0 auto;
}

.container::earlier than ,
.container i {
content material: “”;
width: calc(50% – var(–mh) – var(–s)/2);
float: left;
top: calc(var(–f)*(var(–nr) – 1)/2);
shape-outside: linear-gradient(to backside proper, #000 50%, #0000 0);
}

.container i {
float:proper;
shape-outside: linear-gradient(to backside left, #000 50%, #0000 0);
}

NR is our variable for the variety of rows. The width of the container must be equal to the final row of the pyramid to verify it maintain all the weather. Should you examine the earlier determine, you’ll see that the variety of the gadgets contained within the final row is just equal to the variety of rows, which implies the system is: NR* (S + 2*MH).

You might have additionally seen that we additionally added an <i> aspect in there. We did that as a result of we want two floating components the place we are going to apply shape-outside.

To know why we want two floating components let’s see what is completed behind the scenes:

Pyramidal grid

The blue components are our floating components. Every one is having a width equal to half the container measurement, minus half a form measurement, plus margin. The peak is the same as 4 rows in our case, and to NR – 1 in a extra generic case. Earlier, we outlined the peak of two rows, F, so the peak of one row is F/2. That’s how we landed at top: calc(var(–f)*(var(–nr) – 1)/2.

Now that we’ve the scale of our components, we have to apply a gradient to our shape-outside.

The purple coloration within the determine above is the restricted space for our components (it have to be an opaque coloration). The remaining space is the free house the place the weather can movement (it have to be a clear coloration). This may be performed utilizing a diagonal gradient:

shape-outside: linear-gradient(to backside proper, #000 50%, #0000 0);

We merely change proper with left for the opposite floated aspect. You might have in all probability seen that this isn’t responsive. The truth is, go forward and modify the viewport width of the demo and see simply how unresponsive that is.

We now have a few choices to get responsive:

We are able to fall again to the primary grid when the container width is smaller than the viewport width. It’s a bit tough to code, nevertheless it permits us to protect the identical measurement for our components.We are able to cut back the scale of our components with the intention to maintain the pyramidal grid. That is simpler to code utilizing the percentage-based worth trick, however that might lead to tremendous tiny components on smaller display sizes.

Let’s go together with the primary answer. We like a great problem, proper?

To get the pyramidal grid, we wanted two floated aspect. The preliminary grid wanted only one floated aspect. Fortunately, our construction permits us to have three floated components with no need so as to add extra components to the markup, due to pseudo-elements. We’ll use container::earlier than, i::earlier than, i::after:

/* Similar as earlier than… */

/* The preliminary grid */
.container::earlier than {
content material: “”;
width: calc(var(–s)/2 + var(–mh));
float: left;
top: 120%;
shape-outside: repeating-linear-gradient(#0000 0 calc(var(–f) – 3px),#000 0 var(–f));
}

/* The pyramidal grid */
.container i::earlier than ,
.container i::after {
content material: “”;
width: calc(50% – var(–mh) – var(–s)/2);
float: left;
top: calc(var(–f)*(var(–nr) – 1)/2);
shape-outside: linear-gradient(to backside proper,#000 50%,#0000 0);
}

.container i::after {
float:proper;
shape-outside: linear-gradient(to backside left,#000 50%,#0000 0);
}

Now we want a trick that lets us use both the primary floated aspect or the opposite two, however not all of them on the similar time. This situation needs to be based mostly on the width of our container:

If the container width is larger than the width of the final row, we will have our pyramid and use the floated components within <i>.If the container width is smaller than the width of the final row, we change to the opposite grid and use the primary floated aspect.

We are able to use clamp() for this! It’s type of like a conditional perform that units a minimal and most vary and, inside that vary, we offer it an “very best” worth to make use of between these factors. This fashion, we will “change” between grids utilizing our formulation as clamped values, and nonetheless keep away from utilizing media queries.

Our code will appear like this:

.major {
/* the opposite variables will not change*/
–lw: calc(var(–nr)*(var(–s) + 2*var(–mh))); /* width of final row */
}

.container {
max-width: var(–lw);
}

/* The preliminary grid */
.container::earlier than {
width: clamp(0px, (var(–lw) – 100%)*1000, calc(var(–s)/2 + var(–mh)));
}

/* The pyramidal grid */
.container i::earlier than,
.container i::after {
width: clamp(0px, (100% – var(–lw) + 1px)*1000, calc(50% – var(–mh) – var(–s)/2));
}

On bigger screens, the width of the container (LW) is now equal to its max-width, so 100% == LW. That signifies that the width of .container::earlier than is the same as 0px (and outcomes on this floated aspect turning into disabled).

For the opposite floating components, we clamp the width:

width: clamp(0px, (100% – var(–lw) + 1px)*1000, calc(50% – var(–mh) – var(–s)/2));

…the place the center worth ((100% – LW + 1px)*1000) is the same as (0 + 1px)*1000 = 1000px (an deliberately giant, however arbitrary worth). It will get clamped to calc(50% – var(–mh) – var(–s)/2). In different phrases, these floated components are enabled with the proper width (the one we outlined beforehand)

Voilà! we’ve a pyramidal form on giant display.

Now, when the container width get smaller, LW goes to be larger than 100%. So, (LW – 100%) will probably be constructive. Multiplied by a giant worth, it’s clamped to calc(var(–s)/2 + var(–mh)), which permits the primary floated aspect. For the opposite float components, (100% – LW + 1px) resolves to a unfavorable worth and is clamped to 0px, which disables the float components.

Resize the beneath demo and see how we change between each grids

CodePen Embed Fallback

Let’s attempt including extra components:

CodePen Embed Fallback

See that? Issues are scaling completely. Let’s toss extra components at it only for kicks:

CodePen Embed Fallback

Nonetheless nice. Discover that the final row isn’t even full. Simply reveals that this strategy covers a bunch of circumstances. We are able to additionally mix this with the CSS grid alignment trick we used earlier:

CodePen Embed Fallback

Do you suppose “float” is such a nasty factor now?

Need invert the pyramid?

Like illustrated with the above determine, two modifications to the earlier code can invert our pyramid:

I modify the course of the gradient from to backside left|proper to to prime left|proper, I add a margin-top equal to the peak of 1 row.

CodePen Embed Fallback

And, hey, we will swap between each pyramid simply:

CodePen Embed Fallback

Isn’t this stunning? We now have a responsive pyramidal grid with customized shapes that we will simply invert and that fallback to a different responsive grid on small display whereas every part is completely centred. All this and not using a single media question or JavaScript, however as a substitute utilizing the usually missed float property.

You’ll in all probability discover some missalignment in some specific circumstances. Sure, it’s once more some rounding difficulty associated to the calculation we’re doing and the truth that we try to make this generic with the interactive demos. To rectify this, we merely modify few values manually (epsecially the proportion of the gradient) till we get again an ideal alignment.

That’s a float wrap!

There we’ve it: combining float with shape-outside will help us make advanced, versatile and responsive layouts — lengthy reside float!

The article ends right here however that is solely the start. I offered you with the format and now you’ll be able to simply put any content material contained in the divs, apply a background, shadows, animations, and so forth.

CodePen Embed Fallback

The put up Hexagons and Past: Versatile, Responsive Grid Patterns, Sans Media Queries appeared first on CSS-Methods.

You’ll be able to assist CSS-Methods by being an MVP Supporter.

    About Marketing Solution Australia

    We are a digital marketing company with a focus on helping our customers achieve great results across several key areas.

    Request a free quote

    We offer professional SEO services that help websites increase their organic search score drastically in order to compete for the highest rankings even when it comes to highly competitive keywords.

    Subscribe to our newsletter!

    More from our blog

    See all posts

    Leave a Comment