Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Global Styles: recap & next steps #22296

Closed
oandregal opened this issue May 12, 2020 · 2 comments
Closed

Global Styles: recap & next steps #22296

oandregal opened this issue May 12, 2020 · 2 comments
Labels
[Feature] Themes Global Styles

Comments

@oandregal
Copy link
Member

oandregal commented May 12, 2020

I was looking at how to make progress for the Block Style System and unblock the managed CSS PR. I've noticed that we've been having some scattered convos in issues/PR so it's been difficult to follow, so I thought it'd be a good idea to recap and focus on the next steps.

I'd like the next step for Global Styles to be: how do we allow themes to style the same things a user can at the block level?

Background

The block style system needs to define how the style units work together, accounting for local & global styles. At the scale of the WordPress ecosystem, themeability comes with a lot of complexity, unnecessary CSS loaded in the page, and specificity wars due to the competing needs of core and 3rd party components (themes, blocks, plugins).

One of the key issues is that we lack semantic mechanisms to style blocks in the many contexts they can be used. For example, a paragraph can be a top-level element in a document, but also be present within a column or group block in a sidebar --- it may need different styles for each context.

Take this simple piece of HTML (an actual pattern registered by core) as an example:

2005-08-themeable-pattern

It's made of the columns block and some paragraphs, something along these lines (source code):

<div class="wp-block-colums">
    <div class="wp-block-column">
        <p>Number</p>
    </div>
    <div class="wp-block-column">
        <p>Title</p>
        <p>Description</p>
    </div>
</div>

Depending on context, each paragraph has a different meaning. Design-wise, it can be divided into sections containing three semantic elements: number, title, description. Each piece maps to an HTML <p> element with a different color and font size, which can be considered the style hooks of the block.

Style Hooks for Blocks

How do we make a pattern like the above themeable?

In the first iteration, we tried declaring CSS variables per block to expose its "style hooks" (see). We'd have --paragraph-color, --paragraph-font-size, and so on. This had great power (allow you to target individual pieces), but it was also too specific: if you account for 3rd party blocks, the explosion of variables makes this unwieldy for themes to keep up with. It is also fragile for nested content: do we use specific variables for paragraphs within patterns such as --pattern-numbered-features-title-color, --pattern-numbered-features-description-color? If so, we run into situations where the user can't modify the structure of a pattern, otherwise they'll lose the styles.

The second iteration was about only using general CSS variables such as --color-primary, --color-secondary (see) and map them to blocks. This was too opinionated and themes needed the ability to change those mappings. It didn't solve nested content on its own either.

We had a brief experiment to use CSS variables at the block level, that we reverted back due to cascading issues and to make sure other pieces were ready when this landed: introducing variables into blocks needs themes to adapt so we need to be mindful about how/if/when we do it.

After these iterations, it looks like the core problem we need to solve isn't really about using CSS variables to mark "style hooks", but about how do we target the style hooks of a block depending on its context? How do we add that semantic layer without breaking backward-compatibility? Currently, the way themes deal with this is by using CSS selectors. What if we could make selectors work well at the scale of WordPress?

Managed CSS

The idea is that, instead of having to write CSS that overrides existing CSS by adding specificity, components of the system declare their design choices as per the existing style hooks for blocks. Gutenberg takes those styles and merges them into a single stylesheet.

Let's go back to the example pattern above. The output CSS that we need to style the pattern could be something like this:

/* Target the number in the numbered-features pattern */
.wp-columns .wp-column:first-child p {
    /* styles */
}

/* Target the title in the numbered-features pattern */
.wp-columns .wp-column:nth-child(2) p:first-child {
    /* styles */
}

/* Target the description in the numbered-features pattern */
.wp-columns .wp-column:nth-child(2) p {
    /* styles */
}

The styles within each style rule should be the result of taking into account blocks & theme choices.

The managed CSS PR proposes that components use a pre-defined format to declare their preferences. Themes, for example, would use a theme.json file such as:

{
  "blocks": {
    "core/paragraph": { <style declarations> },
  },
  "patterns": {
    "numbered-features/number": { <style declarations> },
    "numbered-features/title": { <style declarations> },
    "numbered-features/description": { <style declarations> }
  }
}

Core would come with a similar file where styles for core blocks & patterns are declared, and 3rd party blocks would do the same.

Benefits

"Managed CSS" means that theme authors focus on what they do best: provide design direction. It abstracts away some of the peculiarities of how WordPress works and the inner implementation of blocks, and adds a semantic layer to design.

Because CSS is managed, Gutenberg can adapt it for different contexts (editor, front), and reduce the specificity wars. It also means less CSS will be shipped. If block markup changes but the style hooks remain the same, theme authors won't need to do anything: it's the block responsibility to maintain the mapping between style hooks and the specific implementation.

Note that this approach is agnostic about the styles used within each style rule: it doesn't require blocks come with any CSS Custom Properties, although we can use them when it makes sense.

Tasks

So, what do we need to do so a theme can use a theme.json file as described above to style the same things a user can at the block level?

  • #20290 Global Styles: implement a mechanism to generate the "managed CSS" based on theme & core preferences.
  • Blocks & Patterns: need to register a selector to target their "style hooks". For most blocks, it should be only one selector, although there are some that have variations (h1, h2, h3). Patterns are one the ways we target blocks within contexts, so they'll need to have as many selectors as different "style hooks" they have.
  • Blocks: need to declare their "style hooks" as implicit attributes, so we can know programmatically what they support (generate the UI controls automatically, etc). This is related to the above two tasks. It's also already in progress and working at the block level.
  • Blocks: need to be registered in the server so Gutenberg has access to the block selector through the block registry (see convo).
  • Global Styles: enqueue the stylesheet if the theme has a theme.json. This needs to account for editor styles wrapper in the editors to avoid style leaks, etc. Look into whether we can expose this as an external stylesheet instead of an embedded stylesheet.
@kjellr kjellr added [Feature] Themes Global Styles labels May 12, 2020
@karmatosed
Copy link
Member

karmatosed commented May 14, 2020

What a great detailed recap and discussion on next steps @nosolosw.

This phrase resonates for me and highlights the complexity:

The block style system needs to define how the style units work together, accounting for local & global styles.

I am nodding following this over having a big comment, but it's great to see this type of thinking and I am hopeful about the next steps.

@oandregal
Copy link
Member Author

oandregal commented Sep 10, 2020

We've made good progress on several fronts since this recap was posted. Since #24250 landed we have a v1 of the major pieces to make this work, including theme (theme.json) and user (sidebar in edit-site) style preferences. This served us well to gain focus and bring conversations together, but it's now time to close it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Themes Global Styles
Projects
None yet
Development

No branches or pull requests

3 participants