Show Menu

Interested in contributing?

Submit Post

Share with the biggest community of Svelte enthusiasts in the world

Welcome to Svelte Society, homepage for everything Svelte. Find what you're looking for in the navigation above!

Become a sponsor

Support Svelte Society and get your company featured here. Contact us

recipe  posted by  Enrico Sacchetti

Authoring and importing global CSS

There are a few ways to write global or classic CSS classes without generating scoped CSS hashes.

Note this recipe was authored with Svelte 5 and SvelteKit 2 in mind.

Summary of methods

Method Behaviour
import './styles.css' CSS file is loaded via <link /> appended to <head> when component mounts. It does not get removed when component unmounts.
@import './styles.css' within <style> Prepends './styles.css' inline with component CSS
<svelte:head><link rel="stylesheet" href={stylesheet} /></svelte:head> CSS file is loaded via <link /> appended to <head> when component mounts. It does get removed when component unmounts.
:global() Does not scope selectors defined inline within a component <script>. Styles are added or removed from CSSOM with component lifecycle.
:global {} Same as :global(), but applies to nested selectors.
<style global> Same as :global {}, but applies to all selectors within <style>. Requires a preprocessor.

ESM import (Vite)

<script>
  import './styles.css'
</script>
  • When component mounts, imported styles are appended once to the <head> and will remain there even when the component unmounts or re-mounts.
  • Whether or not the page is prerendered, ESM-style imports will eagerly load in SvelteKit (see data-sveltekit-preload-data).
  • In the production build, Vite will convert the file name styles.css to a generated and hashed name for cache busting.

CSS @import (Vite)

<p>Hello world</p>

<style>
  @import "./style.css";
</style>
  • At build time, imported styles are prepended to the component's stylesheet output.
  • When component mounts, component styles are appended to <head> and remain there even when the component unmounts or re-mounts.
  • Whether or not the page is prerendered, component styles with or without using @import will eagerly load in SvelteKit.
  • When component unmounts, all component styles remain in <head> and kept in the CSSOM.

Manually adding stylesheets via <svelte:head>

<script>
  import stylesheet from './styles.css?url'
</script>

<svelte:head>
  <link rel="stylesheet" href={stylesheet} />
</svelte:head>
  • At build time, Vite will detect explicit url imports (?url) and generate a hashed filename for styles.css, and store the asset filename in the default module assignment (stylesheet in the example above).
  • When the component mounts, <link rel="stylesheet" href={stylesheet} /> gets appended to the <head>.
  • When the component unmounts, <link rel="stylesheet" href={stylesheet} /> gets removed from the <head>.
  • This is useful for theming or lazy-loading styles. Though consider adding stylesheets with this method in your root +layout.svelte along with the media attribute.

Svelte Global styles, inline :global()

<script>
  import Input from '$lib/Input.svelte
</script>

<p>Hello world</p>

<div class="input-wrapper">
  <Input />
</div>

<style>
  :global(p) {
    color: crimson;
  }

  /*
    Scoped global selector trick, this only affects
    styles for elements wrapped with your scoped selector.
  */
  .input-wrapper :global(input) {
    border-color: green;
  }
  .input-wrapper {
    /*
      Optional, remove wrapper from box model.
      Should be used with discretion and on presentational
      elements only.
    */
    display: contents;
  }
</style>
  • :global() marks any wrapped selectors to not received scoped classnames from Svelte.
  • Be cautious since component CSS remains in the CSSOM once mounted, and broad selectors wrapper with :global() may affect other elements on the page.
  • One trick to target wrapped elements and write global selectors that won't impact styles outside the component is to wrap child components with an element and give that a scoped class with a :global() marker on the selector's tail.
  • When using the scoped wrapping selector trick, use display: contents with discretion.

Reference: https://svelte.dev/docs/svelte/global-styles.

Svelte Global styles, :global {} block

<p>Hello world</p>

<style>
  :global {
    p {
      color: crimson;
    }
  }

  p {
    /*
      This has higher specificity than the global selector
      and the paragraph will render with green text.
    */
    color: green;
  }
</style>

Reference: https://svelte.dev/docs/svelte/global-styles.

Internal use

Although there are a few ways to author 'classic' CSS selectors without scoped CSS, it's not necessary to do so when styling components you control and author. Svelte provides a built-in way to scope styles that work with the cascade.

For example:

src/lib/styles.css

/* Global links, (0,0,0) specificity for other global overrides */
:where(a) {
  color: crimson;
}

src/routes/+page.svelte

<script>
  import '$lib/styles.css'
</script>

<p>
  Check out this new recipe!
  <a href="#some-area">Bread recipe</a>
</p>

<style>
  /*
    (0,1,1) specificity after scoped classes are generated
    inherits `color: crimson` from global CSS since `a` is still selectable
  */
  a {
    font-weight: bold;
  }
</style>

References

Newsletter

Stay up to date with the Svelte ecosystem.

  • This Week in Svelte — A weekly roundup of the best tutorials, libraries, and community highlights
  • Featured Jobs — Hand-picked Svelte job opportunities from top companies
  • Community News — Announcements, events, and updates from the Svelte team

Newsletter data is processed by Plunk, our email service provider. See our Privacy Policy.