Block Supports: Add background gradient support that can combine with background images#75859
Conversation
|
Size Change: +1.34 kB (+0.02%) Total Size: 7.73 MB
ℹ️ View Unchanged
|
|
Flaky tests detected in 3defdd8. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/23680753946
|
6c9ca1f to
5208c81
Compare
5208c81 to
272f719
Compare
|
Just noting that their might be additional unexpected use cases to drive the need for this improvement for background support. To implement text gradients we can't be modifying the shorthand Leveraging this |
272f719 to
895fab7
Compare
|
Just a quick update here to note that this proposed |
ramonjd
left a comment
There was a problem hiding this comment.
Thanks for the efforts here @aaronrobertshaw
Here's what I tested:
- setting gradient backgrounds on blocks, global styles and in theme.json (
background.gradient) - the above again but combining with images
- setting a gradient using the
color.gradientkey to check for regressions. - opening up existing posts with gradients set on blocks to check for regressions
It feels really natural to me so far and we can finally achieve some interesting effects using opacity settings:
cc @justintadlock who raised this issue in #32787 for his opinion
| * to confirm a url() was actually removed. Without that residue, the | ||
| * gradient alone would already pass core's own check. | ||
| */ | ||
| $gradient_pattern = '(?:linear|radial|conic|repeating-linear|repeating-radial|repeating-conic)-gradient\((?:[^()]|\([^()]*\))*\)'; |
There was a problem hiding this comment.
color-mix means there could be two layers of nesting, e.g., linear-gradient(135deg, color-mix(in srgb, red 50%, blue) 0%, oklch(0.7 0.15 30) 100%)
Not a blocker, and I think it's okay to start off opinionated.
There was a problem hiding this comment.
Thanks, I think I agree. Let's get this in first and iterate around this.
| */ | ||
| if ( isset( $css_declarations['background-image'] ) && isset( $parsed_styles['declarations']['background-image'] ) ) { | ||
| $css_declarations['background-image'] = $css_declarations['background-image'] . ', ' . $parsed_styles['declarations']['background-image']; | ||
| } |
There was a problem hiding this comment.
This relies on the fact that backgroundImage comes first in BLOCK_STYLE_DEFINITIONS_METADATA.
I wonder if we should document the order somewhere, or just add a comment to explicitly state the order dependency.
Anyway, it seems like as good a spot as any to combine the declarations
There was a problem hiding this comment.
Anyway, it seems like as good a spot as any to combine the declarations
Thinking about future alternatives, I wonder if the style engine should not treat backgroundImage and gradient as independent property definitions that happen to share a CSS property.
Instead then consolidation could be done via the value_func that receives the full background style object.
It would mean a divergence in way we treat single properties, and rewiring things a bit. I'm only considering how the logic could be contained, especially if one day we allow reordering of values, or even multiple images.
Nothing to do here, I'm just rambling.
There was a problem hiding this comment.
If I'm understanding the suggestion correctly, this wouldn't change where we're saving the values for background.gradient or background.backgroundImage. So any consolidation here wouldn't have much in the way of backward compatibility concerns.
Sounds like a good follow up.
There was a problem hiding this comment.
Yeah, my thoughts are a bit muddled here.
I was mainly ruminating about down the track when we might support more complex logic, and where that should be.
Like, whether consolidation could take place using the entire object. I don't know if this would ever work, but processing the entire background object in the callback:
'backgroundImage' => array(
'property_keys' => array( 'default' => 'background-image' ),
'path' => array( 'background' ), // <-- whole group, not ['background', 'backgroundImage']
'value_func' => array( self::class, 'get_background_image_css_declaration' ),
),No concerns about backwards compat, only blue sky thinking!
packages/block-editor/src/components/global-styles/background-panel.js
Outdated
Show resolved
Hide resolved
|
I follow your instinct, and too wanted to find better terminology than "Foreground"; Figma calls it "Fill", but that feels inappropriate for the editor context. The thing about the "layer" terminology is that we'll almost certainly add layer handling to the background panel on its own, i.e. you might have layers for each color, gradient, image, all in a single CSS definition, like so: In a dedicated "background" panel, you'd even be able to add drag handles to each of those three definitions, so you could reorder them. It seems worth reserving the "layer" vernacular for that use case. |
This idea was mentioned over in #60401 (comment) too, I think it's a natural progression to this eventually. Even layered images would unlock appealing design choices. |
|
Thanks for the discussion everyone 🙇
@jasmussen there's a good chance that paragraph blocks will not only have a single item inside for long. With #76171 and planned follow-ups, the paragraph block would also get the background image and optional clip control. So it will fill out more rather than appear as an afterthought. Additionally, perhaps it would be better then for #76171 if the "text gradient" selection were its own control rather than a gradient tab within the text color popover and "Foreground" panel.
The renaming of the Background Image panel to Background was proposed here. I initially didn't include it here mostly in that all the current background controls were all still background images (including gradient) I intended to seek design feedback there to settle on a course of action for the Color panel. Reworking the Color panel's background to the Background panel and renaming the panels themeselves might be best as an immediate follow-up to this. |
This PR is slightly related, though it might be outdated: |
|
Thanks for sharing that link @ramonjd, I missed adding it 👍 I'm starting to wonder if we should also give the background color the same treatment as the background gradient here. I mean, in this PR we are creating a new block support so that we can assign the resulting style to a new CSS property free of backward compatibility concerns. If we did the same, creating a If we complete the process to shift away from the shorthand |
Nice. That said, as a tools-panel I'd default those controls to not show by default for paragraphs. The fact that we show background by default is already slightly a stretch since it's a much better user experience to set a background on a container.
I actually still think that a tab inside the popover is the best path forward for this, and one that organically matches the term "foreground" very well. It's a separation of concerns, and it follows design precedence: items in the background panel already have gradient tab, now items in the foregrond panel do as well. It even makes it potentially simpler to add background images to foreground items; we'd need a redesign of the tabs to fit it (perhaps towards icons), but it's a good place to put them. I think the strongest reason for having these separate panels for foreground and background is actually the parallel layering conversation. If we are embracing that for backgrounds you can layer solids, gradients, and images, and eventually reorder them, then potentially we can do the same for foregrounds. It's a stretch, but layering a solid and a gradient for text feels reasonable to me.
Let me know if there's any nuance I'm missing. |
|
I think I might have an approach that avoids the need for block deprecations for blocks adopting the new background.gradient support. Blocks with The On the PHP side, |
- Add background.gradient to block.json and theme.json schemas - Add STYLE_PROPERTY entry (backgroundGradient) in constants.js - Add gradient to VALID_SETTINGS, VALID_STYLES, PROPERTIES_METADATA, INDIRECT_PROPERTIES_METADATA, and APPEARANCE_TOOLS_OPT_INS in class-wp-theme-json-gutenberg.php - Enable gradient globally in lib/theme.json - Add gradient setting in global-styles-engine get-setting.ts
- Add gradient property to BackgroundStyle type definition - Update JS style engine to combine gradient and backgroundImage into a comma-separated background-image CSS value - Add gradient definition to PHP style engine class - Update compute_style_properties in class-wp-theme-json-gutenberg.php to collect both gradient and backgroundImage before passing to the style engine for combined background-image CSS output
- Update background.php render support to handle gradient values, including combined gradient + background image - Add safecss_filter_attr_allow_css filter in kses.php to allow combined gradient+url() background-image values that WordPress core safecss_filter_attr() strips
- Add gradient picker to background-panel.js using ColorPanelDropdown with preset slug encoding/decoding - Suppress color panel gradient tab when background.gradient is enabled to avoid duplicate gradient UIs (color-panel.js) - Update hooks.js to preserve gradient presets for blocks with background.gradient support and disable gradient settings for blocks without support - Add gradient detection in background.js and useBlockSettings in utils.js - Add background panel SCSS styles with hasInnerWrapper pattern - Add slot className for inner wrapper in styles-tab.js and block-inspector/index.js
- Opt Group block into background.gradient in block.json - Update core-blocks.md and theme-json-living.md documentation
- PHP: background block support tests for gradient rendering - PHP: theme-json tests for gradient in compute_style_properties, remove_insecure_properties, and appearance tools opt-in - PHP: style engine tests for gradient CSS generation - JS: style engine tests for gradient and combined gradient+image
The gradient pattern in gutenberg_allow_background_image_combined only matched rgb()/rgba() inside gradient functions. Gradients using hsl(), oklch(), lab(), or other color functions with parentheses were stripped when combined with a url() background image. Broaden the nested parenthesis pattern to allow any single-level nested parens, covering all CSS color functions. Add KSES tests to the background block support test suite verifying combined gradient and url() values survive safecss_filter_attr() across color formats.
…class Replace the gradient control's per-item border workaround and the image control's inline border with a reusable `.block-editor-background-panel__item` class that handles grouped border and radius styling for all panel items.
0567753 to
92d1b99
Compare
|
|
||
| .background-block-support-panel { | ||
| /* Increased specificity required to remove the slot wrapper's row gap */ | ||
| &#{&} { |
There was a problem hiding this comment.
Thanks for spear heading this fix and refactoring things @aaronrobertshaw
This should unblock future background-* controls, e.g., #76171
Did another round of testing (group blocks):
- blocks with gradients and background images are migrated as expected
- overwriting block gradients set in trunk are set to the new
background.gradientprop - global styles apply correctly to blocks and can be overridden on the block level
- also tested setting
background.*in theme.json ✅ - existing blocks and global styles appear as expected (no regression I could see)
I think there are some very minor tweaks we could do in follow ups, mainly around existing color.gradient panel swatch icons some of which aren't cleared when updating background gradient in the new control. These are consistency issues between block and global styles UI controls.
Otherwise it's a good time to get this in so we can test before 7.1
MaggieCabrera
left a comment
There was a problem hiding this comment.
I've given this a try and it seems very solid.
- I can change the body background to a gradient for a full body gradient
- Patterns seem to be working fine, with and without block styles too
- The cover block overlay also works well
I'm excited for this!
|
I've pushed some small refinements for the issues @ramonjd noted. There's now a backport PR up as well. I'll get this PR merged in the next day or so pending passing e2es etc. |
|
While I've merged this PR, note that it doesn't opt into the new I'll hold off on this until further work around text gradient support and background clipping progress. These currently require some further thought around the UI/UX and I'd rather lean toward minimising disruptions in the UI for users of core blocks. |
… background images (#75859) Unlinked contributors: tcmulder. Co-authored-by: aaronrobertshaw <aaronrobertshaw@git.wordpress.org> Co-authored-by: ramonjd <ramonopoly@git.wordpress.org> Co-authored-by: MaggieCabrera <onemaggie@git.wordpress.org> Co-authored-by: jasmussen <joen@git.wordpress.org> Co-authored-by: paaljoachim <paaljoachim@git.wordpress.org> Co-authored-by: Azragh <azragh@git.wordpress.org> Co-authored-by: pbearne <pbearne@git.wordpress.org> Co-authored-by: skorasaurus <skorasaurus@git.wordpress.org> Co-authored-by: bph <bph@git.wordpress.org> Co-authored-by: devanshijoshi9 <devanshijoshi@git.wordpress.org> Co-authored-by: justintadlock <greenshady@git.wordpress.org>
… background images (#75859) Unlinked contributors: tcmulder. Co-authored-by: aaronrobertshaw <aaronrobertshaw@git.wordpress.org> Co-authored-by: ramonjd <ramonopoly@git.wordpress.org> Co-authored-by: MaggieCabrera <onemaggie@git.wordpress.org> Co-authored-by: jasmussen <joen@git.wordpress.org> Co-authored-by: paaljoachim <paaljoachim@git.wordpress.org> Co-authored-by: Azragh <azragh@git.wordpress.org> Co-authored-by: pbearne <pbearne@git.wordpress.org> Co-authored-by: skorasaurus <skorasaurus@git.wordpress.org> Co-authored-by: bph <bph@git.wordpress.org> Co-authored-by: devanshijoshi9 <devanshijoshi@git.wordpress.org> Co-authored-by: justintadlock <greenshady@git.wordpress.org>






Closes #32787
What?
Adds
background.gradientas a new block support, enabling blocks to have a gradient picker in the Background panel. This is separate from the existingcolor.gradientin the Color panel and allows blocks to combine a background gradient with a background image via comma-separatedbackground-imageCSS values.Why?
Currently, the only way to apply a gradient to a block is through the Color panel's
color.gradientsupport. This stores the gradient atstyle.color.gradientand renders it as abackgroundCSS shorthand, which conflicts with and overrides background image properties.By introducing
background.gradient(stored atstyle.background.gradient), gradients become part of the background style group. The style engine can then combine gradient and image values into a singlebackground-imagedeclaration (e.g.,background-image: linear-gradient(...), url(...)), enabling layered backgrounds without conflict.This also lays the groundwork for eventually migrating
color.gradienttobackground.gradientacross all blocks, providing a more consistent and capable background styling system.How?
The implementation is organized into commits representing distinct layers of the system, which may help when reviewing:
1. Schema & constants (
e5aebaf)Adds
background.gradienttoblock.jsonandtheme.jsonschemas,STYLE_PROPERTYconstants, and the theme JSON class (VALID_SETTINGS,VALID_STYLES,PROPERTIES_METADATA,INDIRECT_PROPERTIES_METADATA,APPEARANCE_TOOLS_OPT_INS).2. Style engine & global styles output (
9259102)Updates the JS style engine to combine gradient and
backgroundImageinto a comma-separatedbackground-imageCSS value, adds the gradient definition to the PHP style engine, and updatescompute_style_propertiesto pass both values to the engine.3. Block support rendering & safe CSS (
63faf64)Updates
background.phpto handle gradient values on the frontend (including combined gradient + image), and adds asafecss_filter_attr_allow_cssfilter inkses.phpto allow combinedgradient+url()values that core'ssafecss_filter_attr()strips.4. Editor UI (
522b740)Adds the gradient picker to the Background panel using
ColorPanelDropdown, suppresses the Color panel's gradient tab whenbackground.gradientis enabled, gates gradient settings per block inuseSettingsForBlockElement, and adds panel styles.5. Block opt-in (
45fd7b2)Opts the Group block into
background.gradientas the first adopter, with documentation updates.6. Tests (
0c13dba)PHP tests for block support rendering, theme JSON (
compute_style_properties,remove_insecure_properties, appearance tools), and style engine. JS tests for gradient and combined gradient+image output.Testing Instructions
linear-gradient(135deg, #000 0%, #fff 100%))Global styles
Testing Instructions for Keyboard
Screenshots or screencast