Build Better Blocks logo

Build Better Blocks

  • About
  • Gutenberg and fluid typography

    May 26th, 2022
    Edison's electric pen

    If you’ve recently returned from a multi-decade, extrasolar vacation, or, like me, you’ve been too busy doing other things to notice, you might not have heard of ‘fluid typography’.

    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.

    Why is it good, and why should I bother to pay attention? Very astute question!

    Taking font size as an example, when a site’s font sizes are fluid, it means they will adapt to every change in screen size, for example, by growing larger as the viewport width increases, or smaller as it decreases.

    Contrast that idea with properties that respond to specific viewport sizes, such as those defined by media queries, but do nothing in between. (By the way, if you’ve never Googled or debated with strangers on the internet about perfect CSS break points, then you’ve lived a good life.)

    The potential benefit of fluid typography is that it permits us finer control over how properties such as font size appear at every screen size, not just at specific “mobile”, “tablet” or “desktop” breakpoints, whatever they happen to represent at the time.

    Fluid typography is not just type hype: it’s been around for a while. There is a fluid typography approach for every design with some taking into account minimum and maximum viewport widths, others not, some using calc(), others clamp().

    Given that resounding endorsement, now is as good a time as any to bring it to Gutenberg

    Well, that’s the plan.

    The plan

    When introducing a new feature to Gutenberg, especially one that impacts site design, there are as many considerations as there are fluid typography clamp formulae.

    Here are some:

    1. It’s preferable to limit the amount of new theme.json  properties, and where we do introduce new ones, to make those properties easy to understand.
    2. We need consider how theme authors will apply fluid typography to specific entities such as elements or blocks.
    3. How much flexibility should we provide? For example, should we allow both built-in and custom clamp calculations? What about varying size units?
    4. We also need to balance this flexibility with future usage and potential backwards compatibility should things ever when things change.
    5. Finally, which customization controls, if any, do we need in the Block Editor?

    It’s very easy to become dizzy when contemplating all the variables. It’s fortunate I’m mostly always sitting down.

    Hence, I find it’s much healthier to start with modest goals that will instruct further development and exploration, and, furthermore, prevent unnecessary stupefaction.

    With that in mind, let’s kick things off with the following constraints:

    • Introduce fluid font sizes only.
    • For starters, we’ll have little or no user interface in the editor: fluid font sizes will be activated and tweaked via theme.json.

    Theme.json – the font of all settings

    There’s nothing preventing theme authors from entering any type of fluid font size value for any element or block right now.

    Here’s an example from the TwentyTwentyTwo theme.

    "fontSizes": [
        ...
        {
            "size": "clamp(1.75rem, 3vw, 2.25rem)",
            "slug": "x-large"
        }
    ]

    The example above displays the settings.typography.fontSizes array within theme.json.

    fontSizes, by the way, is one of several presets.

    Using the items in this array, Gutenberg generates CSS vars for use across the theme, for example:

    -wp--preset--font-size--x-large: clamp(1.75rem, 3vw, 2.25rem)

    Also, these items determine the values displayed in the editor via the font size typography control.

    If we are to introduce fluid typography, our mission is to retain the possibility of allowing any font size value (and therefore any fluid font size expression) but also offer an implementation behind the scenes so that users can plug in some numbers to achieve a uniform effect across their sites.

    To get there, we’ll need to extend the theme.json API with a few more properties.

    Okay… rubbing hands… for every font size, let’s create an additional property to house our fluid typography variables:

    "settings": {
        ....
        "typography": {
            "fluid": {
                "min": "768px",
                "max": "1600px"
            },
            "fontSizes": [
                {
                    "size": "2rem",
                    "fluidSize": {
                        "min": "1.8rem",
                        "max": "2.5rem"
                    },
                    "slug": "medium",
                    "name": "Medium"
                }
            }
    }

    Note the new properties settings.typography.fluid and settings.typography.fontSizes.fluidSize, both of which contain the following properties:

    1. min – In fluid, the minimum viewport width, in fluidSize, the minimum font size.
    2. max – In fluid, the maximum viewport width, in fluidSize, the maximum font size.

    The min and max settings in settings.typography.fluid could be optional should we devise appropriate fallbacks.

    So, what prodigious feats can we perform with such properties I hear no-one asking?

    Firstly, we can use this information to construct a unique clamp() formula for every font size. The formula will control how a font scales between minimum and maximum values, relative to the viewport width.

    Just what this mysterious formula might be is still subject to experimentation and open for debate, but for the purposes of this post, let’s pretend that it’s working fabulously.

    What’s more, if we’re missing some pieces, such as a minimum or maximum font size value, which are required to reliably roll our nifty clamp() formula, we could return an alternative font size value using CSS max() or min() accordingly.

    Seeing as we haven’t messed with the current typography properties folks can still use size to define a font size however they please, and both will be available in the editor immediately via the font size UI control.

    What’s next

    A challenge will be to make the implementation generic enough to tweak, but not specific enough so that, if we ever make changes to the algorithm it will break sites.

    For example, we’d want to avoid the situation whereby theme authors find themselves fiddling with their font sizes to accommodate Gutenberg’s implementation only to find that they look terrible as soon as the system environment changes, whether via disabling fluid type or changing the CSS formulae.

    Hopefully we’d insure against this situation by way of baby step iterations. In the current pull request, the proposal is for no user-facing controls during the first stage. Fluid typography controls live exclusively in theme.json.

    The rationale is that we are able test our API choices at the theme-level first, then let any lessons guide how we express fluid typography in the UI.

    One such UI expression could be to exploit the fact that size and fluidSize properties can live alongside each other. This opens up the possibility of adding a UI toggle.

    Have you tried turning fluid font sizes off and on again?

    Thinking beyond, fluidity doesn’t need to stop at font sizes, or even typography either. Our next stop might be to create fluid line heights or letter spacing, all of which will one day peacefully co-exist in a world where individual blocks, layout and block patterns are fluid out of the box.


    Much of this article was inspired by the clumsy stabs at various solutions I took in Github, and the reasoning, for better or worse, from the pull request discussions. The useless cynicism and bottom-of-the-barrel quips I drew from nowhere in particular.

  • Block supports, global styles, and work to consolidate style generation in Gutenberg

    March 3rd, 2022
    Workshop of a painter on glass.

    With full site editing and global styles landing in WordPress 5.9, there’s been a lot of feedback and interest in how WordPress (and in particular Gutenberg) generates styles for blocks, and the relationship between styles generated by WordPress, and styles provided by themes.

    As some of us explore how all this is hooked together, this post seeks to highlight some of the places in the codebases where things happen, and points to a couple of posts and issues in the Gutenberg repository where work is happening to attempt to consolidate and streamline how styles are generated.

    Block supports and where the code lives

    So that each block doesn’t have to implement its own ad hoc controls for common features like spacing, color and typography support, block supports are used to consolidate the logic for these shared features. The public documentation on opting-in to supports can be found here and a great read is the architectural overview of styles in the block editor that was recently added. That document wonderfully captures the current state of things, particularly the section on the current limitations of the global styles API.

    If you’re taking a look at how things are hooked together, some good places to check out in the Gutenberg and WordPress codebase(s) are:

    • /packages/block-editor/src/hooks — block editor JS-based implementation of supports
    • /packages/edit-site/src/components/global-styles — global styles within the site editor, in particular look at hooks.js and for example dimensions-panel.js for the global styles side of implementing things like padding or margin
    • /lib/block-supports — where the PHP-based implementations of block supports live in the Gutenberg repo
    • wp-includes/class-wp-block-supports.php — where the PHP-based implementations are called from.

    Individual block level

    JS implementation

    At an individual block level for (relatively) simple block supports like padding, the style is often saved directly to post content as inline styles, e.g. in hooks/style.js take a look at the filter addSaveProps — this calls the corresponding function that then calls getInlineStyles which looks up the hard-coded style properties in packages/blocks/src/api/constants.js — in this set of style properties, the support array defines the path to the support feature (whether or not it’s opted-into) and the path to get the value from the style object in the block’s attributes.

    PHP implementation

    For server-rendered blocks, or block supports that require more complexity than rendering to inline styles, then the server-side implementation of block supports is applicable. If you take a look at each of them in lib/block-supports, you should see that the supports will check that the block has opted-in to the support, and that there is currently a style value that needs to be rendered.

    Some of the supports, such as the Layout support can get particularly complex. Part the work folks are looking into, will be to try to reduce the complexity and / or improve the API here for how to handle very complex block supports in a more intuitive and less error-prone way. For example, instead of echoing out CSS one string at a time, can the rendering be consolidated?

    Global styles level

    As pointed out in the styles in the block editor documentation, some of the limitations of global styles, are that unlike the individual block-level block supports, they lack any control over how they output their styles and what they target. Global styles is a fairly simple mechanism of looking up a property and rendering a single property assigned to the container of a block via its classname. Some places to look to see how it’s put together:

    • In class-wp-theme-json.php in core (and overridden in Gutenberg) the PROPERTIES_METADATA constant holds an array of CSS properties matched to their path in theme.json and block attributes. E.g. padding-top comes from spacing.padding.top within the style object.
    • compute_style_properties is responsible for performing the lookup and outputting an array of declarations.
    • This function is called from get_block_classes for each style node (and also handles the root block selector).
    • And that function is originally called from get_stylesheet.

    How could things be consolidated?

    There is a tracking issue in the Gutenberg repository for exploring building a “style engine” — this is a general idea that there should be a centralised place for generating and outputting the generated block styles. Given that it’s still an exploratory idea, the scope of what that project might become hasn’t really yet been decided. But, for anyone interested, it’s worth having a read of the linked discussions from the style engine tracking issue — there’s a lot of linked discussion and issues so there’s a fair bit of context to gather!

    The style engine conversation came out of this discussion on improving the saving and rendering of block styles, to address problems of inconsistencies and dealing with deprecations. Some of the things folks have stated that they’d like to achieve by consolidating style rendering include:

    • Currently some block supports (such as the Layout support) render an individual style tag with a randomly generated class name, to link the style to the rendered block. It’d be great to consolidate and de-dupe all these styles and class names, for a cleaner DOM but also, to factor in feedback like this issue raised from the perspective of theme authors.
    • Reduce the duplication and separation between individual block supports and global styles, the JS implementation and PHP implementations.
    • Make it easier to safely add additional block supports / additional layouts, etc, and improve support for more complex blocks.
    • Move more of the block supports to consolidate around a consistent server-rendering approach, to reduce the need for saving styles in post content. This should also help avoid the problem where updating how styling works then requires adding or updating deprecations, or accidentally invalidating blocks.

    It’s still early days in thinking about how all this should work, so there’s ample room for discussion and exploration in all of the topics. Hopefully some of the above links will be useful for folks curious in seeing how things are hooked together, and where there are suggestions for improving how it all works. One potential direction is an early exploratory PR that seeks to explore how the styles generated for the Layout block support can be consolidated into a single style tag, with de-duped styles and meaningful, non-random class names.

    If you’re at all interested in how all this develops, feel free to chime in on any of the issues and discussions!

  • A journey to building better blocks

    February 28th, 2022
    The Travelers, by Henry Macbeth Raeburn

    Nobody – at least nobody we know – lives in a vacuum. Except probably dust mites.

    In the Open Source world this is especially obvious: whenever we add a line of code, or comment on an issue or pull request, whether we’re aware of it or not, we’re entangling ourselves with a vast network of developers, designers, users and contributors, all of whom, despite having diverse experiences and opinions, share a common goal: to build a better web.

    On our way to “Building Better Blocks” for the Gutenberg editor and the WordPress project this goal remains in our minds, propelled by the exciting knowledge that, with the right balance of discovery, compromise, collaboration and experimentation, anything is possible.

    As with any journey, there are challenges: ideas turn stale, work stalls, we find ourselves staring at walls wondering where to go next.

    Yet along the way, we’ve learned a few things that have made our adventure more rewarding and amusing. They’re applicable to any large Open Source project I think, but we’ve drawn them specifically from our experiences working on Gutenberg.

    We hope they’ll help you too.

    Work that goes nowhere can lead us somewhere

    Time and effort devoted to developing a feature or solution to a problem that never makes into the final product is not wasted if we learn something. 

    For example, we might have implemented a prototype for a design, spent days crafting, writing tests, honing the user experience, and seeking feedback but learn only after that the approach is flawed in some way.

    We’ll use that information to guide the design in a new direction. File it under “research”. It’s all good.

    We find it’s also useful to write a summary of why we’re closing a pull request and link to follow ups, if any.

    Even if it’s not us, one day, someone will come along and pick up the thread where we left off and build upon our knowledge.

    Leave sign posts

    Discussions can grow very large. They might change the direction of a PR multiple times. They may even appear to go in circles. In fact, sometimes they do.

    This is also all fine. It’s just humans working things out.

    Where a loop has been closed, or a pull request takes a new direction, we’ll close that PR and create a new one.

    When doing so, it’s very helpful to add backlinks to the original pull request in order to reduce research time for reviewers and contributors both new and experienced.

    You have more fellow travellers than you think

    Knowledge varies wildly between individual Gutenberg contributors, so include prior history, discussion and context in PR and Issue descriptions, or at the very least, links to where folks can find all that.

    This is not only helpful to new contributors, but to other folks such as reviewers, release leads and product managers, all of whom need to be able to gain a quick overview and understanding of the code, how it fits into any milestones, and the reasons behind changes.

    You might have an intended audience in mind, yet you can’t know in advance who’ll land on your pull request or issue via backtracking, via the WordPress Core blog, or otherwise. It might even be your future self returning after a long, and probably well-deserved break.

    Investing a few extra minutes describing the what, how and why behind your pull request in the description field, in addition to how to test your changes, what to look for in a bug fix or bug report, will help others to understand your proposal/changes. So too will creating informative screenshots or demos. We will love you for it.

    Don’t be afraid

    There are high standards, yes. We’re sharing this journey with clever and experienced (and stylish!) people, whose opinions will influence the course of our work.

    Remind yourself: you can afford to be brave. You can experiment with ideas, defend them in the discussions. 

    Collaboration brings with it many opinions, and (theoretically) fewer top-down imperatives: you have the opportunity therefore to learn and contribute to conversations on a relatively level field. 

    Convince us by code or design demos or rhetoric. Strive for compromise and excellent outcomes for users.

    Take time to smell the coconuts

    Open Source runs on its own version of “island time”, which is not to say that nothing happens, more so that things happen when they need to.

    Discussions on issues or open pull requests may appear to never progress, or will be dispersed across many media and be asynchronous. Pull requests sometimes hit a roadblock or ten roadblocks as new dependencies and use cases arise.

    The process of discovery and collaboration is, even if we don’t notice, always evolving.

    It can be frustrating to have your work interrupted or placed on pause. Use the time to read deeply and build context. We’ll all get there.

    In the end, the journey is as important as the goal.

Proudly powered by WordPress