Home > OS >  Load stylesheet with javascript and localStorage
Load stylesheet with javascript and localStorage

Time:02-08

I'm using a Jekyll website, doesn't really matter because this is a static page, I just write it as additional info.

Desired behavior:

I want to load my stylesheet via javascript, so it can depend of a local stored value, let's say dark and light.

I have done a little test of loading it by JS with the following code (which works).

GREEN

<head>
  ...
  <link rel="stylesheet" href="/assets/css/{{'light'}}.css">
  ...
</head>

This loads the CSS file called "light" as expected.

But now I want to depend of the localStorage, with a variable theme that has light as value. I tried the following:

RED

<head>
  ...
  <script>
    var storedTheme = window.localStorage.getItem('theme'); //Tested and working in console
    theme = storedTheme ? storedTheme : 'light'; //global variable (also readable in console)
  </script>

  <link rel="stylesheet" href="/assets/css/{{theme}}.css"> <!-- cant read global variable -->
  ...
</head>

Using global variables doesn't work, it gives me a 404 error as the stylesheet path is /assets/css/.css.

After that I thought that maybe creating an element would do the trick and I created one manually to test it:

RED

<head>
...
<p id="theme" style="display:none;">dark</p>

<link rel="stylesheet" href="/assets/css/{{document.getElementById('theme').innerHTML}}.css">
...
</head>

And nope, the path still appears as: /assets/css/.css

CodePudding user response:

If you change styles on the <body> you get FOUC (Flash Of Unstyled Content). Try using a close equivalent like <main> and spread it 100% x 100% and <html> and <body> as well, but give them margin and padding of 0 in order to ensure <main> covers them completely.

The [disabled] attribute for the <link> is the best way of toggling them because they are still loaded but inert. Also, in the example there is a function called loadTheme(e) that is loaded on the 'DOMContentLoaded' event which insures that all of the DOM is loaded before hand. The example below will not work because localStorage is blocked on SO. There is a functioning example on Plunker.

/* night.css 
main {
  background: #000;
  color: #fff;
}
*/

/* default.css */
:root {
  height: 100%;
  width: 100%;
  margin: 0;
  padding: 0;
  font: 1ch/1.5 'Segoe UI';
}

body {
  height: 100%;
  width: 100%;
  margin: 0;
  padding: 0;
  font-size: 4ch;
}

main {
  height: 100%;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #fff;
  color: #000;
}

form {
  width: 80vw;
  margin: 20px auto;
}

fieldset {
  width: max-content;
  min-height: 25px;
  margin-left: auto;
  padding: 0 1.5px 1.5px;
  border-radius: 8px;
  background: inherit;
  color: inherit;
}

button {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
  font-size: 4rem;
  text-align: center;
  background: transparent;
  cursor: pointer;
}

#theme::before {
  content: '☀️';
}

.night #theme::before {
  content: '           
  •  Tags:  
  • Related