16

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!

NateW
  • 2,856
  • 5
  • 26
  • 46
  • 1
    @JaredChu I'm just looking to update the colors in this one location that multiple other CSS files read from. So I'm asking how to update the variables, not override them. Thanks though! – NateW Apr 21 '17 at 17:24
  • Are you using PostCSS to deal with CSS variables or just using them natively? If PostCSS, what's your current PostCSS plugin stack? – Andrea Carraro May 01 '17 at 08:32
  • @toomuchdesign CSS variables are supported in CSS3 [See the browser support for CSS variables here](http://caniuse.com/#search=CSS%20Variables) but there are a little gap of 12,3% of the browsers there are in use not support it yet – TheCrazyProfessor May 03 '17 at 09:29
  • 1
    Did my solution not work for you? Just noticed you unselected it as the accepted solution. – Michael Coker Jul 01 '17 at 00:00
  • Hey Michael, thanks for following up! I'm using React and a don't want to do 'if / else' statements for css for all of my components for picking the CSS. So though your answer does work, it's not ideal and I'm hoping for a cleaner solution where I just update the values in the CSS and all the components reading from it will automatically update. Did unselecting your answer make you lose points? If so, I'll accept it again. Just hoping to get an answer that's super clean for my project. – NateW Jul 01 '17 at 00:48

3 Answers3

12

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>
Michael Coker
  • 52,626
  • 5
  • 64
  • 64
4

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}
Anthony Cregan
  • 960
  • 11
  • 25
3

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>
Avivbuen
  • 128
  • 9