Understanding WordPress Block CSS

Estimated Reading Time: 9min

Saying that the world of WordPress blocks is complex is probably quite the understatement. Using it as-is already needs some time to grasp. But when you need to work with it not only as a user but as a developer of themes or plugins things start to get complicated and confusing really fast.

This post aims to untangle these complexities concerning block CSS and hopes to at least leave you less confused than you came. It is born from my own ongoing struggle to understand the structure of CSS associated with blocks to then bend them to my own will.

I’ve split this whole thing into two posts. This first one giving you an overview of the current state of things, while the second sketches an approach of how to improve on this.

The structure of block CSS

Core Blocks

The Gutenberg Block Editor quite nicely separates different responsibilities into different packages and files. As such e.g. the styling for the Block Editor User Interface is nicely separated from the styles of individual core blocks.

But it doesn’t stop there. Also the styles for each individual core block are broken into parts. The Block Editor Handbook actually does a quite nice job of explaining these, so I am just going to quote it here:

Core blocks include default structural styles. These are loaded in both the editor and the front end by default. An example of these styles is the CSS that powers the columns block. Without these rules, the block would result in a broken layout containing no columns at all.

The block editor allows themes to opt-in to slightly more opinionated styles for the front end. An example of these styles is the default color bar to the left of blockquotes.
https://developer.wordpress.org/block-editor/how-to-guides/themes/theme-support/#default-block-styles

What this doesn’t explicitly say is that these opinionated styles are indeed opt-in for the front end, but are always loaded for the editor. A comment in the code actually says this:

Always include visual styles so the editor never appears broken.
https://github.com/WordPress/WordPress/blob/a66cb4bb18bbd3d3a96e0ec5f1596705eb1b3a0d/wp-includes/script-loader.php#L1514

What this also doesn’t mention is that there is a third set of styles that is only loaded for the editor. These contain some extra CSS only relevant in the editor. This is sometimes needed since, although often close, the HTML structure of blocks in the editor isn’t the same as the one output on the front end.

If you look at the source code of core blocks you’ll see that these 3 categories are split into 3 files per block, namely editor.scss, style.scss and theme.scss. Not all blocks have CSS for each of these three categories but if they do they are consistently named like this.

For the CSS that actually gets shipped with WordPress one file for each of these categories is built that combines the CSS of all blocks for that specific category.

Let’s summarize what we have learned until here about existing core block styles:

Name Front end Editor
Structural Styles Yes Yes
Opinionated Styles Opt-in Yes
Editor Styles No Yes

Custom Blocks

When writing CSS for a custom block it is recommended to structure it in a similar way as explained in the handbook.

The […] editor_style files will only be enqueued in the editor, while the […] style will be enqueued both in the editor and when viewing a post on the front of your site.
https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/writing-your-first-block-type/#enqueuing-block-scripts

The only difference is the fact that the split between structural and opinionated styles doesn’t exist. This probably makes sense though: Themes can ship their own styles for core blocks, but expecting them to do this for third party blocks is a bit much to ask. So plugins by default need to add a complete and hence opinionated set of styles anyway.

Theme Editor Styles

So far we’ve looked at styles from core blocks and styles from custom blocks. But what about themes? Before the advent of the block editor themes were actually almost solely responsible for styling the front end. As we have seen above this has quite drastically shifted in our new world of blocks. Now themes don’t usually do this on their own but build on top of the styles that already come with WordPress core blocks.

So for the front end themes still add their styles the usual way. For the editor you can still add editor styles, very similar to how you did it before the block editor inside the TinyMCE classic editor.

But all of them now need to be written in a way that goes along well with the core styles outlined before.

With this we’ve arrived at the end of our tour around the structure of block styles. But you might already have noticed things about this whole setup that might sometimes be problematic - which we’ll cover in the next section.

Problems with the way things are right now

Some of you might already have noticed some important properties of the way block styles are structured:

  1. some block styles (structural, editor) are not meant to be configurable and are always loaded
  2. theme styles hence needs to work on top of this core CSS
  3. opting in for opinionated styles is all-or-nothing - you can’t do it just for some blocks

These come with some potential problems which we’re going to look at now before looking at possible solutions.

To make it clear that I am not fighting against some made up or theoretical issues I’ll go at this from a practical perspective: Let’s look at some use cases. Some of them arose in my own work, some of them I’ve come across e.g. in GitHub issues, so they are real world issues people struggle with as we speak.

Opinionated styles for some blocks

What if you like the opt-in opinionated styles for the pullquote block, but not for the other blocks? Well, sorry, you need to decide - either opinionated styles for all blocks or for none at all.

Disabling certain blocks

Another thing you might be doing is disabling certain blocks. You then obviously don’t need to load styles for the disabled blocks. Well, bad luck again. There is no way to configure WordPress to just load the styles for a subset of blocks. Especially for the front end this means a lot of wasted bandwidth and uselessly degraded performance for your site.

Overwriting core CSS

While the core styles try to be as basic as possible they still inevitably make some design decisions.

Let’s look at the Pullquote block as an example. By default it increases the font size for the quote text. In the editor it also adds borders above and below. All fine and you can easily overwrite that with a single line of CSS inside your theme CSS.

So far, so good. Let’s look at another block - the columns block. The structural styles for that block include multiple media queries that among other things switch from the stacked layout for narrow viewports to the columns layout at some point.

If you want to move that breakpoint from say 782px to 900px (because that works better in your themes layout) things get complicated. You first need to make sure that the layout between 782px and 900px stays stacked, fighting against the core media query. Then you are basically copying the core style, just with a breakpoint of 900px this time. But then you notice there are other things that change at that breakpoint you also need to take care of and things quickly get out of hand…

There are way more complicated styles where you’d be simultaneously wrangling media queries, complex selectors and the cascade. You’ll soon be in an all out war fighting against CSS selector specificity and randomly throwing !important statements against your enemy. This can become a quite daunting experience even for experienced CSS-wranglers. And all of this for something that could probably just be a couple of lines of CSS if you’d start from a blank slate.
Even if you manage to get it to work - on top of all of this, block markup and CSS often changes in small but tricky ways from WordPress version to version. So you’re constantly playing a game of catch-up and re-implementing major parts of core CSS.

So making seemingly minor changes, like moving a breakpoint, quickly turns into a nerve-racking endeavor.

Aligning theme CSS with core CSS

Sometimes you might not even want to change core CSS, but just want to amend it. In such a situation you may need to align your styles with core styles. We’ve just talked about breakpoints, but there are also other plenty of other things inside the core block styles like colors, fonts and spacing settings.

Let’s stick with the columns example: Imagine you want to switch between vertical or horizontal lines between columns at the breakpoint the core block styles switch from stacked to column layout. You’d need to figure out this breakpoint manually, copy it to your theme styles and manually keep it in sync with core.

Making it your own

If you’re still not convinced or just interested in reading some more nightmarish stories from the front lines of theme development have a look at this issue for example: https://github.com/WordPress/gutenberg/issues/12299

I hope that by now I’ve convinced most of you that these are real issues that make theme development way less fun. Maybe some were new to you but maybe you’ve been struggling with them since the advent of the block editor just like me.

Last week I’ve finally snapped and started tackling these issues once and for all. What I quickly came to realize is that core block styles don’t fall from the sky. They exist in the Gutenberg GitHub repository, get built and added to WordPress core at some point.

So I thought, maybe, in the spirit of open source, we can just build them on our own adding some tweaks and by doing so solve some of the above issues.

Spoiler: Yes, we can actually build our own core block styles.

This is what I’ll be covering in a follow-up post. If that is something you’d be interested in you may want to subscribe to my RSS feed or follow me on Twitter to not miss when it is published.

I’ve just published the follow-up post.