Alex
Alex

Reputation: 185

How to set JavaScript and SASS constants in the same place?

Sometimes it's necessary to set some constants twice: in SASS and in JS (for better performance for example). Is anyone knows solution for synchronizing SASS/SCSS and JavaScript variables to have access to SCSS variables from JavaScript or from SASS to JavaScript?

Upvotes: 3

Views: 2654

Answers (3)

Daniel
Daniel

Reputation: 1601

In case you are using webpack and CSS Modules and SASS (for example with React), you can just use :export pseudoselector, as described here or here

Upvotes: 0

sam
sam

Reputation: 40698

You could try writing JSON in a SASS/CSS comment block:

/*
    {
        "blue"  : "#{$blue}",
        "green" : "#{$green}"
    }

and then extract and parse it on the client.

Upvotes: 0

Fluoxetine
Fluoxetine

Reputation: 195

I know this was asked almost a year ago, but I'm putting this answer up as a reference for the next poor sod who has this problem. There are probably better solutions out there, but this one is the only thing I could find/come up with.

Since JavaScript doesn't seem to be able to get variables from any .scss file directly, we have to use regex to get the desired value from our file. But since we don't want to make it search though our entire SASS file:

Create a SASS file holding your variables

We create a new file, _variables.scss, for JavaScript to search through. Let's say it looks like this:

$menuMobileArrowRotate: 90;
$articleScale: 1.1;

Importing it to our main SASS file

Import it to SASS by adding @import "variables"; near the top of our stylesheet. We can then use these variables throughout our file instead of manually entering values.

Importing it to JavaScript

I'm going to get JavaScript to read _variables.scss and turn it into a string:

var sassVariables = new XMLHttpRequest();
sassVariables.open("GET", 'http://www.use-absolute-url.com/_variables.scss', false);
sassVariables.send(null);

Note: to support IE6 and earlier, replace var xmlhttp = new XMLHttpRequest(); with:

    if (window.XMLHttpRequest) {
      var sassVariables = new XMLHttpRequest();
    }
    else {
      var sassVariables = new ActiveXObject("Microsoft.XMLHTTP");
    }

(Source)

If I set asynch. to true, Firebug shows me an error claiming that fileContent doesn't exist. And since my file is only 4KB, I'm not going to worry too much about potential performance problems by having to wait for it to load.

Now, I'm going to declare my variables:

var fileContent = sassVariables.responseText, //a string holding the contents of my file
    menuMobileArrowRotate = null,
    articleScale = null;

I declared menuMobileArrowRotate and articleScale before I made sure the file actually loaded, since I don't want JavaScript to give me an error and mess everything up just because it didn't load.

If everything loads fine, I'm just going to use RegEx to find out the value of each of my variables. At least I'm only going through a tiny file instead of searching through my entire stylesheet.

if (sassVariables.status === 200) { //if everything loaded nice and dandy
    menuMobileArrowRotate = fileContent.match(/(?:menuMobileArrowRotate.\s*?)(\d+)/)[1];
    articleScale = data.match(/(?:articleScale.\s*?)((\d+)\.*(\d+)*)/)[1];
}

Notice the [1] after .match(): RegEx returns an array, and I only want the first match (which, in my case, is also the only match).

For all the JS put together:

if (window.XMLHttpRequest) {
  var sassVariables = new XMLHttpRequest();
}
else {
  var sassVariables = new ActiveXObject("Microsoft.XMLHTTP");
}

sassVariables.open("GET", 'http://mysite.com/sass/_variables.scss', false);
sassVariables.send(null);
var fileContent = sassVariables.responseText,
    menuMobileArrowRotate = null,
    articleScale = null;

if (sassVariables.status === 200) {
    menuMobileArrowRotate = fileContent.match(/(?:menuMobileArrowRotate.\s*?)(\d+)/)[1];
    articleScale = fileContent.match(/(?:articleScale.\s*?)((\d+)\.*(\d+)*)/)[1];
}
console.log(menuMobileArrowRotate); //shows 90
console.log(articleScale); //shows 1.1

I can now use these variables anywhere in my JavaScript file following this bit of code.

Bonus: media query variables

SASS doesn't let you use a variable in a media query. However, I can make the whole dang query a mixin, and put it in _variables.scss:

@mixin mediaQuery($point) {
  @if $point == 'mobile' {
    @media only screen and (max-width: 600px) { @content; }
  }
  @if $point == 'somethingElse' {
    @media only screen and (max-width: 1000px) { @content; }
  }
}

In style.scss, I can have:

@include mediaQuery(mobile) {
    //blah
}
@include mediaQuery(somethingElse) {
    //blah
}

I can then use the same process to get the desired values (i.e. 600 and 1000), just with different RegEx.

Upvotes: 2

Related Questions