Try responsive global block styles with states#77513
Try responsive global block styles with states#77513tellthemachines wants to merge 13 commits intotrunkfrom
Conversation
|
Size Change: +1.13 kB (+0.01%) Total Size: 7.77 MB 📦 View Changed
ℹ️ View Unchanged
|
|
Flaky tests detected in e5e4f4f. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/25034626216
|
|
Thanks for picking up this effort, looking forward to seeing it in the wild 🙇 I know it's early days but had a quick question regarding the use of "block states". These were going to be implemented across both Global Styles and block supports correct? There's a PR open for the block supports side of state styles: #76491 (comment). From memory, there were some related PRs spun up for that that potentially involved refactoring the |
This PR only implements responsive block states in global styles. Block instances will be dealt with later, building on Maggie's work in #76491. |
| const RESPONSIVE_BREAKPOINTS = array( | ||
| 'mobile' => '@media (width <= 480px)', | ||
| 'tablet' => '@media (480px < width <= 782px)', | ||
| ); |
There was a problem hiding this comment.
Currently these match the default editor responsive breakpoints, but once #75707 is done they will be configurable from theme.json.
| if ( ! empty( $options['media_query'] ) && ! empty( $block_rules ) ) { | ||
| $block_rules = $options['media_query'] . '{' . $block_rules . '}'; | ||
| } | ||
|
|
There was a problem hiding this comment.
get_layout_styles takes a new media_query option which should be one of the RESPONSIVE_BREAKPOINTS defined above.
| * dimensions/width) — apply the variation class directly to it. | ||
| */ | ||
| $feature_element_selector = str_replace( $shortened_selector, '', $clean_style_variation_selector ); | ||
| $combined_selectors = str_replace( $feature_element_selector, '', $clean_style_variation_selector ); |
There was a problem hiding this comment.
Added this fix because Button width and typography styles were not being applied correctly to block style variations. This is an issue in trunk too, so potentially this fix could be extracted from here. It's a minor thing so not sure it's worth it.
| if ( is_array( $css_feature_selector ) ) { | ||
| $css_feature_selector = $css_feature_selector['root'] ?? null; | ||
| } | ||
| $css_selector = is_string( $css_feature_selector ) ? $css_feature_selector : $selector; |
There was a problem hiding this comment.
Extracted these from the condition below so we can reuse them for the responsive rules.
| : getBlockStyleVariationSelector( | ||
| styleVariationName, | ||
| baseSelector | ||
| ); |
There was a problem hiding this comment.
This is the other part of the fix for the Button variation selector issue mentioned above.
| ) { | ||
| const { user, base, merged, onChange } = useContext( GlobalStylesContext ); | ||
| const isPseudoSelectorState = state?.startsWith( ':' ); | ||
| const pseudoSelectorState = isPseudoSelectorState ? state : undefined; |
There was a problem hiding this comment.
The naming here is a bit confusing. Might we in the future have states that are neither responsive nor pseudo-selectors? If not it might not be a problem
|
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 If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
d4ba7e7 to
c185831
Compare
There was a problem hiding this comment.
The premise of this PR looks pretty good, though I wonder if it'd be best to sort out how the different state groups (responsive, pseudo, navigation block 'current') are going to work together first. What are your thoughts @tellthemachines ?
Another thing is support for elements. The first thing I tried testing naively was setting responsive font styles for heading, but then I realised they're really controlled by heading element styles.
| export const RESPONSIVE_STATES: StateDefinition[] = [ | ||
| { value: 'mobile', label: __( 'Mobile' ) }, | ||
| { value: 'tablet', label: __( 'Tablet' ) }, | ||
| ]; |
| // All blocks receive responsive states by default. | ||
| if ( name.includes( '/' ) ) { | ||
| const blockPseudoStates = VALID_BLOCK_STATES[ name ] ?? []; | ||
| return [ ...blockPseudoStates, ...RESPONSIVE_STATES ]; |
There was a problem hiding this comment.
This does get interesting when a block (like button) has the pseudo states:
We did chat about it in DM (and also mentioned here), how users might want to select specific styles for mobile + focus (as an example), so this should probably end up more like two separate radio groups. The same might also apply for the navigation link's 'current' state (Navigation link: add support to style current menu item via theme.json).
Borrowing the video from #57719, the dropdown should probably look more like this:
button.mp4
I guess it might require some refactoring of how the states work in trunk.
| @@ -53,6 +53,12 @@ export function useStyle< T = any >( | |||
| state?: string | |||
There was a problem hiding this comment.
If as per the other comment, a user is in the future able to select a combination of states, then this would need to be updated to support more than just a string. It's probably not too complicate though, and object like { responsive: 'mobile', pseudo: 'focus' } would work I think, and that would remove the need for some of the isPseudoSelectorState stuff.
Co-authored-by: Copilot <copilot@github.com>
Hmm what are you seeing? In my testing I can set the font styles in the Heading block to specific values for Tablet or Mobile and it seems to be working as expected. If the theme enables fluid typography, then the font size you chose will be inside a
Yeah better solve this sooner than later 😅 |
Maybe I didn't test it correctly. I'll take another look.
Yep, I'm happy to take a look 👍 |




What?
Attempts to solve #13363 by using block states to represent "tablet" and "mobile" breakpoints for block global styles.
"tablet" and "mobile" are using the block editor defaults for now; later it might be possible to customise them.
I had considered trying container queries for this to allow blocks to respond to their container, but it is impractical to do so for global styles due to the requirement that the container be flagged with the
container-typeproperty. In global styles we of course have no way of knowing what container the block will be in, and attempting to add that property wholesale to all containers can have unpredictable effects.WIP - I haven't yet checked whether all supports are working correctly.
Testing Instructions
In theme.json
Under styles > blocks > blockname add "mobile" and "tablet" objects with styles defined as per the doc.
In the UI
Open global styles, head to Blocks and check that each block has a states dropdown with "tablet" and "mobile" states. Check that changes made with those states selected only apply to those breakpoints.
Use of AI Tools
I got copilot to write most of this, with a combination of claude sonnet 4.6 and gpt 5.3 codex. Unusually for gpt it did not add unit tests of its own accord, so I'll probs add those later once we're sure of the direction 😄