syuichi-tsuji
1/27/2015 - 1:42 PM

JSONを使ってSassとJavaScriptで設定値を共有する方法

JSONを使ってSassとJavaScriptで設定値を共有する方法

{
    "themes": {
        "chrome": {
            "user-agent": "chrome",
            "font-color": "red",
            "background-color": "blue"
        },
        "firefox": {
            "user-agent": "firefox",
            "font-color": "blue",
            "background-color": "white"
        }
    }
}
# requireオプションでsass-json-varsを指定してコンパイル
bundle exec  sass style.scss style.css -r sass-json-vars
@import 'variables.json';

@each $browser, $config in $themes {
  body.#{$browser} {
    content: "#{$browser}";
    color: map-get($config, font-color);
    background-color: map-get($config, background-color);
  }
}
# package.json
{
  "name": "gulp-json-sass-sample",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "gulp": "^3.8.10"
  },
  "devDependencies": {
    "gulp": "^3.8.10",
    "gulp-json-sass": "^0.0.2",
    "gulp-sass": "^1.3.1",
    "gulp-concat": "^2.4.3"
  }
}
$themes-chrome-user-agent: chrome;
$themes-chrome-font-color: red;
$themes-chrome-background-color: blue;
$themes-firefox-user-agent: firefox;
$themes-firefox-font-color: blue;
$themes-firefox-background-color: white;
%theme-chrome {
  content: "#{$themes-chrome-user-agent}";
  color: "#{$themes-chrome-font-color}";
  background-color: "#{$themes-chrome-background-color}";
}

%theme-firefox {
  content: "#{$themes-firefox-user-agent}";
  color: "#{$themes-firefox-font-color}";
  background-color: "#{$themes-firefox-background-color}";
}

@mixin set-theme($ua) {
  @extend %theme-#{$ua};
}

$ua: 'chrome' 'firefox';
@each $val in $ua {
  body.#{$val} {
    @include set-theme($val);
  }
}
body.chrome {
  content: "chrome";
  color: "red";
  background-color: "blue"; }

body.firefox {
  content: "firefox";
  color: "blue";
  background-color: "white"; }
  
# 適当なproject作成
bundle exec compass create sample

# 以下のような構成
├── Gemfile
├── Gemfile.lock
└──sample
    ├── config.rb
    ├── sass
    │   ├── ie.scss
    │   ├── print.scss
    │   ├── screen.scss
    │   ├── style.scss
    │   └── variables.json
    └── stylesheets
        ├── SassyJSON
        ├── ie.css
        ├── print.css
        ├── screen.css
        └── style.css

# コンパイル
bundle exec compass compile sample
@import 'SassyJSON';
// パラメーターに指定した変数名にjson値が格納されている
@import 'variables.json?themes';

@each $key, $theme  in $themes {
  @each $browser, $config in $theme {
    body.#{$browser} {
        content: "#{$browser}";
        color: map-get($config, font-color);
        background-color: map-get($config, background-color);
    }
  }
}
/* line 6, ../sass/style.scss */
body.chrome {
  content: "chrome";
  color: red;
  background-color: blue;
}

/* line 6, ../sass/style.scss */
body.firefox {
  content: "firefox";
  color: blue;
  background-color: white;
}
.output {
    content: json_encode($variables);
}
var gulp = require('gulp'),
    jsonSass = require('gulp-json-sass'),
    concat = require('gulp-concat'),
    sass = require('gulp-sass');

gulp.task('default', function() {
  return gulp
    .src(['variables.json', 'style.scss'])
    .pipe(jsonSass({
        delim: '-',
        sass: false,
        ignoreJsonErrors: true,
        escapeIllegalCharacters: true,
        prefixFirstNumericCharacter: true,
        firstCharacter: '_'
    }))
    .pipe(concat('style.scss'))
    .pipe(sass())
    .pipe(gulp.dest('./stylesheets'));
});

JSONを使ってSassとJavaScriptで設定値を共有する方法を調べてみた

cssのプロパティをJavaScriptでも扱う必要があり、方法を検討してみた。 管理するデータを一つにして、JavaScriptからも参照できると、便利そう。 ということで、データをJSON形式でデータを持たせて、 データをSassのMap型にコンバートして扱うことができれば、実現可能そうなので、 変換するmoduleなどを調べてみた。

例えば以下のようなjsonがあった場合でそれぞれのパターンを試してみた。

# variables.json
{
    "themes": {
        "chrome": {
            "user-agent": "chrome",
            "font-color": "red",
            "background-color": "blue"
        },
        "firefox": {
            "user-agent": "firefox",
            "font-color": "blue",
            "background-color": "white"
        }
    }
}

Compass を使っているプロジェクトの場合

compass extentionとして提供されている、SassyJSON を使う。 rubygems.orgよりもGitHubから取得したほうが最新っぽいので、注意したほうが良さそう。

# 適当なproject作成
bundle exec compass create sample

# 以下のような構成
├── Gemfile
├── Gemfile.lock
└──sample
    ├── config.rb
    ├── sass
    │   ├── ie.scss
    │   ├── print.scss
    │   ├── screen.scss
    │   ├── style.scss
    │   └── variables.json
    └── stylesheets
        ├── SassyJSON
        ├── ie.css
        ├── print.css
        ├── screen.css
        └── style.css

# コンパイル
bundle exec compass compile sample

sassは以下のようになり

@import 'SassyJSON';
// パラメーターに指定した変数名にjson値が格納されている
@import 'variables.json?themes';

@each $key, $theme  in $themes {
    @each $browser, $config in $theme {
            body.#{$browser} {
                content: "#{$browser}";
                color: map-get($config, font-color);
                background-color: map-get($config, background-color);
            }
    }
}

コンパイルすると、

/* line 6, ../sass/style.scss */
body.chrome {
  content: "chrome";
  color: red;
  background-color: blue;
}

/* line 6, ../sass/style.scss */
body.firefox {
  content: "firefox";
  color: blue;
  background-color: white;
}

json_encodeメソッドもあるので、contentプロパティ値にJSONの値を持たせることもで、 view側にもstyleとして出力もできそう。


.output {
    content: json_encode($variables);
    }

Ruby プロジェクトの場合

sass-json-varsが良さそう。 JSONのネスト構造もmapに変換してくれて、jsonをそのままsass変数に変換してくれそうなので、 直感的で使いやすそう。

# requireオプションでsass-json-varsを指定してコンパイル
bundle exec  sass style.scss style.css -r sass-json-vars

sassは以下のようになり

@import 'variables.json';

@each $browser, $config in $themes {
    body.#{$browser} {
            content: "#{$browser}";
            color: map-get($config, font-color);
            background-color: map-get($config, background-color);
    }
}

そのほか

ビルドツールを使って、コンパイルする。 この場合は、gulp plugin gulp-json-sass がある。

JSONをsass変数に変換するだけなので、sassファイルの結合とコンパイルには別のプラグインが必要。 今回は次のような感じでつかってみた。

# package.json
{
  "name": "gulp-json-sass-sample",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "gulp": "^3.8.10"
  },
  "devDependencies": {
    "gulp": "^3.8.10",
    "gulp-json-sass": "^0.0.2",
    "gulp-sass": "^1.3.1",
    "gulp-concat": "^2.4.3"
  }
}
# gulpfile.js
var gulp = require('gulp'),
    jsonSass = require('gulp-json-sass'),
    concat = require('gulp-concat'),
    sass = require('gulp-sass');

gulp.task('default', function() {
  return gulp
    .src(['variables.json', 'style.scss'])
    .pipe(jsonSass({
        delim: '-',
        sass: false,
        ignoreJsonErrors: true,
        escapeIllegalCharacters: true,
        prefixFirstNumericCharacter: true,
        firstCharacter: '_'
    }))
    .pipe(concat('style.scss'))
//    .pipe(sass())
    .pipe(gulp.dest('./stylesheets'));
});

gulp-json-sassでJSONをsass変数にconvertできるが、 map形式にはならないのでJSONの構造を考量しておく必要がありそう。

デフォルトのままだと、次のようにconvertされる

$themes-chrome-user-agent: chrome;
$themes-chrome-font-color: red;
$themes-chrome-background-color: blue;
$themes-firefox-user-agent: firefox;
$themes-firefox-font-color: blue;
$themes-firefox-background-color: white;

ということなので、以下のsassファイルとgulp-concatで結合させて

%theme-chrome {
    content: "#{$themes-chrome-user-agent}";
    color: "#{$themes-chrome-font-color}";
    background-color: "#{$themes-chrome-background-color}";
}

%theme-firefox {
    content: "#{$themes-firefox-user-agent}";
    color: "#{$themes-firefox-font-color}";
    background-color: "#{$themes-firefox-background-color}";
}

@mixin set-theme($ua) {
    @extend %theme-#{$ua};
}

$ua: 'chrome' 'firefox';
@each $val in $ua {
    body.#{$val} {
        @include set-theme($val);
    }
}

gulp-sassでコンパイルする

body.chrome {
  content: "chrome";
  color: "red";
  background-color: "blue"; }

body.firefox {
  content: "firefox";
  color: "blue";
  background-color: "white"; }

他にもあるかもしれないけど、現状こんな感じでしょうか。