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

Move away from inline styles #23893

Open
afercia opened this issue Jul 12, 2020 · 12 comments
Open

Move away from inline styles #23893

afercia opened this issue Jul 12, 2020 · 12 comments
Labels
CSS Styling Related to editor and front end styles, CSS-specific issues. [Feature] Design Tools Tools that impact the appearance of blocks both to expand the number of tools and improve the experi [Feature] Themes Questions or issues with incorporating or styling blocks in a theme. [Type] Enhancement A suggestion for improvement.

Comments

@afercia
Copy link
Contributor

afercia commented Jul 12, 2020

Describe the bug
Splitting this out from #20775 (comment)

Some of the blocks custom values are saved as inline CSS styles. For example:

  • custom font size
  • the new custom line-height in WP 5.5
  • more

Inline styles are permanently stored in the HTML blob in the database. This breaks the principle of separation of content from presentation.

It also breaks interoperability of the data: exporting the content for reuse in other applications will bring all these presentational values in the content, where they would likely break the presentation. This brings us back to 15 years ago when web content was often an inextricable "HTML soup" of real content and presentation.

Admittedly, this is not new to the block editor. But, instead of moving away from inline styles, I see the block editor keeps using inline styles like in the case of the new "Line height" control. I think the block editor is doing this maybe a bit too lightly, without a in depth consideration of the final result for the web as a whole.

Instead of more inline styles, I'd expect Gutenberg to explore new solutions to make presentational values be stored separately from content.

Worth also considering that, as of July 2020, WordPress is powering 37.8% of the top 10 million websites in the world. This means the block editor is actually polluting the content of 37.8% of the websites with presentational data. Not a great progress for the Web overall. I'd like the block editor team to be more aware of this problem and feel a stronger responsibility to make the Web better.

WordPress should lead by example and fully embrace Web Standards and best practices.

I don't have a solution, but i strongly feel this should be one of the top priorities for the next releases. Hopefully, this issue can help to start a broader conversation and explore solutions.

@afercia afercia added the CSS Styling Related to editor and front end styles, CSS-specific issues. label Jul 12, 2020
@afercia
Copy link
Contributor Author

afercia commented Jul 12, 2020

Example of inline style rendered in the front end content:

<p style="line-height:1.5;font-size:20px"> ... </p>

Example of HTML blob saved in the database:

<!-- wp:paragraph {"style":{"typography":{"fontSize":20,"lineHeight":"1.5"}}} -->
<p style="line-height:1.5;font-size:20px"> ... </p>
<!-- /wp:paragraph -->

@ellenbauer
Copy link

I experience the same issues with inline styles added by the blocks, which make it difficult to add my own CSS styles to e.g. a theme.

For instance as mentioned above, the font-size should not be included as an inline style in the editor, so theme authors are able to provide their own CSS styling for the custom font sizes. At the moment the inline style overrides my own CSS styles in the editor.

If inline style is added to the frontend this makes it even more difficult and often overwrites custom responsive CSS styles I want to provided via the theme.

@mtias
Copy link
Member

mtias commented Jul 13, 2020

This is the tip of a very large problem space that continues to be discussed at length and is definitely not taken lightly! To put it short, style attributes need to be defined in a way that:

  • Block authors can easily and consistently implement.
  • Themes can control in terms of defaults and enabled-features.
  • Users can interact with using tools in the editor.
  • Block patterns could specify if needed.
  • Removes the need for editor styles altogether.
  • Handles theme switches, granular resetting, web and mobile interoperability, etc.

Please, read #20331 and #22296 for more context on the full style project if necessary. Particularly the item about "Look at style variations as packages of style attributes" aims at turning what is currently expressed through inline attributes into an encapsulated class affecting those attributes and hooked to that specific block. This requires several layers to be implemented and defined before it can start working in unison, though. In the mean time, some block tools fallback to inline styles when the values are custom.

In terms of the vertical scope, these attributes need to be able to affect the global space (theme defaults), the block area space (a sidebar might need to be able to redefine the default attributes), and the block space (a block needs to be able to depart). The aim is for this to work with native web tools as much as possible — at least on the output — for these style contexts, likely through pairing of classes and CSS variables to achieve all the different requirements at render time and keep concerns as separated as possible. However, this all requires a comprehensive system to work effectively, one that themes can opt into and integrate properly, otherwise specificity battles are going to be extremely fragile and seemingly broken in terms of user experience.

In your example above, the "style" object specified in the comment is the seed of that encapsulation, as we'll be able to store it separately and only reference it through a class or style id, which needs to be printed at time of render in a style block or separate stylesheet. This could also help cut down on amount of CSS delivered to the user as it can be determined ahead of time what needs to be present on the page load.

@afercia
Copy link
Contributor Author

afercia commented Jul 13, 2020

aims at turning what is currently expressed through inline attributes into an encapsulated class affecting those attributes and hooked to that specific block.

Glad to hear there are plans to not use inline styles in the long term.

I created this issue to mainly focus on the architectural side. While inline styles certainly affect themes etc. and I do understand all the above considerations, I do believe the fact the block editor is polluting the content of 37.8% of the web (okay, "the 37.8% of the top 10 million websites", to be more exact) is way more important.

In my opinion, this issue should be one of the top priorities of the next release. It's already more than one year that the block editor is spreading inline styles all around the web.

@kjellr kjellr added the [Feature] Themes Questions or issues with incorporating or styling blocks in a theme. label Jul 14, 2020
@ZebulanStanphill ZebulanStanphill added the [Feature] Design Tools Tools that impact the appearance of blocks both to expand the number of tools and improve the experi label Jul 14, 2020
@ZebulanStanphill
Copy link
Member

I think the way that a lot of stuff should be handled is by allowing themes (and/or users) to create presets at a global level.

Here's one specific example I have in mind:

Users/themes would be able to create a font size + line height preset.

This user/theme-defined font size preset would then appear in the font size select dropdowns in the inspector for various blocks like the Paragraph block. (By default, the Custom option would not be available.)

I think line height should be directly tied to font size, so when creating a font size preset, you would also set the associated line height. There would not be separate line height presets or controls. Both the font size and line height would be applied by the same CSS class assigned to the preset. (I guess something like is-font-size-PRESET-NAME.)

This would help ensure consistent theming across the entire website. People would be encouraged to create reusable solutions, rather than one-off band-aid fixes that would result in tons of inline styles.

@aristath
Copy link
Member

aristath commented Aug 4, 2020

Just thinking out loud here, but stripping inline styles, putting them all together and then printiing them in the footer wouldn't be that hard to do...

As a proof of concept here's a simple class that will do just that. (If you remove all the inline comments it's less than 30 lines and pretty simple):

class GutenStylesConcat {

    /**
     * An array of styles.
     * 
     * @access protected
     * @var array
     */
    protected $styles = [];

    /**
     * Run our filters & actions.
     * 
     * @access public
     * @return void
     */
    public function init() {
        // Filter block content.
        add_filter( 'render_block', [ $this, 'render_block' ], 10, 2 );

        // Print all block styles in the footer.
        add_action( 'wp_footer', [ $this, 'print_styles' ] );
    }

    /**
     * Filter the block content.
     * 
     * @access public
     * @param string $block_content The block content.
     * @param array  $block         The block definition.
     * @return string               Returns the $block_content with nline styles stripped.
     */
    public function render_block( $block_content, $block ) {

        // Find instances of inline styles.
        preg_match( '/style=\"[^\"]*\"/', $block_content, $matches );

        // Loop matches.
        foreach ( $matches as $match ) {
            $styles = rtrim( ltrim( $match, 'style="' ), '"' );
            $key    = md5( $styles );

            // Replace the "style" attribute with a custom "block-style".
            $block_content = str_replace( $match, 'block-style="' . $key . '"', $block_content );

            // Set the style in the object's array so we can later print all styles in the footer.
            $this->styles[ $key ] = $styles;
        }

        // Return the content.
        return $block_content;
    }

    /**
     * Print block styles.
     * 
     * @access public
     * @return void
     */
    public function print_styles() {
        // Early exit if there are no inline styles.
        if ( empty( $this->styles ) ) {
            return;
        }

        echo '<style id="block-inline-styles">';
        foreach ( $this->styles as $key => $style ) {
            echo '[block-style="' . $key . '"]{' . $style . '}';
        }
        echo '</style>';
    }
}

$styles_concat = new GutenStylesConcat();
$styles_concat->init();

The above code does the following:

  • Adds a filter in render_block, where it searches the block content for style="...".
  • Any matches are then stripped from the source, and added to a $this->styles array n the object.
  • Each style string uses md5 to generate a unique string/ID.
  • The inline styles are then replaced with block-style="md5-generated-key".
  • In the footer we're then going through the $this->styles array, and simply print them all inside a <style id="block-inline-styles">.

It's a simple approach and in principle it works perfectly fine. One extra benefit is that if there are multiple blocks with the same styles, these styles will only be printed once since their md5 key will be the same.

The md5 thing is ugly and will generate something like <p block-style="3dd9b4c541ac60568b77fd9c54f995b3">, but for the purposes of a proof-of-concept it's good enough.


EDIT: We could probably use hash( 'crc32', $styles ) instead of md5( $styles )... The result would be significantly shorter keys and I believe they'd still be unique

@kanlukasz
Copy link

kanlukasz commented Nov 4, 2020

I have a similar case where I have my own custom blocks.
There is a lot of inline styles (because they come from block components like RangeControl etc.)

Right now I am curious which method will be the fastest:

  1. Using render_block filter as shown by @aristath

or

  1. Using inside render_callback something like:

     `wp_register_style('dummy-handle-md5', false);`
     `wp_enqueue_style('dummy-handle-md5');`
     `wp_add_inline_style('dummy-handle-md5', $build_class);` 
    

Another thing is that both methods generate classes in the footer. It would be much better if it happened in the head

@Tropicalista
Copy link

@aristath This code does not solve the problem of inline hover or pseudoclass. A more generic interface must be provided..

@aristath
Copy link
Member

@aristath This code does not solve the problem of inline hover or pseudoclass. A more generic interface must be provided..

Yes, that code was a simple proof of concept, something to show that it is doable. If it is decided that we should move away from inline styles, then a more robust and abstract solution will need to be implemented.

@caseymilne
Copy link

Is there a filter we can use in a custom theme to stop the inline styles from being rendered?

I'm building a custom theme with Tailwinds, and for some blocks we can add Tailwinds CSS classes under the block advanced and this works. However the aggressive inline styling of columns for instance specifies .column { margin: 0; } which makes using .mx-auto (left/right margin auto) impossible.

@huubl
Copy link
Contributor

huubl commented May 4, 2023

Are there any decisions/updates about removing inline styles on attributes?

Besides the arguments already mentioned. Right now it's very hard, nearly impossible, to add a strict Content Security Policy (CSP) on inline styles on attributes (https://content-security-policy.com/examples/allow-inline-style/).

@cbirdsong
Copy link

cbirdsong commented May 4, 2023

Short version - no. In one of the Slack chat meetings a few weeks ago, I brought up how the editor has made Wordpress essentially incompatible with strict CSPs and I was encouraged to make a new issue explicitly about that, but I hadn't gotten around to it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CSS Styling Related to editor and front end styles, CSS-specific issues. [Feature] Design Tools Tools that impact the appearance of blocks both to expand the number of tools and improve the experi [Feature] Themes Questions or issues with incorporating or styling blocks in a theme. [Type] Enhancement A suggestion for improvement.
Projects
None yet
Development

No branches or pull requests