Is there a way to import variables from javascript to sass or vice versa?

I am making a css grid system that relies on the concept of blocks. So I have a base file like:

$max-columns: 4;
$block-width: 220px;
$block-height: 150px;
$block-margin: 10px;

And it is used by a mixin:

@mixin block ($rows, $columns, $max-columns) {
  display: block;
  float: left;
  margin: $block-margin 0 0 $block-margin;
  box-sizing: border-box;
  width: ($block-width * $columns) - $block-margin;
}

But I'd also like javascript to have access to the variables in the base file. I was thinking that I could make an invisible div, and give it the $block-width, $block-height, and $block-margin attributes and pull the values from there. But max-columns, doesn't map to anything directly, so I'd have to come up with a hacky way to render it in a div. Is there a cleaner way to share values from sass/css to javascript or vice versa?

Answers:

Answer

You can read the sass file with a server side script, "parse" it and echo the values you need to javascript.

Answer

I consider my solution to be quite hokey; but it does work...

In my _base.scss I have some variables defined:

$menu_bg: rgb(45, 45, 45);
$menu_hover: rgb(0, 0, 0);

In a menu.scss I have:

@import "base";

#jquery_vars {
  .menu_bg {
    background-color: $menu_bg;
  }
  .menu_hover {
    background-color: $menu_hover;
  }
}

And in a handy page template:

<span class="is_hidden" id="jquery_vars">
  <span class="is_hidden menu_bg"></span>
  <span class="is_hidden menu_hover"></span>
</span>

Finally this allows in a nearby jQuery script:

var menu_bg = $('#jquery_vars .menu_bg').css("background-color");
var menu_hover = $('#jquery_vars .menu_hover').css("background-color");

This is so ugly my dad is wearing a bag on his head.

jQuery can pull arbitrary CSS values from page elements; but those elements have to exist. I did try pulling some of these values from raw CSS without creating the spans in the HTML and jQuery came up with undefined. Obviously, if these variables are assigned to "real" objects on your page, you don't really need the arbitrary #jquery_vars element. At the same time, one might forget that .sidebar-left nice-menu li is the vital element being use to feed variables to jQuery.

If someone has anything else, it's got to be cleaner than this...

Answer

If you use webpack you can use sass-loader to exportvariables like:

$animation-length-ms: $animation-length + 0ms;

:export {
  animationMillis: $animation-length-ms;
}

and import them like

import styles from '../styles/animation.scss'    
const millis = parseInt(styles.animationMillis)

https://blog.bluematador.com/posts/how-to-share-variables-between-js-and-sass/

Answer

I would like to add that there are now several ways to share data between Sass and JavaScript using JSON. Here are some links to articles detailing various techniques:

It's probably just a matter of time until JSON importing becomes supported natively in Sass.

Answer

I would recommend looking at sass-extract which uses native sass features in order to extract the computed variable values into JSON.

Also if you are using webpack the sass-extract-loader will make it very easy to just require/import the sass files as in const variables = require('sass-extract-loader!./variables.scss'); and have your sass variables in a nice JSON object.

Since it also supports @import statements you can still separate your variables in different files, and no need to add additional preprocessing or separate json files with variables.

There are many alternative ways of accomplishing this as mentioned in other answers, and which one you choose will depend on your use case and environment.

Disclaimer, I am the author of both mentioned libraries.

Answer

Another way could be to use gulp-template so you can generate any structure you want for your JavaScript.

Sharing Variables between Javascript and Sass using Gulp with gulp-template https://youtu.be/UVeUq8gMYco

It's created from scratch so people could see it from the ground up and there is a git repo with the end result:

https://github.com/PocketNinjaCoUk/shared-js-sass-vars-using-gulp/tree/master/dev

You basically have your config object

saved at ./dev/config.js

module.exports = {
  defaults: {
    colours: {
      primary: '#fc0'
    },
    sizes: {
      small: '100px',
      medium: '500px',
      large: '1000px'
    },
    zIndex: {
      model: 100,
      dropdown: 50,
      header: 10
    }
  }
}

Then you have both of your templates for Sass and Javascript, or less or whatever you want.

Sass underscore template

saved at ./dev/templates/sass-config.txt

<% _.each(defaults, function(category, key) { %>
  // Var <%= key %>
  <% _.each(category, function(value, key) { %>
    $<%= key %>: <%= value %>;
  <% }) %>
<% }) %>

Javascript underscore template

saved at ./dev/templates/js-config.txt

namespace.config = {};

<% _.each(defaults, function(monkey, key) { %>
  namespace.config.<%= key %> = {
  <% i = 1 %>
  <% _.each(monkey, function(value, key) { %>
    <% comma = (Object.keys(monkey).length === i) ? '': ',' %>
    <% if(typeof value === 'string') {%>
      <%= key %>: '<%= value %>'<%= comma %>
    <%} else { %>
      <%= key %> : <%= value %><%= comma %>
    <% } %>
    <% i++ %>
  <% }); %>
  };
<% }) %>

Then the gulp to compile it

var gulp = require('gulp');
var template = require('gulp-template');
var rename = require('gulp-rename');
var removeEmptyLines  = require('gulp-remove-empty-lines');

var sharedVars = require('./dev/config');

gulp.task('compile', function() {
  gulp.src('./dev/templates/sass-config.txt')
    .pipe(template(sharedVars))
    .pipe(rename('_sass-config.scss'))
    .pipe(removeEmptyLines())
    .pipe(gulp.dest('./dev/sass'));

  gulp.src('./dev/templates/js-config.txt')
    .pipe(template(sharedVars))
    .pipe(rename('js-config.js'))
    .pipe(removeEmptyLines())
    .pipe(gulp.dest('./dev/js'));
});
Answer

sass-ffi should do the trick, but the opposite way (from JS to SASS/SCSS). It will define a function called ffi-require, which allows you to require .js files from SASS:

config.js:

module.exports = {
     maxColumns: 4,
};

style.scss:

$max-columns: ffi-require('./config', 'maxColumns');

Works with sass-loader (webpack) and node-sass.

Answer

This can be done using gulp-sass-vars-to-js. It generates a .js file from your .scss file. The .js file contains all variables declared in your .scss file. You can then 'require' this generated js into your .js

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.