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: force root min-height of 100% for backgrounds #59809

Merged
merged 6 commits into from
Mar 20, 2024

Conversation

ramonjd
Copy link
Member

@ramonjd ramonjd commented Mar 13, 2024

What?

Initial commit - set html min-height to 100% for backgrounds (background or background-image properties)

See: #59354 (comment)

Why?

The objective is to ensure that the :html selector has a minimum height of 100% when:

  1. There's a background gradient (styles.color.background)
  2. There's a background image (styles.background.backgroundImage)

The reason is so the background gradient or image takes up the entire screen.

The block editor already does this by giving the HTML tag a min-height of 100% all the time, so the corollary objective is to have the frontend match this.

How?

Not sure yet 😄

So far, just detecting the background and hardcoding html { min-height: calc(100% - var(--wp-admin--admin-bar--height, 0px)); }

Testing Instructions

In the site editor or in theme.json, add a gradient background to your site:

{
	"$schema": "https://schemas.wp.org/trunk/theme.json",
	"version": 2,
	"settings": {
		"appearanceTools": true
	},
	"styles": {
		"color": {
			"gradient": "linear-gradient(#e66465, #9198e5)"
		}
	}
}

Also try with a background image:

{
	"$schema": "https://schemas.wp.org/trunk/theme.json",
	"version": 2,
	"settings": {
		"appearanceTools": true
	},
	"styles": {
		"background": {
			"backgroundImage": {
				"url": "https://i0.wp.com/wordpress.org/files/2023/12/sotw-dotorg-drawer.png?w=1807&ssl=1",
				"source": "file"
			},
			"backgroundSize": "cover"
		}
	}
}

Screenshots or screencast

Before After
Screenshot 2024-03-14 at 2 50 07 pm Screenshot 2024-03-14 at 2 50 23 pm

@ramonjd ramonjd self-assigned this Mar 13, 2024
// Abstract into something like static::update_separator_declarations.
// @TODO - how can this be overwritten by theme.json, if at all? styles.dimensions.minHeight?
// @TODO - implement the same logic in the editor https://github.com/WordPress/gutenberg/blob/f079bd2f7fe8e4c5694fc3feb276567777f9997b/packages/block-editor/src/components/iframe/index.js#L252-L252
if ( static::ROOT_BLOCK_SELECTOR === $selector ) {
Copy link
Member Author

@ramonjd ramonjd Mar 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@andrewserong @tellthemachines

Before I go too deep on this PR, I wanted to garner a few opinions on how we might achieve the objectives.

The PR's description outlines the why of this PR, but the technical criteria is that, when there's a gradient background or background size of cover at the root level, we want to force the window (HTML or :root) to have a min-height: 100% so the background stretches the full height without scrolling.

This is a naive attempt to add the requisite CSS.

The first, hopeful, attempt was to switch the static::ROOT_BLOCK_SELECTOR from 'body' to :root/html, and then set the value of styles.dimensions.minHeight. This would have been my preferred approach, however, it came with a bunch of unknowns, one of the weirdest being that it doesn't allow themes to overwrite a browser's default margins.

Then I mused whether html could be a top level "element", and therefore be "styleable", but I abandoned that idea. It might have legs, I don't know, but it'd be a bunch of work.

Then I landed here, at the MVP.

It works, but I would be glad of alternative points of view 😄

Some considerations:

  • How, if at all, could a theme developer overwrite the min-height value? Should they at all? Maybe not since it's tightly coupled to the background option. Or am I thinking to hard about it? 😄
  • I plan to abstract the logic - if you can see avenues for optimization, that'd be great!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just some quick thoughts off the top of my head:

  • I think it's fine if the output is :root but that the ROOT_BLOCK_SELECTOR is still body as the rules here can be different to the selector since it's a slightly non-standard use case. The important thing IMO is that we're outputting root rules of some kind just a single time. Out of curiosity, why do we need the rule to be attached to :root instead of body? Is it because of potential margins on body?
  • Should there be a way for folks to explicitly switch this setting off? I do like that it's guarded behind only being output when background or backgroundImage is set at the root level 👍.
  • Since you asked the question of whether a theme developer could overwrite the min-height value, I think I can imagine someone wanting to do just that! I don't think it'd necessarily need to be implemented in this PR, but if a theme were to set the root styles.dimensions.minHeight value in their theme.json file, perhaps that could overwrite the value used here? In that case, though, I imagine the theme developers would expect the value to always be output, not just when background is set 🤔
  • In terms of abstraction, what did you have in mind? If it's only being used in one place, I like the idea of it essentially being private code so that it could be easier to change in follow-ups, potentially.

Thanks for digging in here!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How, if at all, could a theme developer overwrite the min-height value? Should they at all?

Is there a need for overriding this value? It's an essential part of making sure gradients and background images work correctly on the site background.

A possible alternative would be setting min-height to a custom property via the background block support (so we'd only output it if there were a background gradient/image), and then we'd only have to set the custom property's value in this function when static::ROOT_BLOCK_SELECTOR === $selector. However, that would mean outputting min-height: var(--something) whenever there were a background set. Would we ever want to set min-height together with background in other circumstances?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the topic of abstraction, I'm not entirely sure about the reasoning behind static::update_separator_declarations but it looks like something that should be solved in the block itself by skipping serialization and adding custom logic to deal with it 🤔 It would be great to reduce the amount of functions in the theme.json class if at all possible.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for the helpful feedback! I feel like I have some paths forward, now 🙇🏻

Out of curiosity, why do we need the rule to be attached to :root instead of body? Is it because of potential margins on body?

Good question! Two reasons:

  1. min-height: 100% on the body tag doesn't have any effect on when using background gradients. min-height: 100vh, however, does. See: https://codepen.io/BoganJustice/pen/jORMKKE
  2. I couldn't quite get the scrolling to behave with adding it to the body tag because of various margins of nested elements. The video below is testing 100vh but it's also the same for 100%
2024-03-15.10.06.13.mp4

I haven't reached the end of experimentation, yet though. If it's just the logged-in admin view, then it might be something we can deal with.

Also, I suspect min-height: 100vh; on the body takes care of most situations, in which case it would fit nicely with theme.json styles.dimensions.minHeight.

Should there be a way for folks to explicitly switch this setting off? I do like that it's guarded behind only being output when background or backgroundImage is set at the root level

If I can get it to play with styles.dimensions.minHeight then maybe it'll be already taken care of.

Is there a need for overriding this value? It's an essential part of making sure gradients and background images work correctly on the site background.

You're right. It must be 100% for it to have the intended effect on the background. I like the idea of creating a CSS custom property to be more flexible - that could potentially be overridable.

But yeah, it might be good enough to start with the CSS rule and then decide before creating a global CSS property that folks might rely on.

If it's only being used in one place, I like the idea of it essentially being private code so that it could be easier to change in follow-ups, potentially
It would be great to reduce the amount of functions in the theme.json class if at all possible.

Good points. I'll leave the code in place for now. I'm not excited about another for loop there, but I can't see a tidy alternative.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea of creating a CSS custom property to be more flexible

The custom property wasn't for flexibility, it was a way to avoid the for loop here 😅 .
The idea is you'd set min-height: var(--something) in the background block support, whenever you're setting gradients or background images. But the property itself isn't set unless the declarations are being applied to the root level. You'd probably need something like `html { --something: 100%; } body { --something: unset } so that value doesn't accidentally apply to all background supports. It's messy though, unless there's a use for min-height in non-root cases.

*/
if ( $should_set_root_min_height ) {
$block_rules .= static::to_ruleset(
'html',
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why on the HTML and not BODY?

  • setting it on the body revealed potential issues, e.g., the background gradient did not always stretch (unless we used 100vh)
  • Also unpredictable margins causing scrolling , e.g., an unstyled H1 at the root of the document in empty theme
  • Settings "styles.dimensions.minHeight" in theme.json would overwrite the value - I suppose this would be fine for theme devs who know what they're doing, but for folks using themes that have "styles.dimensions.minHeight" hardcoded it would mean that backgrounds don't behave as they should, that is, with the background gradient/image filling the window.
  • 'HTML' is also the selector that's being used in the editor to achieve the same effect.

@ramonjd ramonjd marked this pull request as ready for review March 15, 2024 04:46
Copy link

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: ramonjd <[email protected]>
Co-authored-by: andrewserong <[email protected]>
Co-authored-by: tellthemachines <[email protected]>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@ramonjd ramonjd added [Type] Experimental Experimental feature or API. Global Styles Anything related to the broader Global Styles efforts, including Styles Engine and theme.json labels Mar 15, 2024
@ramonjd ramonjd force-pushed the update/background-default-to-min-height-100 branch from c59a3a4 to 9a1b6f4 Compare March 15, 2024 04:53
@@ -2633,6 +2641,29 @@ static function ( $pseudo_selector ) use ( $selector ) {
}
unset( $declarations[ $index ] );
}

if ( $is_root_selector && (
'background-size' === $declaration['name'] && 'cover' === $declaration['value'] ||
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wondering, would we also want the min-height rule to be output if we use contain as the background size? I.e. should we always output the min height if any background image is set, a little like how we're outputting if any background shorthand property is in use? 🤔

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wondering, would we also want the min-height rule to be output if we use contain as the background size?

Good question. I don't know, but I'll test it out.

I.e. should we always output the min height if any background image is set, a little like how we're outputting if any background shorthand property is in use?

We could I suppose, so long as it behaves as expected with other possible background property values. I'll also play around with it.

@ramonjd
Copy link
Member Author

ramonjd commented Mar 20, 2024

Just wondering, would we also want the min-height rule to be output if we use contain as the background size?
I.e. should we always output the min height if any background image is set, a little like how we're outputting if any background shorthand property is in use?

In the case of "contain", it kinda depends on the image size I think. All other values, aside from "cover", the min-height has no effect as far as I can see.

background-size: contain

800px - with min-height 100% 800px - without
Screenshot 2024-03-20 at 11 52 47 am Screenshot 2024-03-20 at 11 53 28 am
2800px - with min-height 100% 2800px - without
Screenshot 2024-03-20 at 12 02 29 pm Screenshot 2024-03-20 at 12 03 18 pm

background-size: auto / background-size: unset / no background-size

with min-height 100% without
Screenshot 2024-03-20 at 11 55 09 am Screenshot 2024-03-20 at 11 56 32 am

As with auto above, any other value, e.g., 40%, 100px 400px and so on has no affect.

Given that the site editor has a permanent min-height: 100%, I think there's a justification to always output it.

Maybe later we can decide whether to provide a way for users to control the value or toggle it? 🤔

@andrewserong
Copy link
Contributor

andrewserong commented Mar 20, 2024

In the case of "contain", it kinda depends on the image size I think. All other values, aside from "cover", the min-height has no effect as far as I can see.

Nicely captured, thanks for confirming!

Maybe later we can decide whether to provide a way for users to control the value or toggle it? 🤔

Sounds reasonable to me 👍

Hijacking the existing duotone for loop to do the dirty work.
Removed value test as it's already checked in compute_properties function
@ramonjd ramonjd force-pushed the update/background-default-to-min-height-100 branch from a6353e8 to adb016a Compare March 20, 2024 01:58
Copy link
Contributor

@andrewserong andrewserong left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is testing very nicely for me, and feels safely guarded in that it'll only be output if folks are using a site-wide gradient or background image, so the chances for any negative impact (i.e. sites out in the wild with a site-wide gradient) seem very minimal to me, and most likely it'll feel more like a bug fix 👍

Also, as you mention, we can always explore allowing the value to be customised in follow-ups if need be.

Looking good with site-wide background images in local testing:

Before After
image image

LGTM! ✨

@ramonjd
Copy link
Member Author

ramonjd commented Mar 20, 2024

Thanks for all the help testing these @andrewserong 🙇🏻

@ramonjd ramonjd merged commit f98609b into trunk Mar 20, 2024
57 checks passed
@ramonjd ramonjd deleted the update/background-default-to-min-height-100 branch March 20, 2024 03:20
@github-actions github-actions bot added this to the Gutenberg 18.0 milestone Mar 20, 2024
carstingaxion pushed a commit to carstingaxion/gutenberg that referenced this pull request Mar 27, 2024
…ss#59809)

Set html min-height to 100% for background and background-image
Hijack the existing duotone for loop to do the dirty work.
Update unit tests

Co-authored-by: ramonjd <[email protected]>
Co-authored-by: andrewserong <[email protected]>
Co-authored-by: tellthemachines <[email protected]>
ramonjd added a commit to ramonjd/wordpress-develop that referenced this pull request May 2, 2024
ramonjd added a commit to ramonjd/wordpress-develop that referenced this pull request May 3, 2024
ramonjd added a commit to ramonjd/wordpress-develop that referenced this pull request May 3, 2024
ramonjd added a commit to ramonjd/wordpress-develop that referenced this pull request May 8, 2024
ramonjd added a commit to ramonjd/wordpress-develop that referenced this pull request May 26, 2024
ramonjd added a commit to ramonjd/wordpress-develop that referenced this pull request May 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Global Styles Anything related to the broader Global Styles efforts, including Styles Engine and theme.json [Type] Experimental Experimental feature or API.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants