Skip to content Skip to sidebar Skip to footer

What's The Industry Standard Way To Pass Sass Variable To Javascript?

I have looked around and I've seen one solution where in your html, you'd have a tag dedicated to pass sass variables to javascript. I'm talking about the second answer from Is the

Solution 1:

Not sure about "industry standard", but it's a very handy technique and not too difficult. The content of pseudo elements is not available via text() though, you have to use getComputedStyle.

Example using body:after:

Sass (using the compass breakpoint extension):

body:after {
  display: none;

  @include breakpoint($bp-wide) {
    content: "wide";
  }

  @include breakpoint($bp-medium) {
    content: "medium";
  }

  @include breakpoint($bp-small) {
    content: "small";
  }
}

JavaScript:

if (window.getComputedStyle) {
  var mq = window.getComputedStyle(document.body,':after').getPropertyValue('content');
}

if (mq.indexOf('small') !== -1) {
  // do something
}

Credit: I first saw this technique here: https://coderwall.com/p/_ldtkg

Solution 2:

I believe that injecting SASS variables via CSS content property is a very hackish way to do things.

Instead, you can store the variables in a separate location and have them read both by SASS and JS.

First, store a list of breakpoints in a breakpoints.json file:

["0", "300px", "500px", "700px", "900px", "1100px"]

Then use Ruby to read this JSON file and make its contents available as a SASS list via a SASS function. Put this into your Compass config.rb:

sass_options = { :custom => {'breakpoint_file' => 'breakpoints.json'} }

# This creates a SASS function debug() that returns $debug into SASSmoduleSass::Script::Functionsdefbreakpoints# Reading an array of breakpoints into a fileunless breakpoints_array_raw = JSON.load( IO.read( options[:custom]['breakpoint_file'] ))
      raise Sass::SyntaxError.new("Error: Breakpoints file '#{options[:custom]['breakpoint_file']}' does not exist.")
    end# Converting strings in the array to SASS String literals
    breakpoints_array_sassy = breakpoints_array_raw.map { |s| Sass::Script::String.new(s) }

    # Returning the list into SASS
    Sass::Script::List.new( breakpoints_array_sassy, :space )
  endend

In your SASS code, read breakpoints like this:

$breakpoints: breakpoints()

In JS, use jQuery's .get method to request the JSON file like this:

var
  breakpoints = [],
  requestBreakpoints = $.get('breakpoints.json');

requestBreakpoints.done(function (response, textStatus, jqXHR){
    breakpoints = response; // You might want to remove "px" here
});

When i was assembling this setup, I found an existing solution here, but i decided to reimplement it using my favorite SASS tools: Singularity and Breakpoint Slicer.

For your convenience, i've built a proof-of-concept GitHub project with everything set up nicely, featuring some ugly JS code. :)

And here's a live demo!

Solution 3:

Sharing state trough CSS content property seems dirty. I don't like the idea of making extra XHR requests either.

I've thought of building a custom solution that would just compile SASS file and JS module. But it turned out there's an npm package called rosetta. It does exactly that. Formats of output are pretty flexible and it didn't take me long to set it up as a Grunt.js task.

$ npm install rosetta

Here's example Gruntfile.js:

module.exports = function(grunt) {

  // Project configuration.
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
      watch: {
          css: {
              files: ['sass/*.scss', 'sass/lib/*.scss', 'rosetta/*.rose'],
              tasks: ['rosetta', 'compass']
          }
      },
      compass: {
          dist: {
              options: {
                  sassDir: 'sass',
                  cssDir: '../static/css',
                  imagesDir: '../static/img',
                  javascriptsDir: '../static/js'
              }
          }
      },
      rosetta: {
          default: {
             src: ['rosetta/*.rose'],
             options: {
                 jsFormat: 'requirejs',
                 cssFormat: 'scss',
                 jsOut: '../static/js/lib/rosetta.js',
                 cssOut: 'sass/_shared_variables.scss'
             }
          }
      }
  });

  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-compass');
  grunt.loadNpmTasks('rosetta');
  grunt.registerTask('default', ['watch']);

};

And package.json:

{
  "name": "",
  "version": "0.0.0",
  "description": "",
  "main": "Gruntfile.js",
  "dependencies": {
    "grunt": "^0.4.5",
    "grunt-cli": "^0.1.13",
    "grunt-contrib-compass": "^0.9.1",
    "grunt-contrib-watch": "^0.6.1",
    "rosetta": "git+https://github.com/ukolka/rosetta.git"
  },
  "devDependencies": {},
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

After all that you just need to import _shared_variables.scss in SASS and use rosetta.js module in your JavaScript to access common variables. As you make changes to the *.rose files your styles and JS will be updated.

Solution 4:

If you are using GULP or GRUNT (I hope you are using the first one)

This example shows how to do it using gulp:

Define the colors in the gulpfile, or in another file and then import it to your gulpfile, and then you can dynamically build both the SCSS variables and the javascript like so:

variables_template.scss (not to be imported in your main scss file)

...
$colors : ([COLORS])
...

app.js (some js file which holds the colors variable)

var appColors = {[COLORS]};

gulpfile.js

var gulp    = require('gulp'),
    gutil   = require('gulp-util'),
    replace = require('gulp-replace');

var appColors = {
   "red"   : "#d63737",
   "green" : "#69c962"
};

gulp.task('scssVars', ()=>{
    var colorsString = JSON.stringify(appColors);
    colorsString  = colorsString.slice(2,colorsString.length - 2);

    return gulp.src('css/variables_template.scss')
        .pipe(replace(/[COLORS]/g, colorsString ))
        .pipe(rename('variables.scss'))
        .pipe(gulp.dest('/'))
});

// do more of less the same for your app.js, only without renaming, if possible

Similar NPM gulp packages for SCSS variables:

Post a Comment for "What's The Industry Standard Way To Pass Sass Variable To Javascript?"