wordpress themes – CSS-Tricks https://css-tricks.com Tips, Tricks, and Techniques on using Cascading Style Sheets. Wed, 01 Mar 2023 15:12:49 +0000 en-US hourly 1 https://wordpress.org/?v=6.2.2 https://i0.wp.com/css-tricks.com/wp-content/uploads/2021/07/star.png?fit=32%2C32&ssl=1 wordpress themes – CSS-Tricks https://css-tricks.com 32 32 45537868 How the Style Engine Generates Classes https://css-tricks.com/how-the-style-engine-generates-classes/ Mon, 27 Feb 2023 14:46:43 +0000 https://css-tricks.com/?page_id=376996 The WordPress Style Engine generates the CSS for a block theme. Why would you want to know how an invisible process like that works? Well, just like writing CSS, you will want to ensure your code is organized and structured so that your styles properly use the CSS Cascade.


How the Style Engine Generates Classes originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
In the last article in this series, we went through theme.json presets and style section configurations. Then we discussed how the WordPress Style Engine processes the JSON into CSS and consolidates it with consolidated data received from different sources — WordPress Core styles, theme styles, and user styles — to create a global stylesheet. We also learned how to apply the generated CSS to individual elements, like headings, and specific blocks, like the Query Loop.

The Style Engine is responsible for structuring and organizing your CSS into a single global stylesheet, and understanding how it parses your theme.json file and styles coming from other sources is rather important. Otherwise, you might find yourself in a situation where you’re unsure why one of your styles isn’t working. This way, you’ll have an idea of where to dig in and troubleshoot without being in the dark.

I discuss the WordPress Style Engine in another article. That’s a great place to start if you’re looking for a little more context without all the nitty gritty details we’re covering here.

Table of contents


Where styles come from

The Style Engine has to get its information from somewhere, right? The truth is that there are several places where the Style Engine looks for information before it generates CSS.

  • WordPress Core: That’s right, WordPress ships with pre-defined styles right out of the box. Think of these as default styles authored at the CMS level, sort of like the default styles in browsers. They are there by default, but we can override them in our theme.json file.
  • The theme.json file: We’ve covered this file thoroughly throughout the series. It’s where we enable certain styling features and define default styles, such as colors, fonts, and spacing. You can think of it like the style.css file in a “classic” WordPress theme: the styles we author at the theme level.
  • User styles: WordPress has a number of features that allow you to set styles directly in WordPress without touching code. The “big” one of which is the Global Styles panel in the Site Editor. It uses the styles from WordPress Core and theme.json as default settings, but changing the style settings overrides the other two sources.

Can you sort of see how this forms a hierarchy? WordPress Core styles can be overridden by theme.json, and both theme.json and WordPress Core styles can be overridden by user styles. It’s structured a lot like the CSS Cascade, in a way!

Combining sources

Just so we have a good picture of what we’re working with, here’s a screenshot of the WordPress Site Editor with the Global Styles settings on display.

WordPress Site Editor screen with the Global Styles settings open and highlighted with a red border.

This is the interface where user styles come from. Notice how there is a tile at the top of the panel that provides a preview of the theme’s current typography and colors. That tile is called a style variation, which is basically preset style configurations that are defined in JSON in the theme folder. A theme can have any number of pre-defined style variations, and choosing one instantly swaps the theme’s fonts and colors with the selected tile.

So, already, you can see how the user styles are informed by theme.json. But notice the three categories of style settings below the style variations: Typography, Colors, and Layout. Clicking into any of those settings allows you, as the user, to override the configuration of the currently selected style variation.

WordPress Site Editor screen with the Global Styles settings open to color options.

Now you see how theme.json and WordPress Core styles are overridden by user styles. We can lean on WordPress Core styles for basic layout and styling, customize them and define our own styles in theme.json, then let the user take greater control of things with user styles from the Site Editor’s Global Styles settings.

All of this styling data is stored and parsed as JSON. The Style Engine generates that JSON and then consolidates it into a single global stylesheet for the theme.

Processing theme.json

During the consolidation phase, the Style Engine takes a look at the theme.json file located in the theme directory. We talked earlier about the structure of theme.json and how it is organized into two “top-level” sections, settings, and styles.

{
  "version": 2,
  // Top-level settings
  "settings": {},
  "styles": {
    // Global element styles
    "elements": {},
    // Block styles
    "blocks": {}
  }
}

The Style Engine processes those sections like this. First, the top-level settings generate CSS variables that are applied to the <body> element (e.g. --wp--preset--<category>-<slug>):

{
  "version": 2,
  "settings": {
    // Top-level settings
    "color": {
      "palette": [
        {
          "color": "#F8A100",
          "name": "Primary",
          "slug": "primary"
        }
      ]
    }
  },
  "styles": {
    // Global element styles
    "elements": {},
    // Block styles
    "blocks": {}
  }
}

In this example, we get a new CSS variable, --wp-preset--color--primary. The Style Engine then applies it to new CSS classes with a .has- prefix:

body {
  --wp--preset--color--primary: #F8A100;
}

.has-primary-color {
  color: var(--wp--preset--color--primary) !important;
}
.has-primary-background-color {
  background-color: var(--wp--preset--color--primary) !important;
}
.has-primary-border-color {
  border-color: var(--wp--preset--color--primary) !important;
}

Neat, right? These classes can now be used anywhere in the theme!

Next, the styles.elements object generates element selectors matching the HTML element they represent (e.g. styles.elements.h2 corresponds with the <h2> element).

{
  "version": 2,
  "settings": {},
  "styles": {
    // Global element styles
    "elements": {
       "h2": {
        "color": {
          "text": "#F8A100"
        }
      }
    },
    // Block styles
    "blocks": {}
  }
}

In this example, an h2 selector is generated with a #F8A100 color value:

h2 {
  color: #F8A100;
}

And, hey, we could have used the CSS variable we defined earlier in settings as the color value, knowing the Style Engine is going to generate it:

{
  "version": 2,
  "settings": {},
  "styles": {
    // Global element styles
    "elements": {
       "h2": {
        "color": {
          "text": "var(--wp--preset--color--primary)"
        }
      }
    },
    // Block styles
    "blocks": {}
  }
}

…which gives us this in CSS:

h2 {
  color: var(--wp--preset--color--primary);
}

And, finally, the settings.blocks object uses the concatenation of the block and element selector. This way, the specificity for these selectors is higher, giving them greater priority over the other generated styles we’ve seen so far.

For example, let’s change the color of the Site Title block:

{
  "version": 2,
  "settings": {},
  "styles": {
    // Global element styles
    "elements": {},
    // Block styles
    "blocks": {
      "blocks": {
        "core/site-title": {
          "color": {
            "palette": [
              {
                "color": "#F8A100",
                "name": "SF Orange",
                "slug": "sf-orange"
              }
            ]
          }
        }
      }
    }
  }
}

Here’s how that shakes out in CSS. The Style Engine generates a class for the Site Title block (.wp-block-site-title) and for the color as a descendant combinator selector:

.wp-block-site-title .has-sf-orange-color {
  color: var(--wp--preset--color--sf-orange) !important;
}
.wp-block-site-title .has-sf-orange-background-color {
  background-color: var(--wp--preset--color--sf-orange) !important;
}
.wp-block-site-title .has-sf-orange-border-color {
  border-color: var(--wp--preset--color--sf-orange) !important;
}

Generated CSS classes

So, now we have a pretty good idea of how the WordPress Style Engine processes data it receives from various sources into a block theme’s CSS.

We also got to see how the settings and styles from theme.json produce CSS variables and classes. What you’re probably interested in now is what other CSS classes do we get from Style Engine. Let’s dig into those.

Block classes

A “block” in WordPress is a standalone component that can be dropped into any page or post. Every block gets a CSS class that is used as the block’s parent container.

And all of the class names have a wp-block prefix. For example, the Cover block gets a .wp-block-cover class that we can use to select and style the entire block. WordPress calls these semantic classes because they identify the block in the name.

Blocks get another class in addition to its semantic class, called its stateful class. These classes describe the block’s state, as if it “has” a certain text color, or “is” a certain background color or layout type.

For example, let’s say we add a Post Title block to one of our theme’s templates in the Site Editor. But then we change it, so it has a background color, the “SF Orange” color we defined in an earlier example.

The WordPress Site Editor open on the Homepage template and displaying a large bright orange box with Hello World in it in black.

This results in a stateful class on the element. Here’s the HTML:

<h1 class="wp-block-post-title has-background has-sf-orange-background-color">
  <a href="#" target="_self">Hello world!</a>
</h1>

See the two stateful CSS classes this made?

  • .has-background: This adds padding to the element, so the Post Title does not bump the edges of the container, allowing more background to show.
  • .has-sf-orange-background-color: This applies the CSS variable for the color.

Here is a table of selected WordPress blocks and examples of the sorts of classes that are generated and applied to them.

BlockSemantic ClassStateful Class
Buttons.wp-block-buttons.has-custom-width
Cover.wp-block-cover.is-light.has-parallax
.has-position-vertical
Columns.wp-block-columns.has-2-columns
.has-background
Heading.wp-block-heading.has-text-color
Gallery.wp-block-gallery.has-nested-images
Image.wp-block-image.alignleft
.aligncenter
.alignright
.has-custom-border
Spacer.wp-block-spacer.is-style-dots
.has-text-color
Quote.wp-block-quote.is-layout-constrained

Again, this is not an exhaustive table of blocks. You can find a complete list, however, over at the WordPress Block Editor Handbook. If there is a complete list of stateful classes living somewhere, I could not find it. So, while the stateful class examples in the table are accurate based on my testing, it should also not be considered a complete list of classes.

Layout classes

WordPress provides different layout types that can be applied to container-based blocks. By that, we’re talking about the following blocks:

  • Columns
  • Group
  • Post Content
  • Query Loop

Each of these blocks can be assigned a layout type, and there are three options:

  • Flow layout: Adds vertical spacing between nested blocks in the margin-block direction. Those nested blocks can also be aligned to the left, right, or center.
  • Constrained layout: Same exact deal as a Flow layout, but with width constraints on nested blocks that are based on the contentWidth and wideWidth settings (either in theme.json or Global Styles).
  • Flex layout: This was unchanged in WordPress 6.1. It uses CSS Flexbox to create a layout that flows horizontally (in a row) by default but can flow vertically as well, so blocks stack one on top of another. Spacing is applied using the CSS gap property.
The block editor with a two-column layout and the Layout settings open.

Depending on the settings selections, this corresponds to the following CSS classes:

  • .is-layout-flow
  • .is-layout-constrained
  • .is-layout-flex

See how the stateful naming convention is carried over to these? These aren’t the only layout-related classes, though. Here are all of the available classes, as documented in the WordPress Block Editor Handbook:

Justin Tadlock has an excellent article that explains these layout types and semantic classes with use cases and examples. You can also refer to my article, “Using The New Constrained Layout In WordPress Block Themes”, for even more information on using different layouts.

Additional sources of user styles

We already know we can use the Global Styles settings in the Site Editor to override the CSS styles that come from WordPress Core and theme.json. We called those user styles.

But that’s not the only place where user styles can come from. For example, let’s say you’re writing a new post and want to style a specific paragraph a certain way. And let’s say you have a CSS class that you either defined theme.json or perhaps even your own stylesheet! As long as the CSS for those classes is loaded on the page, you can add them to any block in the block’s Advanced settings.

This Add Additional CSS Classes to Blocks guide walks you through using custom CSS classes on your site.

There’s another place where user styles can go. As of Gutenberg 14.8, a new custom “Additional CSS” box has been added to the Global Styles settings.

Source: Make WordPress Core

And, hey, a big heads-up: The CSS from these user-style sources can override or even remove the CSS settings in theme.json. Another big thing to know is that whatever styles you define here could get lost when changing themes. It’s probably better to actually create these styles in theme.json or by enqueuing your own stylesheet.

Block stylesheets

There’s one more place where the WordPress Style Engine might get some styling data, and that’s from your own stylesheets! That’s right: you can add your own stylesheets to a theme.

Sure, you could also use the required style.css file as your stylesheet. Most block themes won’t be using it anyway. But there’s an even more efficient way to go about it: to enqueue stylesheets for specific blocks.

First off, you may already be familiar with the concept of enqueuing files from working with classic WordPress themes and the wp_enqueue_style() function. That loads a CSS file by providing a path where WordPress can find it.

We can do the same thing but on a block-by-block basis. Each WordPress block has its own associated stylesheet, and we can enqueue our own stylesheets for them. For example, here I am adding a stylesheet of custom styles for the Quote block in my theme’s functions.php file:

add_action( 'init', 'emptytheme_enqueue_block_styles' );

function emptytheme_enqueue_block_styles() {
  wp_enqueue_block_style( 'core/quote', array(
    'handle' => 'emptytheme-block-quote',
    'src'    => get_theme_file_uri( "assets/blocks/quote.css" ),
    'path'   => get_theme_file_path( "assets/blocks/quote.css" )
  ) );
}

Check that out — it’s practically the same way we’d load custom stylesheets in a classic WordPress theme, PHP and all.

If you want to add styles to multiple blocks, you need to enqueue CSS files using an array and then loop through them. The WordPress Developer Blog has a nice example written by Justin Tadlock:

add_action( 'init', 'themeslug_enqueue_block_styles' );

function themeslug_enqueue_block_styles() {
  // Add the block name (with namespace) for each style.
  $blocks = array(
    'core/button'
    'core/heading',
    'core/paragraph'
  );

  // Loop through each block and enqueue its styles.
  foreach ( $blocks as $block ) {

    // Replace slash with hyphen for filename.
    $slug = str_replace( '/', '-', $block );

    wp_enqueue_block_style( $block, array(
      'handle' => "themeslug-block-{$slug}",
      'src'    => get_theme_file_uri( "assets/blocks/{$slug}.css" ),
      'path'   => get_theme_file_path( "assets/blocks/{$slug}.css" )
    ) );
  }
}

All of this is in active development!

Please note that the WordPress Style Engine is still pretty new, and the work for it is ongoing. The Style Engine document lists some of the planned upcoming work:

  • Consolidate global and block style rendering and enqueuing (ongoing)
  • Explore pre-render CSS rule processing with the intention of reduplicating other common and/or repetitive block styles. (ongoing)
  • Extend the scope of semantic class names and/or design token expressions, and encapsulate rules into stable utility classes.
  • Propose a way to control hierarchy and specificity, and make the style hierarchy cascade accessible and predictable. This might include preparing for CSS cascade layers until they become more widely supported, and allowing for opt-in support in Gutenberg via theme.json.
  • Refactor all blocks to consistently use the “style” attribute for all customizations, that is, deprecate preset-specific attributes such as attributes.fontSize.

You can track the development status on the GitHub project board.

Even with these limitations, this tweet from Rich Tabor and the following video demonstrates the unlimited opportunities we have for customizing the appearance of a block theme — without even touching code!

⚠️ Contains auto-playing media
Cycling through various theme styles.

All made possible, thanks to the WordPress Style Engine and its JSON parsing superpowers.

Additional resources

We covered a lot of ground in this article! I thought I would share some of the resources I relied on for the information.

Documentation

Tutorials

GitHub issues

A lot of the context for this article comes from proposals and issues reported to the WordPress GitHub repo.

Next up…

We’re actually all done! But I’ve created a page that pulls all of what we learned about CSS in WordPress Block Themes and provides you with a one-stop place you can reference anytime you need it.


How the Style Engine Generates Classes originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
376996
WordPress Global Styles Reference Tables https://css-tricks.com/wordpress-global-styles-reference-tables/ Tue, 31 Jan 2023 17:41:00 +0000 https://css-tricks.com/?page_id=376849 We’ve covered a lot of ground in this series. So much so that I thought it would be helpful to condense all the various block theme settings and styles from theme.json into a single page right here.


WordPress Global Styles Reference Tables originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
The following information is based on the WordPress documentation for ease of reference only. At the time of writing, Global Styles (theme.json) and user interface customizations are being actively developed. And, of course, all of this is still very much in active development. If you notice something has changed or is incorrect, please let me know in the comments!

Table of contents


Settings

{
  "version": 2,
  "settings": {
    "border": {},
    "color": {},
    "typography": {},
    "layout": {},
    "spacing": {},
    "outline": {},
    "appearanceTools": true | false,
    "useRootPaddingAwareAlignments": true | false
}

We’ll start with the settings configurations, where we have broken this out into multiple tables for Typography, Colors, Custom, and Spacing.

Remember, these “top-level” styles are applied on the <body> element. And it might be helpful to recall the syntax we’re dealing with:

  • CSS Custom properties: --wp--preset--{preset-category}--{preset-slug}
  • CSS classes: .has-{preset-slug}-{preset-category}

Border

The border section enables border controls in the editor UI.

{
  "version": 2,
  "settings": {
    "border": {
      "color": true,
      "radius": true,
      "style": true,
      "width": true
  }
}
JSON PropertyWhat it DoesCSS Equivalent
settings.border.colorEnables the border color control.border-color
settings.border.radiusEnables the border radius control.border-radius
settings.border.styleEnables the border style control.border-style
settings.border.widthEnables the border width control.border-width

Color

The color section sets the theme’s color palettes, gradients, and duotone effects.

{
  "version": 2,
  "settings": {
      "color": {
        "palette": {
          "slug": "",
          "color": "",
          "name": "",
        },
        "gradients": [
          {
            "slug": "",
            "gradient": "",
            "name": ""
          }
        ],
        "duotone": {
          "slug": "",
          "color": "",
          "name": "",
        }
        "link": true | false
      }
    }
  }
}
JSON PropertyWhat it DoesCSS Custom Properties
settings.color.pallete.colorDefines color values for use throughout the theme.--wp–preset--color--{slug}
settings.color.gradients.colorDefines gradient patterns for use throughout the theme.--wp–preset--gradient--{slug}
settings.color.duotoneDefines duotone effects for use throughout the site.–-wp–preset--duotone--{slug}
settings.color.linkEnables the setting to change the theme’s default link color in the Site Editor.–-wp–preset-–color-–link

Typography

{
  "version": 2,
  "settings": {
    "styles": {
      "typography": {
        "dropCap": true | false,
        "customFontSize": true | false,
        "fluid": "<undefined>" | false,
        "fontSizes": [
          {
            "fluid": {
              "min": "",
              "max": ""
            },
           "slug": "",
           "size": "",
           "name": ""
         },
       ],
      "fontFamilies": [
        {
          "fontFamily": "",
          "name": "",
          "slug": "",
          "fontFace": ""
        },
      ],
      "lineHeight": true | false,
      "fontStyle": true | false,
      "letterSpacing": true | false,
      "textDecoration": true | false,
      "textTransform": true | false,
    }
  }
}
JSON PropertiesWhat it DoesCSS Custom Property
settings.typography.fontSizesDefines font size throughout the site.--wp--preset--font-size--{slug}
settings.typography.fontFamiliesDefines typographic font use throughout the site.--wp--preset--font-family--{slug}
settings.typography.lineHeightDefines line height to use throughout the site.--wp--preset--line-height--{slug}
settings.typography.fontStyleDefines font style to use throughout the site.--wp--preset--line-height--{slug}
settings.typography.fontWeightDefines font weight for use throughout the site.--wp--preset--font-weight--{slug}
settings.typography.letterSpacingDefines letter spacing for use throughout the site.--wp--preset--letter-spacing--{slug}
settings.typography.textDecorationDefines text decoration for use throughout the site.–wp-preset–text-decoration–{slug}
settings.typography.textDecoration.lineDefines link text decoration line for use throughout the site.--wp-preset--text-decoration--line
settings.typography.textDecoration.styleDefines link text decoration line style for use throughout the site.--wp-preset--text-decoration--style--{slug}
settings.typography.textDecoration.colorDefines link text decoration color for use throughout the site.--wp–preset--text-decoration--color--{slug}
settings.typography.textDecoration.thicknessDefines link text decoration line thickness for use throughout the site.--wp–preset--text-decoration--thickness--{slug}
settings.typography.textTransformDefines text transformation type (uppercase, lowercase) for use throughout the site.--wp--preset--text-transform--{slug}

Spacing

These settings enable/disable spacing controls for margin and padding in the Site Editor and allow you to set which CSS units to support.

"styles": {
  "spacing":{
    "padding": true,
    "margin": true,
    "units": [ "px", "em", "rem", "vh", "vw", "%" ]
  }
}

The Site and Block Editors include slider form inputs that allow you to set spacing on a scale of predefined values. We can customize that scale with the spacingScale property:

{
  "version": 2,
  "settings": {
    "spacing": {
      "spacingScale": {
        "operator": "+",
        "increment": <number>,
        "steps": <number>,
        "mediumStep": <number>,
        "unit": ""
      }
    }
  }
}
JSON PropertyWhat it DoesExample
settings.spacing.operatorDetermines whether the control scales up or down.+
settings.spacing.incrementDetermines much the spacing changes per step.0.25
settings.spacing.stepsDetermines the number of available steps on the scale.6
settings.spacing.mediumStepSets the midpoint of the range scale.1.5
settings.spacing.unitSets the CSS length unit of the numeric value.rem

One more thing we can do with spacing is create CSS custom properties that can be used throughout the theme:

{
  "version": 2,
  "settings": {
    "spacing": {
      "spacingSizes": [
        {
          "size": "",
          "slug": "",
          "name": ""
        }
      ]
    }
  }
}
JSON PropertyWhat it DoesExample
settings.spacing.spacingSizes.sizeSets the custom size value, including unit.3.5rem
settings.spacing.spacingSizes.slugThe slug used in the CSS custom property name.medium
settings.spacing.spacingSizes.nameProvides the label for the size in the Site and Block Editor UI.Medium

The resulting CSS custom property syntax is: --wp-preset--spacing--<slug>

Layout

{
  "version": 2,
  "settings": {
    "layout": {
      "contentSize": "",
      "wideSize": "",
      "type": "",
    }
  }
}
JSON PropertyWhat it DoesGenerated CSS Property
settings.layout.contentSizeSets the maximum width of the default content container for pages and posts.--wp--style--global--content-size
settings.layout.contentWideSets the maximum width of the“wide” content container for pages and posts.--wp--style--global--wide-size
settings.layout.typeDetermines is the container is default or constrained.

Appearance tools

{
  "version": 2,
  "settings": {
    "appearanceTools": true | false,
}

Setting this to true is a shorthand for enabling the following settings:

{
  "version": 2,
  "settings": {
    "border": {
      "color": true,
      "radius": true,
      "style": true,
      "width": true
    },
    "color": {
      "link": true
    }
    "spacing": {
      "margin": true,
      "padding": true,
      "blockGap": true,
    },
    "typography": {
      "lineHeight": true
    }
  }
}

Root padding-aware alignments

{
  "version": 2,
  "settings": {
    "useRootPaddingAwareAlignments": true | false
}

Setting this to true is a shorthand for enabling the following settings:

{
  "version": 2,
  "settings": {
    "spacing": {
      "margin": true,
      "padding": true
    },
  }
}

Styles

The idea here is that styles are organized by top-level styles (those that set styles on the <body>), global styles (those that set styles on global elements, like headings), and block styles (those that set styles on specific blocks).

{
  "version": 2,
  "styles": {
    // Top-level styles
    // etc.

    // Global-level styles
    "elements": { },

    // Block-level styles
    "blocks": {  }
  }
}

Top-level styles

{
  "version": 2,
  "styles": {
    // Top-level styles
    "border": [],
    "color": [],
    "spacing": [],
    "typography": [],
    "filter": "",
    "shadow": "",
    "outline": []
  }
}
PropertyStyleCSS equivalentAdditional props
bordercolorborder-color
radiusborder-radius
styleborder-style
widthborder-width
topborder-topcolorstylewidth
rightborder-rightcolorstylewidth
bottomborder-bottomcolorstylewidth
leftbottom-leftcolorstylewidth
colorbackgroundbackground-color
gradientbackground-image
textcolor
spacingblockGapgap (in Flexbox and Grid containers)
marginmarginbottomleftrighttop
paddingpaddingbottomleftrighttop
typographyfontFamilyfont-family
fontSizefont-size
fontStylefont-style
fontWeightfont-weight
letterSpacingletter-spacing
lineHeightline-height
textDecorationtext-decoration
textTransformtext-transform
filterduotonefilter
shadowbox-shadow
outlinecoloroutline-color
offsetoutline-offset
styleoutline-style
widthoutline-width

Global styles

{
  "version": 2,
  "styles": {
    "elements": {
      "buttons": {
        "border": {
          "radius": ""
          },
          "color": {
            "background": "",
            "text": ""
          }, 
          "heading": {},  
          "h1": { },
          "h2": { },
          "h3": { },
          "h4": { },
          "h5": { },
          "h6": { },              
          "link": {
            "border": { },
            "color": { },
            "spacing": { },
            "typography": { }
            }
          }
        }
    }
  }
}
JSON PropertyWhat It DoesWhere It Is Used
styles.elements.buttonsDefines button element properties (e.g., bordercolor, etc.) for use throughout the site.Buttons
styles.elements.headingDefines styles of all the headings, the (<h1> to <h6>) elements for use throughout the site.<h1> to <h6> (all)
styles.elements.h1 to styles.elements.h6Individually defines styles for <h1> to <h6> elements of the heading block for use throughout the site.<h1> to <h6> (individually)
styles.elements.linkDefines link <a> element style for use throughout the site.<a>
styles.elements.citeDefines styles for the blockquote.citequote.cite classes for use throughout the site.Quote, Pullquote
styles.elements.captionDefines styles for <figcaption> and <caption> elements for Image and Table blocks, respectively, for use throughout the site.Figure, Table
styles.elements.spacing.paddingSets the padding of headings, row, blocks and paragraph blocks for use throughout the site.Headings, row, blocks, paragraph
styles.elements.typographySets the default typography style for headings and paragraph blocks for use throughout the site.headings, paragraph

Global-level styles: interactive elements

{
  "version": 2,
    "styles": {
      "elements": {
        "button": {
          "color": {
            "background": " ",
            "text": " "
          }
          ":hover": {
            "color": {
              "background": " ",
              "text": " "
            }
          },
          ":focus": {
            "color": {
              "background": " ",
              "text": " "
            }
          },
          ":active": {
            "color": {
              "background": " ",
              "text": " "
          }
        },
        ":visited": {
          "color": {
            "background": " ",
            "text": " "
          }
        }
      }
    }
  }
}

Note: We can use any already predefined JSON properties in settings presets like typography, outline, shadow, etc., to add styling to any global JSON elements.

JSON PropertyStyleWhat It DoesCSS Equivalent
styles.elements.colorBackgroundDefines link background color for use entire site.a:link { background-color }
TextDefines link text color for use entire site.a:link { color }
styles.elements.:hoverBackgroundDefines hover state link background color for use entire site.a:hover { background-color }
TextDefines hover state link text color for use entire site.a:hover { color }
styles.elements.:focusBackgroundDefines focus state link background color for use entire site.a:focus { background-color }
TextDefines focus state link text color for use entire site.a:focus { color }
styles.elements.:activeBackgroundDefines active state link background color for use entire site.a:active { background-color }
TextDefines active state link text color for use entire site.a:active { color }
styles.elements.:visitedBackgroundDefines visited state link background color for use entire site.a:visited { background-color }
TextDefines visited state link text color for use entire site.a:visited { color }

Custom

This table shows examples of custom properties you could make using the Custom section of the theme.json file. The CSS custom properties generated by the Custom section use the following syntax: --wp--custom--<variable-name>

JSON PropertySyntaxGenerated Custom Property
settings.custom.spacing.padding--wp--custom--{padding}--wp--custom--padding
settings.custom.typography--wp--custom--{typography}--wp--custom--typography
settings.custom.fontWeight--wp--custom--{font-weight}--wp--custom--front-weight
settings.custom.lineHeight--wp--custom--{line-height}--wp--custom--line-height
settings.custom.someColor--wp--custom--{some-color}--wp--custom--some-color
settings.custom.someParagraph--wp--custom--{some-paragraph}--wp--custom--some-paragraph

Block-level styles

All the global-level styles including the elements may be used to customize the CSS for individual blocks to overwrite the global customization. Block-level styles have precedence over top-level styles (global).

{
  "version": 2,
  "styles": {
    // Top-level styles
    // etc.

    // Global-level styles
    "elements": { },

    // Block-level styles
    "blocks": {
      "core/<BLOCKNAME>": {
        // Define or overwrite any global styles
        "typography": {
          "fontSize": " ",
          "fontWeight": "",
          "lineHeight": "",
          "letterSpacing": "",
          "textDecoration": "",
          "textTransform": "" 
        },
        // Define or overwrite any global elements styles
        "elements": {
          "link": {
            "typography": {
              "textDecoration": ""
            },
            "color": {
              "text": " ",
              "background-color": ""
            },
            ":hover": {
              "typography": {
                "textDecoration": ""
              },
              "color": {
                "text": "",
                "background-color": ""
              },
            },
            ":focus": {
              "typography": {
                "textDecoration": ""
              },
              "color": {
                "text": " ",
                "background-color": ""
              },
            },
            ":active": {
              "typography": {
                "textDecoration": ""
              },
              "color": {
                "text": " ",
                "background-color": ""
              },
            },
            ":visited": {
              "typography": {
                "textDecoration": ""
              },
              "color": {
                "text": "",
                  "background-color": ""
              },
            },
          },
        },     
      },
      // Additional blocks
      "core/<BLOCKNAME>": {
        "typography": { },
        // etc.
      }
    }
  }
}
JSON PropertyStyleWhat It Does
.styles.core.<BLOCKNAME>.typographyfont-sizeDefines or overwrites the global font size of this block only.
font-weightDefines or overwrites the global font weight of this block only.
line-heightDefines or overwrites he global font height of this block only.
letter-spacingDefines or overwrites he global letter spacing of this block only.
text-decorationDefines or overwrites he global text decoration of this block only.
text-transformDefines or overwrites the global text transformation of this block only.
.styles.core.<BLOCKNAME>.elements.link.typographytext-decorationDefines or overwrites the global link typography of this block only.
.styles.core.<BLOCKNAME>.elements.link.color`background-colorDefines or overwrites the global link background color of this block only.
colorDefines or overwrites the global link text color of this block only.
.styles.core.<BLOCKNAME>.elements.link.:hover.typographytext-decorationDefines or overwrites the global text decoration of hover link state of this block only.
.styles.core.<BLOCKNAME>.elements.link.:hover.colorbackground-colorDefines or overwrites the global background color of hover link state of this block only.
colorDefines or overwrites the global background color of hover link state of this block only.
.styles.core.<BLOCKNAME>.elements.link.:active.typographytext-decorationDefines or overwrites the global text decoration of active link state of this block only.
.styles.core.<BLOCKNAME>.elements.link.:active.colorbackground-colorDefines or overwrites the global background color of active link state of this block only.
colorDefines or overwrites the global background color of active link state of this block only.
.styles.core.<BLOCKNAME>.elements.link.:focus.typographytext-decorationDefines or overwrites the global text decoration of focus link state of this block only.
.styles.core.<BLOCKNAME>.elements.link.:focus.colorbackground-colorDefines or overwrites the global background color of focus link state of this block only.
colorDefines or overwrites the global background color of focus link state of this block only.
.styles.core.<BLOCKNAME>.elements.link.:visited.typographytext-decorationDefines or overwrites the global text decoration of visited link state of this block only.
.styles.core.<BLOCKNAME>.elements.link.:visited.colorbackground-colorDefines or overwrites the global background color of visited link state of this block only.
colorDefines or overwrites the global background color of visited link state of this block only.

For use case examples of block-level CSS customization, you may refer to the latest Twenty Twenty-Three theme and other recent block themes in the theme directory.

Wrapping up

You made it through this compelete guide to WordPress block theme CSS and settings! We started with a brief introduction that compares WordPress block themes to the “classic” PHP templating system. From there, we talked a bit about JSON because, funny enough, that’s how we “write” CSS in WordPress block themes.

Then there’s theme.json the actual file where all of those styles are defined, much like style.css was for classic PHP themes. The file is tightly structured into sections for toggling WordPress settings and defining CSS globally throughout a block theme.

And once we’re done defining a block theme’s settings and styles, the WordPress Style Engine takes over, processing our JSON into a nicely organized set of CSS styles used in the theme.

It’s crazy just how different block themes are when it comes to defining and managing styles in WordPress! All of this is still in active development, and we are likely to see new features and options added to theme.json.

See something that’s new or has changed? Please let me know in the comments!


WordPress Global Styles Reference Tables originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
376849
Defining Global Styles https://css-tricks.com/defining-global-styles-in-wordpress/ Tue, 31 Jan 2023 16:16:18 +0000 https://css-tricks.com/?page_id=376823 Let’s move to the other top-level section of theme.json where we can configure the CSS of a block theme: styles. We’ll learn what it is exactly and how we can use it to override and apply the preset settings values we covered in Part 2.


Defining Global Styles originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
In Part 2 of this series, we covered the process of enabling certain features in a WordPress block theme in the theme.json file. We spent time in the settings section of the file, outlining the various available features and how they allow us to customize the Global Styles UI in the WordPress Site Editor with preset values that map to CSS custom property values that are scoped to the <body> element.

Table of contents


The styles section (styles)

The styles section sits alongside the settings section we covered in the last article as a top-level section.

{
  "version": 2,
  "settings": {},
  "styles": {
    // etc.
  }
}

We learned in Part 2 that the settings section defines default styles at the top level — the CSS generally applied to the <body> element. The styles section is where we can override those presets with more granular styles applied to specific global elements (e.g. <h1>) and specific blocks (e.g. theme.json file from Twenty Twenty-Three, and other latest block themes from theme directory).

In other words, the settings are “top-level” styles that cascade down to all elements. We can override those presets in the styles section where we apply styles to specific elements and blocks. In fact, elements and blocks are subsections of styles:

{
  "version": 2,
  "settings": {},
  "styles": {
    // Global element styles
    "elements": {},
    // Block styles
    "blocks": {}
  }
}

What makes this great is that theme.json is outlined in a way that organizes styles to cascade very much the same way CSS stylesheet does. If settings is for configuring global style features, then styles is where we override those presets when working with specific global elements and individual blocks.

Supported properties

When we looked at the settings section in Part 2, we saw that it contains “features” that can be enabled and configured in a block theme. Regarding the styles sections, we’re defining CSS properties instead.

In fact, the objects contained in the styles section are mapped to actual CSS properties. For example, styles.border-color corresponds to the border-color property in CSS.

So, before we jump into the styles section and how to customize the appearance of a block theme, we ought to know exactly what CSS we’re working with. The following table outlines all of the CSS properties that are currently supported in the styles section as of WordPress 6.1:

Full table of properties
PropertyStyleCSS equivalentAdditional props
bordercolorborder-color
radiusborder-radius
styleborder-style
widthborder-width
topborder-topcolorstylewidth
rightborder-rightcolorstylewidth
bottomborder-bottomcolorstylewidth
leftbottom-leftcolorstylewidth
colorbackgroundbackground-color
gradientbackground-image
textcolor
spacingblockGapgap (in Flexbox and Grid containers)
marginmarginbottom, leftrighttop
paddingpaddingbottomleftrighttop
typographyfontFamilyfont-family
fontSizefont-size
fontStylefont-style
fontWeightfont-weight
letterSpacingletter-spacing
lineHeightline-height
textDecorationtext-decoration
textTransformtext-transform
filterduotonefilter
shadowbox-shadow
outlinecoloroutline-color
offsetoutline-offset
styleoutline-style
widthoutline-width

There are a couple of things worth noting when it comes to setting these properties:

  • There are no logical property equivalents. For example, margin-left is supported, but margin-inline-start is not as of this writing.
  • Multiple color formats are supported, such as rgba and hsla, but the new syntaxes are not, e.g., rgb(255, 255, 255 / .5).

Top-level styles

We already covered top-level styles in Part 2. By “top-level” we mean styles that are applied globally on the root element (<html>) as well as the <body>. These styles are “top-level” in the sense they are inherited by everything in the theme by default.

The classic example in CSS is setting a default font size on the <body> element:

body {
  font-size: 1.125rem;
}

Every element now has a font-size value of 1.125rem, unless it is overridden somewhere else. You might think that top-level styles are set in the styles section of theme.json. But if you recall the last article in this series, top-level styles are the preset values we define in the settings section instead:

{
  "version": 2,
  "settings": {
    "typography": {
      "fontSizes": {
        "size": "1.125rem",
        "slug": "medium"
      }
    }
  },
  "styles": {}
}

Behind the scenes, the WordPress Style Engine generates a CSS custom property that is applied to the <body> element:

body {
  font-size: var(--wp--preset--font-size--medium);
}

…which results in precisely what we’d expect in CSS:

body {
  font-size: 1.125rem;
}

Now we can jump into the styles section to override this sort of top-level style on two different levels: elements and blocks.

Element-level styles

What if we want to scope that top-level font-size to a specific element? A global element is a little tricky to understand because they are both blocks and blocks that can be nested in other blocks.

Think of elements as “core” blocks. That’s actually what they’re called in the WordPress Handbook, and it’s a good description of what they are: blocks that come with WordPress Core out of the box.

A heading is a perfect example of a core block. There is a Heading block we can use to add any heading level (<h1><h6>) to a page or post. So, if you need to drop a Heading 2 element on a page, you have a specific block to do that.

But a Heading 2 might be part of another block. For example, if you were to add a Query Loop block to a page, you would get a list of posts, each with a Post Title block that outputs an <h2> element.

Query Loop block in the WordPress Block Editor with a Heading 2 element.

If you want to style all heading elements, regardless of level, you can do it in the elements object in theme.json:

{
  "version": 2,
  "settings": { }
  "styles": {
    // Global-level styles
    "elements": {
      "heading": { ... },
    }
  }
}

Let’s say the CSS color property is set to black as a top-level style in settings:

{
  "version": 2,
  "settings": {
    // Top-level styles
    "color": {
      "palette": {
        "color": "#000000",
        "name": "Contrast",
        "slug": "contrast"
      }
    }
  },
}

The WordPress Style Engine creates a CSS custom property that can be applied to the <body> at the top level:

body {
  color: var(--wp--preset--color--contrast);
}

Maybe you want all your headings to be a different color than what is already applied to the <body> element. You can set that on styles.elements.heading to override black with, say, a dark gray color:

{
  "version": 2,
  "settings": {
    // Top-level style presets
    "color": {
      "palette": {
        "color": "#000000",
        "name": "Contrast",
        "slug": "contrast"
      }
    }
  },
  "styles": {
    // Global-level styles
    "elements": {
      "heading": {
        "color": {
          "text": "#333333"
        }
      }
    }
  }
}

Another way to go about it is to configure a new color in settings.color.palette and apply the generated CSS custom property to styles.elements.heading.color.text.

OK, but maybe you want the Heading 2 global element to “pop” more than other heading levels. You can override the dark gray for all the core headings element with another color value assigned to the h2 element:

{
  "version": 2,
  "settings": {
    // Top-level style presets
    "color": {
      "palette": {
        "color": "#000000",
        "name": "Contrast",
        "slug": "contrast"
      }
    }
  },
  "styles": {
    // Global-level styles
    "elements": {
      "heading": {
        "color": {
          "text": "#333333"
        }
      },
      "h2": {
        "color": {
          "text": "#F8A100"
        }
      }
    }
  }
}

At the time of this writing, the following global elements are currently supported in the styles.elements section:

JSON PropertyGenerated selectorUse cases
elements.buttonsButtonsButtons block, blocks
elements.headingHeadingsHeadings block,
elements.h1 to elements.h6<h1> to <h6>Site title, post title, blocks
elements.link<a>Links
elements.citeblockquote.cite, quote.citeQuote, Pullquote
elements.caption<figcaption>, <caption>Figure, Table
elements.spacing.paddingPaddingHeadings, row, blocks, paragraph
elements.typographyTypographyHeadings, paragraph

Block-level styles

There’s yet one more level in styles, and it’s used to customize the CSS for individual blocks:

{
  "version": 2,
  "styles": {
    // Top-level styles
    // etc.

    // Global-level styles
    "elements": { },

    // Block-level styles
    "blocks": {  }
  }
}

Let’s go ahead and pick up right where we left off in the last section. We had set the color property to black in the top-level styles, overrode that with a different color for all headings in styles.elements.heading, then overrode that just for the Heading 2 element on styles.elements.h2. Here’s that code again:

{
  "version": 2,
  "styles": {
    // Top-level styles
    "color": "#000000",

    // Global-level styles
    "elements": {
      "heading": {
        "color": {
          "text": "#333333"
        }
      },
      "h2": {
        "color": {
          "text": "#f8a100"
        }
      },
    }
  }
}

Earlier, we discussed how a global element, like Heading 2, can also be part of another block. We used the Query Loop block as an example, where Heading 2 is used for each post title.

So far, the color of the Query Loop’s post title would be #F8A100 because that is what is set on styles.elements.h2. But you can override that in the styles.blocks section if you want to set the Query Loop block’s Heading 2 element to yet another color without interfering with other headings:

{
  "version": 2,
  "styles": {
    // Top-level styles
    "color": "#000000",

    // Global-level styles
    "elements": {
      "heading": {
        "color": {
          "text": "#333333"
        }
      },
      "h2": {
        "color": {
          "text": "#F8A100"
        }
      }
    },
    "blocks": {
      "core/query": {
        "elements": {
          "h2": {
            "color": {
              "text": "var(--wp--preset--color--primary)"
            }
          }
        }
      }
    }
  }
}

Behind the scenes, the WordPress Style Engine creates the CSS for the Query Loop’s <h2> element:

.wp-query h2 {
  color: var(--wp--preset--color--primary);
}

Pretty great, right? Now we have a way to set default styles and override them at various levels in the theme in a structured way that works much like the CSS Cascade.

Check out the WordPress Handbook for a complete list of blocks that are available to use in the Block Editor.

Interactive styles

What if you want to customize the CSS for different interactive states? Everything we’ve looked at so far is great for styling a core block, like Button, but what about the styles when someone hovers their cursor over a Button block? Or maybe when that button is in focus?

We can do that with CSS pseudo-classes. You’re probably already well-versed in using pseudo-classes like :hover, :focus, :active, and :visited. They’re super common!

Thankfully, support for styling interactive states for certain core blocks, like buttons and links, using pseudo-classes gained theme.json support in WordPress 6.1. Here’s an example pulled from one of my previous articles that adds a box-shadow on a theme’s Button elements on hover:

{
  "version": 2,
  "settings": {},
  "styles": {
    "elements": {
      "button": {
        ":hover": {
          "shadow": "10px 10px 5px 0px rgba(0,0,0,0.66)"
        }
      }
    }
  }
}

The WordPress Style Engine reads this and generates the following CSS:

.wp-button:hover {
  box-shadow: 10px 10px 5px 0px rgba(0,0,0,0.66);
}

But before you rush off to create all your interactive styles, you’ll want to note that theme.json currently supports just the :hover, :focus, and :active interactive pseudo-classes as of WordPress 6.1, and even those are limited to the button and link elements. But that is likely to expand to others in the future — including pseudo-classes specific to form elements — as noted in this Make WordPress Core blog post introducing interactive styles.

So, for now, here is an example of the most complete way to customize the interactive styles of a button.

{
  "version": 2,
  "styles": {
    "elements": {
      "button": {
        "color": {
          "background": "#17A2b8",
          "text": "#ffffff"
        }
        ":hover": {
          "color": {
            "background": "#138496"
          }
        },
        ":focus": {
          "color": {
            "background": "#138496"
          }
        },
        ":active": {
          "color": {
            "background": "#138496"
          }
        }
      }
    }
  }
}

The same thing works if we were to change elements.button to elements.link.

One more JSON object is mentioned in the WordPress Handbook called css but there is no documentation for it other than mentioning it is used to set custom CSS that is not handled by other theme.json properties.

Referencing styles

A referencing style feature also available in theme.json. This allows you to refer to a previously defined root-level style property using the ref: term.

In the earlier top-level style example, we have registered the following background color using the styles.color.background property at the root of the styles property.

"styles": {
  "color": {
    "background": "var(--wp--preset--color--base)"
  }
}

We can reuse the same style property to any number of blocks:

{
  "color": {
    "text": { ref: "styles.color.background" }
  }
}

Global style variations

It’s possible for a theme to include more than one theme.json file. Why? Because that’s how you can make Global Styles variations.

That link will take you to the formal documentation for Global Styles variations, but the general idea is this: theme.json contains all your default values and sits in the theme folder’s root directory, and additional theme.json files are added to the theme folder that are “variations” of the default theme.

Here’s how it works. Say we have finished configuring our default theme.json file and it’s sitting in the theme’s root directory. Now say you want to implement a “dark mode” feature that allows the user to toggle colors between light and dark palettes. We’d make a new file — maybe call it dark.json and place it in a new folder in the theme called /styles. We can add as many of these files as we want to create all the variations your heart desires.

theme-folder/
|__ /assets
|__ /patterns
|__ /templates
|__ /parts
|__ /styles
    |__ dark.json
|__ index.php
|__ functions.php
|__ style.css
|__ theme.json

The biggest difference between the default theme.json file and our dark.json variation file is that our variation file includes a title field that allows us to differentiate it from other JSON files.

{
  "version": 2,
  "title": "Dark",
  "styles": {}
}

Anything we put in here overrides what’s in theme.json once it is activated. And how do you activate a global styles variation? You’ll find it in the Site Editor (Dashboard → Appearance → Editor) under “Browse Styles” (Editor → Styles → “Browse Styles”). That’s the secret behind all the different variations offered in the default Twenty Twenty-Three theme.

The full-site template editing screen with the style variations panel open.

You can read more about building block theme style variations in this CSS-Tricks article.

Additional resources

Wrapping up

We are really close to having a more complete picture of the theme.json file. We’ve covered the structure, how to enable features, and how to configure styles at the theme, global, and block level, even going so far as to look at custom styling capabilities and overriding all of our defaults with global styles variations. Hopefully you see just how powerful theme.json is in the block theme era of WordPress.

The next article in this series will give you a deeper look at the Style Engine. We’ve referred to it several times but have only briefly described what it does. It’s an integral piece of the block theme puzzle because it transforms all the JSON we write into vanilla CSS code.

It is the single source of truth when it comes to managing a block theme’s CSS. And it’s a good idea to know what WordPress is doing behind the scenes when a theme is rendered, so let’s move on to the next article!


Defining Global Styles originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
376823
Defining Global Settings https://css-tricks.com/defining-global-settings/ Tue, 31 Jan 2023 15:52:01 +0000 https://css-tricks.com/?page_id=376820 Let's take what we learned about the theme.json structure in WordPress block themes and apply it to two main sections of the file: settings and styles. These arrays are the “top level” for configuring WordPress features and the theme’s CSS output.


Defining Global Settings originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
So far, we’ve spent time getting familiar with theme.json, the foundation for all WordPress block themes. We covered the various JSON data types and common terminology related to working with the JSON syntax.

We are going to build on that knowledge in this article.

Table of contents


What we mean by “top level”

We discussed how JSON has a structured syntax. We can see that in the basic outline of the theme.json file:

{
  "version": 2,
  "settings": {},
  "styles": {},
  "customTemplates": {},
  "templateParts": {}
}

Each object in the basic outline is a “top level” of the file. You can think of the objects as sections where various things are configured. Disregarding the version, there are four top-level sections:

  • settings: This is where we define WordPress presets and defaults; it’s also where we can enable or disable certain WordPress features.
  • styles: This is where we define CSS for global and block-level theme styles.
  • customTemplates: This is where we register new custom theme templates. It’s the equivalent of dropping a new PHP template file in a classic theme.
  • templateParts: This section contains modular pieces that can be included in templates. It’s the equivalent of the parts subfolder you typically see in classic themes.

We’re spending most of our time in the settings and styles sections. Both provide ways to configure the global styles of a WordPress block theme. So, let’s look at each one and the various options we have to customize the theme appearance.

The settings section (settings)

Again, this is where we configure WordPress features, sort of like the add_theme_support function you’d reach for in a classic theme’s functions.php file.

{
  "version": 2,
  "settings": {
    // etc.
  }
}

Why is this relevant to a theme’s global styles? Several WordPress features affect styling, like UI controls for padding, margins, colors, and fonts. Without enabling those, there’s no way to apply these and other styles in the Global Styles UI in the Site Editor.

In short: what we define here is what WordPress uses to add theme support for the Site Editor’s global style settings that are used throughout the theme.

Supported features

The WordPress Block Editor Handbook provides a table that outlines available features we can enable in the settings section and compares them to their equivalent add_theme_support function arguments.

Theme JSON settingsadd_theme_support
color.customcustom-colors
color.paletteeditor-color-palette
color.gradientseditor-gradient-presets
spacing.paddingcustom-spacing
spacing.unitscustom-units
typography.lineHeightcustom-line-height
typography.fontSizeseditor-font-sizes
useRootPaddingAwareAlignmentsN/A

For example, you were using add_theme_support in your classic theme to disable custom font sizes:

<?php
add_theme_support(disable-custom-font-sizes);

The equivalent in theme.json is the settings.typography.customFontSize property:

{
  "version": 2,
  "settings": {
    "typography": {
      "customFontSize": false;
    }
  }
}

As you might imagine, there are nested features within these features. For example, if we were adding support for spacing controls, there are a number of spacing-related features we can individually enable:

{
  "version": 2,
  "settings": {
    "spacing": {
      "margin": false,
      "padding": false,
      "blockGap": null,
      "units": [ "px", "em", "rem", "vh", "vw" ]
    },
  }
}

As of WordPress 6.1, these are the settings features that can be configured in theme.json:

View full table
SettingFeatureData type
borderradiusBoolean
colorBoolean
styleBoolean
widthBoolean
colorcustomBoolean
customDuotoneBoolean
customGradientBoolean
duotoneArray
gradientsArray
linkBoolean
paletteArray
textBoolean
backgroundBoolean
defaultGradientsBoolean
defaultPaletteBoolean
layoutcontentSizeString
wideSizeString
typeString (default and constrained)
spacingmarginBoolean
paddingBoolean
blockGapString
unitsArray
typographycustomFontSizeBoolean
lineHeightBoolean
dropCapBoolean
fontStyleBoolean
fontWeightBoolean
letterSpacingBoolean
textDecorationBoolean
textTransformBoolean
fontSizesArray
fontFamiliesArray

There are ongoing discussions to add the outline and border properties to the Global Styles panel. They are included in this table before formal adoption.

The appearanceTools shorthand

I know that the table shows a ton of features. Configuring each setting could get cumbersome. That’s where the appearanceTools setting comes into play.

{
  "version": 2,
  "settings": {
    "appearanceTools": true
  }
}

Setting it to true enables the following settings in one fell swoop:

{
  "version": 2,
  "settings": {
    "border": {
      "color": true,
      "radius": true,
      "style": true,
      "width": true
    },
    "color": {
      "link": true
    }
    "spacing": {
      "margin": true,
      "padding": true,
      "blockGap": true,
    },
    "typography": {
      "lineHeight": true
    }
  }
}

You can see how many lines of code we can save this way! But let’s say you want to take advantage of appearanceTools, but disable one or two of its supported features. You can do that on an individual basis to override that particular setting:

{
  "version": 2,
  "settings": {
    "appearanceTools": true,
    "border": {
      "radius": false
    }
  }
}

The following screenshot shows how setting appearanceTools to true exposes those controls in the Global Styles UI, taken from the default Twenty Twenty-Three theme.

The WordPress Site Editor.

This Learn WordPress video by Nick Diego explains the appearanceTools properties and the Global Styles interface in great detail.

Padding-aware alignments

This feature is worth calling out because it shipped more recently than many other features as part of WordPress 6.1. It is another shortcut for setting two spacing features.

So, this:

{
  "version": 2,
  "settings": {
    "useRootPaddingAwareAlignments": true
  }
}

…is the equivalent of this:

{
  "version": 2,
  "settings": {
    "spacing": {
      "margin": true,
      "padding": true
    },
  }
}

The real benefit of useRootPaddingAwareAlignments is in the name. By enabling it, we opt into a feature that defines global padding on the <body> of our theme and allows blocks to “break out” of that padding and go full-width if we need a block to span edge-to-edge.

See my previous article for a detailed overview of padding-aware alignments.

Configuring preset values

Presets are predefined values used by Global Styles features. More specifically, they define CSS custom properties used throughout a block theme.

So, let’s say you are defining your block theme’s default color palette and add black (#000000) to it:

{
  "version": 2,
  "settings": {
    "color": {
      "palette": [
        {
          "color": "#000000",
          "name": "Base",
          "slug": "base"
        }
      ]
    }
  }
}

Behind the scenes, something called the Style Engine takes those values and generates the theme’s CSS classes and custom properties. I described the Style Engine in a previous article:

The Style Engine is a new API in WordPress 6.1 that is meant to bring consistency to how styles are generated and where styles are applied. In other words, it takes all of the possible sources of styling and is singularly responsible for properly generating block styles. […] Having a centralized API for styles is probably the most elegant solution given that styles can come from a number of places.

When the Style Engine notices our styles, it creates a set of preset custom properties. For example, that color palette example above? It produces a CSS custom property based on the information we supply it.

If we were to open up DevTools and inspect the <body> element, we would see our custom properties there:

DevTools window showing CSS custom variables on the body element.

Notice how the custom property names are formatted:

--wp-preset--<feature>--<slug>: <value>

So, going back to our original example where we defined black in a color palette:

"color": {
  "palette": [
    {
      "color": "#000000",
      "name": "Base",
      "slug": "Base"
    }
  ]
}

We can expect to find this custom property applied to the <body> element:

body {
  --wp--preset--color--base: #000000;
}

All we’ve looked at are settings.color presets, but nearly every value we define in the settings section results in a custom property:

{
  "version": 2,
  "settings": {
    "spacing": {
      "spacingSizes": [
        {
          // Creates: --wp-preset--spacing--40: 1rem
          "slug": "40",
          "size": "1rem",
          "name": "Small"
        },
        // etc.
      ]
    }
  }
}

Global presets

Now that we know how to define preset values in theme.json, you might want to know what presets are available. The following table outlines what is currently available as of this writing and what they produce.

SettingFeatureCSS custom propertyCSS class
colorduotoneN/AN/A
gradients--wp-preset--gradient--<preset-slug>.has-<preset-slug>-<preset-category>
palette--wp--preset--palette--<preset-slug>Three classes per value:

.has-<preset-value>-color

.has-<preset-value>-background-color

.has-<preset-value>-border-color
spacingspacingScaleN/AN/A
spacingSizes--wp--preset--spacing--<preset-slug>.has-<preset-slug>-spacing
typographyfontSizes--wp--preset--font-size--<preset-slug>.has-<preset-slug>-font-size
fontFamilies--wp--preset--font-family--<preset-slug>.has-<preset-slug>-font-family

Block presets

We can get more granular when defining preset values in theme.json. In addition to the global presets we just saw, we can define presents at the block level.

Let’s say we have the following global color presets:

{
  "version": 2,
  "settings": {
    "color": {
      "palette": [
        {
          // --wp-preset--color--base: #ffffff
          "color": "#FFFFFF",
          "name": "Base",
          "slug": "base"
        },
        {
          // --wp-preset--color--contrast: #000000
          "color": "#000000",
          "name": "Contrast",
          "slug": "contrast"
        }
      ]
    }
  }
}

The custom properties generated by those settings are used throughout the theme, including blocks. So, if we were to add a Separator block to a page in the Block Editor, it will refer to the same color palette when it renders.

But we can override that palette — or any of the others in the global settings — with a palette specifically for the Separator block:

{
  "version": 2,
  "settings": {
    "color": {
      "palette": [ // etc. ]
    },
    "blocks": {
      "separator": {
        "color": {
          "palette": [
            {
              "color": "#F8A100",
              "name": "Orange",
              "slug": "orange"
            }
          ]
        }
      }
    }
  }
}

In this example, the Separator block’s palette overrides the global palette with a single orange (#F8A100) color value.

Custom presets

You can also create “custom” CSS custom properties on any property. In addition to the settings features we’ve looked at so far, there is a custom property where we can do that.

{
  "version": 2,
  "settings": {
    "custom": {
      // etc.
    }
  }
}

The Style Engine takes anything we define in there and generates CSS custom properties from it. The naming convention is pretty similar to the custom properties generated by the other settings:

--wp--custom--<variable-name>: <value>

Your defined values in custom will be transformed into CSS custom properties and use the --wp--custom--<variable-name> naming convention.

Here’s an abbreviated example of custom settings pulled straight from the default Twenty Twenty-Two theme. In it are custom settings for typography.font-size and typography.line-height:

{
  "version": 2,
  "settings": {
    "custom": {
      "typography": {
        "font-size": {
          "huge": "clamp(2.25rem, 4vw, 2.75rem)",
          "gigantic": "clamp(2.75rem, 6vw, 3.25rem)",
          "colossal": "clamp(3.25rem, 8vw, 6.25rem)"
        },
        "line-height": {
          "tiny": 1.15,
          "small": 1.2,
          "medium": 1.4,
          "normal": 1.6
        }
      }
    }
  }
}

Wrapping up

We learned a great deal about the settings section of the theme.json file. We covered the available settings and how they are used to define global styles that are used in the Global Styles UI of the WordPress Site Editor. From there, we learned about preset values, including which ones we can configure and how they are generated into CSS custom properties by the Style Engine.

What we haven’t covered is how we can use theme.json to define CSS styles in a block theme. That happens in another top-level section called styles, which is the focus of the next part of this series.


Defining Global Settings originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
376820
Glossary of Terms for theme.json https://css-tricks.com/glossary-of-terms-for-theme-json/ Tue, 31 Jan 2023 15:45:02 +0000 https://css-tricks.com/?page_id=376818 To kick things off, let’s begin by reviewing a few glossary terms that are important for understanding what the theme.json file is, how it is structured, and how to configure it. We’ll cover examples as we go, but the main goal here is to get familiar with terms that we’ll be seeing throughout this series.


Glossary of Terms for theme.json originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>

Common JSON terms

We’re going to spend a quick moment getting familiar with JSON-related terms before jumping to the next section that outlines the six different types of JSON data types.

JSON

JSON refers to JavaScript Object Notation, a machine-readable data-sharing format. As the name suggests, JSON is derived from JavaScript and applied to many other languages like PHP, Ruby, Python, etc. Many software applications, including React, Gatsby, VS Code, and others, use JSON for settings environments.

Object

Objects are key-value pairs separated by colons : and contained inside curly brackets ({}). You can think of it like CSS in a way. We have a property (or key) followed by a value that defines the property:

color: #9DFF20;

In JSON, that is represented as an object like this:

{ "color": "#9DFF20" }

Note: A JSON object property is also called a field or key. A key-value pair is also called an item or data.

And like a CSS ruleset can contain many key-value pairs, so can a JSON object. This example is an object with three keys — color, name, and slug — each with a corresponding value:

{ "color": "#9DFF20", "name": "Primary", "slug": "primary" }

Contrary to CSS, JSON is not a “forgiving” language, and even one typing error can break the entire website.

Nested object

Objects in JSON can contain other objects. We call these nested objects, and it’s what makes JSON a structured language.

{
  "object1": {
    "object1a": "value",
    "object1b": "value"
  },
  "object2" : {
    "object2a": "value",
    "object2b": "value"
  }
}

Let’s take an example straight from the emptytheme theme.json file:

Array

An array is a comma-separated group of objects in square brackets ([]). The idea is that we might need to define more than one object at a time. A good example is defining the colors of a block theme’s color palette. An array allows us to define a group of colors for that palette:

JSON data types

JSON values must be one of the six data types: a string, a number, an object, an array, a boolean (true or false), and null. JSON data are assessed using dot . notation.

Here is an abbreviated modified TT3 theme.json object file showing all the data types:

{
  "version": 2, // 1: Number (no quotes)
  "settings": {
    "appearanceTools": true, // 2: Boolean (true or false, no quotes)
    "useRootPaddingAwareAlignments": false,
    "color": {
      "palette": [ // 3: Array of string object palette
        { 
          "color": "#ffffff", // 4: Object (in curly brackets)
          "name": "Base",
          "slug": "base"
        }
      ]
    },
    "layout": { "contentSize": "650px"}, // 5: String (in double quotes)
    "styles": {
      "typography": { "lineHeight": "1.6" },
      "spacing": { "blockGap": null } // 6: null (no quotes)
    }
  }
}

Additional resources

Next up…

Now that we have a solid understanding of JSON and how it is structured in the theme.json of WordPress block themes, let’s take a closer look at how global styling works. We can define default styles for a block theme directly in theme.json. We can also use the Global Styles UI in WordPress.

How do those work together? What sort of settings are available? When should you use one over the other? We’ll answer those questions and more next.


Glossary of Terms for theme.json originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
376818
WordPress Block Themes CSS and Style Settings Guide https://css-tricks.com/wordpress-block-theme-guide/ Tue, 31 Jan 2023 15:43:43 +0000 https://css-tricks.com/?page_id=376813 Managing CSS in WordPress has dramatically changed since full-site editing features were introduced to block themes. This guide is geared toward block themes and how to configure them, from enabling editor features and controls to defining theme-wide CSS and customizaing the appearance of specific blocks.


WordPress Block Themes CSS and Style Settings Guide originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
In the 2015 State of the World address, WordPress co-creator Matt Mullenweg famously directed the WordPress community to“Learn JavaScript deeply”. He set that expectation upfront because he wanted everyone to know that JavaScript would be essential to the future of WordPress, which was paving a path toward full-site editing with a React-based editing experience to be called the Block Editor.

That was years ago, and a concerted effort has been taking place to shift WordPress theme development from “classic” PHP-based templating to a more modular, component-driven model centered on “blocks” for constructing page and post layouts.

Now that we’re starting to see new block-based WordPress themes hit the Theme Directory, many of us who have been developing WordPress themes for years using “classic” PHP templates we’re sitting in some sort of middle-ground between “classic” and “block” themes. Geoff expanded on this feeling in another post, but the general sentiment is that working in WordPress is much different than before.

Where do you even start on a WordPress Block Theme project? That’s what this guide is all about. We could get into the nuances of working with React, but there’s already a good guide for that here on CSS-Tricks as well as tutorials on working with blocks.

Instead, this guide is geared toward block themes and how to configure them. Think of it as an extension to my previous article on managing styles in WordPress block themes. In there, we covered how to define CSS styles in the theme.json file — the foundation of all WordPress block themes, akin to how style.css is used in classic themes. We’re going to go deeper in this series, giving theme.json a proper introduction and documenting how it’s used to manage the appearance of a WordPress site that fully supports full-site editing features.

As it currently stands, finding resources and proper documentation for defining and managing styles in WordPress block themes is a task in and of itself. Unless you keep up with GitHub issues, Gutenberg plugin releases, and Make WordPress Core, you could feel lost in this new WordPress landscape. The WordPress Handbook won’t save you either because it is constantly several steps behind the breakneck speed of development.

So, let’s pull all of that together and learn about managing styles in WordPress block themes.


WordPress Block Themes CSS and Style Settings Guide originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
376813
Styling Buttons in WordPress Block Themes https://css-tricks.com/styling-buttons-in-wordpress-block-themes/ https://css-tricks.com/styling-buttons-in-wordpress-block-themes/#comments Mon, 09 Jan 2023 13:56:19 +0000 https://css-tricks.com/?p=376237 A little while back, Ganesh Dahal penned a post here on CSS-Tricks responding to a tweet that asked about adding CSS box shadows on WordPress blocks and elements. There’s a lot of great stuff in there that leverages new features …


Styling Buttons in WordPress Block Themes originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
A little while back, Ganesh Dahal penned a post here on CSS-Tricks responding to a tweet that asked about adding CSS box shadows on WordPress blocks and elements. There’s a lot of great stuff in there that leverages new features that shipped in WordPress 6.1 that provide controls for applying shadows to things directly in the Block Editor and Site Editor UI.

Ganesh touched briefly on button elements in that post. I want to pick that up and go deeper into approaches for styling buttons in WordPress block themes. Specifically, we’re going to crack open a fresh theme.json file and break down various approaches to styling buttons in the schema.

Why buttons, you ask? That’s a good question, so let’s start with that.

The different types of buttons

When we’re talking about buttons in the context of the WordPress Block Editor, we have to distinguish between two different types:

  1. Child blocks inside of the Buttons block
  2. Buttons that are nested inside other block (e.g. the Post Comments Form block)

If we add both of these blocks to a template, they have the same look by default.

A black button above a comment form that also contains a black button.

But the markup is very different:

<div class="wp-block-button">
  <a class="wp-block-button__link wp-element-button">Button 1</a>
</div>
<p class="form-submit wp-block-button">
  <input name="submit" type="submit" id="submit" class="wp-block-button__link wp-element-button" value="Post Comment"> 
</p>

As we can see, the HTML tag names are different. It’s the common classes — .wp-block-button and .wp-element-button — that ensure consistent styling between the two buttons.

If we were writing CSS, we would target these two classes. But as we know, WordPress block themes have a different way of managing styles, and that’s through the theme.json file. Ganesh also covered this in great detail, and you’d do well giving his article a read.

So, how do we define button styles in theme.json without writing actual CSS? Let’s do it together.

Creating the base styles

theme.json is a structured set of schema written in property:value pairs. The top level properties are called “sections”, and we’re going to work with the styles section. This is where all the styling instructions go.

We’ll focus specifically on the elements in the styles. This selector targets HTML elements that are shared between blocks. This is the basic shell we’re working with:

// theme.json
{
  "version": 2,
  "styles": {
    "elements": {
      // etc.
    }
  }
}

So what we need to do is define a button element.

={
  "version": 2,
  "styles": {
    "elements": {
      "button": {
        // etc.
      }
    }
  }
}

That button corresponds to HTML elements that are used to mark up button elements on the front end. These buttons contain HTML tags that could be either of our two button types: a standalone component (i.e. the Button block) or a component nested within another block (e.g. the Post Comment block).

Rather than having to style each individual block, we create shared styles. Let’s go ahead and change the default background and text color for both types of buttons in our theme. There’s a color object in there that, in turn, supports background and text properties where we set the values we want:

{
  "version": 2,
  "styles": {
    "elements": {
      "button": {
        "color": {
          "background": "#17a2b8",
          "text": "#ffffff"
        }
      }
    }
  }
}

This changes the color of both button types:

A light blue button above a comment form that also contains a light blue button.

If crack open DevTools and have a look at the CSS that WordPress generates for the buttons, we see that the .wp-element-button class adds the styles we defined in theme.json:

.wp-element-button {
  background-color: #17a2b8;
  color: #ffffff;
}

Those are our default colors! Next, we want to give users visual feedback when they interact with the button.

Implementing interactive button styles

Since this is a site all about CSS, I’d bet many of you are already familiar with the interactive states of links and buttons. We can :hover the mouse cursor over them, tab them into :focus, click on them to make them :active. Heck, there’s even a :visited state to give users a visual indication that they’ve clicked this before.

Those are CSS pseudo-classes and we use them to target a link’s or button’s interactions.

In CSS, we might style a :hover state like this:

a:hover {
  /* Styles */
}

In theme.json, we’re going to extend our existing button declaration with these pseudo-classes.

{
  "version": 2,
  "styles": {
    "elements": {
      "button": {
        "color": {
          "background": "#17a2b8",
          "text": "#ffffff"
        },
        ":hover": {
          "color": {
            "background": "#138496"
          }
        },
        ":focus": {
          "color": {
            "background": "#138496"
          }
        },
        ":active": {
          "color": {
            "background": "#138496"
          }
        }
      }
    }
  }
}

Notice the “structured” nature of this. We’re basically following an outline:

  • Elements
    • Element
      • Object
        • Property
          • Value

We now have a complete definition of our button’s default and interactive styles. But what if we want to style certain buttons that are nested in other blocks?

Styling buttons nested in individual blocks

Let’s imagine that we want all buttons to have our base styles, with one exception. We want the submit button of the Post Comment Form block to be blue. How would we achieve that?

This block is more complex than the Button block because it has more moving parts: the form, inputs, instructive text, and the button. In order to target the button in this block, we have to follow the same sort of JSON structure we did for the button element, but applied to the Post Comment Form block, which is mapped to the core/post-comments-form element:

{
  "version": 2,
  "styles": {
    "elements" {
      "button": {
        // Default button styles
      }
    }
    "blocks": {
      "core/post-comments-form": {
        // etc.
      }
    }
  }
}

Notice that we’re no longer working in elements anymore. Instead, we’re working inside blocks which is reserved for configuring actual blocks. Buttons, by contrast, are considered a global element since they can be nested in blocks, even though they are available as a standalone block too.

The JSON structure supports elements within elements. So, if there’s a button element in the Post Comment Form block, we can target it in the core/post-comments-form block:

{
  "version": 2,
  "styles": {
    "elements" {
      "button": {
        // Default button styles
      }
    }
    "blocks": {
      "core/post-comments-form": {
        "elements": {
          "button": {
            "color": {
              "background": "#007bff"
            }
          }
        }
      }
    }
  }
}

This selector means that not only are we targeting a specific block — we’re targeting a specific element that is contained in that block. Now we have a default set of button styles that are applied to all buttons in the theme, and a set of styles that apply to specific buttons that are contained in the Post Comment Form block.

A light blue button above a comment form that contans a bright blue button.

The CSS generated by WordPress has a more precise selector as a result:

.wp-block-post-comments-form .wp-element-button,
.wp-block-post-comments-form .wp-block-button__link {
  background-color: #007bff;
}

And what if we want to define different interactive styles for the Post Comment Form button? It’s the same deal as the way we did it for the default styles, only those are defined inside the core/post-comments-form block:

{
  "version": 2,
  "styles": {
    "elements" {
      "button": {
        // Default button styles
      }
    }
    "blocks": {
      "core/post-comments-form": {
        "elements": {
          "button": {
            "color": {
              "background": "#007bff"
            }
            ":hover": {
              "color": {
                "background": "#138496"
              }
            },
            // etc.
          }
        }
      }
    }
  }
}

What about buttons that are not in blocks?

WordPress automagically generates and applies the right classes to output these button styles. But what if you use a “hybrid” WordPress theme that supports blocks and full-site editing, but also contains “classic” PHP templates? Or what if you made a custom block, or even have a legacy shortcode, that contains buttons? None of these are handled by the WordPress Style Engine!

No worries. In all of those cases, you would add the .wp-element-button class in the template, block, or shortcode markup. The styles generated by WordPress will then be applied in those instances.

And there may be some situations where you have no control over the markup. For example, some block plugin might be a little too opinionated and liberally apply its own styling. That’s where you can typically go to the “Advanced” option in the block’s settings panel and apply the class there:

A WordPress block settings panel with the Advanced settings expanded highlighting the CSS classes section in red.

Wrapping up

While writing “CSS” in theme.json might feel awkward at first, I’ve found that it becomes second nature. Like CSS, there are a limited number of properties that you can apply either broadly or very narrowly using the right selectors.

And let’s not forget the three main advantages of using theme.json:

  1. The styles are applied to buttons in both the front-end view and the block editor.
  2. Your CSS will be compatible with future WordPress updates.
  3. The generated styles work with block themes and classic themes alike — there’s no need to duplicate anything in a separate stylesheet.

If you have used theme.json styles in your projects, please share your experiences and thoughts. I look forward to reading any comments and feedback!


Styling Buttons in WordPress Block Themes originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/styling-buttons-in-wordpress-block-themes/feed/ 2 376237
Adding Box Shadows to WordPress Blocks and Elements https://css-tricks.com/adding-box-shadows-to-wordpress-blocks-and-elements/ https://css-tricks.com/adding-box-shadows-to-wordpress-blocks-and-elements/#respond Wed, 07 Dec 2022 13:59:50 +0000 https://css-tricks.com/?p=375412 The CSS box-shadow and outline properties gained theme.json support in WordPress 6.1. Let's look at a few examples of how it works in real themes, and what options we have to apply these styles to WordPress blocks and elements.


Adding Box Shadows to WordPress Blocks and Elements originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
I stumbled across this tweet from Ana Segota looking for a way to add a CSS box-shadow to a button’s hover state in WordPress in the theme.json file.

She’s asking because theme.json is where WordPress wants us to start moving basic styles for block themes. Traditionally, we’d do any and all styling in style.css when working in a “classic” theme. But with the default Twenty Twenty-Three (TT3) theme that recently shipped with WordPress 6.1 moving all of its styles to theme.json, we’re getting closer and closer to being able to do the same with our own themes. I covered this in great detail in a recent article.

I say “closer and closer” because there are still plenty of CSS properties and selectors that are unsupported in theme.json. For example, if you’re hoping to style something with like perspective-origin in theme.json, it just won’t happen — at least as I’m writing this today.

Ana is looking at box-shadow and, luckily for her, that CSS property is supported by theme.json as of WordPress 6.1. Her tweet is dated Nov. 1, the same exact day that 6.1 released. It’s not like support for the property was a headline feature in the release. The bigger headlines were more related to spacing and layout techniques for blocks and block themes.

Here’s how we can apply a box-shadow to a specific block — say the Featured Image block — in theme.json:

{
  "version": 2,
  "settings": {},
  // etc.
  "styles": {
    "blocks" :{
      "core/post-featured-image": {
        "shadow": "10px 10px 5px 0px rgba(0, 0, 0, 0.66)"
      }
    }
  }
}

Wondering if the new color syntax works? Me too! But when I tried — rgb(0 0 0 / 0.66) — I got nothing. Perhaps that’s already in the works or could use a pull request.

Easy, right? Sure, it’s way different than writing vanilla CSS in style.css and takes some getting used to. But it is indeed possible as of the most recent WordPress release.

And, hey, we can do the same thing to individual “elements”, like a button. A button is a block in and of itself, but it can also be a nested block within another block. So, to apply a box-shadow globally to all buttons, we’d do something like this in theme.json:

{
  "version": 2,
  "settings": {},
  // etc.
  "styles": {
    "elements": {
      "button": {
        "shadow": "10px 10px 5px 0px rgba(0,0,0,0.66)"
      }
    }
  }
}

But Ana wants to add the shadow to the button’s :hover state. Thankfully, support for styling interactive states for certain elements, like buttons and links, using pseudo-classes — including :hover, :focus, :active, and :visited — also gained theme.json support in WordPress 6.1.

{
  "version": 2,
  "settings": {},
  // etc.
  "styles": {
    "elements": {
      "button": {
        ":hover": {
          "shadow": "10px 10px 5px 0px rgba(0,0,0,0.66)"
        }
      }
    }
  }
}

If you’re using a parent theme, you can certainly override a theme’s styles in a child theme. Here, I am completely overriding TT3’s button styles.

View full code
{
  "version": 2,
  "settings": {},
  // etc.
  "styles": {
    "elements": {
      "button": {
        "border": {
          "radius": "0"
        },
        "color": {
          "background": "var(--wp--preset--color--tertiary)",
          "text": "var(--wp--preset--color--contrast)"
        },
        "outline": {
          "offset": "3px",
          "width": "3px",
          "style": "dashed",
          "color": "red"
        },
        "typography": {
          "fontSize": "var(--wp--preset--font-size--medium)"
        },
        "shadow": "5px 5px 5px 0px rgba(9, 30, 66, 0.25), 5px 5px 5px 1px rgba(9, 30, 66, 0.08)",
        ":hover": {
          "color": {
            "background": "var(--wp--preset--color--contrast)",
            "text": "var(--wp--preset--color--base)"
          },
          "outline": {
            "offset": "3px",
            "width": "3px",
            "style": "solid",
            "color": "blue"
          }
        },
        ":focus": {
          "color": {
            "background": "var(--wp--preset--color--contrast)",
            "text": "var(--wp--preset--color--base)"
          }
        },
        ":active": {
          "color": {
            "background": "var(--wp--preset--color--secondary)",
            "text": "var(--wp--preset--color--base)"
          }
        }
      }
    }
  }
}

Here’s how that renders:

Showing two red buttons with box shadows.
The button’s natural state (left) and it’s hovered state (right)

Another way to do it: custom styles

The recently released Pixl block theme provides another example of real-world usage of the box-shadow property in theme.json using an alternative method that defines custom values. In the theme, a custom box-shadow property is defined as .settings.custom.shadow:

{
  "version": 2,
  "settings": {
    // etc. 
    "custom": {
      // etc.
      "shadow": "5px 5px 0px -2px var(--wp--preset--color--background), 5px 5px var(--wp--preset--color--foreground)"
    },
    // etc.
  }
}

Then, later in the file, the custom shadow property is called on a button element:

{
  "version": 2,
  "settings": {
    // etc.
  },
  "styles": {
    "elements": {
      "button": {
        // etc.
        "shadow": "var(--wp--custom--shadow) !important",
        // etc.
        ":active": {
          // etc.
          "shadow": "2px 2px var(--wp--preset--color--primary) !important"
        }
      },
    // etc.
  }
}

I’m not totally sure about the use of !important in this context. My hunch is that it’s an attempt to prevent overriding those styles using the Global Styles UI in the Site Editor, which has high specificity than styles defined in theme.json. Here’s an anchored link to more information from my previous article on managing block theme styles.

Update: Turns out there was a whole discussion about this in Pull Request #34689, which notes that it was addressed in WordPress 5.9.

And there’s more…

In addition to shadows, the CSS outline property also gained theme.json support in WordPress 6.1 and can be applied to buttons and their interactive states. This GitHub PR shows a good example.

"elements": {
  "button": {
    "outline": {
      "offset": "3px",
      "width": "3px",
      "style": "dashed",
      "color": "red"
    },
    ":hover": {
      "outline": {
        "offset": "3px",
        "width": "3px",
        "style": "solid",
        "color": "blue"
      }
    }
  }
}

You can also find the real examples of how the outline property works in other themes, including Loudness, Block Canvas, and Blockbase.

Wrapping up

Who knew there was so much to talk about with a single CSS property when it comes to block theming in WordPress 6.1? We saw the officially supported methods for setting a box-shadow on blocks and individual elements, including the interactive states of a button element. We also checked out how we could override shadows in a child theme. And, finally, we cracked open a real-world example that defines and sets shadows in a custom property.

You can find more detailed in-depth discussions about the WordPress and it’s box-shadow implementation in this GitHub PR. There is also a GitHub proposal for adding UI directly in WordPress to set shadow values on blocks — you can jump directly to an animated GIF showing how that would work.

Speaking of which, Justin Tadlock recently developed a block that renders a progress bar and integrated box shadow controls into it. He shows it off in this video:

More information

If you’d like to dig deeper into the box-shadow and other CSS properties that are supported by the theme.json file in a block theme, here are a couple of resources you can use:


Adding Box Shadows to WordPress Blocks and Elements originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/adding-box-shadows-to-wordpress-blocks-and-elements/feed/ 0 https://www.youtube.com/embed/TMd3NHBPZ-8 Box Shadow Control with the Progress Bar WordPress Block nonadult 375412
Using The New Constrained Layout In WordPress Block Themes https://css-tricks.com/using-the-new-constrained-layout-in-wordpress-block-themes/ https://css-tricks.com/using-the-new-constrained-layout-in-wordpress-block-themes/#comments Wed, 30 Nov 2022 14:11:10 +0000 https://css-tricks.com/?p=375278 One of the main goals of the WordPress Site Editor (and, yes, that is now the “official” name) is to move basic block styling from CSS to structured JSON. JSON files are machine-readable, which makes it consumable by …


Using The New Constrained Layout In WordPress Block Themes originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
One of the main goals of the WordPress Site Editor (and, yes, that is now the “official” name) is to move basic block styling from CSS to structured JSON. JSON files are machine-readable, which makes it consumable by the JavaScript-based Site Editor for configuring a theme’s global styles directly in WordPress.

It’s not all the way there yet! If we look at the Twenty Twenty-Two (TT2) default theme, there were two main unresolved issues: styling interactions (like :hover, :active, :focus), and the margins and padding of layout containers. You can see how those were temporarily fixed in the TT2 style.css file rather than making it into the theme.json file.

WordPress 6.1 fixed those issues and what I want to do is look specifically at the latter. Now that we have JSON-ified styles for the margins and padding of layout containers, that opens us up to more flexible and robust ways to define spacing in our theme layouts.

What kind of spacing are we talking about?

First off, we already have root-level padding which is a fancy way of describing padding on the <body> element. That’s nice because it ensures consistent spacing on an element that is shared on all pages and posts.

But there’s more to it because now we have a way for blocks to bypass that padding and align themselves full-width. That’s thanks to padding-aware alignments which is a new opt-in feature in theme.json. So, even if you have root-level padding, you can still allow, say, an image (or some other block) to break out and go full-width.

That gets us to another thing we get: constrained layouts. The idea here is that any blocks nested in the layout respect the layout’s content width — which is a global setting — and do not flow outside of it. We can override that behavior on a block-by-block basis with alignments, but we’ll get to that.

Let’s start with…

Root-level padding

Again, this isn’t new. We’ve had the ability to set padding on the <body> element in theme.json since the experimental Gutenberg plugin introduced it in version 11.7. We set it on the styles.spacing object, where we have margin and padding objects to define the top, right, bottom, and left spacing on the body:

{
  "version": 2,
  "styles": {
    "spacing": {
      "margin": {
        "top": "60px",
        "right": "30px",
        "bottom": "60px",
        "left": "30px"
      },
      "padding": {
        "top": "30px",
        "right": "30px",
        "bottom": "30px",
        "left": "30px"
      }
    }
  }
}

This is a global setting. So, if we were to crack open DevTools and inspect the <body> element, we would see these CSS styles:

body {
  margin-top: 60px;
  margin-right: 30px;
  margin-bottom: 60px;
  margin-left: 30px;
  padding-top: 30px;
  padding-right: 30px;
  padding-bottom: 30px;
  padding-left: 30px;
}

Cool. But herein lies the issue of how in the world we can allow some blocks to break out of that spacing to fill the full screen, edge-to-edge. That’s why the spacing is there, right? It helps prevent that from happening!

But there are indeed plenty of cases where you might want to break out of that spacing on a one-off instance when working in the Block Editor. Say we plop an Image block on a page and we want it to go full-width while the rest of the content respects the root-level padding?

Enter…

Padding-aware alignments

While attempting to create the first default WordPress theme that defines all styles in the theme.json file, lead designer Kjell Reigstad illustrates the challenging aspects of breaking out of root-level padding in this GitHub issue.

Root-level padding prevents blocks from taking up the full viewport width (left). But with padding-aware alignments, some blocks can “opt-out” of that spacing and take up the full viewport width (right). (Image credit: Kjell Reigstad)

New features in WordPress 6.1 were created to address this issue. Let’s dig into those next.

useRootPaddingAwareAlignments

A new useRootPaddingAwareAlignments property was created to address the problem. It was actually first introduced in the Gutenberg plugin v13.8. The original pull request is a nice primer on how it works.

{
  "version": 2,
  "settings": {
    "appearanceTools": true,
    "useRootPaddingAwareAlignments": true,
    // etc.
  },

Right off the bat, notice that this is a feature we have to opt into. The property is set to false by default and we have to explicitly set it to true in order to enable it. Also notice that we have appearanceTools set to true as well. That opts us into UI controls in the Site Editor for styling borders, link colors, typography, and, yes, spacing which includes margin and padding.

Setting appearanceTools set to true automatically opts blocks into margin and padding without having to set either settings.spacing.padding or setting.spacing.margin to true.

When we do enable useRootPaddingAwareAlignments, we are provided with custom properties with root padding values that are set on the <body> element on the front end. Interestingly, it also applies the padding to the .editor-styles-wrapper class so the spacing is displayed when working in the back-end Block Editor. Pretty cool!

I was able to confirm those CSS custom properties in DevTools while digging around.

Enabling useRootPaddingAwareAlignments also applies left and right padding to any block that supports the “content” width and “wide” width values in the Global Styles image above. We can also define those values in theme.json:

{
  "version": 2,
  "settings": {
    "layout": {
      "contentSize": "640px",
      "wideSize": "1000px"
    }
  }
}

If the Global Styles settings are different than what is defined in theme.json, then the Global Styles take precedence. You can learn all about managing block theme styles in my last article.

  • contentSize is the default width for blocks.
  • wideSize provides a “wide” layout option and establishes a wider column for blocks to stretch out.

So, that last code example will give us the following CSS:

/* The default content container */
.wp-container-[id] > * {
  max-width: 640px;
  margin-left: auto !important;
  margin-right: auto !important;
}

/* The wider content container */
.wp-container-[id] > .alignwide {
  max-width: 1000px;
}

[id] indicates a unique number automatically generated by WordPress.

But guess what else we get? Full alignment as well!

.wp-container-[id] .alignfull {
  max-width: none;
}

See that? By enabling useRootPaddingAwareAlignments and defining contentSize and wideSize, we also get a full alignment CSS class for a total of three container configurations for controlling the width of blocks that are added to pages and posts.

This applies to the following layout-specific blocks: Columns, Group, Post Content, and Query Loop.

Block layout controls

Let’s say we add any of those aforementioned layout-specific blocks to a page. When we select the block, the block settings UI offers us new layout settings based on the settings.layout values we defined in theme.json (or the Global Styles UI).

We’re dealing with very specific blocks here — ones that can have other blocks nested inside. So, these Layout settings are really about controlling the width and alignment of those nested blocks. The “Inner blocks use content width” setting is enabled by default. If we toggle it off, then we have no max-width on the container and the blocks inside it go edge-to-edge.

If we leave the toggle on, then nested blocks will adhere to either the contentWidth or wideWidth values (more on that in a bit). Or we can use the numeric inputs to define custom contentWidth and wideWidth values in this one-off instance. That’s great flexibility!

Wide blocks

The settings we just looked are set on the parent block. Once we’ve nested a block inside and select it, we have additional options in that block to use the contentWidth, wideWidth, or go full-width.

This Image block is set to respect the contentWidth setting, labeled “None” in the contextual menu, but can also be set to wideWidth (labeled “Wide width”) or “Full width”.

Notice how WordPress multiplies the root-level padding CSS custom properties by -1 to create negative margins when selecting the “Full width” option.

The .alignfull class sets negative margins on a nested block to ensure it takes up the full viewport width without conflicting with the root-level padding settings.

Using a constrained layout

We just covered the new spacing and alignments we get with WordPress 6.1. Those are specific to blocks and any nested blocks within blocks. But WordPress 6.1 also introduces new layout features for even more flexibility and consistency in a theme’s templates.

Case in point: WordPress has completely restructured its Flex and Flow layout types and gave us a constrained layout type that makes it easier to align block layouts in themes using the content width settings in the Site Editor’s Global Styles UI.

Flex, Flow, and Constrained layouts

The difference between these three layout types is the styles that they output. Isabel Brison has an excellent write-up that nicely outlines the differences, but let’s paraphrase them here for reference:

  • Flow layout: Adds vertical spacing between nested blocks in the margin-block direction. Those nested blocks can also be aligned to the left, right, or center.
  • Constrained layout: Same exact deal as a Flow layout, but with width constraints on nested blocks that are based on the contentWidth and wideWidth settings (either in theme.json or Global Styles).
  • Flex layout: This was unchanged in WordPress 6.1. It uses CSS Flexbox to create a layout that flows horizontally (in a row) by default, but can flow vertically as well so blocks stack one on top of another. Spacing is applied using the CSS gap property.

This new slate of layout types creates semantic class names for each layout:

Semantic layout classLayout typeSupported blocks
.is-layout-flowFlow layoutColumns, Group, Post Content, and Query Loop.
.is-layout-constrainedConstrained layoutColumns, Group, Post Content, and Query Loop.
.is-layout-flexFlex layoutColumns, Buttons, Social Icons

Justin Tadlock has an extensive write-up on the different layout types and semantic classes, including use cases and examples.

Updating your theme to support constrained layouts

If you’re already using a block theme of your own making, you’re going to want to update it to support constrained layouts. All it takes is swapping out a couple of things in theme.json:

{
  "version": 2,
  "settings": {
    "layout": {
      "type": "constrained", // replaces `"inherit": true`
      "type": "default", // replaces `"inherit": false`
    }
  }
}

These are recently released block themes that have enabled spacing settings with useRootPaddingAwareAlignments and have an updated theme.json file that defines a constrained layout:

ThemeRoot-level paddingConstrained layout features
TT3Source codeSource codeTemplates
ProWPSource codeSource codeTemplates
TriangulateSource codeSource codeTemplates
OaknutSource codeSource codeTemplates
LoudnessSource codeSource codeTemplates
PixlSource codeSource codeTemplates
Block CanvasSource codeSource code, Templates
RainfallSource codeSource codeTemplates

Disabling layout styles

The base layout styles are default features that ship in WordPress 6.1 Core. In other words, they’re enabled right out of the box. But we can disable them if we need to with this little snippet in functions.php:

// Remove layout styles.
add_theme_support( 'disable-layout-styles' );

Big warning here: disabling support for the default layout types also removes all of the base styling for those layouts. That means you’ll need to roll your own styles for spacing, alignments, and anything else needed to display content in different template and block contexts.

Wrapping up

As a great fan of full-width images, the new contained WordPress 6.1 layout and padding aware alignment features are two of my most favorites yet. Taken together with other tools including, better margin and padding control, fluid typography, and updated List and Quote blocks, among others, is solid proof that WordPress is moving towards a better content creation experience.

Now, we have to wait and look at how the imagination and creativity of ordinary designers and content creators use these incredible tools and take it to a new level.

Because of the site editor development iterations in progress, we should always anticipate a difficult path ahead. However, as an optimist, I am eager to see what will happen in the upcoming version of WordPress 6.2. Some of the thing, that I am keeping a close eye on are things like features being considered for inclusion, support for sticky positioning, new layout class names for inner block wrappers, updated footer alignment options, and adding constrained and flow layout options to Cover blocks.

This GitHub issues #44720 lists the layout related discussions slated for WordPress 6.2.

Additional resources

I consulted and referenced a lot of sources while digging into all of this. Here’s a big ol’ list of things I found helpful and think you might enjoy as well.

Tutorials

WordPress posts

GitHub pull requests and issues


Using The New Constrained Layout In WordPress Block Themes originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/using-the-new-constrained-layout-in-wordpress-block-themes/feed/ 5 375278
Managing CSS Styles in a WordPress Block Theme https://css-tricks.com/managing-css-styles-in-a-wordpress-block-theme/ https://css-tricks.com/managing-css-styles-in-a-wordpress-block-theme/#comments Mon, 07 Nov 2022 14:05:11 +0000 https://css-tricks.com/?p=374910 The way we write CSS for WordPress themes is in the midst of sweeping changes. I recently shared a technique for adding fluid type support in WordPress by way of theme.json, a new file that WordPress has been pushing


Managing CSS Styles in a WordPress Block Theme originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
The way we write CSS for WordPress themes is in the midst of sweeping changes. I recently shared a technique for adding fluid type support in WordPress by way of theme.json, a new file that WordPress has been pushing hard to become a central source of truth for defining styles in WordPress themes that support full-site editing (FSE) features.

Wait, no style.css file? We still have that. In fact, style.css is still a required file in block themes, though its role is greatly reduced to meta information used for registering the theme. That said, the fact is that theme.json is still in active development, meaning we’re in a transitional period where you might find styles defined there, in styles.css or even at the block level.

So, what does styling actually look like in these WordPress FSE days? That’s what I want to cover in this article. There’s a lack of documentation for styling block themes in the WordPress Theme Developer Handbook, so everything we’re covering here is what I’ve gathered about where things currently are as well as discussions about the future of WordPress theming.

The evolution of WordPress styles

The new developmental features that are included in WordPress 6.1 get us closer to a system of styles that are completely defined in theme.json, but there is still be plenty of work to do before we can fully lean on it. One way we can get an idea of what’s coming in future releases is by using the Gutenberg plugin. This is where experimental features are often given a dry run.

Another way we can get a feel for where we are is by looking at the evolution of default WordPress themes. To date, there are three default themes that support full-site editing:

But don’t start trading the CSS in style.css for JSON property-value pairs in theme.json just yet. There are still CSS styling rules that need to be supported in theme.json before we think about doing that. The remaining significant issues are currently being discussed with an aim to fully move all the CSS style rules into theme.json and consolidate different sources of theme.json into a UI for for setting global styles directly in the WordPress Site Editor.

The Global Styles UI is integrated with the right panel in the Site Editor. (Credit: Learn WordPress)

That leaves us in a relatively tough spot. Not only is there no clear path for overriding theme styles, but it’s unclear where the source of those styles even come from — is it from different layers of theme.json files, style.css, the Gutenberg plugin, or somewhere else?

Why theme.json instead of style.css?

You might be wondering why WordPress is moving toward a JSON-based definition of styles instead of a traditional CSS file. Ben Dwyer from the Gutenberg development team eloquently articulates why the theme.json approach is a benefit for theme developers.

It’s worth reading Ben’s post, but the meat is in this quote:

Overriding CSS, whether layout, preset, or block styles, presents an obstacle to integration and interoperability: visual parity between the frontend and editor becomes more difficult to maintain, upgrades to block internals may conflict with overrides. Custom CSS is, furthermore, less portable across other block themes.

By encouraging theme authors to use theme.json API where possible, the hierarchy of “base > theme > user” defined styles can be resolved correctly.

One of the major benefits of moving CSS to JSON is that JSON is a machine-readable format, which means it can be exposed in the WordPress Site Editor UI by fetching an API, thus allowing users to modify default values and customize a site’s appearance without writing any CSS at all. It also provides a way to style blocks consistently, while providing a structure that creates layers of specificity such that the user settings take the highest priority over those defined in theme.json. That interplay between theme-level styles in theme.json and the user-defined styles in the Global Styles UI is what makes the JSON approach so appealing.

Developers maintain consistency in JSON, and users gain flexibility with code-less customizations. That’s a win-win.

There are other benefits, for sure, and Mike McAlister from WP Engine lists several in this Twitter thread. You can find even more benefits in this in-depth discussion over at the Make WordPress Core blog. And once you’ve given that a read, compare the benefits of the JSON approach with the available ways to define and override styles in classic themes.

Defining styles with JSON elements

We’ve already seen a lot of progress as far as what parts of a theme theme.json is capable of styling. Prior to WordPress 6.1, all we could really do was style headings and links. Now, with WordPress 6.1, we can add buttons, captions, citations, and headings to the mix.

And we do that by defining JSON elements. Think of elements as individual components that live in a WordPress block. Say we have a block that contains a heading, a paragraph, and a button. Those individual pieces are elements, and there’s an elements object in theme.json where we define their styles:

{
  "version": 2,
  "settings": {},
  // etc.
  "styles": {
    // etc.
    "elements": {
        "button": { ... },
        "h1": { ... },
        "heading": { ... },
    },
  },
  "templateParts": {}
}

A better way to describe JSON elements is as low-level components for themes and blocks that do not need the complexity of blocks. They are representations of HTML primitives that are not defined in a block but can be used across blocks. How they are supported in WordPress (and the Gutenberg plugin) is described in the Block Editor Handbook and this Full Site Editing tutorial by Carolina Nymark.

For example, links are styled in the elements object but are not a block in their own right. But a link can be used in a block and it will inherit the styles defined on the elements.link object in theme.json. This doesn’t fully encapsulate the definition of an element, though, as some elements are also registered as blocks, such as the Heading and Button blocks — but those blocks can still be used within other blocks.

Here is a table of the elements that are currently available to style in theme.json prior to WordPress 6.1, courtesy of Carolina:

ElementSelectorWhere it’s supported
link<a>WordPress Core
h1 – h6The HTML tag for each heading level: <h1><h2><h3><h4><h5> and <h6>WordPress Core
headingStyles all headings globally by individual HTML tag: <h1><h2><h3><h4><h5> and <h6>Gutenberg plugin
button.wp-element-button.wp-block-button__linkGutenberg plugin
caption.wp-element-caption,
.wp-block-audio figcaption,
.wp-block-embed figcaption,
.wp-block-gallery figcaption,
.wp-block-image figcaption,
.wp-block-table figcaption,
.wp-block-video figcaption
Gutenberg plugin
cite.wp-block-pullquote citeGutenberg plugin

As you can see, it’s still early days and plenty still needs to move from the Gutenberg plugin into WordPress Core. But you can see how quick it would be to do something like style all headings in a theme globally without hunting for selectors in CSS files or DevTools.

Further, you can also start to see how the structure of theme.json sort of forms layers of specificity, going from global elements (e.g. headings) to individual elements (e.g. h1), and block-level styles (e.g. h1 contained in a block).

Additional information on JSON elements is available in this Make WordPress proposal and this open ticket in the Gutenberg plugin’s GitHub repo.

JSON and CSS specificity

Let’s keep talking about CSS specificity. I mentioned earlier that the JSON approach to styling establishes a hierarchy. And it’s true. Styles that are defined on JSON elements in theme.json are considered default theme styles. And anything that is set by the user in the Global Styles UI will override the defaults.

In other words: user styles carry more specificity than default theme styles. Let’s take a look at the Button block to get a feel for how this works.

I’m using Emptytheme, a blank WordPress theme with no CSS styling. I’m going to add a Button block on a new page.

The background color, text color, and rounded borders come from the block editor’s default settings.

OK, we know that WordPress Core ships with some light styling. Now, I’m going to switch to the default TT3 theme from WordPress 6.1 and activate it. If I refresh my page with the button, the button changes styles.

The background color, text color, and rounded corner styles have changed.

You can see exactly where those new styles are coming from in TT3’s theme.json file. This tells us that the JSON element styles take precedence over WordPress Core styles.

Now I am going to modify TT3 by overriding it with a theme.json file in a child theme, where the default background color of the Button block is set to red.

The default style for the Button block has been updated to red.

But notice the search button in that last screenshot. It should be red, too, right? That must mean it is styled at another level if the change I made is at the global level. If we want to change both buttons, we could do it at the user level using the Global Styles UI in the site editor.

We changed the background color of both buttons to blue and modified the text as well using the Global styles UI. Notice that the blue from there took precedence over the theme styles!

The Style Engine

That’s a very quick, but good, idea of how CSS specificity is managed in WordPress block themes. But it’s not the complete picture because it’s still unclear where those styles are generated. WordPress has its own default styles that come from somewhere, consumes the data in theme.json for more style rules, and overrides those with anything set in Global Styles.

Are those styles inline? Are they in a separate stylesheet? Maybe they’re injected on the page in a <script>?

That’s what the new Style Engine is hopefully going to solve. The Style Engine is a new API in WordPress 6.1 that is meant to bring consistency to how styles are generated and where styles are applied. In other words, it takes all of the possible sources of styling and is singularly responsible for properly generating block styles. I know, I know. Yet another abstraction on top of other abstractions just to author some styles. But having a centralized API for styles is probably the most elegant solution given that styles can come from a number of places.

We’re only getting a first look at the Style Engine. In fact, here’s what has been completed so far, according to the ticket:

  • Audit and consolidate where the code generates block support CSS in the back end so that they are delivered from the same place (as opposed to multiple places). This covers CSS rules such as margin, padding, typography, colors, and borders.
  • Remove repetitive layout-specific styles and generate semantic class names.
  • Reduce the number of inline style tags we print to the page for block, layout, and element support.

Basically, this is the foundation for establishing a single API that contains all the CSS style rules for a theme, wherever they come from. It cleans up the way WordPress would inject inline styles pre-6.1 and establishes a system for semantic class names.

Further details on the long-term and short-term goals of Style Engine can be found in this Make WordPress Core discussion. You can also follow the tracking issue and project board for more updates.

Working with JSON elements

We talked a bit about JSON elements in the theme.json file and how they are basically HTML primitives for defining default styles for things like headings, buttons, and links, among others. Now, let’s look at actually using a JSON element and how it behaves in various styling contexts.

JSON elements generally have two contexts: the global level and the block level. The global level styles are defined with less specificity than they are at the block level to ensure that block-specific styles take precedence for consistency wherever blocks are used.

Global styles for JSON elements

Let’s look at the new default TT3 theme and examine how its buttons are styled. The following is an abbreviated copy-paste of the TT3 theme.json file (here’s the full code) showing the global styles section, but you can find the original code here.

View code
{
  "version": 2,
  "settings": {},
    // ...
  "styles": {
    // ...
    "elements": {
      "button": {
        "border": {
          "radius": "0"
        },
        "color": {
          "background": "var(--wp--preset--color--primary)",
          "text": "var(--wp--preset--color--contrast)"
        },
        ":hover": {
          "color": {
            "background": "var(--wp--preset--color--contrast)",
            "text": "var(--wp--preset--color--base)"
          }
        },
        ":focus": {
          "color": {
            "background": "var(--wp--preset--color--contrast)",
            "text": "var(--wp--preset--color--base)"
          }
        },
        ":active": {
          "color": {
            "background": "var(--wp--preset--color--secondary)",
            "text": "var(--wp--preset--color--base)"
          }
        }
      },
      "h1": {
        "typography": { }
      },
      // ...
      "heading": {
        "typography": {
          "fontWeight": "400",
          "lineHeight": "1.4"
      }
      },
      "link": {
        "color": {
          "text": "var(--wp--preset--color--contrast)"
        },
        ":hover": {
          "typography": {
            "textDecoration": "none"
          }
        },
        ":focus": {
          "typography": {
            "textDecoration": "underline dashed"
          }
        },
        ":active": {
          "color": {
            "text": "var(--wp--preset--color--secondary)"
          },
          "typography": {
            "textDecoration": "none"
          }
        },
        "typography": {
          "textDecoration": "underline"
        }
      }
     },
    // ...
  },
  "templateParts": {}
}

All buttons are styled at the global level (styles.elements.button).

Every button in the Twenty Twenty-Three theme shares the same background color, which is set to the --wp--preset--color--primary CSS variable, or #B4FD55.

We can confirm this in DevTools as well. Notice that a class called .wp-element-button is the selector. The same class is used to style the interactive states as well.

Again, this styling is all happening at the global level, coming from theme.json. Whenever we use a button, it is going to have the same background because they share the same selector and no other style rules are overriding it.

As an aside, WordPress 6.1 added support for styling interactive states for certain elements, like buttons and links, using pseudo-classes in theme.json — including :hover, :focus, and :active — or the Global Styles UI. Automattic Engineer Dave Smith demonstrates this feature in a YouTube video.

We could override the button’s background color either in theme.json (preferably in a child theme since we’re using a default WordPress theme) or in the Global Styles settings in the site editor (no child theme needed since it does not require a code change).

But then the buttons will change all at once. What if we want to override the background color when the button is part of a certain block? That’s where block-level styles come into play.

Block-level styles for elements

To understand how we can use and customize styles at the block level, let’s change the background color of the button that is contained in the Search block. Remember, there is a Button block, but what we’re doing is overriding the background color at the block level of the Search block. That way, we’re only applying the new color there as opposed to applying it globally to all buttons.

To do that, we define the styles on the styles.blocks object in theme.json. That’s right, if we define the global styles for all buttons on styles.elements, we can define the block-specific styles for button elements on styles.block, which follows a similar structure:

{
  "version": 2,
  // ...
  "styles": {
    // Global-level syles
    "elements": { },
    // Block-level styles
    "blocks": {
      "core/search": {
        "elements": {
          "button": {
            "color": {
              "background": "var(--wp--preset--color--quaternary)",
              "text": "var(--wp--preset--color--base)"
            }
          }
        },
        // ...
      }
    }
  }
}

See that? I set the background and text properties on styles.blocks.core/search.elements.button with two CSS variables that are preset in WordPress.

The result? The search button is now red (--wp--preset--color--quaternary), and the default Button block retains its bright green background.

We can see the change in DevTools as well.

The same is true if we want to style buttons that are included in other blocks. And buttons are merely one example, so let’s look at another one.

Example: Styling headings at each level

Let’s drive all this information home with an example. This time, we will:

  • Style all headings globally
  • Style all Heading 2 elements
  • Style Heading 2 elements in the Query Loop block

First, let’s start with the basic structure for theme.json:

{
  "version": 2,
  "styles": {
    // Global-level syles
    "elements": { },
    // Block-level styles
    "blocks": { }
  }
}

This establishes the outline for our global and block-level styles.

Style all headings globally

Let’s add the headings object to our global styles and apply some styles:

{
  "version": 2,
  "styles": {
    // Global-level syles
    "elements": {
      "heading": {
        "color": "var(--wp--preset--color--base)"
      },
    },
    // Block-level styles
    "blocks": { }
  }
}

That sets the color for all headings to the preset base color in WordPress. Let’s change the color and font size of Heading 2 elements at the global level as well:

{
  "version": 2,
  "styles": {
    // Global-level syles
    "elements": {
      "heading": {
        "color": "var(--wp--preset--color--base)"
      },
      "h2": {
        "color": "var(--wp--preset--color--primary)",
        "typography": {
          "fontSize": "clamp(2.625rem, calc(2.625rem + ((1vw - 0.48rem) * 8.4135)), 3.25rem)"
        }
      }
    },
    // Block-level styles
    "blocks": { }
  }
}

Now, all Heading 2 elements are set to be the primary preset color with a fluid font size. But maybe we want a fixed fontSize for the Heading 2 element when it is used in the Query Look block:

{
  "version": 2,
  "styles": {
    // Global-level syles
    "elements": {
      "heading": {
        "color": "var(--wp--preset--color--base)"
      },
      "h2": {
        "color": "var(--wp--preset--color--primary)",
        "typography": {
          "fontSize": "clamp(2.625rem, calc(2.625rem + ((1vw - 0.48rem) * 8.4135)), 3.25rem)"
        }
      }
    },
    // Block-level styles
    "blocks": {
      "core/query": {
        "elements": {
          "h2": {
            "typography": {
              "fontSize": 3.25rem
            }
          }
        }
      }
    }
  }
}

Now we have three levels of styles for Heading 2 elements: all headings, all Heading 2 elements, and Heading 2 elements that are used in the Query Loop block.

Existing theme examples

While we only looked at the styling examples for buttons and headings in this article, WordPress 6.1 supports styling additional elements. There’s a table outlining them in the “Defining styles with JSON elements” section.

You’re probably wondering which JSON elements support which CSS properties, not to mention how you would even declare those. While we wait for official documentation, the best resources we have are going to be the theme.json files for existing themes. I’m going to provide links to themes based on the elements they customize, and point out what properties are customized.

ThemeWhat’s customizedTheme JSON
BlockbaseButtons, headings, links, core blocksSource code
Block CanvasButtons, headings, links, core blocksSource code
DiscoButtons, headings, core blocksSource code
FrostButtons, headings, links, captions, cite, core blocksSource code
PixlButtons, headings, links, core blocksSource code
RainfallButtons, headings, links, core blocksSource code
Twenty Twenty-ThreeButtons, headings, links, core blocksSource code
VivreButtons, headings, links, core blocksSource code

Be sure to give each theme.json file a good look because these themes include excellent examples of block-level styling on the styles.blocks object.

Wrapping up

Frequent changes to the full-site editor are becoming a major sources of irritation to many people, including tech-savvy Gutenberg users. Even very simple CSS rules, which work well with classic themes, don’t seem to work for block themes because of the new layers of specificity we covered earlier.

Regarding a GitHub proposal to re-design the site editor in a new browser mode, Sara Gooding writes in a WP Tavern post:

It’s easy to get lost while trying to get around the Site Editor unless you are working day and night inside the tool. The navigation is jumpy and confusing, especially when going from template browsing to template editing to modifying individual blocks.

Even as a keen early rider in the world of Gutenberg block editor and block-eye themes, I do have tons of my own frustrations. I’m optimistic, though, and anticipate that the site editor, once completed, will be a revolutionary tool for users and techno-savvy theme developers alike. This hopeful tweet already confirms that. In the meantime, it seems that we should be preparing for more changes, and perhaps even a bumpy ride.

References

I’m listing all of the resources I used while researching information for this article.

JSON elements

Global Styles

Style Engine


Thanks for reading! I’d love to hear your own reflections on using the block themes and how you managing your CSS.


Managing CSS Styles in a WordPress Block Theme originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/managing-css-styles-in-a-wordpress-block-theme/feed/ 7 374910
Adding Fluid Typography Support to WordPress Block Themes https://css-tricks.com/fluid-typography-wordpress-block-themes/ https://css-tricks.com/fluid-typography-wordpress-block-themes/#respond Fri, 07 Oct 2022 13:19:23 +0000 https://css-tricks.com/?p=373905 Fluid typography is a fancy way of “describing font properties, such as size or line height, that scale fluidly according to the size of the viewport”. It’s also known by other names, like responsive typography, flexible type, fluid type, …


Adding Fluid Typography Support to WordPress Block Themes originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Fluid typography is a fancy way of “describing font properties, such as size or line height, that scale fluidly according to the size of the viewport”. It’s also known by other names, like responsive typography, flexible type, fluid type, viewport sized typography, fluid typography, and even responsive display text.

Here is an example of fluid typography that you can play live (courtesy of MDN documentation). CSS-Tricks has covered fluid typography extensively as well. But the point here is not to introduce you to fluid typography, but how to use it. More specifically, I want to show you how to implement fluid typography in WordPress 6.1 which recently introduced a fluid type feature directly in the WordPress Block Editor.

Open up your style.css file, slap in a style rule with fancy clamp()-ing on the font-size property, and good to go, right? Sure, that’ll give you fluid text, but to get Block Editor controls that make it possible to apply fluid type anywhere on your WordPress site? That requires a different approach in these block-ified days.

Fluid typography support in Gutenberg

Some WordPress theme developers have been using the clamp() function to define a fluid font-size, in their WordPress themes, even in newer “block” themes such as Twenty Twenty-Two, Twenty Twenty-Three, and others.

But the Gutenberg plugin — the one that contains experimental development for WordPress Block and Site Editor features — introduced support for fluid typography starting in version 13.8. That opened the door for implementing at a theme level so that fluid type can be applied to specific elements and blocks directly in the Block Editor. CSS-Tricks was even given a shout-out in the Pull Request that merged the feature.

That work became part of WordPress Core in WordPress 6.1. Rich Tabor, one of the earlier advocates of fluid typography in the Block Editor says:

[Fluid typography] is also a part of making WordPress more powerful, while not more complicated (which we all know is quite the challenge). […] Fluid typography just works. Actually, I think it works great.

This Make WordPress post highlights the approach taken to support the feature at the block level so that a fluid font size is applied to blocks dynamically by default. There are some benefits to this, of course:

  • It provides a way for theme authors to activate fluid typography without worrying about implementing it in code.
  • It applies fluid typography to specific typographical entities, such as elements or blocks in a maintainable and reusable way.
  • It allows flexibility in terms of font size units (e.g. px, rem, em, and %).

Now that this new feature is available in the WordPress Block Editor by default, theme authors can apply uniform fluid typography without writing additional code.

Blocks that support typography and spacing settings

Gutenberg 14.1 released on September 16, 2022, and introduced typographic settings on a bunch of blocks. That means the text settings for those blocks were set in CSS before and had to be changed in CSS as well. But those blocks now provide font and spacing controls in the Block Editor interface.

Illustrated list of WordPress blocks that received font and spacing controls in the Gutenberg plugin. There are 31 total blocks.

That work is currently slated to be added to WordPress 6.1, as detailed in this Make WordPress blog post. And with it is an expanded number of blocks that with typography support.

Illustrated list of 60 WordPress blocks gaining typography and font size support in WordPress 6.1.
WordPress blocks that will support typography settings in the upcoming WordPress 6.1 release.

Declaring fluid type in a WordPress block theme

So, how do we put this new fluid typography to use in WordPress? The answer is in theme.json, a new-ish file specific to block themes that contains a bunch of theme configurations in key:value pairs.

Let’s look at a rule for a large font in theme.json where contentSize: 768px and we’re working with a widesize: 1600px layout. This is how we can specify a CSS font-size using the clamp() function:

"settings": {
  "appearanceTools": true,
  "layout": {
    "contentSize": "768px",
    "wideSize": "1600px"
  },
  "typography": {
    "fontSizes": [ 
      {
        "name": "Large",
        "size": "clamp(2.25rem, 6vw, 3rem)",
        "slug": "large"
      }
    ]
  }
}

As of WordPress 6.1, only rem, em and px units are supported.

That’s great and works, but with the new fluid type feature we would actually use a different approach. First, we opt into fluid typography on settings.typography, which has a new fluid property:

"settings": {
  "typography": {
    "fluid": true
  }
}

Then we specify our settings.fontSizes like before, but with a new fluidSize property where we can set the min and max size values for our fluid type range.

"settings": {
  "appearanceTools": true,
  "layout": {
    "contentSize": "768px",
    "wideSize": "1600px"
  },
  "typography": {
    "fontSizes": [ 
      {
        "size": "2.25rem",
        "fluidSize": {
          "min": "2.25rem",
          "max": "3rem"
        },
        "slug": "large",
        "name": "Large"
      }
    ]
  }
}

That’s really it. We just added fluid type to a font size called “Large” with a range that starts at 2.25rem and scales up to 3rem. Now, we can apply the “Large” font to any block with font settings.

How does this works under the hood? Rich Tabor offers a nice explanation, as does this Pull Request in GitHub. In short, WordPress converts the theme.json properties into the following CSS rule:

.has-large-font-size {
  font-size: clamp(36px, calc(2.25rem + ((1vw - 7.68px) * 1.4423)), 48px);
}

…which is applied to the element, say a Paragraph Block:

<p class="has-large-font-size">...</p>

Initially, I found it hard to understand and wrap around in my mind the concept of the CSS clamp() function without also learning about the min(), max(), and calc() functions. This calculator tool helped me quite a bit, especially for determining which values to use in my own theme projects.

For demonstration purposes, let’s use the calculator to define our font-size range so that the size is 36px at a 768px viewport width and 48px at a 1600px viewport width.

Entering values into the online calculator for fluid typography.

The calculator automatically generates the following CSS:

/* 36px @ 768px increasing to 48px @ 1600px */
font-size: clamp(36px, calc(2.25rem + ((1vw - 7.68px) * 1.4423)), 48px);

The calculator provide options to select input units as px, rem, and em. If we select rem unit, the calculator generates the following clamp() value:

/* 2.25rem @ 48rem increasing to 3rem @ 100rem */
font-size: clamp(2.25rem, calc(2.25rem + ((1vw - 0.48rem) * 1.4423)), 3rem);

So, those minimum and maximum values correspond to the the fluidSize.min and fluidSize.max values in theme.json. The min value is applied at viewports that are 768px wide and below. Then the font-size scales up as the viewport width grows. If the viewport is wider than 1600px, the max is applied and the font-size is capped there.

Examples

There are detailed testing instructions in the merged Pull Request that introduced the feature. There are even more testing instructions from Justin Tadlock’s pre-prelease post on Make WordPress.

Example 1: Setting a new fluid font setting

Let’s start with Justin’s set of instructions. I used in a modified version of the default Twenty Twenty-Three theme that is currently under development.

First, let’s make sure we’re running the Gutenberg plugin (13.8 and up) or WordPress 6.1, then opt into fluid type on the settings.typography.fluid property in the theme.json file:

{
  "version": 2,
  "settings": {
    "appearanceTools": true,
    "layout": {
      "contentSize": "768px",
      "wideSize": "1600px"
    },
    "typography": {
      "fluid": true
    }
  }
}

Now, let’s drop the settings.typography.fontSizes examples in there:

{
  "version": 2,
  "settings": {
    "appearanceTools": true,
    "layout": {
      "contentSize": "768px",
      "wideSize": "1600px"
    },
    "typography": {
      "fluid": true
      "fontSizes": [
        {
          "name": "Normal",
          "size": "1.125rem",
          "fluid": {
            "min": "1rem",
            "max": "1.5rem"
          },
          "slug": "normal"
        }
      ]
    }
  }
}

If everything is working correctly, we can now head into the WordPress Block Editor and apply the “Normal” font setting to our block:

The WordPress Block Editor interface showing a paragraph block and the fluid typography settings for it.

Nice! And if we save and inspect that element on the front end, this is the markup:

Inspecting the WordPress Paragraph block in DevTools.

Very good. Now let’s make sure the CSS is actually there:

DevTools showing the font-size custom property for the WordPress Paragraph block's fluid typography.

Good, good. Let’s expose that CSS custom property to see if it’s really clampin’ things:

Revealing the custom property value in DevTools, showing a CSS clamp function.

Looks like everything is working just as we want it! Let’s look at another example…

Example 2: Excluding a font setting from fluid type

This time, let’s follow the instructions from the merged Pull Request with a nod to this example by Carolina Nymark that shows how we can disable fluid type on a specific font setting.

I used the empty theme as advised in the instructions and opened up the theme.json file for testing. First, we opt into fluid type exactly as we did before:

{
  "version": 2,
  "settings": {
    "appearanceTools": true,
    "layout": {
      "contentSize": "768px",
      "wideSize": "1000px"
    },
    "typography": {
      "fluid": true
    }
  }
}

This time, we’re working with smaller wideSize value of 1000px instead of 1600px. This should allow us to see fluid type working in an exact range.

OK, on to defining some custom font sizes under settings.typography.fontSizes:

{
  "version": 2,
  "settings": {
    "typography": {
      "fluid": true,
      "fontSizes": [
        {
          "size": ".875rem",
          "fluid": {
            "min": "0.875rem",
            "max": "1rem"
        },
          "slug": "small",
          "name": "Small"
        },
        {
          "size": "1rem",
          "fluid": {
            "min": "1rem",
            "max": "1.5rem"
          },
          "slug": "normal",
          "name": "Normal"
        },
        {
          "size": "1.5rem",
          "fluid": {
            "min": "1.5rem",
            "max": "2rem"
          },
          "slug": "large",
          "name": "Large"
        },
        {
          "size": "2.25rem",
          "fluid": false,
          "slug": "x-large",
          "name": "Extra large"
        }
      ]
    }
  }
}

Notice that we’ve applied the fluid type feature only on the “Normal”, “Medium”, and “Large” font settings. “Extra Large” is the odd one out where the fluid object is set to false.

the WordPress Block Editor interface with four Paragraph blocks, each at a different font size setting.

What WordPress does from here — via the Gutenberg style engine — is apply the properties we set into CSS clamp() functions for each font size setting that has opted into fluid type and a single size value for the Extra Large setting:

--wp--preset--font-size--small: clamp(0.875rem, 0.875rem + ((1vw - 0.48rem) * 0.24), 1rem);
--wp--preset--font-size--medium: clamp(1rem, 1rem + ((1vw - 0.48rem) * 0.962), 1.5rem);
--wp--preset--font-size--large: clamp(1.5rem, 1.5rem + ((1vw - 0.48rem) * 0.962), 2rem);
--wp--preset--font-size--x-large: 2.25rem;

Let’s check the markup on the front end:

Inspecting the WordPress Paragraph blocks in DevTools.

Good start! Let’s confirm that the .has-x-large-font-size class is excluded from fluid type:

Showing the font-size custom property for the Extra Large font setting in DevTools.

If we expose the --wp--preset--font-size--x-large variable, we’ll see it’s set to 2.25rem.

Revealing the Extra Large font size custom property value, showing 2.25rem.

That’s exactly what we want!

Block themes that support fluid typography

Many WordPress themes already make use of the clamp() function for fluid type in both block and classic themes. A good example of fluid typography use is the recently released Twenty Twenty-Three default theme.

I’ve reviewed all the block themes from WordPress Block Theme directory, examining theme.json file of each theme and to see just how many block themes currently support fluid typography — not the new feature since it’s still in the Gutenberg plugin as of this writing — using the CSS clamp() function. Of the 146 themes I reviewed, the majority of them used a clamp() function to define spacing. A little more than half of them used clamp() to define font sizes. The Alara theme is the only one to use clamp() for defining the layout container sizes.

Understandably, only a few recently released themes contain the new fluid typography feature. But here are the ones I found that define it in theme.json:

And if you read my previous post here on CSS-Tricks, the TT2 Gopher Blocks theme I used for the demo has also been updated to support the fluid typography feature.

Selected reactions to the WordPress fluid typography features

Having fluid typography in WordPress at the settings level is super exciting! I thought I’d share some thoughts from folks in the WordPress developer community who have commented on it.

Matias Ventura, the lead architect of the Gutenberg project:

Rich Tabor:

As one of the bigger efforts towards making publishing beautifully rich pages in WordPress, fluid typography is a pretty big experience win for both the folks building with WordPress — and those consuming the content.

Automattic developer Ramon Dodd commented in the Pull Request:

Contrast that idea with font sizes that respond to specific viewport sizes, such as those defined by media queries, but do nothing in between those sizes. theme.json already allows authors to insert their own fluid font size values. This won’t change, but this PR offers it to folks who don’t want to worry about the implementation details.

Nick Croft, author of GenesisWP:

Brian Garner, designer and principal developer advocate at WPEngine:

A few developers think some features should be an opt-in. Jason Crist of Automattic says:

I love the power of fluid typography, however I also don’t believe that it should just be enabled by default. It’s usage (and the details of it) are important design decisions that should be made carefully.

You can also find a bunch more comments in the official testing instructions for the feature.

Wrapping up

The fluid typography feature in WordPress is still in active development at the time of this writing. So, right now, theme authors should proceed to use it, but with caution and expect some possible changes before it is officially released. Justin cautions theme authors using this feature and suggests to keep eye on the following two GitHub issues:

There is also still lots of ongoing work on typography and other design-related WordPress tools. If you’re interested, watch this typography tracking GitHub ticket and design tools related GitHub issues.

Resources

I used the following articles when researching fluid type and how WordPress is implementing it as a feature.

Tutorials and opinions

CSS-Tricks


Adding Fluid Typography Support to WordPress Block Themes originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/fluid-typography-wordpress-block-themes/feed/ 0 373905
How to Create Style Variations in WordPress 6.0 Block Themes https://css-tricks.com/creating-style-variations-in-wordpress-block-themes/ https://css-tricks.com/creating-style-variations-in-wordpress-block-themes/#respond Mon, 16 May 2022 14:38:29 +0000 https://css-tricks.com/?p=365377 Global styles, a feature of the block themes, is one of my favorite parts of creating block themes. The concept of global style variations in WordPress were introduced in Gutenberg 12.5 which would allow theme authors to create alternate …


How to Create Style Variations in WordPress 6.0 Block Themes originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Global styles, a feature of the block themes, is one of my favorite parts of creating block themes. The concept of global style variations in WordPress were introduced in Gutenberg 12.5 which would allow theme authors to create alternate variations of a block theme with different combinations of colors, fonts, typography, spacing, etc. Different theme.json files stored under /styles folder “lets users quickly and easily switch between different looks in the same theme.”

The global styles panel UI is in active development iteration. More details on the development of this feature can be found and tracked here at this GitHub ticket (#35619).

In this article, I will walk through creating a proof-of-concept global style variation using alternate /styles/theme.json files and create child themes with different color modes by swapping color palettes only.

Table of contents

Prerequisites

This article is intended for those who have basic understanding of WordPress block themes and some familiarity of using Full Site Editor (FSE) interface. If you’re new to block themes and the FSE, you can get started here on CSS-Tricks with this deep introduction to WordPress block themes and site editor documentation. This Full Site Editing website is one of the most up-to-date tutorial guides to learn all FSE features including block themes and styles variations discussed in this article.

Global style variations

For some background, let’s briefly overview global style variation. Twenty Twenty-Two (TT2) theme lead and Automattic design director Kjell Reigstad introduced global styles variations with this tweet and GitHub ticket #292 as child themes. In the ticket, Kjell notes that they were initially intended as alternate color patterns and fonts combinations, but they can be used for building simple child themes.

This example from Kjell demonstrates how different style combinations could be selected from options available in the sidebar.

Since then, the Automattic theme team has been experimenting with the concept to create variable child themes (variable color and fonts only), including the following:

  • geologist with blue, cream, slate, yellow variations
  • quadrat with black, green, red, white, and yellow versions

Global style switcher

The Gutenberg 12.5 release has introduced a global styles switcher which would allow users quickly and easily switch between different looks in the same theme via different theme.json files stored under a /styles folder.

The concept of allowing switching global style variation via theme.json has been discussed on GitHub for a while now. Gutenberg lead engineer Matias Ventura gave renewed importance to it by adding it to the WordPress 6.0 roadmap recently.

Embrace style alternates driven by json variations. This was teased in various videos around the new default theme and should be fully unveiled and presented in 6.0. One of the parallel goals is to create a few distinct variations of TT2 made just with styles. (35619)

Matias Ventura, “Preliminary Roadmap to 6.0”

The latest development iteration of theme style variation switcher is available with Gutenberg 13.0 and included in WordPress 6.0. In this Exploring WordPress 6.0 video, Automattic product liaison Anne McCarthy provides an overview of its major features, including style variations and Webfonts API (starting 5:18) discussed in this article.

Theme style variation versus child theme

In my previous article, I briefly covered building block child themes. Global style variations have blurred the line between alternate-theme.json and child themes. For example, the only difference between a recently released alante-dark child theme and its parent theme is an alternate.json file in the child theme that overrides the global theme styles like this:

Screenshot of the Visual Studio Code UI displaying the contents of alante-dark.
The alante-dark theme.

Likewise, the two recent Alara child themes in the WordPress directoryFramboise and Richmond — differ only in their single theme.json file.

Section 1: Creating theme style variations

At the root of your child theme folder, create a /styles folder, which holds style variations as JSON files. For this demo example, I created three variations of Twenty Twenty-Two’s theme.json color palettes — blue.json, maroon.json, and pink.json — by swapping the foreground and background colors:

Screenshot of the Visual Studio Code UI displaying the child theme file structure of "blue.json", "maroon.json", and "pink.json" in the styles directory.
The child theme file structure of “blue.json”, “maroon.json”, and “pink.json” in the styles directory.

Here is the final result after clicking the styles icon from the admin dashboard (located at Appearance → Editor):

Animated GIF showing the theme variations in WordPress.
Walking through the WordPress admin interface to select the “blue”, “maroon”, and “pink” styles.

Click the Other Styles button (recently revised to Browser styles), which displays “blue”, “maroon”, and “pink” color style icons in addition to its original styles.

To change and choose a style, select your preferred variation and click the Save button (top-right), which is displayed on the front end of your browser.

Adding labels to alternate style variations and file name with hover animation effect are available in Gutenberg 13.0.

Step 1: Setup and installation

First, install and set up a WordPress site with some dummy content. For this demo, I made a fresh WordPress install, activated Twenty Twenty-Two theme, and added Gutenberg test data.

The theme style variations and WebFonts API discussed in this article require installation and activation of the Gutenberg 13.0 plugin or WordPress 6.0.

Step 2: Create a TT2 child theme

In this demo child theme example, let’s slightly vary the body color from the header and footer color, with all site content centered:

The lower part of the site design are not visible because it is not scrolled into view. Site navigation is present in the header. A large banner image with a bird is visible. A date and title for the latest blog entry is also visible.
Screenshot of the default appearance of the demo theme in a browser window.

Step 3: Create JSON files

Create /styles in your child theme’s root folder with blue, maroon, and pink.json files:

__ style.css
__ theme.json
__ functions.php
__ index.php
__ templates
__ ...
__ parts
__ ...
__ styles
__ blue.json
__ maroon.json
__ pink.json

Step 4: Create alternate theme JSON files

Next up, create your alternate-theme.json files with desired color pallets under /styles folder. For this demo example, I created three color palettes (blue, maroon, and pink). Here is the code for maroon.json:

{
  "version": 2,
  "title": "Maroon",
  "settings": {
    "color": {
      "palette": [
        { "slug": "foreground", "color": "#7C290F", "name": "Foreground" },
        { "slug": "background", "color": "#ffffff", "name": "Background" },
        { "slug": "foreground-dark", "color": "#000000", "name": "Foreground Dark" },
        { "slug": "background-body", "color": "#ffd8be", "name": "Background Body" },
        { "slug": "primary", "color": "#000000", "name": "Primary" },
        { "slug": "secondary", "color": "#ffe2c7", "name": "Secondary" },
        { "slug": "tertiary", "color": "#55ACEE", "name": "Tertiary" }
      ]
  },
  "typography": {}
},
"styles": {
  "color":
      {
        "background": "var(--wp--preset--color--background-body)",
        "text": "var(--wp--preset--color--foreground-dark)"
      },
  "elements": {
      "link": {
        "color": { "text": "var(--wp--preset--color--primary)" }
      }
    }
  }
}

The other two alternate blue.json and pink.json files swap values of foreground and background-body, foreground-dark and primary color properties with their respective blue and pink hex color values.

Section 2: An example of a use case

As I noted in my previous article, I have been working on block themes and using them for my own personal project site. Inspired by the theme style variations and Webfonts API features in Gutenberg plugin, I started tweaking my work-in-progress block theme with an alternate dark color mode and by configuring the Webfonts API.

In this section, I will walk you through how I created TT2 Gopher Blocks, a demo sibling of my work-in-progress block theme created for this article. The theme includes maroon, dark, and light color modes created using theme style variations and Webfonts API that became available with the Gutenberg 12.8 release.

Showing the homepage we are creating with style variations in WordPress.
Screenshot displaying a sample site using the TT2 Gopher theme with maroon default color.

Some highlights of the TT2 Gopher theme include centered, single-column content display, distinct header and footer, more user-friendly archive and search pages.

A copy of TT2 Gopher Blocks is available at the GitHub repository, which you can fork and customize.

Creating dark mode on WordPress

First, some background on dark mode. Dark mode is a personal preference and developers offer it or other mode toggle switches like on this site, which is not a small job for most regular developers. Creating dark mode is well-covered here at CSS-Tricks, including this complete guide to dark mode and dark mode typography.

In a WordPress site, we can add a dark mode toggle using the WP Dark Mode plugin. Erin Myers of WP Engine and WPBeginner describe how to use the WP Dark Mode plugin, while Brenda Barron lists other dark mode plugin options in this WPExplorer post.

Creating a dark mode in WordPress block themes without a plugin involves several steps. Over a year ago, Ari Stathopoulos created a dark support for the TT1 Blocks theme at the GitHub. Looking at the example here, it involves some JavaScript knowledge to create assets (e.g., toggler, customize, editor-mode-support), dark color CSS variables, and expanded functions.php files.

In this short video, Automattic’s Anne McCarthy demonstrates how simple it is to create a dark mode of TT2 block theme with global style variation by adding kllejr’s gist of JSON snippets in the TT2 /styles folder.

Creating the demo TT2 Gopher blocks theme

The TT2 Gopher is a very simple and modified version of the default Twenty Twenty-Two theme. It includes three theme style variations — maroon, dark, and white.

Describing each customization step is beyond the scope of this article, but you can learn more from my deep introduction to WordPress block themes as well as the Block Editor Handbook over at WordPress.org.

A brief overview of the TT2 Gopher theme color and font combinations include:

  • Light mode
    • The header is white and the footer has a smoky body background color.
    • Open Sans is the primary font.
  • Dark mode
    • The header and footer are black with lighter dark colors for the body backgrounds.
    • Source Serif Pro is the primary font.
  • Maroon mode
    • The header and footer are both a dark maroon color, with a lighter yellowish body background.
    • Work Sans is the primary font.

Let me briefly walk you through how I created theme style variations.

Adding and configuring webfonts

The Gutenberg 12.8 plugin introduced a new Webfonts API that allows the authors to load local (bundled) fonts “in a performance-friendly, privacy-friendly, and future-proof manner.” This feature can be implemented in a block theme the PHP way or the theme.json way.

Currently this feature works only with fonts bundled with block themes and does not support Google-hosted fonts because of privacy concerns. More details on the current status of Webfonts API development are covered in this make WordPress core article and this WP Tavern article.

Step 1: Download and add fonts in block theme

The TT2 theme adds Source Serif Pro font files to the theme’s assets/fonts folder. Two additional fonts — Work Sans and Public Sans — are also provided in he GitHub repository.

Step 2: Registering webfonts

In the TT2 theme, local Source Serif Pro webfonts are registered with PHP in its functions.php file:

function twentytwentytwo_get_font_face_styles() {
  return "
  @font-face{
    font-family: 'Source Serif Pro';
    font-weight: 200 900;
    font-style: normal;
    font-stretch: normal;
    font-display: swap;
    src: url('" . get_theme_file_uri( 'assets/fonts/SourceSerif4Variable-Roman.ttf.woff2' ) . "') format('woff2');
  }
  @font-face{
    font-family: 'Source Serif Pro';
    font-weight: 200 900;
    font-style: italic;
    font-stretch: normal;
    font-display: swap;
    src: url('" . get_theme_file_uri( 'assets/fonts/SourceSerif4Variable-Italic.ttf.woff2' ) . "') format('woff2');
  }
  ";
}

Gutenberg 12.8 introduced the ability to register local web fonts with theme.json file. The following theme.json snippets from the demo TT2 Gopher theme show how local Work Sans web fonts are registered in the maroon theme style variation:

"typography": {
  "fontFamilies": [
    {
      "fontFamily": "'Work Sans', -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Helvetica', sans-serif",
      "slug": "work-sans",
      "name": "Work Sans",
      "fontFace": [
        { "fontFamily": "Work Sans", "fontDisplay": "block", "fontWeight": "400", "fontStyle": "normal", "fontStretch": "normal", "src": [ "file:./assets/fonts/work-sans/WorkSans-VariableFont_wght.ttf" ] },
        { "fontFamily": "Work Sans", "fontDisplay": "block", "fontWeight": "700", "fontStyle": "normal", "fontStretch": "normal", "src": [ "file:./assets/fonts/work-sans/WorkSans-VariableFont_wght.ttf" ] },
        { "fontFamily": "Work Sans", "fontDisplay": "block", "fontWeight": "400", "fontStyle": "italic", "fontStretch": "normal", "src": [ "file:./assets/fonts/work-sans/WorkSans-Italic-VariableFont_wght.ttf" ] },
        { "fontFamily": "Work Sans", "fontDisplay": "block", "fontWeight": "700", "fontStyle": "italic", "fontStretch": "normal", "src": [ "file:./assets/fonts/work-sans/WorkSans-Italic-VariableFont_wght.ttf" ] }
      ]
    }
  ]
}

Additional information on how to register and use local webfonts in block themes is described in this tutorial and this WP Tavern article.

Creating theme style variations

Following the steps described in the previous section, I created two alternate versions of the theme.json file — white.json and black.json — with different color and fonts combinations inside the child theme’s /styles folder.

This feature requires version 2 of theme.json. Since Gutenberg 12.5, title can also be added at theme.json to display style label in the site editor or file name (without extension) will be displayed by default.

Here is an example of white.json:

{
  "version": 2,
  "title": "White",
  "settings": {
    "color": {
      "palette": [
        { "slug": "foreground", "color": "#000000", "name": "Foreground" },
        { "slug": "background", "color": "#f2f2f2", "name": "Background" },
        { "slug": "background-header", "color": "#ffffff", "name": "Background header" },
        { "slug": "primary", "color": "#0d0d0d", "name": "Primary" },
        { "slug": "secondary", "color": "#F0EAE6", "name": "Secondary" },
        { "slug": "tertiary", "color": "#eb3425", "name": "Tertiary" },
        { "slug": "quaternary", "color": "#7c7e83", "name": "Quaternary" }
      ]
    },
    "typography": {
      "fontFamilies": [
        {
        "fontFamily": "\"Public Sans\", sans-serif",
        "name": "Public Sans",
        "slug": "public-sans",
        "fontFace": [
          { "fontFamily": "Public Sans", "fontDisplay": "block", "fontStyle": "normal", "fontStretch": "normal", "src": [ "file:.assets/fonts/publicSans/PublicSans-VariableFont_wght.ttf.woff2" ] },
          { "fontFamily": "Public Sans", "fontDisplay": "block", "fontStyle": "italic", "fontStretch": "normal", "src": [ "file:./assets/fonts/publicSans/PublicSans-Italic-VariableFont_wght.ttf.woff2" ] }
        ]
      }
    ]
  }
},
"styles": {
  "blocks": {
    "core/image": {
      "filter": { "duotone": "var(--wp--preset--duotone--default-filter)" }
    },
    "core/post-title": {
      "typography": { "fontFamily": "var(--wp--preset--font-family--public-sans)", "fontWeight": "700", "fontSize": "var(--wp--custom--typography--font-size--gigantic)" }
    },
    "core/query-title": {
      "typography": { "fontFamily": "var(--wp--preset--font-family--public-sans)", "fontWeight": "300", "fontSize": "var(--wp--custom--typography--font-size--gigantic)" }
    },
    "core/post-featured-image": {
      "filter": { "duotone": "var(--wp--preset--duotone--default-filter)" }
    },
    "core/site-logo": {
      "filter": { "duotone": "var(--wp--preset--duotone--default-filter)" }
    },
    "core/site-title": {
      "typography": { "fontFamily": "var(--wp--preset--font-family--public-sans)", "fontSize": "var(--wp--preset--font-size--normal)", "fontWeight": "normal" }
    }
    },
    "color": { "background": "var(--wp--preset--color--background)", "text": "var(--wp--preset--color--foreground)" },
    "elements": {
      "h1": {
        "typography": { "fontFamily": "var(--wp--preset--font-family--public-sans)", "fontWeight": "600", "fontSize": "var(--wp--custom--typography--font-size--colossal)" }
      },
      "h2": {
        "typography": { "fontFamily": "var(--wp--preset--font-family--public-sans)", "fontWeight": "600", "fontSize": "var(--wp--custom--typography--font-size--gigantic)" }
      },
      "h3": {
        "typography": { "fontFamily": "var(--wp--preset--font-family--public-sans)", "fontWeight": "300", "fontSize": "var(--wp--custom--typography--font-size--huge)" }
      },
      "h4": {
        "typography": { "fontFamily": "var(--wp--preset--font-family--public-sans)", "fontWeight": "300", "fontSize": "var(--wp--preset--font-size--x-large)" }
      },
      "h5": {
        "typography": { "fontFamily": "var(--wp--preset--font-family--public-sans)", "fontWeight": "700", "textTransform": "uppercase", "fontSize": "var(--wp--preset--font-size--medium)" }
      },
      "h6": {
        "typography": { "fontFamily": "var(--wp--preset--font-family--public-sans)", "fontWeight": "400", "textTransform": "uppercase", "fontSize": "var(--wp--preset--font-size--medium)" }
      },
      "link": {
        "color": { "text": "var(--wp--custom--color--foreground)" }
      }
    },
    "typography": { "fontFamily": "var(--wp--preset--font-family--public-sans)", "fontSize": "var(--wp--preset--font-size--normal)" }
  }
}

This code swaps color palettes from theme.json and also registers and defines the local Public Sans font files.

The black.json is also very similar and uses Source Serif Pro fonts registered in the functions.php file.

Screenshot of the light color theme on the left. And screenshot of the dark color theme on the right. The heading navigation and first blog entry are visible.
Side-by-side comparison of the light (left) and dark (right) color themes for TT2 Gopher.

Example of block themes with theme styles variations

  • Twenty Twenty-Two – the first default theme to include style variations. Its updated 1.2, bundled with WordPress 6.0 includes three style variations — “Blue”, “Pink”, and “Swiss” — allowing users to quickly swap between different visual styles.
  • Frost – an experimental block theme with dark theme style variation.
  • Alara – has above 100 active installs and includes 7 style variations.
  • Wabi– which powers Rich Tabor website contains 3 style variants and 300+ active installations.
  • Brisky – has more than 600 installs and one dark theme style variation.
  • Pendant – a theme by Automattic theme team under development at GitHub contains 3 theme style variation.

In this WP Tavern article, Justin speculates that this new feature may be utilized by theme authors by tying to the site visitor’s settings, while some users may prefer to tweak their site giving a seasonal or event-based design look. This is probably a little early, but only time will tell how this powerful feature would be utilized by both theme authors and users.

Wrapping up

Creating style variations of a block theme with different typography and color combination has been greatly simplified, without using plugins. It’s one of my favorite feature of the block editor that I plan to apply in my personal projects.

In my opinion, theme style variations are definitely a game changer for block themes and with this handy feature there might not be a need for child themes or even many cooky-cutter block themes. A few well-designed base block themes, similar to Automattic theme team’s block-canvas or blockbase (work-in-progress base block themes at GitHub), could be customized with theme style variation.


Resources

Dark Mode


How to Create Style Variations in WordPress 6.0 Block Themes originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/creating-style-variations-in-wordpress-block-themes/feed/ 0 365377
A Deep Introduction to WordPress Block Themes https://css-tricks.com/a-deep-introduction-to-wordpress-block-themes/ https://css-tricks.com/a-deep-introduction-to-wordpress-block-themes/#comments Fri, 04 Feb 2022 15:07:04 +0000 https://css-tricks.com/?p=362799 The relatively new WordPress editor, also known as the WordPress Block Editor, always under development via the Gutenberg plugin, has been with us since 2018. You can use the block editor on any WordPress theme, provided the theme …


A Deep Introduction to WordPress Block Themes originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
The relatively new WordPress editor, also known as the WordPress Block Editor, always under development via the Gutenberg plugin, has been with us since 2018. You can use the block editor on any WordPress theme, provided the theme loads CSS that the blocks use. But there are new themes that lean into the Block Editor much more deeply.

WordPress Block Themes allow you to build out the entire site using blocks, meaning the theme’s responsibility is mostly design guidelines, and less about controlling the pages and the content on them. This is referred to as Full-Site Editing in WordPress and the themes that are built for this are called Block Themes, because you build out everything with blocks.

Let’s dig into all this.

Illustration of a black vinyl record coming out of a record sleep sleeve from the left that contains a blue tinted image of jazz singer Joséphine Baker's profile looking right with a soft smile and parted lips. The image includes white text that says WordPress 5.9 and code is poetry.
Credit: WordPress.org

Table of Contents

Introduction

Except for those who follow its day-to-day development iterations at GitHub, most development surrounding the block editor is largely visible to users — and that’s not necessarily a bad thing. I have been personally trying to keep myself updated with the block editor through WP Tavern and Gutenberg posts, and have been using both the legacy — or “Classic” editor — as well as the block editor in my personal learning project sites.

After taking a detour to learn and experience headless WordPress sites with Gatsby and Frontity frameworks, I am now back to my native WordPress home.

Though I have been aware of the WordPress theme-experiment GitHub repository for a while — themes made completely out of blocks! — I have only started digging into block themes recently. In fact, I have been using an experimental block-based theme here in this project site.

WordPress 5.9 is now out in the wild and with it comes block-based theming for the masses. This release, dubbed Joséphine, is the formal introduction to WordPress full site editing and Block Themes.

Even though the block-based theming functionality has been available in various iterative forms in previous releases, this is a big deal for the WordPress platform and the ecosystem that relies on it. I’ve had my hands on it and thought I’d share what I’ve learned about block themes in my hands-on experience, as well as some personal thoughts on how it works.

Disclaimer: I am not a block themes expert by any stretch. I am well-versed in WordPress and a major fan of the content management system. My goal here is not to critique WordPress 5.9 or steer you in the direction of whether or not you should like it or want to use it. I’m merely coming from the perspective of an open-minded learner who is building personal sites with fairly deep understanding and familiarity with the WordPress Block Editor.

Before we dive straight into block themes, I think it’s a good idea to form a baseline understanding of just what we’re talking about when we’re tossing around terms, like blocks and site editing, as they’re so incredibly new and game-changing relative to what we’ve known and loved about WordPress for decades.

Block Editor

This is really what we mean any time we refer to the “WordPress Editor.” We call the WordPress Editor the Block Editor because it allows us to create pages and posts where each element— including text, images, videos, headers, footers, etc. — is inserted into the post using blocks that can be arranged modularly to complete page layouts. It evolved from what’s now called the “classic” editor, which was more squarely based on entering content to be published on a page or post in a predefined layout.

A full screenshot of the WordPress Block editor split into three numbers parts that are highlighted in red.
WordPress Block Editor including the block inserter (1), block editor content area (2), and the document and block settings (3)
Credit: WordPress Block Editor Handbook.

It’s sort of like content and layout coming together, where both are managed in the WordPress Editor. So, where we used to rely on the editor for content and (more or less) theme templates to define layout, both are directly editable in the WordPress Editor interface.

You can find more detail here on using the Block Editor.

Block Theme

As explained in the WordPress docs:

A block theme is a WordPress theme with templates entirely composed of blocks so that in addition to the post content of the different post types (pages, posts, …), the block editor can also be used to edit all areas of the site: headers, footers, sidebars, etc.

This WordPress documentation provides an overview of block themes in its knowledgebase, including how to create block themes and styling in this primer.

The bottom line: Block themes are different than “classic” WordPress themes. Rather than relying strictly on PHP files that conform to the WordPress Template Hierarchy, a WordPress Block Theme consists of block-based HTML templates — assembled groups of blocks that can be styled and arranged in the WordPress Site Editor (that’s coming up next) as well as using a theme.json file for global styling tokens.

Site Editor

This is the crown jewel of WordPress 5.9. While it is officially called the WordPress Site Editor, it’s largely been referred to as Full-Site Editing** (FSE) during development and is described as “the cohesive experience that allows you to directly edit and navigate between various templates, template parts, styling options, and more.” Phew, that’s a lot!

Credit: WordPress Support

The WordPress Site Editor allows us to create and editing templates that are made of blocks. So the idea is that we can assemble a group of blocks that can be applied globally to a site. Like a header component, for example. That might consist of blocks for a site logo, a primary menu, and a tagline. The site editor allows us to create a new block theme or modify an existing theme to give the site’s global appearance a completely new look without writing a line of code.

So, you know how you’ve had to build a theme in the past with a bunch of PHP templates? That’s no longer the case. Theme “development” now has a UI that’s available directly in WordPress.

More detail on using site editor is in the WordPress documentation.

The official WordPress Glossary has additional terms and definitions you may want to explore as we dig deeper into WordPress Block Themes and FSE.

Using the block editor with classic themes

The WordPress Block Editor can be used in both the classic and block themes. When the Gutenberg editor project began, the classic TinyMCE-based editor was detached from WordPress Core into the Classic Editor plugin. As long as the Classic Editor plugin is installed and active, content writing is pretty normal as it was before blocks were introduced.

Prior to the formal introduction of block editor features, we had to install the experimental Gutenberg plugin. By simply switching plugins, individual page or post contents could be created with either editor. The WordPress 5.0 release introduced the block editor alongside the default Twenty Nineteen theme, demonstrating how to add block editor features and explore its power.

In other words, the evolution toward FSE has been building for a while. And because of that, we get to enjoy a high level of backwards compatibility that allows us all to adopt block-based features when we’re good and ready.

The anatomy of block-based themes

Experimental block-based themes have been in development since early 2020. At the time I’m writing this, the GitHub theme experiment repository lists 12 block themes that explore some aspect of creating themes using blocks or block templates.

But it was probably the Twenty Twenty-One theme that was the first “default” theme to make blocks a first-class citizen, introducing block styles and block patterns, though the recently updated versions of Twenty Nineteen, and Twenty Twenty also include bundled block styling and block patterns. Currently, there are more than 130 themes from the community with bundled block editor patterns, block styles feature, including my favorite, Anders Noren’s Eksell theme.

With the ongoing development of the WordPress Block Editor’s FSE features, even more block-based themes are also being introduced.

So, what does the development of block-based themes mean for those of us who are deeply entrenched in the “classic” way of building WordPress themes? That’s what I want to look at in this section.

The file structure of block themes

In classic PHP-powered theming, markup elements are generated with PHP and JavaScript, while in block themes those templates are entirely composed of HTML blocks and structural CSS provided by the block editor. This might sound scary for lots of folks, but it’s easy to imagine just how liberating it is for others as it lowers the bar when it comes to developing a WordPress theme.

The structure of a block theme is drastically different from the classic WordPress Template Hierarchy that we all are used to. In classic PHP-based themes, page element markup has to be generated with PHP and JavaScript, whereas in block themes, the WordPress Core provides both the markup and basic styling. For example, the default Twenty Twenty-One theme contains 48 PHP files and 11 JavaScript files weighing in at 4.5 MB. Its block-based sibling, the experimental TT1 Blocks theme, contains only four PHP files, one JavaScript file, and eight HTML files at 3.5 MB.

Screenshot of a Mac window open to the default Twenty Twenty-One WordPress theme, displaying a long list of files.
Twenty Twenty-One theme folder
Screenshot of a Mac window open to the TT1 theme folder, showing that WordPress Block Themes contain fewer files.
TT1 theme folder

A block theme structure can be very simple with just a few required files : index.php, style.css and template/index.html. The following is a typical block theme file structure, pulled from the WordPress Editor Handbook:

#! basic block-theme structure
theme
|__ style.css
|__ functions.php
|__ index.php
|__ theme.json
|__ templates
    |__ index.html
    |__ single.html
    |__ archive.html
    |__ ...
|__ parts
    |__ header.html
    |__ footer.html
    |__ sidebar.html
    |__ ...
  • styles.css: Contains theme’s style sheet
  • functions.php: Contains theme setup and may include additional files, enable an editor style sheet, and enqueue style.css, if there are any
  • index.php: An empty file to switch to default file in case the block theme is activated without the WordPress Block Editor.
  • theme.json: Optional configuration file used to enable or disable features and set default styles for both the website and blocks
  • templates: Contains page templates that are composed of blocks. These files follow the same template hierarchy as traditional themes.
    • index.html: The primary template to generate a post or page, analogous to index.php in classic themes
    • single.html: The template to generate single posts or pages
    • archive.html: The template to generate archive lists of posts
  • parts: The common collections of blocks to be used in block templates
    • header.html: The global header block
    • footer.html: The global footer block
    • sidebar.html: An optional global sidebar block

A list of theme blocks including that are specific to block themes is available in WordPress Block Editor Handbook.

Templates and template parts

Templates are basically group of assembled blocks that might include reusable block parts, like a site header or footer. Different blocks are used to compose a page template. For example, that might be a list of blog posts, a list of products, or even a widget.

Here’s an example of a block template pulled from the WordPress Block Editor Handbook.


<!-- wp:site-title /-->

<!-- wp:image {"sizeSlug":"large"} -->
<figure class="wp-block-image size-large">
    <img src="https://cldup.com/0BNcqkoMdq.jpg" alt="" />
</figure>
<!-- /wp:image -->

<!-- wp:group -->
<div class="wp-block-group">
    <!-- wp:post-title /-->
    <!-- wp:post-content /-->
</div>
<!-- /wp:group -->

<!-- wp:group -->
<div class="wp-block-group">
    <!-- wp:heading -->
    <h2>Footer</h2>
    <!-- /wp:heading -->
</div>
<!-- /wp:group -->

Creating WordPress Block Themes

The WordPress Site Editor is now the primary tool for defining the look and feel of a WordPress website. You may be used to using the WordPress Customizer to do these things — and some themes have heavily tapped into that to do what the site editor is now designed to do.

So, no longer is the block editor for pages and posts; it’s the way WordPress themes are created.

I’m assuming that many of you have already used the block editor, and don’t really need a deep lesson on what it is or how to use it. That said, it’s worth poking at it a bit since it’s the impetus for everything related to WordPress theming moving forward, now that WordPress 5.9 is in the wild.

In fact, when we talk about block editing and theming, yes, we’re talking about the block editor. But really what we’re talking about is the WordPress Site Editor.

The WordPress Site Editor interface

Even as an early adopter of the Gutenberg plugin, I find the experience of the site editor intimidating and frustrating. It changes frequently and often drastically with each new release. I am hopeful, though, that WordPress 5.9 is a sort of line in the sand that helps stabilize that rocky feeling.

The site editor is accessed the same way you’re already used to accessing the WordPress Customizer. It’s located under Appearance in the dashboard menu, called Editor.

Screenshots of the WordPress admin Themes screen side-by-side, the first showing the classic WordPress menu items like Customize, Widgets, and Menus, while the second shows how a WordPress Block Themes only displays a single Editor menu item.
The site editor option is available only when a block theme is activated. If you’re using a classic theme, you’ll get the classic UI to go with it.

Let’s briefly walk-through the new Editor interface.

First, navigate to the site editor by clicking Appearance → Editor from the WordPress admin menu. That menu item may have a red “beta” label on it, like it currently does in WordPress 5.9.

That takes you to the site editor, which displays either your homepage or post archive, depending on what you have your homepage set to in Settings → Reading. From there it sort of looks like the fullscreen version of the block editor when creating or editing a page or post. But click on the WordPress logo in the top-left of the screen, and a left panel opens up revealing the WordPress Site Editor and its menu to navigate between different parts of the site. This includes Site, Templates, and Template Parts.

Screenshot of the WordPress Site Editor. There is a dark gray left panel open with an Editor heading and three links for Site, Templates, and Template Parts. The main content shows a preview of the site homepage in the WordPress Block Editor.

Let’s click into Templates. This shows us a list of the available templates provided by the theme, complete with a description of each one and where it is registered (e.g. the parent or a child theme).

Screenshot of the site editor's Templates screen which shows a two-column table listing template on the left and who a template was added by on the right.

The other way to get to this screen is from the initial page we landed on when entering the site editor. Click the name of the template in the top admin bar to reveal a button that takes you directly to the same Templates screen.

Screenshot of the Home template open in the WordPress Site Editor. The template name is at the top of the screen in a white toolbar and is expanded with a submenu that describes the template and provides a black button with white text to view all templates.

Any of templates can be edited just like any page or post in the block editor. Let’s say I don’t like to have a featured image on my index page and want to remove it. Simply delete the featured image block and save the template.

The other key part of the site editor UI is a list view that outlines the current blocks that are placed in the template. This has been a feature in WordPress since the introduction of the block editor, but what’s new this time around is that you can open and close parent blocks that contain child blocks like an accordion. Not only that, but it supports dragging and dropping blocks to change the layout directly from there.

The WordPress Site Editor with a white left panel expanded revealing an outline of the current blocks that are applied to the template.

One more thing in the site editor UI: you can clear out customizations with the click of a button. From the Templates screen, click the kebob menu next to a template and select the option to Clear customizations. This is a nice way to reset and start from scratch, should you need to.

Screenshot of the Template Parts screen in the WordPress Site Editor, showing a two-column able with a column that displays template names, and a column that identifies the location of the template part.

The WordPress Core team publishes regular updates on what’s new at Make WordPress Core. It’s worth bookmarking that to stay posted on the latest changes to the WordPress Block Editor and Site Editor.

Creating Templates and Template Parts

Templates, as you know, are core to WordPress theming. They enforce consistent and reusable layouts. That doesn’t change in WordPress 5.9. And neither does the fact that we can create template parts that are like module pieces that can be used in multiple template, say a post query that lives in an archive template and the home template.

What’s different in WordPress 5.9 is that they are created and managed with the site editor rather than PHP files that live in the theme folder.

The Block Editor Handbook lists three ways to create templates and template parts: (a) manually, by creating HTML files containing block markup, (b) using the site editor, and (c) using the template editing mode in the block editor.

Brief descriptions of creating template in the site editor and template editing mode are available in the Block Theme handbook. The WordPress 5.9 allows to create a new template using editor mode.

Screenshot of the Template Parts screen open in the WordPress Site Editor. A modal is open above the UI that contains an interface to create a template part, including the part's name and area.

The customized templates can then be exported to include in a block theme. So, yeah, we now have the ability to create a fully functioning WordPress theme without writing a line of code! The exported folder currently does not contain theme.json file, however there is a proposal over at GitHub to allow exporting both block themes and styles.

Screenshot of the WordPress Site Editor preferences panel open as a white panel to the left of the screen.

But for those who prefer working more closely with code, then manually creating WordPress templates and template parts is still a thing. You can still crack open a code editor and create HTML files containing block markup.

Global settings and styles (theme.json)

In classic themes, we write the styling rules in a style.css file. In block themes, styling is more challenging because CSS comes from different sources (e.g. core blocks, themes, and users). WordPress 5.8 introduced a concept of Global Styles — which is essentially a theme.json file — that, according to the docs, consolidate “the various APIs related to styles into a single point – a theme.json file that should be located inside the root of the theme directory.“

Screenshot of a theme dot jayson file open in the VS Code editor. The file contains objects for version and settings. The settings object contains a color object. The color object contains a palette objects which contains properties for slightly, color, name, and default.

The theme.json file is said to have been designed to offer more granular styling structure for theme authors with options to manage and customize the CSS styles coming from various origins. For example, a theme author may set certain styling features that are hidden from users, define default colors, font sizes and other features available to the user, and may set the default layout of the editor as well. Plus, theme.json allows you to customize styling on a per-block basis. It’s powerful, flexible, and super maintainable!

The block editor is expected to provide all the basic styling that theme authors are allowed to customize style, as defined by the theme.json file. However, the theme.json file could get quite long for a complex theme, and currently there is no way to partition it in a more digestible way. There is a GitHub ticket to restructure it so that different theme.json files map to a /styles folder. That would be a nice enhancement for developer experience.

The default Twenty Twenty-Two theme is a good example of how WordPress full-site editing features use theme.json for global settings and styling blocks.

WordPress Block Theme approaches

Maybe you’ve always made WordPress themes from scratch. Perhaps you’ve relied on the Underscores theme as a starting point. Or maybe you have a favorite theme you extend with a child theme. The new features of the WordPress Site Editor really change the way we make themes.

Following are a few emerging strategies for block-based theme development that are deeply integrated with the WordPress Site Editor.

Universal themes

The Automattic team has built a Blockbase universal theme that’s dubbed as a new way to build themes, sort of similar to the Underscores starter theme. The Blockbase theme provides temporary “ponyfill” styles that the block editor “does not yet take into account on theme.json ‘custom’ properties” and that may eventually become obsolete once the Gutenberg plugin fully matures and is integrated into WordPress Core.

Using the universal parent theme approach, the Automattic has already released eight Blockbase child themes, and several others are in progress over at GitHub.

Twenty Twenty-Two default theme

The Twenty Twenty-Two default theme is another excellent starting point, as it’s really the first WordPress theme that ships with WordPress that is designed to work with the site editor.

In my opinion, this theme is excellent for theme developers who are already familiar with FSE features to showcase what is possible. For others users who are not developers and are not familiar with FSE features, customizations it in the block editor, then exporting it as a child theme could be painfully frustrating and overwhelming.

Hybrid themes

The concept of “Hybrid” themes in the context of FSE is discussed in this GitHub ticket. The idea is to provide paths for any user to use the site or template editor to override traditional theme templates.

Justin Tadlock in this WP Tavern post predicts four types of themes — block only, universal, hybrid, and classic — and speculates that theme authors may split between “block themes and a mashup of classic/hybrid themes.”

Proof in the pudding is provided by Frank Klein in “What I Learned Building a Hybrid Theme”:

A hybrid theme mixes the traditional theming approach with full-site editing features. A key component here is the theme.json file. It offers more control over the block editor’s settings, and simplifies styling blocks. A hybrid theme can use block templates as well, but that’s optional.

Frank is the author of the Block-Based Bosco theme and has expanded further on what a “hybrid theme” is by creating a hybrid version of the default Twenty Twenty theme. The theme is available on GitHub. Currently, there are no hybrid themes in the WordPres Theme Directory.

WordPress community themes

At the time of writing, there are 47 block-based themes with FSE features available in the theme directory. As expected, this approach is widely varied.

For example, in this post, Aino block theme author Ellen Bower discusses how they converted their classic theme into a block theme, detailing what makes a theme a “block” theme. The file structure of this approach looks different from the standard block theme structure we covered earlier.

Another popular block theme, Tove by Andars Noren, is described as a flexible base theme that follows the standard block theme file structure.

There’s also a very simple single page proof of the concept theme by Carolina Nymark that contains nothing but a single index.html called Miniblock OOAK. It’s already available in the theme directory, as is another one from Justin Tadlock that’s a work in progress (and he wrote up his process in a separate article).

Block Theme Generator app

Even though we’ve already established how friendly WordPress Block Themes are for non-developers, there are tools that help create complete block themes or merely a customized theme.json file.

David Gwyer, an Automattic engineer, has been working on a Block theme generator app which, at the time of writing, is in beta and available for testing by request.

Screenshot of the Block Theme Generator app homepage. It has a bright blue background and dark blue text that welcomes you to the site, and a screenshot of the app.

In my brief testing, the app only allowed me to generate customized theme.json file. But Gwyer told to WP Tavern that the app isn’t fully baked just yet, but features are being added often. Once complete, this could be a very helpful resource for theme authors to create customized block themes.

Block themes that are currently in use

This Twitter thread from Carolina Nymark shows some examples of block themes that are live and in production at the time of this writing. In a recent Yoast article, Carolina listed a bunch of personal and business websites that use block themes.

Personal sites

Business sites

As I mentioned earlier, I also have been using a block theme for one of my personal websites for a while. The default Twenty Twenty-Two theme also currently shows more than 60,000 active installs, which tells me there are many more examples of block-based theme implementations in the wild.

Building Block Child Themes

Child theming is still a thing in this new era of WordPress blocks, though something that’s still in early days. In other words, there is no clear approach to do make a block-based child theme, and there are no existing tools to help at the moment.

That said, a few approaches for creating WordPress child block themes are emerging.

Create Blockbase Theme plugin

The Automattic team is working on a plugin called Create Blockbase Theme. This will make it fairly trivial to create child themes based on the Blockbase universal theme we talked about earlier. Ben Dwyer has discussed how theme authors can build Blockbase child themes with simple six steps and without writing a line of code.

I tested the plugin in my own local environment, making only small changes to my Blockbase theme install, and everything appeared to work. Just note that the plugin is still experimental and under development, though you can follow the roadmap to see what’s up.

Using an alternate theme.json file

Kjell Reigstad, author of the default WordPress Twenty Twenty-Two theme, demonstrates how swapping a single theme.json file with another theme.json file that contains different style configurations can change the look and feel of a block-based theme design.

Kjell has opened a pull request that shows off several experimental child themes that are available for testing at the GitHub theme-experiment GitHub repository.

A three-by-two grid of screenshots of child themes based on the default WordPress Twenty Twenty-Two theme in alternate colors schemes.

Along these same lines, Ryan Welcher is in the process of developing a theme.json builder tool that will generate a customized theme.json file to facilitate non-coders to create similar child themes. More can be found in this WP Tavern post.

The Framboise child theme (available in theme directory) is an early example of that approach which includes only a single theme.json file.

Is there even a need for child themes?

Rich Tabor asks the question:

Indeed, a single theme.json file could serve as a child theme on its own. There is an ongoing discussion about allowing theme authors to ship multiple theme.json files with block themes that offer multiple global style variations. This way, a WordPress user could pick one of the variations to use on the site.

Some features of global style variations are already included in Gutenberg v12. 5 and expected to be available with WordPress 6.0.

Some personal thoughts

I’d be remiss to end this without weighing in on all this from a personal level. I’ll do this briefly in a few points.

Block themes are a WordPress answer to Jamstack criticisms

Jamstack enthusiasts have lobbed criticisms at the WordPress platform, most notably that WordPress themes are bloated with PHP files. Well, that’s no longer the case with WordPress Block Themes.

We saw earlier how an entire theme can be a single index.html file and a theme.json file. No bloat there. And nothing but markup.

I miss the WordPress Customizer

Especially the ability to inject custom code. From here on out, it’s going to require a deep level of familiarity with the WordPress Site Editor UI to accomplish the same thing.

Customizations a site is easy-peasy.

Customizing a classic theme — even something as minimal as changing fonts — can be difficult if you don’t know what you’re doing. That’s changed now with the site editor and the introduction of the theme.json file, where a theme can be customized (and even exported!) without writing a single line of code.

I still hold my opinion, though that the site editor interface is confusing. I think a pleasant user experience is a far ways off but looking forward to the next WordPress 6.0 release for better user experience.

Barriers to designing themes is getting lower.

It’s less about PHP and template files, and more about developing patterns and creating content. That sounds exactly what a content management system should be designed to do! I am already excited with new features being considered for the WordPress 6.0 release.

Resources

There is already a ton of other articles that cover WordPress Block Themes, full-site editing, and the block editor. And many of those came before WordPress 5.9 was released!

So, in addition to this article, here’s a collection of others for you to consider as you begin or continue down your journey of WordPress blocks and site editing.

WordPress 5.9

Site editor and block themes

Selected blog posts


As expected in beta testing, the site editor is still intimating and confusing, nevertheless, I am finding it a fun to work with block themes. Indeed, I have been already modifying Twenty Twenty-Two as a child theme and plan to create style alternatives using single theme.json file.

Have you been using block themes in your project, if so, share your experience and thoughts; I love reading any comments and feedback!


A Deep Introduction to WordPress Block Themes originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/a-deep-introduction-to-wordpress-block-themes/feed/ 9 362799