Skip to content

Commit

Permalink
Global styles: output :root selector for CSS custom properties (WordP…
Browse files Browse the repository at this point in the history
…ress#42084)

Replacing usages of body with :root for generated CSS properties, presets and some layout settings. This is a naive replacement without much thought put into which styles should be printed under :root and which under body.
I've limited the use of root to CSS vars, with the exception of `--wp--style--root--padding-X`, which are generated along with other styles as part of PROPERTIES_METADATA
Using :root for CSS custom properties in the site editor and for duotone as well.

Unlinked contributors: keithdevon, Inwerpsel, gyurmey2.

Co-authored-by: ramonjd <ramonopoly@git.wordpress.org>
Co-authored-by: andrewserong <andrewserong@git.wordpress.org>
Co-authored-by: noisysocks <noisysocks@git.wordpress.org>
Co-authored-by: jorgefilipecosta <jorgefilipecosta@git.wordpress.org>
Co-authored-by: markhowellsmead <markhowellsmead@git.wordpress.org>
Co-authored-by: aaronrobertshaw <aaronrobertshaw@git.wordpress.org>
Co-authored-by: tellthemachines <isabel_brison@git.wordpress.org>
Co-authored-by: aristath <aristath@git.wordpress.org>
Co-authored-by: getdave <get_dave@git.wordpress.org>
Co-authored-by: colorful-tones <colorful-tones@git.wordpress.org>
Co-authored-by: webmandesign <webmandesign@git.wordpress.org>
Co-authored-by: cbirdsong <cbirdsong@git.wordpress.org>
Co-authored-by: nextgenthemes <nico23@git.wordpress.org>
Co-authored-by: fabiankaegy <fabiankaegy@git.wordpress.org>
Co-authored-by: annezazu <annezazu@git.wordpress.org>
  • Loading branch information
16 people authored and cbravobernal committed Apr 9, 2024
1 parent 1bfad55 commit 7920cb5
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 51 deletions.
2 changes: 1 addition & 1 deletion lib/class-wp-duotone-gutenberg.php
Original file line number Diff line number Diff line change
Expand Up @@ -623,7 +623,7 @@ private static function get_svg_definitions( $sources ) {
* @return string The CSS for global styles.
*/
private static function get_global_styles_presets( $sources ) {
$css = 'body{';
$css = WP_Theme_JSON_Gutenberg::ROOT_CSS_PROPERTIES_SELECTOR . '{';
foreach ( $sources as $filter_id => $filter_data ) {
$slug = $filter_data['slug'];
$colors = $filter_data['colors'];
Expand Down
39 changes: 23 additions & 16 deletions lib/class-wp-theme-json-gutenberg.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ class WP_Theme_JSON_Gutenberg {
*/
protected static $blocks_metadata = array();

/**
* The CSS selector for the top-level preset settings.
*
* @since 6.6.0
* @var string
*/
const ROOT_CSS_PROPERTIES_SELECTOR = ':root';

/**
* The CSS selector for the top-level styles.
*
Expand Down Expand Up @@ -1751,7 +1759,7 @@ static function ( $carry, $element ) {
* @return string The result of processing the presets.
*/
protected static function compute_preset_classes( $settings, $selector, $origins ) {
if ( static::ROOT_BLOCK_SELECTOR === $selector ) {
if ( static::ROOT_BLOCK_SELECTOR === $selector || static::ROOT_CSS_PROPERTIES_SELECTOR === $selector ) {
// Classes at the global level do not need any CSS prefixed,
// and we don't want to increase its specificity.
$selector = '';
Expand Down Expand Up @@ -2277,7 +2285,7 @@ protected static function get_setting_nodes( $theme_json, $selectors = array() )
// Top-level.
$nodes[] = array(
'path' => array( 'settings' ),
'selector' => static::ROOT_BLOCK_SELECTOR,
'selector' => static::ROOT_CSS_PROPERTIES_SELECTOR,
);

// Calculate paths for blocks.
Expand Down Expand Up @@ -2704,6 +2712,7 @@ static function ( $pseudo_selector ) use ( $selector ) {
* Outputs the CSS for layout rules on the root.
*
* @since 6.1.0
* @since 6.6.0 Use `ROOT_CSS_PROPERTIES_SELECTOR` for CSS custom properties.
*
* @param string $selector The root node selector.
* @param array $block_metadata The metadata for the root block.
Expand All @@ -2714,16 +2723,6 @@ public function get_root_layout_rules( $selector, $block_metadata ) {
$settings = $this->theme_json['settings'] ?? array();
$use_root_padding = isset( $this->theme_json['settings']['useRootPaddingAwareAlignments'] ) && true === $this->theme_json['settings']['useRootPaddingAwareAlignments'];

/*
* Reset default browser margin on the root body element.
* This is set on the root selector **before** generating the ruleset
* from the `theme.json`. This is to ensure that if the `theme.json` declares
* `margin` in its `spacing` declaration for the `body` element then these
* user-generated values take precedence in the CSS cascade.
* @link https://github.com/WordPress/gutenberg/issues/36147.
*/
$css .= 'body { margin: 0;';

/*
* If there are content and wide widths in theme.json, output them
* as custom properties on the body element so all blocks can use them.
Expand All @@ -2733,11 +2732,19 @@ public function get_root_layout_rules( $selector, $block_metadata ) {
$content_size = static::is_safe_css_declaration( 'max-width', $content_size ) ? $content_size : 'initial';
$wide_size = isset( $settings['layout']['wideSize'] ) ? $settings['layout']['wideSize'] : $settings['layout']['contentSize'];
$wide_size = static::is_safe_css_declaration( 'max-width', $wide_size ) ? $wide_size : 'initial';
$css .= '--wp--style--global--content-size: ' . $content_size . ';';
$css .= '--wp--style--global--wide-size: ' . $wide_size . ';';
$css .= static::ROOT_CSS_PROPERTIES_SELECTOR . ' { --wp--style--global--content-size: ' . $content_size . ';';
$css .= '--wp--style--global--wide-size: ' . $wide_size . '; }';
}

$css .= ' }';
/*
* Reset default browser margin on the body element.
* This is set on the body selector **before** generating the ruleset
* from the `theme.json`. This is to ensure that if the `theme.json` declares
* `margin` in its `spacing` declaration for the `body` element then these
* user-generated values take precedence in the CSS cascade.
* @link https://github.com/WordPress/gutenberg/issues/36147.
*/
$css .= 'body { margin: 0; }';

if ( $use_root_padding ) {
// Top and bottom padding are applied to the outer block container.
Expand Down Expand Up @@ -2767,7 +2774,7 @@ public function get_root_layout_rules( $selector, $block_metadata ) {
$css .= ':where(.wp-site-blocks) > :last-child:last-child { margin-block-end: 0; }';

// For backwards compatibility, ensure the legacy block gap CSS variable is still available.
$css .= "$selector { --wp--style--block-gap: $block_gap_value; }";
$css .= static::ROOT_CSS_PROPERTIES_SELECTOR . " { --wp--style--block-gap: $block_gap_value; }";
}
$css .= $this->get_layout_styles( $block_metadata );

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
getStylesDeclarations,
processCSSNesting,
} from '../use-global-styles-output';
import { ROOT_BLOCK_SELECTOR } from '../utils';
import { ROOT_BLOCK_SELECTOR, ROOT_CSS_PROPERTIES_SELECTOR } from '../utils';

describe( 'global styles renderer', () => {
describe( 'getNodesWithStyles', () => {
Expand Down Expand Up @@ -254,7 +254,7 @@ describe( 'global styles renderer', () => {
],
},
},
selector: ROOT_BLOCK_SELECTOR,
selector: ROOT_CSS_PROPERTIES_SELECTOR,
},
{
presets: {
Expand Down Expand Up @@ -342,7 +342,7 @@ describe( 'global styles renderer', () => {
};

expect( toCustomProperties( tree, blockSelectors ) ).toEqual(
'body{--wp--preset--color--white: white;--wp--preset--color--black: black;--wp--preset--color--white-2-black: value;--wp--custom--white-2-black: value;--wp--custom--font-primary: value;--wp--custom--line-height--body: 1.7;--wp--custom--line-height--heading: 1.3;}h1,h2,h3,h4,h5,h6{--wp--preset--font-size--small: 12px;--wp--preset--font-size--medium: 23px;}'
':root{--wp--preset--color--white: white;--wp--preset--color--black: black;--wp--preset--color--white-2-black: value;--wp--custom--white-2-black: value;--wp--custom--font-primary: value;--wp--custom--line-height--body: 1.7;--wp--custom--line-height--heading: 1.3;}h1,h2,h3,h4,h5,h6{--wp--preset--font-size--small: 12px;--wp--preset--font-size--medium: 23px;}'
);
} );
} );
Expand Down Expand Up @@ -614,7 +614,7 @@ describe( 'global styles renderer', () => {
},
};
expect( toStyles( Object.freeze( tree ), 'body' ) ).toEqual(
'body {margin: 0; --wp--style--global--content-size: 840px; --wp--style--global--wide-size: 1100px;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'
':root { --wp--style--global--content-size: 840px; --wp--style--global--wide-size: 1100px;}body {margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'
);
} );
} );
Expand Down Expand Up @@ -734,7 +734,7 @@ describe( 'global styles renderer', () => {
} );

expect( layoutStyles ).toEqual(
':where(body .is-layout-flow) > * { margin-block-start: 0; margin-block-end: 0; }:where(body .is-layout-flow) > * + * { margin-block-start: 0.5em; margin-block-end: 0; }:where(body .is-layout-flex) { gap: 0.5em; }body { --wp--style--block-gap: 0.5em; }body .is-layout-flow > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }body .is-layout-flow > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }body .is-layout-flow > .aligncenter { margin-left: auto !important; margin-right: auto !important; }body .is-layout-flex { display:flex; }body .is-layout-flex { flex-wrap: wrap; align-items: center; }body .is-layout-flex > * { margin: 0; }'
':where(body .is-layout-flow) > * { margin-block-start: 0; margin-block-end: 0; }:where(body .is-layout-flow) > * + * { margin-block-start: 0.5em; margin-block-end: 0; }:where(body .is-layout-flex) { gap: 0.5em; }:root { --wp--style--block-gap: 0.5em; }body .is-layout-flow > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }body .is-layout-flow > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }body .is-layout-flow > .aligncenter { margin-left: auto !important; margin-right: auto !important; }body .is-layout-flex { display:flex; }body .is-layout-flex { flex-wrap: wrap; align-items: center; }body .is-layout-flex > * { margin: 0; }'
);
} );

Expand All @@ -751,7 +751,7 @@ describe( 'global styles renderer', () => {
} );

expect( layoutStyles ).toEqual(
':where(body .is-layout-flow) > * { margin-block-start: 0; margin-block-end: 0; }:where(body .is-layout-flow) > * + * { margin-block-start: 12px; margin-block-end: 0; }:where(body .is-layout-flex) { gap: 12px; }body { --wp--style--block-gap: 12px; }body .is-layout-flow > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }body .is-layout-flow > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }body .is-layout-flow > .aligncenter { margin-left: auto !important; margin-right: auto !important; }body .is-layout-flex { display:flex; }body .is-layout-flex { flex-wrap: wrap; align-items: center; }body .is-layout-flex > * { margin: 0; }'
':where(body .is-layout-flow) > * { margin-block-start: 0; margin-block-end: 0; }:where(body .is-layout-flow) > * + * { margin-block-start: 12px; margin-block-end: 0; }:where(body .is-layout-flex) { gap: 12px; }:root { --wp--style--block-gap: 12px; }body .is-layout-flow > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }body .is-layout-flow > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }body .is-layout-flow > .aligncenter { margin-left: auto !important; margin-right: auto !important; }body .is-layout-flex { display:flex; }body .is-layout-flex { flex-wrap: wrap; align-items: center; }body .is-layout-flex > * { margin: 0; }'
);
} );

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { privateApis as componentsPrivateApis } from '@wordpress/components';
import {
PRESET_METADATA,
ROOT_BLOCK_SELECTOR,
ROOT_CSS_PROPERTIES_SELECTOR,
scopeSelector,
appendToSelector,
getBlockStyleVariationSelector,
Expand Down Expand Up @@ -543,7 +544,7 @@ export function getLayoutStyles( {
);
// For backwards compatibility, ensure the legacy block gap CSS variable is still available.
if ( selector === ROOT_BLOCK_SELECTOR && hasBlockGapSupport ) {
ruleset += `${ selector } { --wp--style--block-gap: ${ gapValue }; }`;
ruleset += `${ ROOT_CSS_PROPERTIES_SELECTOR } { --wp--style--block-gap: ${ gapValue }; }`;
}
}

Expand Down Expand Up @@ -729,7 +730,7 @@ export const getNodesWithSettings = ( tree, blockSelectors ) => {
nodes.push( {
presets,
custom,
selector: ROOT_BLOCK_SELECTOR,
selector: ROOT_CSS_PROPERTIES_SELECTOR,
} );
}

Expand Down Expand Up @@ -781,24 +782,28 @@ export const toStyles = (
const nodesWithSettings = getNodesWithSettings( tree, blockSelectors );
const useRootPaddingAlign = tree?.settings?.useRootPaddingAwareAlignments;
const { contentSize, wideSize } = tree?.settings?.layout || {};
let ruleset = '';

if ( contentSize || wideSize ) {
ruleset += `${ ROOT_CSS_PROPERTIES_SELECTOR } {`;
ruleset = contentSize
? ruleset + ` --wp--style--global--content-size: ${ contentSize };`
: ruleset;
ruleset = wideSize
? ruleset + ` --wp--style--global--wide-size: ${ wideSize };`
: ruleset;
ruleset += '}';
}

/*
* Reset default browser margin on the root body element.
* This is set on the root selector **before** generating the ruleset
* Reset default browser margin on the body element.
* This is set on the body selector **before** generating the ruleset
* from the `theme.json`. This is to ensure that if the `theme.json` declares
* `margin` in its `spacing` declaration for the `body` element then these
* user-generated values take precedence in the CSS cascade.
* @link https://github.com/WordPress/gutenberg/issues/36147.
*/
let ruleset = 'body {margin: 0;';

if ( contentSize ) {
ruleset += ` --wp--style--global--content-size: ${ contentSize };`;
}

if ( wideSize ) {
ruleset += ` --wp--style--global--wide-size: ${ wideSize };`;
}
ruleset += 'body {margin: 0;';

// Root padding styles should only be output for full templates, not patterns or template parts.
if ( useRootPaddingAlign && isTemplate ) {
Expand Down Expand Up @@ -1000,7 +1005,10 @@ export const toStyles = (
}

nodesWithSettings.forEach( ( { selector, presets } ) => {
if ( ROOT_BLOCK_SELECTOR === selector ) {
if (
ROOT_BLOCK_SELECTOR === selector ||
ROOT_CSS_PROPERTIES_SELECTOR === selector
) {
// Do not add extra specificity for top-level classes.
selector = '';
}
Expand Down Expand Up @@ -1211,6 +1219,7 @@ export function useGlobalStylesOutputWithConfig( mergedConfig = {} ) {
updatedConfig,
blockSelectors
);

const globalStyles = toStyles(
updatedConfig,
blockSelectors,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { getValueFromObjectPath } from '../../utils/object';

/* Supporting data. */
export const ROOT_BLOCK_SELECTOR = 'body';
export const ROOT_CSS_PROPERTIES_SELECTOR = ':root';

export const PRESET_METADATA = [
{
Expand Down
Loading

0 comments on commit 7920cb5

Please sign in to comment.