CSS: complex grid layout
Tags: css, grid, tutorial, wordpress
Published: 2023-09-12 13:23:41

At Plank, we build many of our projects with Wordpress. Making menus in the CMS is pretty user friendly but when it comes to more complex menu structures, it can be difficult for us as the frontend developer to style when all we are given is nested lists upon nested lists. 

To solve this problem, I came up with this grid layout recently and wanted to share how it is done. I’ll also discuss a big struggle I had to overcome for this to work properly, be flexible and easy to tweak. 

## The markup: 
In this example, we are working with one unordered list with several children. The first child is a call to action and the rest are links. Wordpress allows us to add classes to the individual links (as well as a description to support the call to action), so I added a class and a description to the call to action `list__item--cta`. 

I decided to go with grid over flex in this case because the call to action will take the whole vertical height of the menu while the rest of the links were tiled towards the right side of the screen. 

```css
.list {
   display: grid;
   // need to name the start and end of the 
   // first column so it can be referenced by the CTA
   // declare 4 columns, 
   // first spot for CTA then repeat 3 for the links
   grid-template-columns: [cta-start] minmax(200px, auto) [cta-end] repeat(3, minmax(50px, 1fr));
   grid-auto-rows: min-content;
}
.list__item--cta {
	grid-row: 1 / 4;
	grid-column: cta-start / cta-end;
	height: 100%;	
}
```
Since we did not define the amount of rows on the parent, the `--cta` child is telling the parent grid how many rows there will be with the property `grid-row: 1 / 4;`. The value is spanning from the first line (start of the first row) to the fourth line (end of the third row). In this example we have 7 links, so we need 3 rows and 3 columns (in practice I used a bit of JavaScript to adjust the number of rows and columns based on the number of links). 

I made the description of the call to action `contenteditable` to show where I went wrong. Edit the text and see how the grid falls apart


{% codepen https://codepen.io/plankdesign/pen/abQGWrR %}


The gap between the rows shouldn't start stretching out like that. So what is there to do?

## The Fix
Grid will fill its rows before columns by default. We need three rows for the amount of links we have. But what if we create one extra row that starts at a height of 0 and its only job is to expand to take the extra height of the CTA description? In this case, we update the grid-row property on `--cta` to create an extra row: 

```css
.list__item--cta {
   grid-row: 1 / 5;
}
```
Remember that when setting the `grid-row` property, the last line in the grid will always be one more than the number of rows.

The cta is now adding a fourth row that won't be filled up by the other links, the last row only exists as a buffer. If the CTA doesn't need that space, the row will have a height of zero.

Now we can add as much text as we want to the cta description and the other links will be completely unaffected!

## The final result:
{% codepen https://codepen.io/plankdesign/pen/xxQNYKq %}

Done!