Skip to content

Add support for aspect ratio and related controls in viewport states#78795

Merged
tellthemachines merged 8 commits into
trunkfrom
add/responsive-aspect-ratio
Jun 12, 2026
Merged

Add support for aspect ratio and related controls in viewport states#78795
tellthemachines merged 8 commits into
trunkfrom
add/responsive-aspect-ratio

Conversation

@tellthemachines

Copy link
Copy Markdown
Contributor

What?

Part of #77817.

Aspect ratio, width, height and min-height don't work when viewport states are enabled in Image, Featured image and Cover blocks. Most of these controls have custom implementations across these blocks, which we should standardize later. But for now, let's get the current tools working responsively because these will be quite useful as responsive styles.

Testing Instructions

  1. On Cover (with an image set), Image and Featured Image blocks:
  2. Set an aspect ratio and then enable a viewport state and set a different aspect ratio. They should work as expected
  3. Set a height or min-height and then set an aspect ratio in a viewport state. They should both work for their respective viewport sizes. (Aspect ratio should unset height/min-height and vice-versa).
  4. Scale controls (cover/contain) should also work per viewport.

This PR doesn't handle focal point; that'll be for a follow-up. (We should also add focal point controls to featured image for consistency with the other blocks)

Screenshot 2026-05-29 at 3 48 10 pm

Use of AI Tools

Built with codex/gpt 5.5

@tellthemachines tellthemachines requested a review from talldan May 29, 2026 05:52
@tellthemachines tellthemachines self-assigned this May 29, 2026
@tellthemachines tellthemachines added [Type] Enhancement A suggestion for improvement. [Feature] Style States Related to block style states (currently viewport and pseudo-states) labels May 29, 2026
@github-actions github-actions Bot added [Package] Block library /packages/block-library [Package] Block editor /packages/block-editor [Package] Style Engine /packages/style-engine labels May 29, 2026
Comment thread lib/block-supports/states.php Outdated
* @param array $declarations CSS declarations generated by the style engine.
* @return array CSS declarations with fallback dimension styles applied where needed.
*/
function gutenberg_get_state_declarations_with_fallback_dimension_styles( $declarations ) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

If at some point we have all blocks using standard block support heights, min-heights etc.. we can move this logic over there.

@github-actions

github-actions Bot commented May 29, 2026

Copy link
Copy Markdown

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: tellthemachines <[email protected]>
Co-authored-by: andrewserong <[email protected]>
Co-authored-by: ramonjd <[email protected]>
Co-authored-by: talldan <[email protected]>

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

@github-actions

github-actions Bot commented May 29, 2026

Copy link
Copy Markdown

Size Change: +579 B (+0.01%)

Total Size: 8.59 MB

📦 View Changed
Filename Size Change
build/scripts/block-editor/index.min.js 380 kB +114 B (+0.03%)
build/scripts/block-library/index.min.js 323 kB +446 B (+0.14%)
build/scripts/style-engine/index.min.js 2.44 kB +19 B (+0.78%)

compressed-size-action

@github-actions

github-actions Bot commented May 29, 2026

Copy link
Copy Markdown

Flaky tests detected in 17efda2.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/27187129964
📝 Reported issues:

@andrewserong andrewserong left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Good idea adding these controls in for viewport states support, things like aspect ratio or width for images at different sizes feels really powerful 👍.

Also adding objectFit to what the style engine can output sounds good, and dimensions feels like the closest bucket we have for it (and conceptually it's good to sit it alongside the other dimensions properties). Will we want to graduate this to a proper block support at some point — by which I mean, should this be included in theme.json schema, etc? I think everything else the style engine handles is covered, so wondered what the ideal scope is there 🤔

I also like the inclusion of a utils file for the style-state. Looking over the code changes for each of the blocks, I was wondering if it's possible to add a hook to consolidate some of the repetitive changes. It might help tidy things up and also set things up for other blocks that might need to use this in the future? I.e. something like a useStateAwareDimensions hook that takes attributes, setAttributes, clientId as params and returns stateDimensions and setDimensions and so on.

Then the consumer could grab the width, height etc from stateDimensions rather than needing to use its own ternaries (the returned object would have already resolved which value to use). Similarly, the transformation from scale to objectFit could occur within the hook?

In manual testing, things seems to be working pretty well so far!

<ToolsPanelItem
<InspectorControls
group="dimensions"
resetAllFilter={ ( attrs ) => ( {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm not sure if I've found a bug or now.

I assume, when you are in Mobile, “Reset all” should reset the current selected state’s dimensions, not every breakpoint?

Here I'm setting a different height on an image block at all 3 breakpoints (66 for desktop, 243 tablet and 474 for mobile).

With mobile selected, I hit reset all. Mobile resets as expected. Tablet's value remains, but Desktop/default also being reset.

Kapture.2026-06-02.at.18.18.20.mp4

I think this is because the top level attribute is being reset?

{
  height: undefined, // incorrectly reset by Image resetAllFilter
  style: {
    tablet: { dimensions: { height: '243px', objectFit: 'cover' } },
    // mobile height reset by scoped generic dimensions reset
    // mobile objectFit may also be left behind unless Image's reset is state-aware
  },
}

Is that right?

If not, maybe we need to make Image’s resetAllFilter branch on hasSelectedStyleState 🤔

onDeselect={ () =>
setAttributes( getResetMinHeightAttributes() )
}
resetAllFilter={ getResetMinHeightAttributes }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Cover has a different behaviour from the image one I described. I add a different min height to all breakpoints. Resetting all on mobile wipes mobile and tablet, but keeps the desktop value 🤔

GPT says

ToolsPanelItem currently keeps a stale resetAllFilter when the item rerenders, so responsive controls can reset the wrong breakpoint.

What's the correct behaviour here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Reset all should only reset for the current breakpoint. I'll look into it!

@tellthemachines tellthemachines force-pushed the add/responsive-aspect-ratio branch from b916c71 to 04b398c Compare June 3, 2026 00:27
@tellthemachines

Copy link
Copy Markdown
Contributor Author

I was wondering if it's possible to add a hook to consolidate some of the repetitive changes. It might help tidy things up and also set things up for other blocks that might need to use this in the future?

I was rather hoping to standardise all these custom tools as proper block supports as a follow-up, so we wouldn't need all this extra logic in the blocks themselves 😅
I considered doing it in this PR but didn't want it to blow out into a huge changeset so enabling the tools took priority for now.

@andrewserong

Copy link
Copy Markdown
Contributor

I considered doing it in this PR but didn't want it to blow out into a huge changeset so enabling the tools took priority for now.

Gotcha, that all makes sense! Better to keep things in each block then rather than making it seem like it's an API when the plan is to eventually go the block support route 👍

@tellthemachines

Copy link
Copy Markdown
Contributor Author

Hmm, now I'm wondering whether it would be better to standardise these as block supports first, because most block supports worked pretty seamlessly with states with not much adjustment needed 🤔 I might explore that route too

@andrewserong

Copy link
Copy Markdown
Contributor

now I'm wondering whether it would be better to standardise these as block supports first, because most block supports worked pretty seamlessly with states with not much adjustment needed

Definitely worth trying to see how much work is involved, it could also unlock some cool features that other blocks (or plugins) can use, too

@tellthemachines

Copy link
Copy Markdown
Contributor Author

Ok the reset issues should be fixed. I'm going to do a little exploration of standardising block supports ⛏️ 👷 and see how it compares

@tellthemachines

Copy link
Copy Markdown
Contributor Author

Ok so I did a little AI-assisted investigation. Standardising all these controls as block supports is a multi-PR process whichever way we look at it 😅

  • Scale and Focal point need adding as new block supports (presumably under dimensions, because they should sit next to aspect ratio, and that one's already in dimensions);
  • Image block needs migrating width, height, aspect ratio, scale and focal point to block supports;
  • Featured image needs migrating width, height and aspect ratio;
  • Cover needs migrating min-height and focal point (it already uses aspect ratio block support);
  • All these blocks will need some degree of deprecation where they're currently using top-level attribs.

It would also be nice to add scale and focal point to Featured image for consistency with Image.

I'm thinking it might be best to proceed with the current PR for now so we can add much needed responsive features sooner rather than later.

In terms of back compat, this approach won't cause any extra pain because the responsive attributes in this PR are already being added in the correct shape, e.g styles.tablet.dimensions.aspectRatio, so we'll only have to deprecate/migrate the default attribs anyway.

Keen to hear all your thoughts!

@ramonjd

ramonjd commented Jun 3, 2026

Copy link
Copy Markdown
Member

Ok the reset issues should be fixed.

I just re-tested. Looks good! Thanks for fixing that.

@andrewserong

Copy link
Copy Markdown
Contributor

all these controls as block supports is a multi-PR process whichever way we look at it 😅

Oh, yeah, that does sound like a lot!

I'm thinking it might be best to proceed with the current PR for now so we can add much needed responsive features sooner rather than later.

So long as, as you say, the shape of how the data is stored is consistent with how the block support will work, I think going with the current PR is a pragmatic way to proceed. My only hesitation is that if we think opting-in to block supports is going to be a ways off, then it might be worth seeing if we can consolidate some of the logic here into helper functions or hooks for readability.

This isn't a strongly held view, but something I notice working with the image block in particular is that the image.js file is very complex and hard to follow, so if there's a way to tuck logic away where we can, it might help with maintainability if we think this is going to be the shape for a while.

One potential benefit of shifting things to hooks / utility functions where we can is that we might be able to cover some of the transformation logic with tests, too?

@ramonjd

ramonjd commented Jun 3, 2026

Copy link
Copy Markdown
Member

Image block needs migrating width, height, aspect ratio, scale and focal point to block supports

The width, height bit was noted as a stretch goal on the 7.1 block supports issue

A drop in the ocean, but something 😄

@tellthemachines tellthemachines force-pushed the add/responsive-aspect-ratio branch from 27a88eb to 3c2ea3a Compare June 3, 2026 23:58
}
},
"selectors": {
"dimensions": ".wp-block-image img",

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Once the dimensions controls are migrated to block supports this selector will still be accurate.

@andrewserong andrewserong Jun 4, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Oh, this one might need to be specified per property. It's quite common for themes to set margin for the image block in global styles, expecting it to target the outer wrapper and not the img element (i.e. to give more breathing room surrounding image blocks in the overall layout of a post or page).

@andrewserong andrewserong Jun 4, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Oh wait, margin is spacing, not dimensions. Ignore me! 🤦

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yeah the naming of these supports is pretty random 😅

@talldan

talldan commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Some things I noticed when testing:

Image block

If switching breakpoints using state dropdown, the aspect ratio controls don't update to show the correct value. If I set 'square' on mobile, then switch to tablet, the dropdown still shows 'square' as selected, even though the correct value is 'original'. Similar happens with the scale tool.

Cover block

It works better than image, but the 'Original' aspect ratio seems to be broken. If I insert a cover, add an image, the initial setting is original, but I find the image to be not fully visible (I'm not sure what 'Original' is supposed to mean in this context). Setting the aspect ratio to something else then back to original results in the image becoming really small. It seems kind of broken in trunk too, but with different results (the image gets bigger instead of small).

Featured image

Has the same sort of issues as Image, where switching back and forth between breakpoints shows the wrong value.

@tellthemachines tellthemachines force-pushed the add/responsive-aspect-ratio branch from 8c39662 to 16fa011 Compare June 9, 2026 03:29
@tellthemachines

Copy link
Copy Markdown
Contributor Author

Cover block
It works better than image, but the 'Original' aspect ratio seems to be broken. If I insert a cover, add an image, the initial setting is original, but I find the image to be not fully visible (I'm not sure what 'Original' is supposed to mean in this context)

Cover block has a min-height of 430px and that's what it'll be by default unless its content is taller than that, in which case it'll grow. The img inside it is absolutely positioned to the edges of its container, so it behaves like a background-image.

Setting the aspect ratio to something else then back to original results in the image becoming really small. It seems kind of broken in trunk too, but with different results (the image gets bigger instead of small).

This is because when we set aspect-ratio, we also unset min-height. This unsetting persists even when we set aspect-ratio back to original, so the default Cover min-height of 430px is overridden. In my testing on trunk it behaves just like this branch, which is expected because that part of the style output hasn't changed.

I think we could perhaps avoid outputting the min-height unset if aspect-ratio is default. Otherwise I think what you report is expected Cover block behaviour (it isn't intended to automatically assume the aspect ratio of its "background" image because in most of its uses the shape of its content should take precedence)

The issues with the control not resetting on Image/Featured image are specific to this branch; I'll look into them!

@talldan

talldan commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

In my testing on trunk it behaves just like this branch, which is expected because that part of the style output hasn't changed.

Ah yes, you're right, so it does, something else must have been happening when I tested before 👍

Might be best to treat it as a separate bug. I can make an issue if that helps?

@tellthemachines

Copy link
Copy Markdown
Contributor Author

Might be best to treat it as a separate bug. I can make an issue if that helps?

I was going to try fixing it in this branch, assuming it's just a small tweak. If it ends up being bigger, might be worth fixing separately.

@tellthemachines

Copy link
Copy Markdown
Contributor Author

I was going to try fixing it in this branch

OK I pushed a fix! Minor adjustments to the dimensions files, but aside from that it was mostly changing logic from this PR, so neater to do the whole thing here.

panelId={ clientId }
>
<CoverHeightInput
value={ activeAspectRatio ? '' : activeMinHeight }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Quick question: cover doesn't need the isExplicitAspectRatio check for auto? Guessing not, just checking!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Cover is using the aspect ratio block support and it works well out of the box!

@ramonjd ramonjd left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is working well for me across all blocks tested (Cover/Featured/Image)

I tested adding dimensions and aspect ratio at every breakpoint and the previewing works well. Not related to this PR, but I was wondering why my desktop changes weren't showing up after I'd selected "Desktop" until I realized by window width was too narrow!

Reset works as expected again too. Thanks for all the changes.

If it's okay with @talldan then it also LGTM

@talldan

talldan commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

It tests mostly well. The one unusual issue I find is that the 'Fill' option on featured image blocks doesn't seem to work. It looks like it works in the editor, but the attribute is never saved, and so the styles don't apply on the frontend.

The controls look like this:
Screenshot 2026-06-11 at 5 17 32 pm

But the saved markup is just:

<!-- wp:post-featured-image {"aspectRatio":"1"} /-->

I tested trunk and it does work there, so it'd be a regression that this branch is introducing.

@ramonjd

ramonjd commented Jun 12, 2026

Copy link
Copy Markdown
Member

It tests mostly well. The one unusual issue I find is that the 'Fill' option on featured image blocks doesn't seem to work. It looks like it works in the editor, but the attribute is never saved, and so the styles don't apply on the frontend

Good catch!

Can confirm. Here's my markup where I applied "Fit" to desktop and mobile:

<!-- wp:post-featured-image {"aspectRatio":"1","style":{"mobile":{"dimensions":{"aspectRatio":"9/16"}}}} /-->

I guess "objectFit":"fill" is missing? Or is it "scale" 🤔 but I suppose it looks okay in the editor because 'fill' is the default in the scale tool

@ramonjd

ramonjd commented Jun 12, 2026

Copy link
Copy Markdown
Member

Oh sorry, didn't refresh. I see 0f47824 was just added 😄

@tellthemachines

Copy link
Copy Markdown
Contributor Author

The one unusual issue I find is that the 'Fill' option on featured image blocks doesn't seem to work

Fixed! There was some faulty logic due to fill being the default for object-fit. We're now always outputting the property whatever its value is.

@ramonjd

ramonjd commented Jun 12, 2026

Copy link
Copy Markdown
Member

I guess "objectFit":"fill" is missing? Or is it "scale" 🤔 but I suppose it looks okay in the editor because 'fill' is the default in the scale tool
Oh sorry, didn't refresh. I see 0f47824 was just added 😄

Here's what I'm seeing now:

<!-- wp:post-featured-image {"aspectRatio":"1","scale":"fill","style":{"mobile":{"dimensions":{"aspectRatio":"4/3","objectFit":"fill"}}}} /-->

Looks like it's fixed in my testing! 🌮

I'm a bit out of the loop on the data structure here:"scale" is the top-level block attribute, and we're following the CSS properties in style with "objectFit". Makes sense. So that connects to the "one day" effort of the top-level preset style attrs migration (?)

@tellthemachines

Copy link
Copy Markdown
Contributor Author

So that connects to the "one day" effort of the top-level preset style attrs migration (?)

scale isn't an actual block support yet, so we can probably migrate it into style when we make it a block support and migrate these custom controls too.

@talldan talldan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Works well now 🎉

@tellthemachines tellthemachines merged commit 0b846fc into trunk Jun 12, 2026
43 checks passed
@tellthemachines tellthemachines deleted the add/responsive-aspect-ratio branch June 12, 2026 05:06
@github-actions github-actions Bot added this to the Gutenberg 23.5 milestone Jun 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Feature] Style States Related to block style states (currently viewport and pseudo-states) [Package] Block editor /packages/block-editor [Package] Block library /packages/block-library [Package] Style Engine /packages/style-engine [Type] Enhancement A suggestion for improvement.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants