Does Any of This Scare You?

That’s the last question our Chief Creative Officer asked me during the design review over the homepage of Dixon Schwabl’s 2018 website redesign. That design included a grid at the bottom that looked like this:

DS homepage grid

On the one hand, I was excited because I had just spent some time pouring over Racheal Andrew’s fantastic site, Grid By Example. However, in the back of my mind I had to think through how it would be at all possible to content manage this entire thing in Craft CMS. The idea of the content constantly changing was a priority to the team and I really wanted to add the ability to let the layout change with it.

Fast forward a bit.

After some trial and error, we landed on a matrix field driving the different types of content. Each matrix block could link to an entry, display a video, add custom text, or be a well for a custom JS component. This matrix field would also be used around the rest of the site, so it was important that the layout would be handled outside of the matrix field. This way we didn’t complicate things for content editors who needed to populate the matrix field in places that it wouldn’t be set in a two-dimensional layout.

They layout of the matrix wound up being based on a set of table fields that laid out the blocks by the order they appeared in the matrix. For example, the two-column grid would be made from a two-column table field and the first row would be 1|1”; the second row would be 2|2”; then to put two blocks side-by-side, the third row would be 3|4”.

If that sounds confusing, it was. I had to draw sketches of each layout to make sure that the number of items in our matrix block would fit on each of our six layouts. If we decided to move items around or adjust any of the layouts, I wound up re-drawing the sketches each time.

This was a situation where yes, the grid could be managed through the CMS, but it was so confusing and inefficient to do so that once we set up the grid for the first time, we left it where it was so we didn’t have to mess with it again. In that kind of situation it’s better to just hard code the grid’s CSS, but we had already done all of the work, so we kept it.

Screen-Shot-2019-02-06-at-9.53.33-AM

There Has Got to Be a Better Way

After the site launched, I talked with friend and co-worker, Marc Hartwig, about this setup and through our discussions we realized you could handle this by making a custom UI for CSS Grid layout. This might come in the form of a field on the page, it could be a set of layout dropdowns that are added to matrix blocks themselves, or it could be a checkbox-based layout that lives in the sidebar on an entry edit page. There would have to be a way to store the layout info and attach it to the entry.

The end result turned into the Grid plugin.

Grid wound up taking the form of a field that lets you lay out sequential items in the Craft CP and then generate CSS Grid Layout CSS that gets appended to the front-end markup.

Demo-field-input

Upgrading Upgridding?

The actual upgrade of the homepage grid took about an hour in total. Some of that time was just making sure the code was going to be applied only to the homepage (since another grid is used on other pages to lay out the matrix field). Also, the rendering of the items on the grid needed to be abstracted to a Twig macro so I could use them on the homepage and on interior pages.

I started the upgrade by installing Grid, then setting up my field. It helped that I had figured out the grid template and row sizing when I manually created the grid with CSS. I knew that each column would use 1fr (to calculate even columns within the allotted space). For most layouts, the rows were all 150px high (more on that in a little bit). Also, there’s a grid-gap of 20px on all layouts.

Settings

The first thing I did was set my Target Field to the matrix field that populates the grid. Then I looked at my CSS and figured out which breakpoints are used to go from a one-column grid up to the six-column grid. In my Grid field settings, I set the breakpoints and device icon for each of my layouts then I went back up to set the column and row sizes.

Ds-feature-grid-settings

On the first layout (used for mobile devices), I wanted to maintain the square size as much as possible, so instead of setting a fixed row size of 150px, I looked at my padding and came up with a vw calculation that kept the size of the grid items close to a square: calc(85vw - 10px).

Ds-feature-grid-settings-mobile

Input

DS grid screenshot

At first glance, the grid looks pretty simple. There are items that span a 1:1 square size and other items that span either one or two columns and one or two rows. But actually—at the behest of this website‘s art director—if you look closely in the top-right area you‘ll see that one item spans 1.5 rows and another 0.5 to even things out. This added a bit of complexity when the grid was made with CSS and table fields, and this complexity remained when converting it to a Grid field.

Ds-feature-grid-one-column
The mobile layout was straightforward and each grid row was equal to the height of each grid item.
Ds-feature-grid-five-column
All of the other layouts were based on each row being 50% of the height of a square grid item.

Laying out the grid was pretty quick and before I knew it, all of the layouts in the Grid field matched the old table field layouts. Speaking of those table fields, at this point I happily removed them from my Homepage’s field layout.

Templating

I made my way to my craft-grid documentation page and grabbed the embed code from the templating section. By default, the demo code had most of the things I needed:

{% grid entry.gridHandle as gridItems %}
    {% for item in gridItems %}
        {% griditem %}
            {# use item.content.fieldHandle to render grid item content #}
        {% endgriditem %}
    {% endfor %}
{% endgrid %}

I had to add in my new rendering macro to handle each grid item. This required me to pass in each matrix block using item.content.

{% grid entry.featureGridLayout as gridItems %}
    {% for item in gridItems %}
        {% griditem %}
            {{ featureGrid.render(item.content) }}
        {% endgriditem %}
    {% endfor %}
{% endgrid %}

The only thing that was missing was the wrapper class that set the margins around the grid, and another class used to set the grid-gap via CSS.

{% grid entry.featureGridLayout as gridItems with { classes: 'home__feature_grid wrapper--grid' } %}
    {% for item in gridItems %}
        {% griditem %}
            {{ featureGrid.render(item.content) }}
        {% endgriditem %}
    {% endfor %}
{% endgrid %}
The final code to embed the grid (with all of the rendering done in a Twig macro).

Fin

So that was it. After doing all of this planning, testing, and writing of the Grid plugin, I was happy to see that my plugin worked for its intended purpose. Since releasing the plugin I‘ve found a few other use cases and—thanks to some folks in the Craft community—I learned about some use cases I didn’t even plan for.

Grid icon

Grid

A field that lets you content manage CSS Grid in Craft CMS.

Recent Posts

Code
Guide 2

Guide 2

Code
Pencil in front of alcohol bottles

Loading Admin Bar via Javascript

Code
DS homepage grid

Does Any of This Scare You?