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

Question about the CSS loading strategy #1392

Open
bakura10 opened this issue Feb 23, 2022 · 16 comments
Open

Question about the CSS loading strategy #1392

bakura10 opened this issue Feb 23, 2022 · 16 comments

Comments

@bakura10
Copy link

Hi,

Disclaimer: I am the developer of Maestrooo themes.

This is not rather a question, but more curiosity targeted to the dev team of Dawn and their own experiments. While splitting JS is a solved problem, CSS is a more complex solution and I am still not super convinced by the approach taken by Dawn (and why we are not doing it here) but I would be curious as I may be missing something here.

As of today, all our themes have a single CSS file (theme.css) containing the whole code. We try to minimize its size and for a full theme we manage to keep it around 35Kb.

Dawn, on the other hand, has a "base.css" file, and per-section (and per-component) CSS files. Generating this base and per-section CSS is not really a problem, but the loading strategy is.

In the case of a single, optimized CSS, loading in the , the browser will block the rendering while downloading the file and render everything once done. This is optimal for UX: there is zero FOUT. With preloading the file can nearly be here instantaneously.

However, on Dawn, each section includes another blocking CSS in front of every sections: https://github.com/Shopify/dawn/blob/main/sections/main-list-collections.liquid#L1

As Shopify only allows two resources per page to be pre-loaded, those cannot.

As a consequence, the browser rendering is being blocked at the start of every sections.

From my understanding, this means that with a single pre-loaded file, the rendering may be blocked for 50ms (for instance) before being able to render the page content.

However, with Dawn strategy, the rendering will be blocked by 50ms (or maybe 40ms, because the "base.css" will be a bit smaller, but the improvement here will be negligeable), but then it will be blocked again at the start of the first section, and as the file will not be preloaded it will incur another 50ms, so way much more than what you would have with a single file.

I know there is a strategy to prevent CSS blocking by using a media print, but of course this is the worse approach as it cause a very bad FOUT.

Am I missing something here, or may the approach taken by Dawn effectively suboptimal?

@Peristyledesignlab
Copy link

Peristyledesignlab commented May 29, 2022

Hi @bakura10,
I have tested both single CSS file approach and with Dawn's approach. I am seeing a huge performance boost in case of a single CSS file. When I use modular CSS in every sections, lighthouse score drops (at least 10 points) and render blocking is reported. Am I correct?
I think best approach will like this ->
Make critical css as inline and remaining in a single file

Does this makes sense?

@bakura10
Copy link
Author

I don't think Dawn approach is the best one when it comes to CSS. The biggest issue actually is more the fact that when you load a CSS it is re-parsed as many times as it is included. If you add several instances of a section that load a CSS, then this CSS will appear duplicated in the inspectors.

With using one CSS file, especially if this one is pretty lightweight and preloaded, I think this offers better performance and dev experience.

@Peristyledesignlab
Copy link

Peristyledesignlab commented May 30, 2022

Hi @bakura10,
Yes, you are correct. Dawn's main CSS file is pretty big in every aspect. I think that's why they have chosen this route (separate modular CSS files for each section). I am creating a lightweight single CSS file and trying to reduce the size within 10KB for all sections for my first theme. Your insights are very helpful for me. Thank you Mr. Michaël Gallego

@bakura10
Copy link
Author

Keeping a whole CSS within 10Kb is really hard if you have more than a few sections. One approach you can try is using Tailwind to keep your CSS super light. It is a different approach of CSS, but can lead to very lightweight stylesheet ;)

@Peristyledesignlab
Copy link

Peristyledesignlab commented May 30, 2022

Hi @bakura10,
Thanks for the tip!. I have already created the commonly used CSS for the sections with a single CSS file (mostly using Tailwind's techniques) and I have improved it for each sections. And I created separate CSS files for page specific components for collection page, product page, Cart page and other pages like Dawn's approach. The main CSS comes around ~8 KB. I did not follow the modular(component like approach) by Dawn.

Still researching to reduce File size :)

@tin-soldier
Copy link

Have tested combining all css files except those in tags or those starting with 'template'. The Lighthouse score went from 88 to 95.

@bakura10
Copy link
Author

Thanks for doing the test, it does not surprise me. I’d say that as long the CSS is less than 35-40Kb, splitting has no benefit.

I also went backward on JS: I realised that splitting file actually resulted in more JS being loaded due to poorer usage of Gzip compression. The same will likely apply to CSS.

@kyle-tully
Copy link

Found this thread while doing a speed optimisation project on a Dawn theme that has loading issues because of this very reason.

@2ten
Copy link

2ten commented Nov 29, 2022

Did anyone test inlining the css in the sections rather than linking? and the effect that had? Is that a viable strategy?

@kyle-tully
Copy link

Did anyone test inlining the css in the sections rather than linking? and the effect that had? Is that a viable strategy?

Yes I inlined one or two critical sections and it helped.

@vfonic
Copy link
Contributor

vfonic commented Dec 20, 2022

I think this is a very important question. I'm searching for a speed-optimized theme to recommend to a client and this is the only reason why I'm hesitant to recommend Dawn.

Can someone from Shopify provide some insight?

ping @eugenekasimov @sofiamatulis @kmeleta
Thank you! 🙏

@bakura10
Copy link
Author

@vfonic , while Dawn may not have taken the best approach here and that there are slightly faster way to do it, it still remains a very fast theme. Any themes from the theme store or Dawn will never be a bottleneck and all are fast enough by default so that they do not cause issue. We are talking about a few ms of potential difference here. Any apps, large image… will have a much larger impact.

@vfonic
Copy link
Contributor

vfonic commented Dec 20, 2022

I've also found this on Shopify community forums:

The Shopify CDN uses HTTP/3 which allows the browser to download multiple resources simultaneously. So this reduces the concern about more network requests.

I'll run a few page speed tests for Dawn and a few other themes just to see for myself. It's not really 1:1 comparison, so let me know if you have some ideas how to run more comparable tests.

The "at least 10 points" difference on page speed score (noted above) is quite a lot of difference in the battle one CSS file vs multiple CSS files.

A bit off-topic: so you'd say that most of the page speed decrease comes from large images and apps? I always thought that one big (S)CSS file was a big contributor to lower page speed scores as well.

@bakura10
Copy link
Author

bakura10 commented Dec 21, 2022

@vfonic, it is quite a difference while being a small one, actually. As said, you should definitely not use this as a criteria for rejecting Dawn (and I am the co-founder of Maestrooo, a company that sell premium theme, who tell you that :D).

First, PageSpeed is unreliable, you can have 10 points in one run, 5 points in another run... Google will only penalize abnormally slow stores. A fast theme vs a slighter faster than fast theme will both be ranked equally good. While, on the other hand, a badly coded app can easily reduce your store by 20, 30 or 40 points for a single app.

Theorically, the approach taken by Dawn is better (only load the files that need based on the sections). In practice, having one file is better for performance (better usage of cache, less reflows...).

One big CSS file is a contributor, but it depends on what "big" is. Any CSS file below 50Kb will likely never be a bottleneck. With features such as preloading (that Shopify allows) the CSS has great probability to be already downloaded before the page starts to fully download. And those 50Kb (which is already big for a CSS, for instance our theme Impact which has tons of sections has a single CSS of around 30Kb) will be a grain of salt compared to all the scripts, images, videos... embedded in a modern online store. A single high quality slideshow image will already weight at least 3 or 4 times the size of a CSS file.

So I really want to emphasize this: I opened this issue because I wanted to discuss about the choices done by Dawn developers, and share my experience and findings from our themes if they can benefit to Dawn as well. But in all cases, Dawn and all other themes are all fast enough to never cause an issue. You should really not use performance as a criteria for your choice of theme: none is slow enough to cause any kind of issue. Rather, spend this time on trying to find if some apps are useful or not, or trying to spend time on custom code to eliminate an app for instance. The wins are magnitude bigger in this area rather than the theme.

@jeremyquinton
Copy link

jeremyquinton commented Feb 22, 2023

I'm very perplexed by the dawn them. A basic page has over 100 requests for css/javascript and image files etc. It's not very performant on slower mobile connections and ranks fairly poorly in google pagespeed insights.

Is there any solution at all to reducing the amount of http requests that are needed.
As an example main-product.liquid below has 8 css files.

{{ 'section-main-product.css' | asset_url | stylesheet_tag }}
{{ 'component-accordion.css' | asset_url | stylesheet_tag }}
{{ 'component-price.css' | asset_url | stylesheet_tag }}
{{ 'component-rte.css' | asset_url | stylesheet_tag }}
{{ 'component-slider.css' | asset_url | stylesheet_tag }}
{{ 'component-rating.css' | asset_url | stylesheet_tag }}
{{ 'component-loading-overlay.css' | asset_url | stylesheet_tag }}
{{ 'component-deferred-media.css' | asset_url | stylesheet_tag }} 

One thing that I could do here is remove all css files and make the css inline or potentially combine all 8 files into one taking 8 http requests to 1. This would cause problems if the css is needed to be edited but in most instances I'm not touching any of the css for development.

Can anyone suggest a them that is super performant aka doesn't have so many requests per page.

@gregjotau
Copy link

@bakura10 have you done more research on this topic?

Lighthouse is complaining about

{{ 'component-list-social.css' | asset_url | stylesheet_tag }}

Ideally it should be loaded only once the customer scrolls down close to the footer (and then be cached by browser for next pages).

I also see that Dawn use the print stylesheet hack ref. https://community.shopify.com/c/technical-q-a/why-is-dawn-theme-importing-css-files-like-this/m-p/1850881:

{%- if settings.predictive_search_enabled -%}

{%- endif -%}

Which at least can be used if you only use social icons in the footer.

Image

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

No branches or pull requests

8 participants