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

10

51

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?

Tranship answered 19/2, 2012 at 23:18 Comment(0)
J
9

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

Judicial answered 19/2, 2012 at 23:36 Comment(0)
Z
26

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/

Zacynthus answered 13/12, 2017 at 15:21 Comment(6)
This! This should be the accepted answer. And I recommend to strip the unit on export like :export { animationMillis: strip-unit($animation-length-ms);} with strip-unit so we can directly use the variable as a number without the need to parse a string.Impenetrability
Perfect sollution!Virgil
Does not work in my environment, running [email protected], [email protected] and [email protected]. The variable styles is logged as undefined, as such I can't access variables declared in :export. Any ideas?Benzo
Same here, it was working fine until I update my dependencies.Tien
@LeonWillens, Julien B any update?Penrose
@ChandlerBing Made some tests with [email protected], [email protected] and [email protected]. Apparently, it only works if the SCSS files that are :exporting values are named like <anything>.modules.scss, else the import results in an undefined value.Benzo
R
14

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...

Recuperate answered 25/6, 2012 at 18:24 Comment(0)
H
11

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.

Hudak answered 13/5, 2019 at 14:32 Comment(0)
J
9

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

Judicial answered 19/2, 2012 at 23:36 Comment(0)
E
4

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.

Essequibo answered 22/10, 2014 at 12:51 Comment(0)
C
3

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.

Cirilla answered 29/1, 2017 at 17:10 Comment(0)
S
2

For ViteJS + React =>

foo.scss => foo.modules.scss

$mobileMax: 720px;

:export {
   mobileMax: #{$mobileMax}
}

Component.jsx

import styles from "./foo.modules.scss";

const { mobileMax } = styles;
Strapping answered 17/3, 2023 at 18:57 Comment(0)
S
0

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'));
});
Sladen answered 24/10, 2016 at 13:34 Comment(0)
K
0

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

Kenner answered 20/1, 2018 at 22:42 Comment(0)
B
0

I think it depends on your context. If u are using node solutions like nextjs or vite, u can import javascript inside your style file using node-sass-json-importer.

Balsamic answered 21/7, 2023 at 20:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.