Skip to content
This repository has been archived by the owner on Feb 23, 2024. It is now read-only.

Fix: skewed placeholder of product image - issue#7553 #7651

Merged
merged 13 commits into from
Nov 16, 2022

Conversation

kmanijak
Copy link
Contributor

@kmanijak kmanijak commented Nov 10, 2022

Summary

Fix for the issue #7553.

Placeholder image was skewed (during loading and once loaded) when there was not enough space for it to expand, for example:

  • when used in a Columns block,
  • on a narrow screen.

What wasn't mention in the issue is that the issue could be reproduced on too wide screens as well (when single product had more than 500px width).

Cause

The cause of the glitch were inline styles on the placeholder image in Product Image block:

    <img src={ PLACEHOLDER_IMG_SRC } alt="" width={ 500 } height={ 500 } />

width was overridden by more specific styles, while height was not, which made the placeholder skewed with the height fixed to 500px.

Changes

  • Removal of the inline styles let the placeholder to keep the image ratio depends on the width. That works in both cases: when there's not enough or too much space for a product.

  • Additionally, the corresponding styles where removed from a PHP code. First commit shows that the styles were anyway not even applied, which proves it's safe to remove them.

  • Fix a couple of TS errors in tests: commit

  • Add explicit comments about alt text being empty in decorative images: commit

Fixes:

Screenshots

Case Before After
Single product (wider than 500px) image image
Single product (narrower than 500px) image image
Product Query / All Products image image

Testing

Automated Tests

  • Changes in this PR are covered by Automated Tests.
    • Unit tests
    • E2E tests

User Facing Testing

Prerequisites:
0. Make sure you have a product without a highlighted image (you can create a new product or remove the image from an existing one).

Case 1: image is wider than 500px

  1. Go to Appearance > Site Editor > Templates > Product Catalog.
  2. Remove the legacy placeholder block.
  3. Add blocks that use Product Image placeholder:
  • Single Product
  • All Products
  • Product Query
  1. ✅ Check on the wide-screen (image should have more than 500px width) if the placeholder image is a square (not skewed)

Case 2: image is narrower than 500px

  1. Add a Columns block.
  2. Inside one of the columns, add the Single Product block, to another one add Product Query block. Columns block limits the available space for a product to display (you should achieve less than 500px width for product image)
  3. ✅ Check if the placeholder image is a square (not skewed)

WooCommerce Visibility

  • WooCommerce Core
  • Feature plugin
  • Experimental

Changelog

Fix skewed placeholder of a Product Image block

Karol Manijak and others added 4 commits November 10, 2022 13:36
Typo caused rendering of incorrect HTML attributes: width and height of Product Image placeholder that were anyway ignored by the browser
…uctElements > Image block

Inline height took precedence over the inherited styles which made the placeholder image skewed (in loading and loaded state). Removal of those styles allows the ImagePlaceholder to adapt the height to the available space keeping the ratio or inherit the styles from the parent
…ductImage.php block

Inline styles applied to the placeholder image of ProductImage block were overriden by other styles with higher specificity, which made them redundant. Additionally, corresponding styles were removed from the placeholder image from Editor code as they caused UI glitches. Additional proof that it's safe to remove them is in the first commit in this branch, the purpose of which was to fix those styles as there was a typo which corrupted them and eventually inline width and height were ignored by the browser and not applied to the element
…inline attributes

This is to prevent adding inline width and height attributes so the sizing of the placeholder image is controlled by the inherited styles or element styles, in the same way as a regular product image
@rubikuserbot rubikuserbot requested review from a team and thealexandrelara and removed request for a team November 10, 2022 12:48
@github-actions
Copy link
Contributor

The release ZIP for this PR is accessible via:

https://wcblocks.wpcomstaging.com/wp-content/uploads/woocommerce-gutenberg-products-block-7651.zip

@github-actions
Copy link
Contributor

github-actions bot commented Nov 10, 2022

TypeScript Errors Report

Files with errors: 431
Total errors: 2072

🎉 🎉 This PR does not introduce new TS errors.

@kmanijak kmanijak changed the title Fix: skewed placeholder of product image #7642 Fix: skewed placeholder of product image issue#7642 Nov 10, 2022
@kmanijak kmanijak changed the title Fix: skewed placeholder of product image issue#7642 Fix: skewed placeholder of product image - issue#7553 Nov 10, 2022
@github-actions
Copy link
Contributor

github-actions bot commented Nov 10, 2022

Size Change: -58 B (0%)

Total Size: 991 kB

Filename Size Change
build/all-products-frontend.js 26.4 kB +1 B (0%)
build/all-products.js 33.5 kB -11 B (0%)
build/cart-blocks/cart-cross-sells-products-frontend.js 4.67 kB -12 B (0%)
build/cart-frontend.js 54.5 kB +2 B (0%)
build/cart.js 46.3 kB -13 B (0%)
build/product-image-frontend.js 1.9 kB -13 B (-1%)
build/product-image.js 3.92 kB -13 B (0%)
build/single-product-frontend.js 32.2 kB +1 B (0%)
ℹ️ View Unchanged
Filename Size
build/active-filters-frontend.js 7.74 kB
build/active-filters-wrapper-frontend.js 6.02 kB
build/active-filters.js 7.32 kB
build/all-reviews.js 7.79 kB
build/attribute-filter-frontend.js 22.6 kB
build/attribute-filter-wrapper-frontend.js 7.13 kB
build/attribute-filter.js 12.2 kB
build/blocks-checkout.js 18.5 kB
build/cart-blocks/cart-accepted-payment-methods-frontend.js 1.37 kB
build/cart-blocks/cart-cross-sells-frontend.js 253 B
build/cart-blocks/cart-cross-sells-products--product-add-to-cart-frontend.js 5.47 kB
build/cart-blocks/cart-express-payment--checkout-blocks/express-payment-frontend.js 5.01 kB
build/cart-blocks/cart-express-payment-frontend.js 764 B
build/cart-blocks/cart-items-frontend.js 298 B
build/cart-blocks/cart-line-items--mini-cart-contents-block/products-table-frontend.js 5.29 kB
build/cart-blocks/cart-line-items-frontend.js 1.07 kB
build/cart-blocks/cart-order-summary-frontend.js 1.11 kB
build/cart-blocks/cart-totals-frontend.js 320 B
build/cart-blocks/empty-cart-frontend.js 346 B
build/cart-blocks/filled-cart-frontend.js 783 B
build/cart-blocks/order-summary-coupon-form-frontend.js 1.73 kB
build/cart-blocks/order-summary-discount-frontend.js 2.16 kB
build/cart-blocks/order-summary-fee-frontend.js 273 B
build/cart-blocks/order-summary-heading-frontend.js 455 B
build/cart-blocks/order-summary-shipping--checkout-blocks/order-summary-shipping-frontend.js 5.66 kB
build/cart-blocks/order-summary-shipping-frontend.js 428 B
build/cart-blocks/order-summary-subtotal-frontend.js 273 B
build/cart-blocks/order-summary-taxes-frontend.js 433 B
build/cart-blocks/proceed-to-checkout-frontend.js 1.19 kB
build/checkout-blocks/actions-frontend.js 1.77 kB
build/checkout-blocks/billing-address--checkout-blocks/shipping-address-frontend.js 3.9 kB
build/checkout-blocks/billing-address-frontend.js 952 B
build/checkout-blocks/contact-information-frontend.js 1.77 kB
build/checkout-blocks/express-payment-frontend.js 1.12 kB
build/checkout-blocks/fields-frontend.js 343 B
build/checkout-blocks/order-note-frontend.js 1.14 kB
build/checkout-blocks/order-summary-cart-items-frontend.js 3.67 kB
build/checkout-blocks/order-summary-coupon-form-frontend.js 1.89 kB
build/checkout-blocks/order-summary-discount-frontend.js 2.28 kB
build/checkout-blocks/order-summary-fee-frontend.js 275 B
build/checkout-blocks/order-summary-frontend.js 1.11 kB
build/checkout-blocks/order-summary-shipping-frontend.js 603 B
build/checkout-blocks/order-summary-subtotal-frontend.js 273 B
build/checkout-blocks/order-summary-taxes-frontend.js 433 B
build/checkout-blocks/payment-frontend.js 7.77 kB
build/checkout-blocks/shipping-address-frontend.js 1.06 kB
build/checkout-blocks/shipping-methods-frontend.js 4.89 kB
build/checkout-blocks/terms-frontend.js 1.63 kB
build/checkout-blocks/totals-frontend.js 323 B
build/checkout-frontend.js 56.6 kB
build/checkout.js 40.3 kB
build/featured-category.js 13.2 kB
build/featured-product.js 13.4 kB
build/filter-wrapper-frontend.js 13.8 kB
build/filter-wrapper.js 2.41 kB
build/general-style-rtl.css 1.29 kB
build/general-style.css 1.29 kB
build/handpicked-products.js 7.29 kB
build/legacy-template.js 2.84 kB
build/mini-cart-component-frontend.js 20 kB
build/mini-cart-contents-block/empty-cart-frontend.js 366 B
build/mini-cart-contents-block/filled-cart-frontend.js 230 B
build/mini-cart-contents-block/footer-frontend.js 2.97 kB
build/mini-cart-contents-block/items-frontend.js 237 B
build/mini-cart-contents-block/products-table-frontend.js 591 B
build/mini-cart-contents-block/shopping-button-frontend.js 288 B
build/mini-cart-contents-block/title-frontend.js 368 B
build/mini-cart-contents.js 17.1 kB
build/mini-cart-frontend.js 1.77 kB
build/mini-cart.js 4.29 kB
build/price-filter-frontend.js 13.6 kB
build/price-filter-wrapper-frontend.js 7.01 kB
build/price-filter.js 8.37 kB
build/price-format.js 1.19 kB
build/product-add-to-cart--product-button--product-category-list--product-image--product-price--product-r--a0326d00.js 226 B
build/product-add-to-cart--product-button--product-image--product-rating--product-title.js 151 B
build/product-add-to-cart-frontend.js 1.25 kB
build/product-add-to-cart.js 8.36 kB
build/product-best-sellers.js 7.62 kB
build/product-button--product-category-list--product-image--product-price--product-rating--product-sale-b--e17c7c01.js 431 B
build/product-button--product-image--product-rating--product-sale-badge--product-title.js 302 B
build/product-button-frontend.js 1.89 kB
build/product-button.js 3.82 kB
build/product-categories.js 2.36 kB
build/product-category-list-frontend.js 884 B
build/product-category-list.js 502 B
build/product-category.js 8.62 kB
build/product-new.js 7.63 kB
build/product-on-sale.js 7.95 kB
build/product-price-frontend.js 1.92 kB
build/product-price.js 1.53 kB
build/product-query.js 2.89 kB
build/product-rating-frontend.js 1.2 kB
build/product-rating.js 787 B
build/product-sale-badge-frontend.js 1.15 kB
build/product-sale-badge.js 812 B
build/product-search.js 2.62 kB
build/product-sku-frontend.js 377 B
build/product-sku.js 376 B
build/product-stock-indicator-frontend.js 1.01 kB
build/product-stock-indicator.js 646 B
build/product-summary-frontend.js 1.29 kB
build/product-summary.js 921 B
build/product-tag-list-frontend.js 878 B
build/product-tag-list.js 498 B
build/product-tag.js 8 kB
build/product-title-frontend.js 1.33 kB
build/product-title.js 3.3 kB
build/product-top-rated.js 7.86 kB
build/products-by-attribute.js 8.54 kB
build/rating-filter-frontend.js 7.16 kB
build/rating-filter-wrapper-frontend.js 5.41 kB
build/rating-filter.js 5.79 kB
build/reviews-by-category.js 11.2 kB
build/reviews-by-product.js 12.3 kB
build/reviews-frontend.js 7.01 kB
build/single-product.js 10 kB
build/stock-filter-frontend.js 7.78 kB
build/stock-filter-wrapper-frontend.js 6.03 kB
build/stock-filter.js 6.7 kB
build/vendors--attribute-filter-wrapper--mini-cart-contents-block/footer-frontend.js 6.86 kB
build/vendors--attribute-filter-wrapper-frontend.js 8.22 kB
build/vendors--cart-blocks/cart-cross-sells-products--cart-blocks/cart-line-items--cart-blocks/cart-order--671ca56f-frontend.js 5.26 kB
build/vendors--cart-blocks/cart-cross-sells-products--cart-blocks/order-summary-shipping--checkout-blocks--18f9376a-frontend.js 19.1 kB
build/vendors--cart-blocks/cart-cross-sells-products--product-add-to-cart-frontend.js 7.53 kB
build/vendors--cart-blocks/cart-line-items--checkout-blocks/order-summary-cart-items--mini-cart-contents---233ab542-frontend.js 3.14 kB
build/vendors--cart-blocks/order-summary-shipping--checkout-blocks/billing-address--checkout-blocks/order--5b8feb0b-frontend.js 4.85 kB
build/wc-blocks-data.js 18.5 kB
build/wc-blocks-editor-style-rtl.css 5.24 kB
build/wc-blocks-editor-style.css 5.24 kB
build/wc-blocks-google-analytics.js 1.56 kB
build/wc-blocks-middleware.js 931 B
build/wc-blocks-registry.js 2.92 kB
build/wc-blocks-shared-context.js 1.51 kB
build/wc-blocks-shared-hocs.js 1.72 kB
build/wc-blocks-style-rtl.css 24.2 kB
build/wc-blocks-style.css 24.2 kB
build/wc-blocks-vendors-style-rtl.css 1.95 kB
build/wc-blocks-vendors-style.css 1.95 kB
build/wc-blocks-vendors.js 62.4 kB
build/wc-blocks.js 2.63 kB
build/wc-payment-method-bacs.js 816 B
build/wc-payment-method-cheque.js 811 B
build/wc-payment-method-cod.js 909 B
build/wc-payment-method-paypal.js 837 B
build/wc-settings.js 2.6 kB

compressed-size-action

@kmanijak kmanijak added the type: bug The issue/PR concerns a confirmed bug. label Nov 10, 2022
@kmanijak kmanijak self-assigned this Nov 10, 2022
Copy link
Contributor

@sunyatasattva sunyatasattva left a comment

Choose a reason for hiding this comment

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

I've got just a small question, otherwise it looks amazing! Great PR description!

<ProductDataContextProvider product={ productWithImages }>
<ProductDataContextProvider
product={ productWithImages }
isLoading={ false }
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you clarify why isLoading is hardcoded to false in the context of this test, and why was it needed to be added as a fix for this issue? 🤔

Copy link
Contributor Author

@kmanijak kmanijak Nov 11, 2022

Choose a reason for hiding this comment

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

Can you clarify why isLoading is hardcoded to false in the context of this test

Sure! I added isLoading prop to each test, as I realised it's a required prop for ProductDataContextProvider and TypeScript checker complained about that.
And considering the tests are checking the behaviour of component with images loaded already, I checked the code and isLoading passed as false seems to set such condition. Also, there's no default value for isLoading, so before adding that to tests, it was implicitly falsy.
But I may be missing something, so I'm all ears if you see that may be troublesome! 👂

and why was it needed to be added as a fix for this issue? 🤔

TS fixes/improvements were added as an extra to this PR and are not required as a fix for issue. I gathered them in a separate commit, but maybe I should've added it as a separate PR to avoid confusion. Let me know the way forward 🙌
EDIT: Or add it to the PR description in "Changes" section. Will keep that in mind for future.

return (
<img src={ PLACEHOLDER_IMG_SRC } alt="" width={ 500 } height={ 500 } />
);
return <img src={ PLACEHOLDER_IMG_SRC } alt="" />;
Copy link
Contributor

Choose a reason for hiding this comment

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

I saw that alt prop was already empty before, but I'm wondering if it would be better to add some text to explicitly say it is a placeholder image instead. What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

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

Super-duper agreed!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you for this suggestion! I was thinking about that, but then in a test I spotted the placeholder is searched by the empty alt:

const placeholderImage = component.getByAltText( '' );

and assumed it may be empty for a reason. But two aye!s are enough to convince me! 💪

I'll double-check there's no other logic based on that and provide it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Alt text added in the commit.

I considered what should be the alt text:

  • what's really on the image, like "Simple landscape drawing"
  • what's the purpose, like "Generic placeholder", since in this case it doesn't really matter what's there
  • something else

I went for a second option since the image itself is set externally through the settings and may change over time. Also, the content is kind of redundant in this context, the purpose matters. There are even opinions that placeholder image doesn't need alt text at all (https://www.seroundtable.com/google-alt-text-small-images-23672.html - thanks @imanish003 for sharing that! 🙌 ), but I'm not convinced.

Happy to hear your opinion!

Copy link
Contributor

Choose a reason for hiding this comment

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

Great work @kmanijak. I think it is great that @imanish003 mentioned the fact that placeholder images may not need an alt text and yes I just remembered that are some situations in which the alt text must be empty, but I cannot remember from the top of my mind all those situations so I went ahead looking for resources related to that.

I found this alt Decision Tree from the W3C Web Accessibility Initiative (WAI) that I think we can use to make this decision: https://www.w3.org/WAI/tutorials/images/decision-tree/. It seems that if we consider the placeholder image as being just decorative or not intended for the user the best solution would be to leave it empty. Here is also a resource talking about Decorative Images: https://www.w3.org/WAI/tutorials/images/decorative/, it states that "Text values for these types of images would add audible clutter to screen reader output or could distract users if the topic is different from that in adjacent text", which is something I can agree since we can have dozens of placeholder images that is going to be read by the screen readers.

Copy link
Contributor

Choose a reason for hiding this comment

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

This was a very interesting discussion. After reading it, I agree that alt text would add audible clutter to screen reader users. People do not need to hear over and over about the placeholder image which is there just to keep the layout, actually. Does not add any information.

I agree with removing it. Sorry @kmanijak for the extra work. But it's a good opportunity also because I saw there were some mistakes in the implementation which we take for granted and it's a good time to inform you about them. We never use naked strings in either JS or PHP code, we always use WordPress localization functions.

Here are two resources:

Most generally, you will see that you'll often find yourself using the __ function.

With that said, I think we should make this decision of leaving the alt text empty explicit by adding a comment in the relevant places, perhaps linking to this discussion thread. Someone else could see the empty alt text and it would be the same story all over again!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you @thealexandrelara and @sunyatasattva for your valuable input! I'm happy with the conclusion.

The changes are available in this commit:

  • remove alt text (especially as an explicit string, thanks Lucio for pointing this out, I'll keep that in mind!)
  • add explicit comments to all the relevant places I found.

Alt text added in this commit is a generic text, not description of the actual image. That's because the image itself is set externally through the settings and may change over time
@kmanijak
Copy link
Contributor Author

@sunyatasattva, I responded to your comments. Happy to hear your opinion regarding alt text of the placeholder image!

Copy link
Contributor

@sunyatasattva sunyatasattva left a comment

Choose a reason for hiding this comment

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

Left a comment in the alt text thread. Sorry for the back and forth.

kmanijak and others added 2 commits November 15, 2022 15:10
… empty alt explicit

After a Github discussion: https://github.com/woocommerce/woocommerce-blocks/pull/7651\#discussion_r1019560494 it was decided the placeholder should NOT have alt text as it serves the purpose of decorative image. According to the guidelines decorative images should not have alt text: https://www.w3.org/WAI/tutorials/images/decorative/. Comments were added also to other places where it happens
@kmanijak
Copy link
Contributor Author

No worries @sunyatasattva, I'm happy we came up with a proper conclusion 🙌

  • I updated the alt text and add explicit comments as suggested
  • left the comment in alt discussion
  • left the comment in isLoading discussion

I'd appreciate another round of review.

Copy link
Contributor

@thealexandrelara thealexandrelara left a comment

Choose a reason for hiding this comment

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

Great work! LGTM!

@github-actions github-actions bot added this to the 9.0.0 milestone Nov 15, 2022
Copy link
Contributor

@sunyatasattva sunyatasattva left a comment

Choose a reason for hiding this comment

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

Excellent! :shipit: !

@kmanijak kmanijak merged commit 6dccf6f into trunk Nov 16, 2022
@kmanijak kmanijak deleted the fix/placeholder-product-image-is-skewed branch November 16, 2022 09:25
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
type: bug The issue/PR concerns a confirmed bug.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants