Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove async CSS pattern where it may introduce layout shifts #2270

Merged
merged 1 commit into from
Mar 3, 2023

Conversation

krzksz
Copy link
Contributor

@krzksz krzksz commented Feb 1, 2023

PR Summary:

This PR removes the usage of asynchronous CSS pattern from stylesheets that may actually be required to render the initial screen. Having those stylesheets as not render blocking leads to unstyled content being shown and shifting when they are downloaded and applied.

Why are these changes introduced?

Marking some of the stylesheets as targeted for printing with media="print" and then switching them to apply for all devices with onload="this.media='all'" is a common pattern that lets developers download additional CSS with low priority and without blocking the initial render. As a rule, this technique should only be applied for styles that do not influence the look of anything that users may see without interacting with the page.

Unfortunately, it seems like this solution ended up in too many places when it comes to Dawn. Below you can see the experiment that I run using WebPageTest where I remove the pattern for some of the stylesheets.

experiment

You may notice the whole Obsessive Attention. Intelligent Effort. shifting to the right in the control run because of asynchronous component-rte.css. This is not the case after applying changes from this PR in the experiment run, improving Cumulative Layout Shift score by 0.065 (95%). This is especially important, because sites need to be below 0.1 to be considered as "Good" within this metric.

What approach did you take?

I analysed all of the occurrences of this pattern and checked if a certain CSS is required to render anything that may be visible for users before they interact with the page.

Other considerations

Initially, I thought that the pattern would have to be removed from everywhere. This could slow down the initial render as pointed out by @siakaramalegos as the browser would have to download more files. Fortunately, there's only a bunch of stylesheets that needed adjusting. I also made multiple tests across different Dawn-based stores and all rendering metrics land within the margin of error.

Decision log

# Decision Alternatives Rationale Downsides
1

Visual impact on existing themes

Parts of the page that relied on styles from asynchronous stylesheets will no longer appear initially unstyled, especially on first visits and/or slower connections.

Testing steps/scenarios

  • Setup page with sections or features that incorrectly used asynchronous styles.
  • Disable caching in the browser, you can also slow down the internet connection using DevTools.
  • Open the page and confirm that with this change above sections and features no longer render partially unstyled.

Demo links

  • Store - There are sections on homepage + Github integration setup for preview.

Checklist

@stufreen
Copy link
Contributor

stufreen commented Feb 15, 2023

I double-checked how this affects the page performance and I agree that it is a net-positive and we should ship it. I created some test themes with the affected sections on the index. As you say, it brings up the CSS files earlier in the network waterfall and reduces CLS. It does seem to increase blocking time but maybe that is to be expected. These lighthouse reports are the clearest examples:

Before
lighthouse - main

After
lighthouse - branch

Related note: I wonder if our pattern of having many small CSS files is hurting us and we should put them in one medium-sized CSS file that can easily be cached. But that's out of scope for this PR.

Let's wait for one of the other devs with more context in the codebase to review for whether there are any other CSS files that should/should not be loaded synchronously instead of async.

@stufreen stufreen self-requested a review February 15, 2023 22:31
stufreen
stufreen previously approved these changes Feb 15, 2023
@ludoboludo ludoboludo self-requested a review February 23, 2023 16:15
Copy link
Contributor

@ludoboludo ludoboludo left a comment

Choose a reason for hiding this comment

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

Looking good 👍 Thanks for doing this.

I think we just need a rebase maybe and removing any calls to component-rte.css.

Comment on lines 3 to 7
{{ 'component-newsletter.css' | asset_url | stylesheet_tag }}
{{ 'component-list-menu.css' | asset_url | stylesheet_tag }}
{{ 'component-list-payment.css' | asset_url | stylesheet_tag }}
{{ 'component-list-social.css' | asset_url | stylesheet_tag }}
{{ 'component-rte.css' | asset_url | stylesheet_tag }}
{{ 'disclosure.css' | asset_url | stylesheet_tag }}
Copy link
Contributor

Choose a reason for hiding this comment

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

component-rte.css is now part of base.css so you might have to do a rebase and remove the calls for this CSS file 👍

Also here in the footer, shouldn't we stick to loading the asset as non blocking ? Since it's at the bottom of the page 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It depends, there are pages with short content where footer is visible right away on desktop. Example: https://theme-dawn-demo.myshopify.com/pages/shipping

Copy link
Contributor

@ludoboludo ludoboludo left a comment

Choose a reason for hiding this comment

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

One last comment 😅

I see two spots that are untouched, featured-product.liquid with the component-deferred-media.css as well as the main-search.liquid page with the component-search.css file.

Should those be updated as well ?
main-search.liquid would see to make sense 🤔
not as sure for featured-product.liquid but since it's a section, it can be anywhere on a page, above and below the fold.

stufreen
stufreen previously approved these changes Mar 1, 2023
@krzksz
Copy link
Contributor Author

krzksz commented Mar 2, 2023

One last comment 😅

I see two spots that are untouched, featured-product.liquid with the component-deferred-media.css as well as the main-search.liquid page with the component-search.css file.

Should those be updated as well ? main-search.liquid would see to make sense 🤔 not as sure for featured-product.liquid but since it's a section, it can be anywhere on a page, above and below the fold.

True, I overlooked them, component-deffered-media.css is needed when there is a product video. I fixed that and it's now aligned with main-product.liquid.

I also tested main-search.liquid and component-search.css is needed to style the input above search results so I made it synchronous as well. Thanks!

@krzksz krzksz requested review from ludoboludo and stufreen March 2, 2023 08:27
Copy link
Contributor

@ludoboludo ludoboludo left a comment

Choose a reason for hiding this comment

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

🚀 Thanks Mateusz 🎉

@krzksz krzksz merged commit 6d4ec13 into main Mar 3, 2023
@krzksz krzksz deleted the async-styles branch March 3, 2023 09:51
uniorusa added a commit to uniorusa/unior-usa-b2b that referenced this pull request Mar 3, 2023
Remove async CSS pattern where it may introduce layout shifts (Shopify#2270)
pangloss added a commit to pangloss/dawn that referenced this pull request Mar 11, 2023
* shopify/main:
  Improve image sizes in the multicolumn section (Shopify#2349)
  Fix the Page section's width.  (Shopify#2364)
  Update 12 translation files (Shopify#2366)
  Removing "my" from cart popup notification (Shopify#2353)
  [Cart.js] Fix fetch url so it's not hard coded (Shopify#2357) (Shopify#2365)
  Update 1 translation file (Shopify#2352)
  Default Follow on Shop to on
  [Header] Add localization selectors (Shopify#2258)
  Remove async CSS pattern where it may introduce layout shifts (Shopify#2270)
  Change rich text section heading to be of type inline_richtext, also moved rte styling into base.css (Shopify#2326)
  Add drawer menu desktop (Shopify#2195)
  Make header image preload and proper width (Shopify#2307)
phapsidesGT pushed a commit to Gravytrain-UK/gt-shopify-dawn-theme that referenced this pull request Sep 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants