Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Update CSS Module variables from Javascript

I'm using a (now older) version of react-boilerplate which came with CSS Modules. What's nice about them is that you can create variables and import them in other CSS files.

Here's my colors.css file

:root {
  /* Status colors */
  --error: #842A2B;
  --success: #657C59;
  --pending: #666;
  --warning: #7E6939;
}

When I'm importing that file I just have to use at the top of my .css file:

@import 'components/App/colors.css';

I'm looking to have the option for two themes for my website and I would like to be able to dynamically update those variables with Javascript. What's the best way to do this?

Edit: I was hoping there's a way to update the colors.css file and not have to do conditional imports in all the components that draw from two possible css files... let me know if there's a way to do that and if there is I'll change the accepted answer. Thank you to all who answered!

like image 546
NateW Avatar asked Apr 21 '17 00:04

NateW


People also ask

Can you change CSS variables in JavaScript?

CSS variables have access to the DOM, which means that you can change them with JavaScript.

Can you change SCSS variable value dynamically?

We can dynamically update SCSS variables using ReactJS with the help of a project by achieving theme switching of the card component between light and dark theme.

Can you import variables into CSS?

Now, when we wrote all our CSS variables we can import them. Because we import variables in the :root we can import them just once in our common stylesheet style. scss . And then we can use these variables without import in other files that will be imported among common styles.


Video Answer


3 Answers

I would just use the default color vars on the element/body/whatever, then put the alternate theme colors in another class, and toggle the theme class via JS. Here's a demo.

$("button").on("click", function() {
  $("body").toggleClass("foo");
});
body {
  --red: red;
  --blue: blue;
  --yellow: yellow;
  background: #ccc;
  text-align: center;
  font-size: 5em;
}

.foo {
  --red: #ce1126;
  --blue: #68bfe5;
  --yellow: #ffd100;
}

.red {
  color: var(--red);
}

.blue {
  color: var(--blue);
}

.yellow {
  color: var(--yellow);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span class="red">RED</span> <span class="blue">BLUE</span> <span class="yellow">YELLOW</span>
<br>
<button>click me</button>
like image 146
Michael Coker Avatar answered Oct 07 '22 17:10

Michael Coker


I would have 2 sheets and conditionally switch between the two:

colours.scss

:root {
  /* Status colors */
  --error: #842A2B;
  --success: #657C59;
  --pending: #666;
  --warning: #7E6939;
}

otherColours.scss

:root {
  /* Status colors */
  --error: #FF0000;
  --success: #00FF00;
  --pending: #6666FF;
  --warning: #FF00FF;
}

then in your react code import them and use them as you wish:

import styles from 'colours.scss';
import alternativeStyles from 'otherColours.scss';

...

{this.props.useNormalStyle ? styles.myClass : alternativeStyles.myClass}
like image 30
Anthony Cregan Avatar answered Oct 07 '22 18:10

Anthony Cregan


Is this what you are looking for?

      // get the inputs
      const inputs = [].slice.call(document.querySelectorAll('.controls input'));

      // listen for changes
      inputs.forEach(input => input.addEventListener('change', handleUpdate));
      inputs.forEach(input => input.addEventListener('mousemove', handleUpdate));

      function handleUpdate(e) {
        // append 'px' to the end of spacing and blur variables
        const suffix = (this.id === 'base' ? '' : 'px');
        document.documentElement.style.setProperty(`--${this.id}`, this.value + suffix);
      }
:root {
  --base: #ffc600;
  --spacing: 10px;
  --blur: 10px;
}

body {
  text-align: center;
}

img {
  padding: var(--spacing);
  background: var(--base);
  -webkit-filter: blur(var(--blur));
  /* 👴 */
  filter: blur(var(--blur));
}

.hl {
  color: var(--base);
}

/*
        misc styles, nothing to do with CSS variables
      */

body {
  background: #193549;
  color: white;
  font-family: 'helvetica neue', sans-serif;
  font-weight: 100;
  font-size: 50px;
}

.controls {
  margin-bottom: 50px;
}

a {
  color: var(--base);
  text-decoration: none;
}

input {
  width:100px;
}
<h2>Update CSS Variables with <span class='hl'>JS</span></h2>
<div class="controls">
  <label>Spacing:</label>
  <input type="range" id="spacing" min="10" max="200" value="10">

  <label>Blur:</label>
  <input type="range" id="blur" min="0" max="25" value="10">

  <label>Base Color</label>
  <input type="color" id="base" value="#ffc600">
</div>

<img src="http://unsplash.it/800/500?image=899">

<p class="love">😘</p>

<p class="love">Chrome 49+, Firefox 31+</p>
like image 3
Avivbuen Avatar answered Oct 07 '22 16:10

Avivbuen