ResponsiveWrapper: Fixed rendering SVGs as a featured image.#48307
Conversation
The feature image gets rendered within a ResponsiveWrapper. That relies on the image's height and width being able to be determined. In the PostFeaturedImage component, it isn't able to do that for an SVG. This leads the ResponsiveWrapper assigning an undefined value to the paddingBottom style. As suggested, I added a check for an undefined value and in that case set padding bottom to 100%. Props aaronrobertshaw, Mamaduka. Fixes #48184, #5477.
|
👋 Thanks for your first Pull Request and for helping build the future of Gutenberg and WordPress, @tomdevisser! In case you missed it, we'd love to have you join us in our Slack community, where we hold regularly weekly meetings open to anyone to coordinate with each other. If you want to learn more about WordPress development in general, check out the Core Handbook full of helpful information. |
There was a problem hiding this comment.
Thanks for taking the time and effort to work on this @tomdevisser 👍
Unfortunately, it looks like the old comment of mine that you were directed to, might have put this PR on the wrong track. At the time, I suspected the use of paddingBottom: 100% would have its shortcomings but I didn't have the bandwidth to explore it and since then the issue has fallen off my radar.
To test this PR and the updates to the ResponsiveWrapper component in a more isolated manner, I tweaked the component's storybook example to use various SVGs.
So long as the SVG's height is <= to its width, the SVG appears to display ok. Once the height is greater than the width however paddingBottom: 100% doesn't provide enough real estate and the bottom of the image gets cropped.
Quick diff adding storybook example used above
diff --git a/packages/components/src/responsive-wrapper/stories/index.tsx b/packages/components/src/responsive-wrapper/stories/index.tsx
index 5f48b91d27..f6b86289ec 100644
--- a/packages/components/src/responsive-wrapper/stories/index.tsx
+++ b/packages/components/src/responsive-wrapper/stories/index.tsx
@@ -36,3 +36,35 @@ Default.args = {
/>
),
};
+
+export const WithoutNaturalDimensions = Template.bind( {} );
+WithoutNaturalDimensions.args = {
+ children: (
+ <svg xmlns="http://www.w3.org/2000/svg" height="320px" width="140px">
+ <rect
+ x="20"
+ y="20"
+ width="100"
+ height="280"
+ style={ { fill: 'blue' } }
+ />
+ <g>
+ <circle style={ { fill: 'red' } } cx="70" cy="80" r="30" />
+ <circle style={ { fill: 'yellow' } } cx="70" cy="160" r="30" />
+ <circle style={ { fill: '#40CC40' } } cx="70" cy="240" r="30" />
+ </g>
+ </svg>
+ ),
+};
Following some of the other links from the original issue, there does appear to be an alternate approach that might be worth exploring here as well.
Whichever approach we end up settling upon to fix this issue, it would be good to add a storybook example that demonstrates the behaviour with SVGs, along with a changelog entry for the components package.
Thanks again for submitting the PR. I'll be happy to review again when needed 🙂
|
@aaronrobertshaw Thanks for reviewing. Will be interesting to try and create a Storybook example, I have no experience with it yet. While searching I found 10up also has a pretty easy solution for this in their plugin: Would you say that's the right way to go? If so, I could implement this, but I'd like your opinion on it before diving into the code again. As far as I can see, the only thing they've changed is to set the width to 100% if the image source is an SVG. |
The Storybook docs are pretty helpful and worth taking a look at before you jump in. There are also some examples you can follow in the components package, though I'd tend to focus more on those components whose stories are in TypeScript as they'll be more up-to-date with best practices. Luckily, the Speaking of best practices, the components package has its own contributing readme you might find handy, complete with a section on the Storybook.
Unfortunately, I can't say at the moment. I'd need to take a closer look at the featured image use case and the linked approach but I'm out of time today. At a quick glance, it looks a little hacky to be wrapping the image in additional markup. My gut feeling is it would be better to solve the issue a little closer to its source if possible. |
I think the extra markup is just for the plugin to be sure it keeps working if Gutenberg changes the wrapper/classes around it. We can apply the width 100% directly to the image using an existing class or an inline style, I don't know what the standard approach is in the Gutenberg project. |
|
Thank you @tomdevisser for working on this! @aaronrobertshaw shared some great feedback, pretty much the same that I would have also shared. Regarding an alternative approach, have we considered |
I haven't yet, but worth trying! When writing new styles in Gutenberg, is there a common practice in choosing what selector to use? And the specificity, should it be as low as needed? Would love some pointers on this! |
|
As suggested from Aaron, the fix should be applied as close to the source as possible (in this case, in the
We usually use classnames, following a BEM-like convention (as you can also see in the More specifically regarding the
In terms of specificity, it's good practice to keep it as low as necessary, in order to prevent "specificity wars" in the library. Having said that, we strongly discourage any style overrides outside of the library (and especially the overrides that rely on the internal components' class names), since they are prone to breakages any time the internal implementation of the component changes. |
Thank you for linking this, and for sharing the other helpful information. Learning more about contributing and the project every day. I have checked out the branch again, reverted my previous changes and tried the object-fit, but without any luck. I also tried different solutions using fit-content, different display values, etc. The only fix that seems to work with different SVGs, also when height is bigger than width, is the padding-bottom: 100%, a fix that was already there partially, but could also be applied through CSS on the I'll keep trying some other solutions, but if any of you has more ideas they're more than welcome! |
|
I think I found a fix, using a position of This might be too big a change and I don't know what implications this has to this component. But after testing with several images of different mime types everything seems to work well, so I wanted to give it a chance anyway. 🙂 It does do this one weird thing when replacing from svg to image, not sure why. buggy-img.mov |
|
Update: Looking at the StoryBook locally I see how this obviously breaks things as I could've expected. Starting to think with the current markup it's near to impossible to fix, and when changing the markup there's too much that'll possibly break as everything is depending on each other. We could make a separate component just for the Featured Image wrapper, so we can't break anything else, but I'm not sure if that's the right solution. I would almost propose to go with the padding fix for now as that seems to work for almost everything without breaking anything, and it's just a preview so it isn't too bad that it gets cropped. It gives us more time to think about a better implementation while it "works". |
|
Could you commit the changes to Storybook that introduce a new example with the SVG image? I may also attempt to have a look :) |
|
@ciampo Sure thing! But where can I grab a good svg for adding to the Storybook? The URL being used right now is https://s.w.org/style/images/about/WordPress-logotype-standard.png, is there like a place to upload images to w.org to use here? Or a shared folder with assets we can use? |
|
Grabbed an SVG I could find online of the WordPress logo, should be fine temporarily, but it's probably better to replace it before any merge happens. |
|
Aaron posted a diff earlier today in which he had created an ad-hoc SVG image for the Storybook example, if it can be useful |
|
It might also be worth noting that if the SVG defines The The following diff contains an updated SVG for testing with my earlier Storybook example snippet. Click for SVG code <svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 140 320"
preserveAspectRatio="xMinYMin meet"
height="320px"
width="140px"
>
<rect
x="0"
y="0"
width="140"
height="320"
style={ { fill: 'blue' } }
/>
<g>
<circle style={ { fill: 'red' } } cx="70" cy="80" r="30" />
<circle style={ { fill: 'yellow' } } cx="70" cy="160" r="30" />
<circle style={ { fill: '#40CC40' } } cx="70" cy="240" r="30" />
</g>
</svg> |
Is it possible to get these values on upload and add them to the WP Image? Cause in that case we don't have to change anything in the ResponsiveWrapper component. This is getting a bit out of my scope, so if anyone else wants to try a commit I encourage you to, I will stay active here and try to think along. |
|
@tomdevisser, can we close this PR now that #48573 is merged? |


The feature image gets rendered within a ResponsiveWrapper. That relies on the image's height and width being able to be determined. In the PostFeaturedImage component, it isn't able to do that for an SVG. This leads the ResponsiveWrapper assigning an undefined value to the paddingBottom style.
As suggested, I added a check for an undefined value and in that case set padding bottom to 100%.
Props aaronrobertshaw, Mamaduka.
Fixes #48184, #5477.
What?
Fixing the rendering of SVG images when set as a featured image.
Why?
The natural height and width of an SVG can't reliably be determined, resulting in a CSS bug. See #48184.
How?
As suggested by @aaronrobertshaw, I added a check for an undefined value on the naturalWidth in the
<ResponsiveWrapper />component and in that case setpadding-bottomto 100%.Testing Instructions