Gutenberg short code for making columns
One of the things I like about Gutenberg (the static site generator used for this blog) is the support for short codes. Short codes are essentially tiny Tera templates you can call in the markdown files for the content. This immediately lead me to look for a way to make short codes for multiple columns of content.
My first attempts looked something like this:
{% columns() %}
{% column() %}
Content in the left column
{% end %}
{% column() %}
Content in the right column
{% end %}
{% end %}
It didn't work. Turns out the short code parser in Gutenberg doesn't support nested short codes. The reason I wanted to nest two short codes is that the essential bit in embedding some columns in the content is that you need two levels of divs: An outer div as a container for the columns, and inner divs wrapping each column.
So, I was stuck. Later, when browsing the Tera docs for an unrelated reason, I was that it has a split method. That gave me an idea. I don't really need an inner short code, I just need a way to tell apart the content for different columns. What I could do is have one short code that splits the body of the short code based on some specified string.
The use of the new columns
short code looks like this:
{% columns() %}
Content in the left column
[[gutter]]
Content in the right column
{% end %}
It splits the body into columns any time it comes across [[gutter]]
. One weakness of this is that there is no way to escape [[gutter]]
so you can't write about it in a column. There is also no way to specify different column sizes. The code for the short code ended up being short and sweet:
<div class="columns">
{% set cols = body|split(pat="[[gutter]]") %}
{% for col in cols %}
<div class="column">
{{col}}
</div>
{% endfor %}
</div>
Then all that is needed is some CSS to layout the classes. Here is an example using flexbox to be compatible with IE11:
$gutter: 1rem;
$min-viewport-size: 600px;
.columns {
display: flex;
flex-direction: column;
}
.column {
margin-bottom: $gutter;
flex-grow: 1;
flex-basis: 0;
&:last-child {
margin-bottom: 0;
margin-right: 0;
}
}
@media (min-width: $min-viewport-size) {
.columns {
display: flex;
flex-direction: row;
}
.column {
margin-bottom: 0;
margin-right: $gutter;
}
}
It uses two variables:
$gutter
: Space between column.$min-col-size
: Min viewport width for switching from single column to multi column mode.
If IE11 support doesn't matter, then one could, of course, do something slick with CSS grids:
.columns {
display: grid;
grid-gap: 1rem;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
}
That is a lot less CSS to write. This one spills columns over onto the next row to avoid them being narrower than 260px. It end up looking like this: