Standardizing Theme.json Site Spacing in WordPress Block Themes


6 min read

This is part three, of three, in a series on standardizing how we build this next generation of WordPress block themes to accompany the Full Site Editing effort.

If you like this article on spacing, read on about standardizing color slugs, and standardizing font sizes. Each of these are what I would consider core design tenets of a website, of which should be functionally standardized.

As I mention in my other articles in this series, by standardizing just key high-level entries within a WordPress theme’s theme.json file, we can finally create a class of themes that truly are interchangeable. Interchangeable in function, while remaining distinct in style.

So here’s my take on spacing.

What do I mean by “spacing”?

Spacing is an ambiguous term, but I’m referring to the baseline spacing that occurs between elements that may be implemented as padding and margin in the form of “white space”.

White space is the blank area around, inside, or between the various elements of a site. The proper use of white space instills a form of “silence” between content, allowing for improved comprehension, balance, rhythm and visual hierarchy.

White spac
White space is the blank area around, inside, or between the various elements of a site

In the context of a WordPress theme, think of the left/right site padding between a page’s content and the viewport, the padding that is applied to a Group block with a background color, the space between Paragraph blocks, or even the gap between columns.

All of these are what I believe should be applied in a systematic fashion, were one or two values can determine the baseline spacing of a site.

So here’s what I’ve explored, and what could unlock a whole new level of simplicity in designing block themes.

Standardizing spacing in theme.json

While my previous articles on standardizing color and font size slugs within theme.json files is a quicker — edit one file and you’re done — solution, this idea has a bit more weight to it.

First, within the theme.json file, you’ll want to add a new object in settings.custom.spacing, with a value for baseline:

"settings": {
     "custom": {
	"spacing": {
	   "baseline": "2rem"

What we’re doing here is adding the spacing baseline value as a theme’s custom setting, which will then be accessible as a CSS custom property within Gutenberg, as well as the front-end:

body {
  --wp--custom--spacing--baseline: 2rem;

And now we can use that value within the theme’s styling, to allow that one entry to define consistent spacing across the site.

Leveraging the spacing CSS Custom Property throughout the site

There are a few areas to apply the new variable throughout the theme, to standardize the baseline spacing value all across the theme’s design.

First, you’ll likely want to target the header, footer and general content wrappers. These may very well be different for different themes, but here’s what I use on my site:

.wp-block-post-content {
    padding-left: var(--wp--custom--spacing--baseline);
    padding-right: var(--wp--custom--spacing--baseline);

You’ll also need to apply the spacing value within Gutenberg, as .wp-block-post-content does not exist within the block editor.

I just add this to my main theme stylesheet, as I’ve not actually needed many editor styles to warrant creating another stylesheet just to target the editor:

.is-root-container {
    padding-left: var(--wp--custom--spacing--baseline);
    padding-right: var(--wp--custom--spacing--baseline);

You will also want to account for when a block is fullwidth. This snippet forces those fullwidth blocks to extend all the way to the edge of the viewport, negating the parent .wp-block-post-content padding we added earlier.

This applies the effect to blocks within the block editor, as well as the front-end of the site:

 .wp-block-post-content > .alignfull,>.wp-block[data-align=full] {
    margin-left: calc(-1 * var(--wp--custom--spacing--baseline)) !important;
    margin-right: calc(-1 * var(--wp--custom--spacing--baseline)) !important;
    width: calc( 100% + var(--wp--custom--spacing--baseline) + var(--wp--custom--spacing--baseline) ) !important;

Next, let’s add space between text elements:

p, h1, h2, h3, h4, h5, h6 {
    margin-top: var(--wp--custom--spacing--baseline);
    margin-bottom: var(--wp--custom--spacing--baseline);

And last, let’s override the default padding value added to Paragraph blocks that have a background color:

p.has-background {
    padding: var(--wp--custom--spacing--baseline);

Using calculations in spacing

You could take this method a step further even, and make the spacing value more powerful by leveraging calculations.

For example, the .site-header block template part is likely to have more spacing on the top/bottom than on the left/right axis.

Here’s how you would achieve that:

.site-header {
    padding: var(--wp--custom--spacing--baseline) calc(var(--wp--custom--spacing--baseline) * 0.5);

Another common design pattern is to have more space (translated as padding) to a parent Group or Columns block when a background color is added to either block.

Use this snippet to make those blocks have double the baseline padding, but only if there is no custom padding value applied to the block:

.wp-block-group.has-background:not([style*="padding"]) {
    padding: calc(var(--wp--custom--spacing--baseline) * 2);

If you’re using calculations to tailor spacing values, I recommend a consistent scaled proportionate approach. This way, changing the baseline value properly scales across the various ways you’ve implemented it.

Supporting block gaps

There’s been quite a bit of work on how block themes can set the spacing between child blocks, such as a flex layout Group block, or the columns within a parent Columns block.

This PR on Github addresses how the block gap will apply to blocks that opt-into the new feature.

A proposal for how block gap will work, sourced from this PR.

This aims to have the block gap support added to the styles.spacing.blockGap, object like this:

"styles": {
    "spacing": {
        "blockGap": "2rem"

That would generate the --wp--style--block-gap CSS property to use throughout the theme’s styling, and set the default value for whichever blocks that support setting a gap between blocks.

This is still in the works today, but perhaps this same value could be used instead of the custom setting we used in the earlier examples. Either way, the idea is the same — to have one value that systemizes spacing across a theme’s design language.

What do you think?

A clear and consistent systematic approach to spacing, that works across themes, would be huge for unlocking the creative potential of themes — while also making them that much easier to express with.

To illustrate this, here’s a comparison of how changing the value of the settings.custom.spacing.baseline setting on my site’s theme.json file affects the overall feel of the site:

Pretty cool, eh!?

And while this is an interesting real-world exploration of how themes can leverage a theme.json setting to drive design language, site spacing — and even most of the CSS I’ve implemented above — should be a provided by core.

Any styling that themes have to share — especially foundational design components, like spacing — should be a part of the core WordPress experience, if your site is published with a theme.json block theme.

For folks diving into building WordPress block themes, have you implemented a system like this here, or have any other ideas?

I’d love to hear your thoughts — @richard_tabor.

If you like this article on site spacing, read the others in this standardization series covering color slugs and font sizes.