Skip to content

Can CSS be inlined in the server-rendered pages ? #962

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

Closed
Litarvan opened this issue Apr 10, 2021 · 22 comments · Fixed by #2620
Closed

Can CSS be inlined in the server-rendered pages ? #962

Litarvan opened this issue Apr 10, 2021 · 22 comments · Fixed by #2620
Milestone

Comments

@Litarvan
Copy link

Currently, HTML is rendered in the response by the server, but the CSS is linked through attributes, thus delaying proper page rendering until the stylesheet request is done.

Is it possible to inline CSS (or at least the 'start' stylesheet) like Next.JS does? Or is it planned?

@Maggi64
Copy link

Maggi64 commented Apr 11, 2021

CSS loading got worse in comparison to sapper i think.
With the migration to sveltekit i saw a loss in 18 lighthouse points.
This seems mostly related to more css files that need to be loaded.
I can provide more detailed info if needed.

Sveltekit

image

image

Sapper

image

@benmccann
Copy link
Member

benmccann commented Apr 13, 2021

This seems mostly related to more css files that need to be loaded.

Sapper used rollup-plugin-css-chunks to chunk the CSS files in the same way that the JS files were chunked. Vite is most compatible with Rollup plugins, so potentially you could include that in your build. If that doesn't work, you'd have to put in a feature request over in that repo if you'd like to see that behavior added to Vite

@andreiborisov
Copy link

andreiborisov commented Apr 17, 2021

Inlining critical CSS is a huge win for perceived performance, even when loading assets through HTTP/2. I'd say this is a crucial feature on the road to SvelteKit's production-ready status.

Worth mentioning that it's needed both for SSR and static pages.

@Maggi64
Copy link

Maggi64 commented Apr 18, 2021

Sapper used rollup-plugin-css-chunks to chunk the CSS files in the same way that the JS files were chunked. Vite is most compatible with Rollup plugins, so potentially you could include that in your build.

Sadly didn't work. I tried to disable vite css splitting, but it doesn't seem to respect my config settings.

@andreiborisov
Copy link

I've successfully mitigated the issue by using HTTP/2 Server Push, depending on your backend, you might wanna look into that

@mvolfik
Copy link
Contributor

mvolfik commented May 30, 2021

Interesting to note, CSS is inlined when using dev server, but not during build (adapter-static in my case)

@mehdiraized
Copy link

i use postcss config in sveltekit starter but not work in build project

@livehtml

This comment has been minimized.

@Rich-Harris
Copy link
Member

As of the most recent version, you can inline stylesheets smaller than a certain size with the inlineStyleThreshold option:

// svelte.config.js
export default {
  kit: {
    // inline all stylesheets smaller than 1kb
    inlineStyleThreshold: 1024
  }
};

@julienchazal
Copy link

thx @Rich-Harris !

CSS is inlined, but is it normal that in the HTML still appears :

<link disabled rel="stylesheet" href="/_app/assets/index-f3af5aa6.css">

Chrome is loading this CSS file, and it contains CSS that has been inlined

@gerardo-rodriguez
Copy link

As of the most recent version, you can inline stylesheets smaller than a certain size with the inlineStyleThreshold option:

// svelte.config.js
export default {
  kit: {
    // inline all stylesheets smaller than 1kb
    inlineStyleThreshold: 1024
  }
};

This is great, @Rich-Harris! 🎉

Does it matter where the source CSS file exists? Does it matter how or where the CSS file is imported? Does the use of an adapter (I'm using @sveltejs/adapter-static) disable the inlineStyleThreshold setting?

I'm setting inlineStyleThreshold to different values (including extremely large values) and I don't see anything getting inlined. I wonder what I'm doing wrong. We are running version 1.0.0-next.254. Is this the best place to ask these types of questions, or should I ask elsewhere? 🤔

My endgoal is to inline both the JS and CSS, I found this CSS option first so figured I'd start there.

Thank you! I've enjoyed using SvelteKit and Svelte so much thus far! 😄

@wiesson
Copy link
Contributor

wiesson commented Feb 26, 2022

I'm setting inlineStyleThreshold to different values (including extremely large values) and I don't see anything getting inlined.

Same here!

@pavelloz
Copy link

pavelloz commented Mar 23, 2022

Im afraid i have the same issue.

With prerender: false it just plain doesnt work.

With prerender true i can find:

  • html file in build directory is wrong, without any CSS inlined
  • html file in .svelte-kit/output/prerendered/output is correct, CSS is inlined. svelte-kit preview shows correct build.

Im using static adapter so it shouldnt matter, but i did the test to see if it will make a difference. And it did, just not in the file that i was expecting to.

=> npx envinfo --npmPackages "{svelte,@sveltejs/*,vite}"           

  npmPackages:
    @sveltejs/adapter-static: next => 1.0.0-next.29 
    @sveltejs/kit: next => 1.0.0-next.302 
    svelte: ^3.46.4 => 3.46.4 

@robots4life
Copy link

robots4life commented Mar 30, 2022

@pavelloz I can confirm with prerender: false it does not work, but I think this is the desired behavior when using the static adapter.

Adapter for SvelteKit apps that prerenders your entire site as a collection of static files. If you'd like to prerender only some pages, you will need to use a different adapter together with the prerender option.

For a site that uses adapter static and has a high value for inlineStyleThreshold I get a build with inline CSS in the head.

svelte.config.js
https://github.com/robots4life/daiki/blob/3a3df50070e147b9a709d9b2d6dbba02c6da361a/svelte.config.js#L21

/build/index.html
https://github.com/robots4life/daiki/blob/c5c24877baa0000a6c98427b243f4ac88db991c6/build/index.html#L9

Don't mind the fact that other adapters are installed, they are not used in the svelte.config.js file. Here are the versions of the pacakges.
npm ls

[email protected] /shared/httpd/daiki
├── @sveltejs/[email protected]
├── @sveltejs/[email protected]
├── @sveltejs/[email protected]
├── @sveltejs/[email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
└── [email protected]

However.. given https://www.filamentgroup.com/lab/load-css-simpler/ I like to change the output of the disabled CSS file from

<link rel="stylesheet" href="/_app/assets/pages/__layout.svelte-01120fe0.css" disabled media="(max-width: 0)">

to

<link rel="stylesheet" href="/_app/assets/pages/__layout.svelte-01120fe0.css" media="print" onload="this.media='all'">

To start, the link's media attribute is set to print. “Print” is a media type that says, “apply this stylesheet’s rules for print-based media,” or in other words, apply them when the user tries to print the page. Admittedly, we want our stylesheet to apply to all media (especially screens) and not just print, but by declaring a media type that doesn’t match the current environment, we can achieve an interesting and useful effect: the browser will load the stylesheet without delaying page rendering, asynchronously! That’s helpful, but it’s not all we want. We also want the CSS to actually apply to the screen environment once it loads. For that, we can use the onload attribute to set the link's media to all when it finishes loading.

Could this be added as a option to the static adapter perhaps ?

@johntron
Copy link

johntron commented Oct 18, 2022

inlineStyleThreshold doesn't work for me either (using adapter-static). There may be a regression if it was working 7 months ago when @robots4life made the commit that worked for him.

I should note that I'm using PostCSS: svelte.config.js

@benmccann benmccann reopened this Oct 21, 2022
@benmccann benmccann added the bug Something isn't working label Oct 21, 2022
@benmccann benmccann added this to the 1.0 milestone Oct 21, 2022
@newsroomdev
Copy link

newsroomdev commented Oct 31, 2022

Thank you for reopening @benmccann.

I did some exploration last night and noticed that the inlineStyleThreshold is always set to 0 after it's returned from the options function in kit/src/core/config/index.js. I believe there may be a bug with the number validator in kit/src/core/config/options.js, despite its similarity to the adjacent string_array and boolean validators. I hope this helps!

@dummdidumm
Copy link
Member

dummdidumm commented Nov 2, 2022

Could someone provide a minimum reproducible so we can look into it? I did set inlineThreshold to an arbitrary high number and ran the build of the SvelteKit site; styles were inlined as expected. Don't get confused by the <link href="..."> tags still present, they are disabled (there should be such an attribute on them) so not actually loaded - it's a hint for Vite to not do funky stuff.

@benmccann benmccann removed the bug Something isn't working label Nov 2, 2022
@The-Noah
Copy link
Contributor

The-Noah commented Nov 3, 2022

The styles inside the link tags are loaded though, if you open DevTools and go to the network tab you can see them being loaded.

@dummdidumm
Copy link
Member

That's strange, I don't see this behavior (using Chrome); according to the spec a disabled link tag should be neither downloaded nor executed. A reproducible would really help.

@The-Noah
Copy link
Contributor

The-Noah commented Nov 3, 2022

#7130

@dummdidumm
Copy link
Member

Thanks, closing in favor of that issue.

@dummdidumm
Copy link
Member

The inline styles being loaded seems to have been a bug in Vite. It fails with 3.1.x, but works with 3.2.x. Updating to the latest version of Vite fixes the bug.

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 a pull request may close this issue.