Gutenberg: 🖍Global Style System

Created on 13 Jan 2020  ·  46Comments  ·  Source: WordPress/gutenberg

👋 Hello everyone!

First off, Happy New Year at all! I hope you all had the happiest of holidays.

I'd like to expand upon the original "Block Style System" issue @mtias started at https://github.com/WordPress/gutenberg/issues/9534.

I originally proposed a concept last year in November. Even before then, the thread has evolved a lot, with a lot of exciting ideas and feedback.

This Github issue is also very much related to https://github.com/WordPress/gutenberg/issues/19255. Serving as the technical complementary piece to the Global Styles / FSE design work that is happening!

Recap

The idea is to provide a unified system for Gutenberg blocks (core + 3rd party) and themes to work well with each other. They also have to understand and respect user overrides. These defined styles can be applied globally throughout the user's site (e.g. Declaring font scale, or colors, or how all Buttons look).

At the moment, Gutenberg only supports style customization at the per-block level. So updating a Button in one post, will not retroactively update Buttons on other pages.

Terminology

"Builders" - People who create things to help create content. Examples: Block creators, themers, plugin authors.
"Users" - People who create content.
"Backend" - Gutenberg's Editor. What the User uses to create content.
"Frontend" - Rendered site. What the User sees.


Demo

Screen Capture on 2020-01-13 at 16-33-31

I think a good way to start this one would be an interactive demo!
The demo can be found here:

👉https://9w53w.csb.app/

CodeSandbox (for code/preview):
https://codesandbox.io/s/github/itsjonq/wp-gs

Github Repo for source code:
https://github.com/itsjonq/wp-gs

In the demo, click on "Toggle Inspector" to see the style configs (outlined below)

To simulate the "loading" of a theme, go to:
https://codesandbox.io/s/github/itsjonq/wp-gs

Uncomment the following line:

//import "./load-theme";

And click the refresh icon in the browser preview (right)


Note: The code I have is mostly prototype code. Code to discover and realize the various moving pieces, and how they all fit together. I wrote it outside the context of Gutenberg to make iterations/builds faster. It also enabled me to publish it onto CodeSandbox for live code/preview purposes.


The Parts

01-parts

For my proposal, global styles is a system of setting and rendering a (giant) config. These mechanisms can be represented by 5 parts (above).

  1. Default theme styles
  2. Theme styles (e.g. Twenty Twenty)
  3. User styles
  4. Merged styles
  5. CSS Variable rendering

1. Default Theme Styles

These determine the default properties how the sites/blocks will render. These are the bare-bone essentials for rendering site's front-end. They are not opinionless, but very close to being so.

They also help establish structure when it comes to adding/updating values. For example, colors and fontSizes will always exist.

The current structure follows the semantics outlined by Theme UI spec, which is a (mostly React) based theming convention that's gaining in popularity. Of course, we don't have to use this schema :).

What qualifies as default styles?

Some core colours and typography would be a great start.

Gutenberg's core blocks have style opinions. They kind of have to. For certain blocks to be functional, they need some styling in order to work correctly on the front-end. These would qualify for default styles as well.

2. Theme styles

In the future, once Global Styles x Gutenberg is in place, one way a Gutenberg supported theme may want to customize blocks would be to include a theme.json file. The key/value pairs follow the same schema.

The .json file works similarly to the current add_theme_support() php function, but I feel like it's easier to declare.

These will add to/override the values from default styles.

3. User styles

The ability for the user to customize these values would be presented in the Global Styles editor/tool interface. The concept is very similar to the customizer.

The experience of this can be seen in my demo.

Global Styles x Blocks

In addition to updating colors or typography, (in the future) this interface can update (style based) attributes for blocks. Using a registration system (like how core/custom Gutenberg blocks are registered), block style attributes can appear in this global editing experience.

Hierarchy

User styles overrides theme styles.
Theme styles overrides defaults.

Leading us to...

4. "Merged" styles

This is the consolidation of User > Theme > Default styles. These are consolidated and enhanced to prepare the values to be rendered.

Enhanced with "plugins"

03-transforms

A mechanism I built into the system allows for Builders to modify/enhance values from the style config. For example, in the above screenshot, the original single text value has become an array of various color shades. This is applied to any color value under the colors key.

With my prototype, this is how a plugin may look like:
https://github.com/ItsJonQ/wp-gs/blob/master/src/global-styles/plugins/color-scheme-plugin.js

By interpolating/enhancing values, we can improve and simplify the values to be rendered with CSS

5. CSS Variable rendering

Finally, the defined and enhanced styles are rendered via CSS variables. The last stage of the system flattens and transforms the data into CSS variables.


Global Styles x Blocks

For blocks to start using global styles, their CSS will need to be refactored to use the CSS variables outputted by system.

Example:

.wp-block-button {
    box-sizing: border-box;
    border: 1px solid var(--wp-gs-color-primary-dark20);
    display: inline-flex;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
        "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans",
        "Helvetica Neue", sans-serif;
    line-height: 1.2;
    font-weight: bold;
    text-decoration: none;
    cursor: pointer;

    background-color: var(--wp-gs-button-backgroundColor);
    border-radius: var(--wp-gs-button-borderRadius);
    border-width: var(--wp-gs-button-borderSize);
    box-shadow: var(--wp-gs-button-dropShadow);
    color: var(--wp-gs-button-textColor);
    padding: var(--wp-gs-button-padding);
}

Global Styles x Themes

With this system, the overhead of styling blocks outputted from Gutenberg has been tremendously reduced. By leveraging a theme.json file, the Themer has a lot of controls over the visuals of the WordPress x Gutenberg. Better yet, they will be able to confidently adjust the visuals of custom blocks as well (assuming they're using global styles).


Rendering on the Front End

Similar to how Gutenberg blocks are saved/rendered, we can save and store the outputted HTML from Global Styles. This HTML contains the generated variables, which can be injected into the head via PHP, meaning there's not variable/style consolidation required on load. It's already been done.

Any change made to global styles will trigger a save, following the mechanism that Gutenberg has for its blocks.

This style generation mechanism needs to be triggered regardless if Gutenberg is loaded or not. For example:

A user installs and opens WordPress for the very first time. They download and activate a custom theme (with global styles support). They view their site, without having written a page/post yet. The site should render correctly.


Customizing rendering of "sections"

Since UI on the front-end will be rendered with CSS Variables, we will be able to customize how blocks render in "sections" in a robust manner.

For example, your site is white with black text, but your sidebar is black with white text.

Certain blocks that get added to your sidebar need to adjust their colors to be readable. From a technical standpoint, this can now be done by inline styling a CSS variable, example:

<div class="wp-sidebar-block" style="--wp-gs-colors-text: white;">
  ...
</div>

For those who made it to the end of this very long post, thank you!

🙏 🙏 🙏 🙏

There are a lot of moving parts for this idea. We're still very early days. I'm sure there are a lot of nuances and edge cases that I haven't thought of yet. Which is why I'd love to hear from everyone!

Thoughts and feedback are 💯 welcome.

Thank you so much for your time!

Global Styles Needs Technical Feedback [Feature] Full Site Editing

Most helpful comment

I've just read through all of #9534 and this issue and I'd like to bring up a perspective that hasn't been mentioned at all yet as far as I've read.

Users Styling vs. Builders Styling

All of the above is mostly concerned with maximum flexibility and control for "Users", offering them a solid base in the form of core and theme styling but giving them the final say and a broad array of capabilities to alter the styling of a website.

This is a valid and quite surely the most common use case, but I am coming from a totally different (not to say opposite) direction: Sites where there are multiple users as well as a clear separation between designers, developers and editors. In that setting users specifically should have no or at least very little control over the styling of the site. They create semantic content using the (heavily moderated) set of blocks leaving the styling in the hands of designers and developers. Think separation of concerns between content and layout/styling for the sake of consistency.

In that situation the "Style Hierarchy" mentioned above is not what one needs or wants since styling should solely be defined by the theme. Changing anything on the Global, Document and Block Levels shouldn't be possible. And even the Core Styling might be too opinionated. Instead the Theme Level should be the first, last and only one to decide how everything is styled.

Shouldn't we just embrace users being in control?

Generally yes, but maybe not here. Let's see why.

If a website is based on a corporate design, a styleguide or any other well thought through system a button looks like a button and there is no need for a user (think content editor) to ever even be able to micro-manage things like the background color of a button. Maintaining global consistency is impossible with individual user control.

(Even more so I personally think taking away some choices like the ones relating to styling actually helps users be content editors by freeing them from needing to think about styling. This actually makes them feel more in control even if they might not technically be. _"Decisions, not Options"_)

Core styles are always opinionated.

I understand that there has to be some baseline, but even that often needs to be changed drastically if not even removed. Simple example: Currently Column and Gallery Blocks use CSS Flexbox for layout, making any Core Block CSS totally obsolete if not even hindering if having your whole site layout based on CSS Grid.

So basically here the whole concept of multi-layer overwrites is somewhere between irrelevant to harmful beyond the fact that one can disable, overwrite or take as much control over it as possible. And even if some things may be allowed to be styleable by users I'd see the pyramid shuffled such as that the theme layer is on top having the final say and only "letting through" certain styling choices by a user.

So if this whole system gives even more styling control to users than we already have right now please make sure that any setting that is being introduced as user-controllable has a way to be disabled, restricted or overwritten. This is so that it isn't as difficult to stay in control as it currently is with things like custom colors/gradients, fonts sizes, number of columns, drop caps,...

Final thoughts

To close things up I am aware that the general direction Gutenberg is moving towards is a very visual approach to content editing. WordPress has always been quite oblivious to the separation of content and layout, but currently I see the risk that this might become the final nail in the coffin so that it isn't only difficult but becomes outright impossible the further down we go the route of giving unbound styling power to users.

All 46 comments

Thanks for posting this! Very excited for the possibilities 😍

These defined styles can be applied globally throughout the user's site (e.g. Declaring font scale, or colors, or how all Buttons look).

At the moment, Gutenberg only supports style customization at the per-block level. So updating a Button in one post, will not retroactively update Buttons on other pages.

To clarify, will users be able to update the color on all the buttons, or the font-size on all the paragraphs, through the editor UI? And if so, will they still be able to make adjustments on a per-block basis?

Similar to how Gutenberg blocks are saved/rendered, we can save and store the outputted HTML from Global Styles. This HTML contains the generated variables, which can be injected into the head via PHP, meaning there's not variable/style consolidation required on load. It's already been done.

Would there be a good alternative to using CSS variables on the front end? The concern here is that any website using WP would stop working on IE. Even if WP as a project decides to stop supporting IE (which is likely at some point in the future), if users can no longer build IE-compatible websites with it that could be a huge problem for any government or other official institution that uses WP.

So cool and can't wait for this feature!

Would there be a good alternative to using CSS variables on the front end? The concern here is that any website using WP would stop working on IE. Even if WP as a project decides to stop supporting IE (which is likely at some point in the future), if users can no longer build IE-compatible websites with it that could be a huge problem for any government or other official institution that uses WP.

This is an important point and unfortunate reality. It'd be nice if we could get some hard data on exactly how much of an impact this would have though.

With that said, I wonder if something like https://www.npmjs.com/package/postcss-css-variables would be something that could be used in the build process to assist with the final css. Maybe there could be a plugin for WP that would do on the fly processing of the css output to transpile (using that package) to a IE friendly output that could then be used by those sites needing it?

@tellthemachines + @nerrad Thanks for your feedback! I agree, the concern with CSS Variables and the lack of (older) browser support is very real.

Maybe there could be a plugin for WP that would do on the fly processing of the css output to transpile (using that package) to a IE friendly output that could then be used by those sites needing it?

That would be interesting! Something server-side to reduce the need for a JS-based polyfill fill client side.

I'm really hoping we can use CSS Variables for the styling mechanism for this project. Either using a technique like what @nerrad suggested, and pony/polyfill, or something else.


With that said, I don't think CSS variables the piece that makes/breaks global styles.

I think the most critical piece, would be creating the system that allows Themes, Blocks, and user Customizations (globals + one-offs) to play nicely with each other. A system that reduces complexity and overhead for Block Developers and Themers. This will then provide a more cohesive experience for users. Perhaps a user who customizes things often or tries using different custom blocks from different block authors.

Focusing on that user experience is, I think, ultimately a big part of the Gutenberg experience :). I'm reminded of that by a comment @nerrad wrote (link below), where he eloquently emphasized the importance of user experience within WordPress.

https://github.com/WordPress/gutenberg/pull/16384#issuecomment-573430079

👋Hallooo all!

I have an update. I've been working with @karmatosed to figure out the flows for how global styles will work in the context of Full Site editing, as well as with themes and blocks.

I've created a prototype that demonstrates the flow + hierarchy of how global styles will work with blocks and themes

I recorded a screencast that goes over prototype + concepts:

:video_camera: Video
https://www.loom.com/share/73f721797f524dfeb2c3a222e9e24561

:raised_hands: Demo
https://yvz8y.csb.app/#/v2/post


Too Long, Didn't Watch

No worries! I'll try to summarize <3

The style hierarchy can be represented by this pyramid:

Screen Shot 2020-01-15 at 4 38 43 PM

Core: Base styles that come with Gutenberg/global styling system
Theme: Custom styles defined by a theme
Global: Custom styles applied by the user, intended for the entire site
Document: Custom styles applied by the user, intended for certain pages/template parts (FSE)
Block: Custom styles applied by the user, for individual blocks

In the above pyramid, we can see that the Core styles (black text), has persisted it's way up, as no styles were defined on any other layer. Resulting in something that looks like this:

Screen Shot 2020-01-15 at 4 43 43 PM

If we switch the theme to Blue, the blue theme's custom styles (in this case, blue text), will override core's styles. It will persist upwards as no other custom styles are applied

Screen Shot 2020-01-15 at 4 38 48 PM

Resulting in a site that looks like this:

Screen Shot 2020-01-15 at 4 44 53 PM

If we apply a global style, it will override the theme's:

Screen Shot 2020-01-15 at 4 39 01 PM

If we apply a document style, it will override global's (if applicable):

Screen Shot 2020-01-15 at 4 39 12 PM

Lastly, if we customize a specific block, it will override the other layers:

Screen Shot 2020-01-15 at 4 39 21 PM

Resulting in:
Screen Shot 2020-01-15 at 4 39 33 PM


We will also have the ability to "reset" or remove custom settings. In this example, let's say the user removes their global styles setting. However, the document style remains, which renders like so:

Screen Shot 2020-01-15 at 4 39 51 PM


Theme Switching

Global + Document styles are coupled with the theme. You can think of them as user theme configs. If the user switches to another theme, it will apply that themes' global + document styles.

Let's say the user has customized their existing theme ("blue") a bunch.
Let's say the user installs a brand new theme ("red"). A theme they just downloaded.

Once they switch, the global + document styles will be reset.

The reason is because they've never customized anything on the "red" theme yet.

Switching back to "blue", will restore their previous global/document styles.

Screen Capture on 2020-01-15 at 16-51-17


TLDR (Too Long, Didn't read)

  • There's a style hierarchy - Core, Theme, Global, Document, Block
  • Global, Document, Block styles are customized by the user
  • Global + Document styles are associated with a theme
  • This allows for theme switching with minimized side effects

Thank you so much for your time! Thoughts + feedback welcome 🙌

Excellent breakdown, thanks @ItsJonQ!
Isn't Theme & Global pretty much the same thing though?
I mean thinking of what the future of themes might look like, most themes will probably switch from using the customizer to the global-styles system. Settings that now exist in the customizer will be migrated to this system... They can be thought of as the same thing. We can call them "theme" if the theme uses the customizer and "global" if the theme is using the global-styles system, but it's one or the other, no theme will have the same settings both in the customizer & the global-styles editor because there's no reason to do so, there's no benefit in having both.

Regarding the css-vars: I wouldn't worry about IE support... Parsing the content and replacing css-vars with their values won't be difficult to do in PHP.
IMO we can work with css-vars and a simple filter that does search-and-replace server-side on the PHP side of things can work perfectly fine.

Would there be a good alternative to using CSS variables on the front end? The concern here is that any website using WP would stop working on IE.

This is solvable by creating a fallback such as:

p {
    font-size: 16px; // Fallback for IE.
    font-size: var( --font-size-paragraph );
}

It can be automated using https://www.npmjs.com/package/postcss-custom-properties Another approach would be a SASS mixin, although the CSS gets muddy (you have to write @include font-size-mixin( 16px ); which is a bit unnatural. There are options to overcome older web citizens, so CSS custom properties are fine to use.

I've just read through all of #9534 and this issue and I'd like to bring up a perspective that hasn't been mentioned at all yet as far as I've read.

Users Styling vs. Builders Styling

All of the above is mostly concerned with maximum flexibility and control for "Users", offering them a solid base in the form of core and theme styling but giving them the final say and a broad array of capabilities to alter the styling of a website.

This is a valid and quite surely the most common use case, but I am coming from a totally different (not to say opposite) direction: Sites where there are multiple users as well as a clear separation between designers, developers and editors. In that setting users specifically should have no or at least very little control over the styling of the site. They create semantic content using the (heavily moderated) set of blocks leaving the styling in the hands of designers and developers. Think separation of concerns between content and layout/styling for the sake of consistency.

In that situation the "Style Hierarchy" mentioned above is not what one needs or wants since styling should solely be defined by the theme. Changing anything on the Global, Document and Block Levels shouldn't be possible. And even the Core Styling might be too opinionated. Instead the Theme Level should be the first, last and only one to decide how everything is styled.

Shouldn't we just embrace users being in control?

Generally yes, but maybe not here. Let's see why.

If a website is based on a corporate design, a styleguide or any other well thought through system a button looks like a button and there is no need for a user (think content editor) to ever even be able to micro-manage things like the background color of a button. Maintaining global consistency is impossible with individual user control.

(Even more so I personally think taking away some choices like the ones relating to styling actually helps users be content editors by freeing them from needing to think about styling. This actually makes them feel more in control even if they might not technically be. _"Decisions, not Options"_)

Core styles are always opinionated.

I understand that there has to be some baseline, but even that often needs to be changed drastically if not even removed. Simple example: Currently Column and Gallery Blocks use CSS Flexbox for layout, making any Core Block CSS totally obsolete if not even hindering if having your whole site layout based on CSS Grid.

So basically here the whole concept of multi-layer overwrites is somewhere between irrelevant to harmful beyond the fact that one can disable, overwrite or take as much control over it as possible. And even if some things may be allowed to be styleable by users I'd see the pyramid shuffled such as that the theme layer is on top having the final say and only "letting through" certain styling choices by a user.

So if this whole system gives even more styling control to users than we already have right now please make sure that any setting that is being introduced as user-controllable has a way to be disabled, restricted or overwritten. This is so that it isn't as difficult to stay in control as it currently is with things like custom colors/gradients, fonts sizes, number of columns, drop caps,...

Final thoughts

To close things up I am aware that the general direction Gutenberg is moving towards is a very visual approach to content editing. WordPress has always been quite oblivious to the separation of content and layout, but currently I see the risk that this might become the final nail in the coffin so that it isn't only difficult but becomes outright impossible the further down we go the route of giving unbound styling power to users.

In that setting users specifically should have no or at least very little control over the styling of the site.

@kraftner This is really spot on and I just want to point out that this level of control already happens “out there”. There's currently no shortage of plugins that empower the user to micromanage it's own website layout – even to it's own detriment.

By implementing this new system in core, that practice would be finally condoned by WordPress itself, which IMO is not in the best interest of that specific kind of user that have no clue about what design systems are, and therefore, their relevance and impact. And I would even say that this kind of user represents the majority of the user base.

This is something important to tackle before moving on.

Thanks for your detailed thoughts, @kraftner, these are good points.

All of the above is mostly concerned with maximum flexibility and control for "Users", offering them a solid base in the form of core and theme styling but giving them the final say and a broad array of capabilities to alter the styling of a website.

I don't think this is necessarily the case here. The system proposes a way to structure the style capabilities of a block in a way that can be better controlled, but it doesn't say much about who will bear this control. It's entirely possible that most of this would just be exposed as theme builder tools, to admins and designers, not necessarily to end users.

Think of it more as the evolution of the "theme editor" than necessarily giving control of all the style details to users. The latter would also not be great to most users, since it would be quite overwhelming, but themes need better and easier control over blocks (particularly blocks they don't know even exist!).

Sites where there are multiple users as well as a clear separation between designers, developers and editors. In that setting users specifically should have no or at least very little control over the styling of the site.

This is perfectly reasonable, and it should go without saying that a site would have control over whether these tools are exposed, to which roles, and which capacity — the same way your regular users don't have access to the PHP theme editor.

And even the Core Styling might be too opinionated. Instead the Theme Level should be the first, last and only one to decide how everything is styled.

It should be in your control to setup things this way — don't load default block styles (outside of the structural ones, maybe) and restrict the ability to edit global and local block style options. I think what you outline is a perfectly valid use case that should be easy to accommodate and improve upon.

So if this whole system gives even more styling control to users than we already have right now please make sure that any setting that is being introduced as user-controllable has a way to be disabled, restricted or overwritten.

Definitely. Again, I see this foundation as giving more deliberate control to the theme over blocks. A side effect is that we end up with a system that could also be exposed to users if they want to have that level of control using a GUI rather than writing CSS and modifying PHP templates by hand, but this is not going to be a one-size-fits-all-use-cases, as the world of WordPress is incredibly diverse and we need tools that accommodate diverse use cases.

If there are more examples of things that you feel are relinquishing that control from you, please, report them as issues so that it could be discussed and addressed. I do agree that currently it can take effort to go through all the things you might want to disable. Part of the motivation for a more comprehensive block style system is to make this easier to control — either by opening up or closing it down.

I think what you outline is a perfectly valid use case that should be easy to accommodate and improve upon.

This sounds great @mtias. I just wanted to re-emphasize this, especially the point that I think that it should be a blocking requirement for each and any of these user-controllable features to only go into the plugin or at least core when it comes with an option to control (configure, restrict, disable).

The reason I came here basically is due to the fact that you have pretty much said the same thing in the Office Hours at WCEU in June when you, me and @m where talking about this particular topic. But I already then had the impression that this was seen as a "nice-to-have" thing for later, not a hard requirement or even a priority. But without such control it is currently practically impossible to use Gutenberg in a tightly controlled setup.

Concerning the examples of the loss of control I am talking about - most of them already have issues, but unfortunately for a lot of them there is little to no movement. Often I also don't understand how corresponding bugs can even happen, why turning it off apparently isn't even tried for new features during development.
So in the end it feels like a very frustrating "Whac-a-mole" situation where for every feature one can regain control of, two more that are not controllable are entering the editor. Just to emphasize what I am talking about, here is a list of issues I am currently or was previously struggling with, having no or only hacky ways of controlling them. (This is right out of my still ongoing research for my upcoming WC talk on this very topic)

  • Drop caps: #6184 / #14654 -> #6023 (This was known/reported to be problematic long before WP 5.0, why did this feature ever go in at all?)
  • Background colors for tables #16478 / #19659 (Why was that "trade-off" ok and not a blocking issue?)
  • Font sizes #13824 / 46290 (How could this slip through? Disabling stuff is one of the first things to try after adding any option, no?)
  • Gradients: #18213 (Why doesn't this feature wait for a general solution to disable, instead adding an experimental flag, no documentation, introducing just another new mechanism to disable something?)
  • Numbers of columns #10791 -> #18892 (I understand the need for a general solution, but why aren't new features on hold until then?)
  • Template locking #8112 / #7845 (These are urgent requirements to be able to lock down CPT structure to replace the old Custom Fields Plugins approach)

I know that at the end of this list I am somewhat digressing from styling issues, but I believe all of this together shows the overarching theme: Taking control of Gutenberg is still somewhere between hard and impossible.

Don't get me wrong: I do understand that Gutenberg is still under heavy development and looking at all of these issues in isolation one can of course say bugs happen, nothing is ever perfect and we can only work on one thing after the other. But the sum of all of the above makes me feel like it isn't seen as a priority by the project leadership and instead of solving this important issues with content editing first, we're already pressing ahead to the next, even more complex area of full site editing.

TL;DR: Control over users capabilities is an important and urgent need across the whole of Gutenberg, and I really think that it is high time to put some more focus on this. Please, please give us back control before implementing any more features. :pray:

I don't want to dig into the weeds too much, but one thing jumped out to me in one of the examples from the issue description:

For blocks to start using global styles, their CSS will need to be refactored to use the CSS variables outputted by system.

and then this is part of the example:

border: 1px solid var(--wp-gs-color-primary-dark20);

Colors are always difficult when it comes to theming because it's hard to base them on a particular semantic. Essentially this is hard-coding a relationship between the theme schema and a block's style, and that might be restrictive. I might be wrong, but I think it means the number of colors and types of color that can be defined are fixed. Also the block implementor has to make a judgement about the theme's configuration and what sort of color this should be. I wondered if there might need to be a separate layer where these styles are wired up to the theme's schema.

Instead, this is maybe defined as:

border: 1px solid var(--wp-button-block-border-color);

And then a relationship is defined (by the theme?):

--wp-button-block-border-color: --wp-gs-color-primary-dark20

Not sure if I've explained that clearly. It's already sounding quite complicated, but it's something I anticipate might need to be solved.

edit: On further though not sure how what I've proposed would work with third-party blocks. Perhaps the issue is that semantics need to be defined more clearly, so we avoid naming something 'dark' or 'light'.

As I am visual, I wondered if this might help anyone to see what gets effected each time something was iterated. For example, how the layers filter down. This builds on the pyramid cascade @ItsJonQ created and is done in collaboration.

Flow_ typography

What this does is look at specific actions:

  • Globally changing a style: for example, increasing baseline font size. In this case it goes across everything as global. The dots show that is the top (respecting the hierarchy) and what is therefore affected.
  • Local/document changing a style: for example baseline font size increase just on the about page.
  • Block style changes: for example just changing baseline font size just on a quote block.

If you notice there are 2 columns which don't have any interaction there, these persist throughout before you do any interactions.

Another point to note blocks includes a few things:

  • Style variations
  • Custom styling
  • Developer (plugin) block styles

In this image, the theme is the layer next to the core default, anything that changes globally above that all way up to the block at the top.

Global Styles - The First Iteration

This morning (Toronto time), I hopped on a call with @nosolosw and @jorgefilipecosta to sync up on this new Global Styles focus.

We have each independently worked on this problem at one point in time. Given that many aspects of Global styles is brand new (in the context of Gutenberg), and the complexities involved in all of the various moving parts, we felt like it would be good to sync up - to share our experiences, thoughts, experiments, and to start planning.

The 3 Parts

gs-mechanics-flow

After discussing the various implementation details and various edge cases, we simplified the original proposed concept into 3 main parts:

  • Resolver (we called it "Merge" during the meeting)
  • Blocks
  • Controls

These 3 parts still embody the spirit of the original design, except the "Transformers", "Hooks", and "Renderer" pieces were simplified and consolidated into "Resolver" and "Blocks"

Resolver

The Resolver is responsible for checking a theme.json file and the previously saved global styles data from the database. It will then merge the dataset together and prepare something for Gutenberg to consume.

Blocks

Blocks are the Gutenberg blocks we all know and love! Updates will need to be made to the blocks' .css to start using the CSS variables that will be core to the Global Styling system.

Controls

Controls are user-interfaces that enable the user to adjust global style values. These will be presented within the Full Site Editing experiences.

Note: Controls also exists for individual block instances. They are the various control fields that are available in a block's InspectorControls. The update will only adjust how the style values are applied, i.e. adding inline style CSS variables, rather than hard coded values. (More on that later)

Flow ("Backend")

The following will detail the backend flow of the Global Style system.

Resolver

gs-resolver

When the Resolver starts, it first looks locally for a theme.json file.

1. theme.json

For this proposal, a theme.json file is an easy way for a theme to:

a. Opt-in to global styles
b. Declare theme specific style values

An example of a theme.json may look like this:

{
    "name": "Awesome Theme",
    "global": {
        "color": {
            "background": "black",
            "text": "red"
        }
    },
    "blocks": {
        "core/paragraph": {
            "color": {
                "text": "hotpink"
            }
        }
    }
}

In this example, the theme is overriding the global default color.background and color.text. It's also specifically adjusting the core Paragraph block's color.text.

2. Checking the Database

If a theme.json is found, the resolver will then check the database for previously saved global styles.

Theme Specific global styles

Global styles are to be saved in a way that's specific to a theme. This enables the ability to safely switch themes without style aesthetic conflicts.

This can be demonstrated in this demo

(Try applying some global / document styles and switching the themes).

3. Merging

The theme.json data and database data are merged and prepared to be consumed by Gutenberg.

Block

gs-block

1. Rendered

Blocks are loaded and rendered by the Gutenberg editor. Blocks use a series of CSS variables that correspond to the global styling conventions.

CSS Variables

The following is an example of the core Paragraph block using Global Styles:

p {
    color: currentColor;
}

.wp-gs p {
    color: var(--wp-gs-paragraph-color-text, var(--wp-gs-color-text));
}
.wp-gs scope

For our initial implementation, the idea is to apply a specific CSS selector (.wp-gs) to either the html or body DOM node to effectively establish a "Global Style supported environment".

This raises the CSS specificity for globally styled blocks.

In the above example, a <p> rendering without global styles (like how they do today) would inherit it's color from a parent selector.

However, within a "Global style supported environment", the .wp-gs p rule would apply.

var(...)

The convention we're going with is to prefix the global style CSS variables with --wp-gs (WordPress Global Styles). In the example above:

.wp-gs p {
    color: var(--wp-gs-paragraph-color-text, --wp-gs-color-text);
}

var() is setup to:

  1. Handle custom block specific style rendering
  2. Fallback to generic values

The convention of using block specific styles with fallbacks gives the system both finer grain control as well as stability.

2. Block x Controls

If a block instance has custom aesthetic changes, e.g. a textColor update, the updated attribute(s) will be rendered as inline styles. The difference between the current implementation and the proposed implementation, is the use of CSS Variables over hard coded values.

Current:

<p style="color: red;">...</p>

Proposed:

<p style="--wp-gs-paragraph-color-text: red;">...</p>

In many ways, the effects are the same. However, using CSS Variables allows for most of the CSS cascading effects to apply.

Controls

gs-controls-3

Controls will be present within the site edit flow from Full Site Editing.

1. Update

gs-controls-1

When an update is made, the updated attribute is sent to the resolver.

gs-controls-2

The resolver does it's thing (perhaps coordinating with the @wordpress/data store), and pushes the updated consumable data back down to Gutenberg.

gs-controls-3

Lastly, that updated data (as well as updated CSS variables) are hydrated and rendered to the FSE user interface, and any visible blocks.

Flow ("Frontend")

The solution we've come up with (currently) requires the Resolver to check/read the theme.json and database to get and create the latest combinations of style values for a given page.

This happens server side on page load.

The Resolver will then create a <style> tag to be injected into the <head> of the page on load. Example:

<head>
    ...
    <style>
        :root {
            --wp-gs-color-text: black;
            --wp-gs-color-background: white;
            --wp-gs-color-primary: blue;
            ...
            --wp-gs-paragraph-color-text: hotpink;
        }
    </style>
</head>

Lastly, the .wp-gs CSS selector needs to be injected to activate the global styles from blocks.

- <html>
+ <html class="wp-gs">

And that's it!

The First Initiative

@nosolosw, @jorgefilipecosta, and I will be working together to create the 3 parts outlined above:

  • Resolver - @jorgefilipecosta
  • Blocks - @nosolosw
  • UI Controls - @itsjonq

The first initiative we're going to be building for allows for users to:

  1. Set global styles for default text color
  2. Enable the core Paragraph + Heading blocks to use global styles
  3. Allow a theme to customize the default text color, heading and paragraph block text colors

Gotchas

The biggest gotcha at the moment is we're unsure how to properly support IE. Our current system relies very heavily on CSS Variables, and browser native feature that is not supported in IE11.

There are polyfills available, but there are not sufficient to do the rendering consolidations that we need (at least, not out of the box).

We are very mindful of this gap. For now, we're going to proceed with a CSS Variable based solution, as we want to validate the mechanics and flow of the system. Not only do they work, but they should not break backwards compatibility, and they should help Block Builders, Themers, and Users feel empowered rather than overwhelmed (by things like verbose API or CSS fiddliness).

Feedback + Thanks!

First off, if you've made it to the read (whether you've skimmed this or not), thank you so much! I know this was an awful lot to read. :heart:

My intention is to be as transparent as possible in regards to any designs, experiments, and implementations.

Global styles involves a lot of moving parts. The more context + updates I can give, the more informed folks involved with this project can be. Which will lead to better discussions and decisions.

As always, thoughts and feedback welcome!!

Thanks again :)

The biggest gotcha at the moment is we're unsure how to properly support IE. Our current system relies very heavily on CSS Variables, and browser native feature that is not supported in IE11.

Just to surface statistics around IE11 in case it helps folks to chime in:

  • IE11 usage 1.43% as of January 2020 (via CanIUse)
  • IE11 Screen reader usage 10.9% as of August-September 2019 (via WebAim. In 2017 it was 23.3%).

It's a common industry standard to leave IE11 support to "functional" rather than "perfect visual" level.

That might be sufficient enough here too especially considering screen reader use case as well that rest of the theme and block styles work as a fallback?

I don't know how solid e.g. ie11CustomProperties polyfill is, but developers could always include it manually when needed. You could even provide it from the core via some kind of opt-in toggle?

IE11 usage 1.43% as of January 2020 (via CanIUse)

Of all desktop visits from January 2019 until January 2020 the IE11 usage was:

It's a common industry standard to leave IE11 support to "functional" rather than "perfect visual" level.

Agreed

I don't know how solid e.g. ie11CustomProperties polyfill is, but developers could always include it manually when needed. You could even provide it from the core via some kind of opt-in toggle?

From personal experience most css-vars polyfills don't work as they should, and when they do they severely impede performance.

It's a common industry standard to leave IE11 support to "functional" rather than "perfect visual" level.

That is the way most of us deal with css-vars & the IE conundrum... Defining some sane global CSS rules which then get overriden by css-vars. If the visitor is on IE, then they're still able to use the website perfectly fine - just with a different color scheme, spacing etc.
WordPress is compatible with IE11, but "compatible with IE11" doesn't mean that IE11 should show things the way a post-dinosaurs browser renders them... As long as it's functional we're in the clear.

I am the autor of ie11CustomProperties. https://github.com/nuxodin/ie11CustomProperties/
Meanwhile the Polyfill is quite fast and supports a lot.
If you would like to try it I will support you with pleasure if it comes to problems.

@nuxodin to be fair, I haven't tested it in months, last time I checked that specific repo it was on v1.3, I see it has come a long way since then :+1:

The Resolver will then create a