-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
Tracking: Add a Style Engine to manage rendering block styles #38167
Comments
We already use cssnano, which can do a lot of this stuff. From basic testing, it seems like if we stored the styles (in a store?) and then ran them concatenated through cssnano we might get something useful. I can take a look at this further. |
These two styles are different than the others in the sense that the generated styles shouldn't be applied to the "block wrapper" but instead to the "inner blocks wrapper". The difference is subtle since for most containers blocks, these two wrappers are the same but for something like Cover, they are not the same and that's why it's not possible to enable the current implementation of Layout bock supports for that block. (we need to first refactor the block support to apply to the inner blocks wrapper). I think that's something important to have in my mind while iterating on the style engine to avoid repeating the same mistake we have now. |
I believe the initial version of the style engine PR (#37978) is in a good place for wider feedback / review now, and to confidence check the approach. I've added a tiny comment/update to the PR. |
It looks like the automatically generated class names to move granular class names and styles outside of the block's HTML to the There are vast benefits of the single automatically generated class name for a given block:
However, it would be great to keep the flexibility of the current blocks that use several discrete class names to indicate selected block customizations like colors, fonts, etc. |
Update: the initial version of the style engine package has been merged in #37978, so we're now in a good place to start opening up smaller PRs to explore some of the ideas raised in discussions. I'm keen to have a play with how the server-rendering implementation might look. Thanks @gziolo for linking in those related discussions. And good points about pollution of the HTML and targeting inner HTML elements. Since we're moving in a direction where most of the styles will ultimately be rendered server-side, hopefully that means if we expose discrete class names, it'll be fairly safe, because we'll be bypassing the issues of block validation and deprecations in post content. Let's look at these issues in more depth in the discussions and related PRs. |
Glad to have found this tracking issue! Thanks @ramonjd for linking it! Which channel in slack is this stuff discussed in? Been looking for months for discussion around these issues! Developed a CSS API via plugin to handle this exactly - taking sources from global styles, a CSS file (re-tooling some old PEAR PHP package for parsing CSS from css files), CPT etc, universalizes it then renders the styles inline, which was originally meant as a way to override the implementation of Layout Support (since we've been using FSE in production sites since 5.8 launched with the Gutenberg plugin). I'd be happy to migrate the PHP classes to WP's coding standard (I've been writing in PSR style and tend to make smaller classes split up among files using interfaces & setter injection via containers) to get the ball rolling on a PHP side implementation. In the plugin we made, we've been using a CPT as a data store for values, following the logic behind block-templates & navigation block. The flow is a little like this:
Where the declaration block acts as the selector name.
This is also done for overriding core block styles to deregister and reregister new default block styles based on user / developer preference, which is the main reason for the CPT - the CPT provides an easy front end interface to 'hot swap' values on the defaults. So, for example, if I wanted to change all 'margin-left' properties of all blocks & auto generated styles (e.g. from layout support), to be margin-inline-start, then I can just change a single setting and the above API does all the work for me, replacing the corresponding properties, but not their values - or vice versa. What we're also experimenting with is, rather than using a new class name for each user defined custom value (which doesn't happen often - 99% of the time a block using contentSize and wideSize is just using the theme default, we've literally overrode this with a custom value once across ~13 production sites in the wild. For instance, if you assign contentSize and wideSize (or a flex property or whatever) to a custom property, and then add a css style that says "#make200" that sets the value of the customproperty to something different, then it'll change the custom prop just for that unique id - eliminating the need for a new class altogether.
Ultimately, the trickiest / most verbose part comes in expanding flex properties and a custom user setting, and so far the cleanest solution has just been to break up the overall declaration block into smaller declarations, but that does make for a long class="" line. In the end, that one just gets tricky if a box has an option to be both say, horizontal and vertical and have a variety of different options - you end up with a large matrix pretty fast. Adding global / common alignment options for e.g. items-justified-center, etc as already exists seems to be the most prudent there - we just tap into those already declared classes rather than re-rendering them in a separate call. For cases like row vs column, it's probably just more prudent to keep handling that via block style variants, such as is already done with row block & group block. We also reduce the overall styling duplication with a couple smart global defaults, like:
The above allows us to remove any box-sizing property in core blocks, because they by default inherit border-box and inline elements aren't effected. Then the direct children only of the post_content area have padding visibly only on mobile completely preventing the problem of a paragraph block's text being flush with the side of the mobile device. The slight tweak to .has-background on a paragraph element to make it still flush is like this:
This keeps the element in alignment as expected and not doubled up on padding via inheritance. |
Can personally attest to how finicky this subtly is to work with. The cover block overall is simultaneously one of the most useful blocks in the arsenal, but also the hardest to work with and tweak because of it's structure. Part of it's finicky nature is the fact that it's trying to handle so much at once - it's pretty much got n possibilities of configuration. Current manipulation to specific sizing usually involves stacking it within other container blocks or other container blocks within the cover block to achieve desired widths inside/outside (even stacking covers inside covers!). In the end we made a few custom blocks that separated out that logic, rather than try to contain it all within a single block, and used block patterns to handle the re-use. I've got thoughts on a few potential work arounds, but will have to consolidate thoughts on them later. |
Thanks for sharing your thoughts here! Just adding that most of the discussion is happening async in Github, which works nicely for a lot of us since there's such a wide timezone spread of people contributing to the discussions. (Many of which began in this discussion thread). I've linked a few of the discussions and issues in the issue description. If there are issues or discussions that anyone thinks should be included here, please feel free to link to this tracking issue and we can update the description so that they're all gathered together. |
I just opened a ticket that overlaps with many of the things being discussed here on #38998. As it relates to this ticket, I hope this can call attention to the needs of theme and plugin developers for core markups and styles to be consistent and easy to customize, both through standardized conventions in WP and with custom CSS. |
As reported in #38917 by @oldrup, after upgrading to WordPress 5.9, sites have issues with HTML validation: "Error: Element style not allowed as child of element body in this context". These errors seem to be related to the styling of blocks when |
Thanks for taking the time to write down your comments and questions @mrwweb I'll do my best to answer with as much information as I have 🤞 Maybe grab a tea or kombucha first. The usual disclaimer is warranted: these are my own ideas and I'm expressing them using my limited knowledge. The TL;DR for folks who don't want to read my babble is that:
It's not just you 😄 I joke that the style engine will also achieve interstellar travel and decrypt the Voynich manuscript such have the goals and potential of the project been inflated with various offhand comments such as "Oh, the style engine will take care of that". If strapped to a chair with a hot poker to my eye, I would confess that the style engine will one day allow us to reason better about and even implement solutions to the big problems you've cited. This is the hope. However, I'm sitting in Phase 1 and I might be there for a while. As mentioned above, Phase 4 is when we can really start thinking about how to leverage a consolidated system of style generation. Right now the aim is not to invent new ways to generate styles and classnames. Rather, the initial goal is to centralize 'where' we generate styles. As you're aware we're rendering styles in a bunch of areas. It's not optimal. It's not pretty, and we have to rein them in. Controlling 'where' Gutenberg generates styles I think is the first step towards addressing the 'how'.
I share your concern, and agree that it comes down to the lack of concrete plans in relation to the desired state of the frontend code. I'm personally focussed on the centralization effort at present, and have therefore made peace with the fact that it might take time to get to point where the style engine is ready to assume the responsibility of processing and rendering better frontend CSS. So for me, the boundary is Phase 1: generating styles that previously were generated in block supports, and later, by global styles. Bear in mind I feel like I've been working in a U-boot, and I need nudges like yours at times in order to surface and see the horizon. 😄 Nevertheless, my opinion is that, once the plugin can start responding to known pain points via code, for example, ridding ourselves of redundant style blocks, feedback on these specific points in the context of the style engine will be invaluable.
The issues you've mentioned are the things that really need fixing. It's important to me to other folks working closely with styles to understand these problems, and listen to your advice and experience so that contributors can agree on a "final desired outcome". It's also possible that some of theme will be incrementally addressed by parallel efforts outside the current style engine scope. For example, @andrewserong is looking at introducing semantic classnames to our layouts in #40875. (See also the surrounding layout discussions in #39336) With regards to unease about the "long-term results" of this project, I think one should be careful about overpromising what the style engine will deliver, at least for today. Yes, Gutenberg has to improve the way it approaches styles and classnames. To get there, I think it first must cease the adhoc printing of styles + classnames and have a central, unified means of generating them.
If the plugin were to be measured by whether "front-end code is both efficient and extensible", then yeah, the test results wouldn't be flattering. I'm trying to get to a point where the style engine can incrementally improve the situation. You've made a great point: the frontend code will be the proof of success of any work in this area, not the implementation so much. The reason I keep banging on about "centralization" and consolidation, which are the current goals of the backend implementation, is because I see it as them means to arrive at the situation in which we can judge the output; where the implementation remains hidden.
Definitely. There'll be a need to propose and communicate the outcome and this gets my 👍 Moreover, if no-one else puts their hands up, I'll be the first to sit in the firing line and get a draft proposal up when the time comes. My focus is getting to that stage by creating the means by which we all can demonstrate and experiment with a "final desired outcome ... represented by working front-end code". To be clear, I'm not stating that it's too early or not helpful to start communicating about "target markup" or otherwise now: there are probably various desired "end results". A "what if" post could be beneficial, not so much to act as a compass but to inspire and to instruct our work as to the most coveted state of Gutenberg classnames and styles. I am however wary of talking about a contract to which outcomes must adhere. Along the way, there's the challenge of dealing with a the push and pull of new features, changes to existing features, and backwards compatibility. As more folks work on the code, and @youknowriad returns from his break 😄 , new and better ideas will flow in as well. I don't know if any of this been instructive or has left you feeling more optimistic, sorry! I'm writing all this as one would write the first entry of a diary: with the present firmly in mind. Please let me know if you have any questions in relation to what I've written here. I might have made some erroneous assumptions (and probably typos!). |
Thanks for writing out your thoughts @ramonjd! I share many of the same views, and my efforts in reviews and experimental PRs (like #40875) has been to focus on attempting to consolidate how things work, and fix bugs that are high priority for the next major WordPress release. In the case of Layouts, which is work that I think of as related to, but adjacent to the style engine, my main goal at the moment is to see if I can help get My hope with the work in #40875 and the Layout tracking issue in #39336, is that along with the style engine work, we'll have a more consolidated, closer-to-declarative way to define and output styles, as a pre-requisite for the bigger conversations about what form those styles and classes will take. There's been (and continues to be) a lot of very useful discussions and ideas, some of them quite aspirational, so I think it's good for us to focus on the nuts-and-bolts of getting things more or less working in a consolidated way (perhaps we could call this working bottom-up) before imposing a more top-down approach that aims to achieve an end state. One of the concerns that folks raised early on with adding in the style engine package (I can't remember where this was raised, I'm sorry!) was with open-ended or large scale projects that never manage to ship because the scope is too big. I think part of the rationale for working iteratively on existing features, and fix bugs along the way, is so that the code changes have immediate code quality / stability value in the short-term, without becoming too monolithic of a project. So, I think I'd say that the counter point to potential anxiety over not knowing the shape that the final output will take, is that the current work will make it easier for us to change the final output, whatever it'll be. For me, having a goal be "let's make this whole system easier to change" seems to be one that lines up with whatever decisions or proposals folks make for how we think styles should ultimately be output. Fortunately, there's a bunch of work happening in parallel (e.g. spacing presets in #39371 (comment)) that don't depend on the style engine directly, so I wouldn't think of the style engine work as being a blocker for anything right now, per se. |
Thanks @andrewserong This neatly wraps up what I tried to say in a bazillion words! There are lots of stepping stones when crossing this bridge, and some are bound to trigger poison darts! 😆 I still think the idea of eventually having an ideal outcome published somewhere might help guide us across. |
@ramonjd @andrewserong Thanks for the excellent replies! I look forward to the day the Style Engine brings us world peace and free ice cream every day! I don't think a huge point-by-point response is needed (largely because your replies were so informative).
This totally makes sense. An accounting and consolidating makes total sense as a first step.
1000% percent. You've totally convinced me that early work in the back end also makes lots of sense, and so maybe the best metaphor is that we should know the starting point and ending point of this tunnel and the goal is meet the tunnels in the middle.
The primary goal of my last comment is not to say that incremental work is bad. I agree that it's probably the only way a task this large happens. Rather, the concern is that this journey will accidentally repeat past errors and lose folks' confidence along the way regardless of the final destination. Like I said:
That's why I recommend publishing a goal end point sooner than later. I think doing that can increase buy-in up front, identify risks of the path along the way, and find quick wins that can be implemented quickly once you're ready to start changing how the front-end code is shaped and output. |
Thanks for the feedback @mrwweb I've just published a post that publicizes the rough roadmap towards better styles: https://make.wordpress.org/core/2022/06/24/block-editor-styles-initiatives-and-goals/ Much of it has been covered in this tracking PR, with the exception of the layout improvement, which I think will address a lot of the immediate pain. The post deliberately doesn't refer to an end point because I don't know what that will look like yet, but I think we can imagine one, and agree that it would do more help than harm to discuss a wish list. 😄 |
I've been working a lot on this in my own plugin, and like the broader effort here, am having a few issues with scoping the StyleEngine class (been mostly working on it from the PHP side for now). Almost all of my effort so far has centered around the Layout Support module of Block Supports, since it's by far the biggest issue when it comes to implementing theme designs. Colors, Border, Typography is mostly fine as-is, and precision implementations can easily be overridden via skipping serialization on blocks that support the features. Layout and spacing however, force a never-ending re-adjustment of what should be sensible global defaults. Just the nature of the beast. One approach that I'm having success with in minimizing the amount of rendered CSS via PHP (that implementation proved very difficult to maintain and adjust over time natively), is to set a series of CSS custom props that render the dynamic values from merged styles. My perspective has been so far that For example:
These are then hooked into a basic global reset:
Solving the content-size & wide-size problem without dynamic properties & while respecting CSS flow / default layoutFirst, to override specificity of the universal selector above on HTML tags that are either commonly used as containers or as sectional elements that would be intended to expand in width, a basic selector in the reset follows like so:
Then, two utility classes to account for content-alignment wide & full:
Conceivably, an align-right & align-left class could simply adjust where the margin-property is autoing. Importantly with the two align-wide and align-full utility classes, now a block, such as the group block, can be nested inside of another block with a different content-width setting and "bust out" of the container, respecting the new larger width value (100vw, & explicit content-wide value is used because % or "none" would simply match the parent container size), while maintaining it's place in the normal document flow. This means we no longer need any repetition or redeclaration of the CSS classes or new stylesheets and they can simply pull from the same one, because the only dynamic value that's actually changed is the CSS Custom Property at the top level. Plus, child elements respect the content size of their parent containers by default and we don't need to do any goofy things like:
For the case of a user set value for layout width on a block, rather than generate a new inline style, the custom property is simply updated, like so:
This gives:
StyleEngine scopeThis part is a bit messy. Generally, I've been tinkering with a two part API. One for generating CSS style declarations, and the other for retrieving, registering and rendering styles. So a single StyleEngine class is responsible for generating the styles themselves, and a StyleManager centralizes the sources of data, 'sanitizes' the output through the StyleEngine and outputs / registers with WP the result. What I'm really aiming for is total separation between the Block Support API and style-generation or registration of any kind, simply providing the flags for the styles to 'hook' into, since we'd basically want to be able to at a glance see where every style is coming from in a centralized repo, without having to do research on why that one random file is appearing. |
Hi @fwazeter, Thanks for the comment, and for taking the time to write down your thoughts! The layout ideas might be also related to the proposals going on over at Tracking: extend layout options in Gutenberg as well.
This is close to the current thinking on the division of labour of any "style engine/manager". So registering, storing, generating and outputting CSS style declarations and CSS rules. See for example #41424 and #41896
The "centralized repo" part is where folks are concentrating efforts right now. See the Make Core post. Beyond that, the hope is that it will make working on how to express, store and access styles a bit easier. |
Update Wednesday, July 6, 2022The following updates are loosely grouped according to the Phases outlined in the recent Make Core post Block editor styles: initiatives and goals Phase 1 (block supports and foundation building)Work continues on creating equivalent style generation tools in JS for the block editor (non-frontend facing) As 6.1 approaches there have been some PRs to improve operability and tighten up naming conventions:
Phase 2 (global styles consolidation and reducing style tags)To achieve style tag reduction, we'll need a way to store CSS rules and enqueue stylesheets. Given that, a discussion about the longer term architecture of the style engine is open: #42028 There have also been some experimental PRs that are testing boundaries and various approaches:
The first candidate for reducing style tags will be the layout abstraction as proposed in #40875. As for global styles, there are a couple of experimental PRs looking at how to integrate the style engine:
Global styles contains many custom rules and style compilations. Furthermore, it's an area of active work and so the class changes every week. One of the first tasks, therefore, will be to ensure we can introduce the style engine into global styles iteratively. For example, that we only parse certain top-level styles like Phase 3 (to infinity and beyond! 🚀)While this is beyond the scope of current work, there are things to keep in mind now. In particular, how to store styles in a way that will allow us to control and output "layers" according to CSS cascade layers paradigm. See the description in #41424 |
Update Wednesday, August 3, 2022This update highlights important milestone PRs. A complete overview of completed and ongoing tasks is available on the Gutenberg Style Engine project board. For more information about planned phases, see the Make Core post Block editor styles: initiatives and goals Phase 1 (block supports and foundation building)Much of the backend groundwork is now complete. Augmenting the JS package has taken a back seat to backend operability and code enhancement changes, e.g., There has also been a lot of movement on removing repetitive layout-specific styles, paving the way for the style engine to combine selectors and bundle a more optimized block supports CSS. See: Phase 2 (global styles consolidation and reducing style tags)PRs to optimize CSS rules, enqueue styles and reduce the number of style tags have been merged 🎉
Work continues on refining the public methods, documentation and experimenting with global styles: |
@ramonjd What's the latest on this one? I think work has wrapped for 6.1 on this? |
Aside from any incoming stability/code enhancement tweaks or bug fixes, there are no further plans to extend functionality until after 6.1. The focus will be to assist with 6.1 migration and related core patches. Merged plugin features that are planned for WordPress 6.1Following the Block editor styles: initiatives and goals, Phase 1 is complete:
A major goal from Phase 2 has also been concluded:
Outstanding PRsThe JS version of the style engine covers all foundational block supports styles, i.e., There is a lone PR to switch over to the style engine in the editor hooks. This PR is optional and not required for 6.1. Beyond 6.1Imminent plans to complete Phase 2 and augment functionality include:
|
Update Friday, November 18, 2022The Style Engine is running in WordPress 6.1 🎉 Not much has happened since then aside from monitoring stability (there have been few, if no, bugs). Completed since 6.1
In progress PRs
What's next
|
Nice work! It's a huge improvement overall. |
@andrewserong @ramonjd seems most of the items are concluded or no longer relevant. Should this be closed in favor of separate issues for remaining follow ups and ideas? |
Good call. I'll create a follow up tracking issue with the main items we still have to address (but have had not time/resources). I'll close this for for now and link the follow up here when I get a chance to collate and publish. Note to self, important items in the medium term:
|
This is a tracking issue for implementing a Style Engine as discussed in improving our saving/rendering of block styles. The goal is to have a consistent API for rendering styling for blocks, across both client-side and server-side applications. The server implementation is preferred for a site's frontend.
Rather than a monolithic refactor, the aim should be to build the smallest implementation possible and land it in the plugin, and iteratively enhance it with small PRs as we go.
In principle, the style engine should be able to receive a style object, and return the rendered styling for that style object, along with any required class names or other data needed to reassemble or use those styles in all required environments. Depending on the implementation, it may be possible for us to avoid or minimise the current reliance on rendering inline styles directly into block markup.
⭐ Current phase - Phase 1: block styles consolidation and refactoring the layout abstraction
Goals:
Planning discussions
To-do
The below to-do list is an assortment of shorter-term to longer-term features that would be great to implement. We should aim to not let the longer-term goals block landing the shorter-term goals — but let's try to use the longer-term goals to inform the design decisions for the shorter-term ones.
The approach will be work iteratively rather than treating this as a project that needs to be complete all at once.
style
vs. describingstate
#38694style
differences in block validation: Ignore style validation errors #37942uniqid()
in generated CSS class names breaks ability to cache parsed CSS #38889WP_Theme_JSON
class, and frontend inpackages/edit-site/src/components/global-styles/use-global-styles-output.js.
See Style engine: output global styles CSS rules using selectors #40955ELEMENTS
const to style engine once we've dealt with JS global stylesProject board
We've started a project board for managing the above tasks over in: https://github.com/orgs/WordPress/projects/19/views/1
Relevant discussions
style
vs. describingstate
#38694The text was updated successfully, but these errors were encountered: