gulp-ruby-sassでfont-awesomeをコンパイルしたら文字化けした件

  • 5
    いいね
  • 3
    コメント
この記事は最終更新日から1年以上が経過しています。

はじめに

gulp-ruby-sassでfont-awesomeをコンパイルした時に、出力されるcssで文字化けするという現象に遭遇しました。現象とその対処法をまとめてみたので、何かの役に立てば幸いです。なお普通のsassでのコンパイルでも同様に再現しました。

対処法はスマートではない気もするので、もっとよい方法があればご教授ください!

遭遇した環境は以下になります
- windows7
- gulp-ruby-sass": "^2.0.5",
- sass 3.4.4

なお既にissuesに上がっているようです
https://github.com/sass/sass/issues/1395

何をしようとして、何が起こったのか

font-awesomeを使ったmixin()を作成しようと以下のようなコードを書いていました

背景にアイコンを設定する.scss
@mixin bgFontAwesome($content) {
    font-family: FontAwesome;
    content: $content;
    /* ... */
}
.icon {
    &:before {
        @include bgFontAwesome($fa-var-android);
        // 変数はfont-awesome.scss内で既に↓のように定義
        // $fa-var-android: "\f17b";
    }
}

ところがコンパイルしてみると、contentの中が文字化けしていました。
※ブラウザでは問題なくアイコンが表示されています(chromeでのみ確認)。

コンパイルされた.css
.icon:before {
    content: "";
    /* ... */
}

色々試してみた

問題を抽出・整理するために色々と試してみました。

1. mixinをやめて直接変数を指定してみる

1.scss
.icon:before {content: $fa-var-android;}
1.css
.icon:before {content: "";}

文字化けしてしまいました

2. 変数をやめて直接文字列を指定してみる

2.scss
.icon:before {content: "\f17b";}
2.css
.icon:before {content: "\f17b";}

正常にコンパイルされました!

3. mixinの引数に直接文字列を指定してみる

3.scss
.icon:before {@include bgFontAwesome("\f17b");}
3.css
.icon:before {content: "";}

文字化けしてしまいました

4. エスケープを試してみる

4.scss
// mixin側
@mixin bgFontAwesome($content) {
    content: #{$content};
}

// include側
.icon:before {@include bgFontAwesome(#{$fa-var-android});}
4.css
// どちらの場合でも
.icon:before {content: ;}

文字化けしてしまいました

5. mixinの引数に""を使わないでみる

5.scss
.icon:before {@include bgFontAwesome(\f17b);}
5.css
.icon:before {content: \f17b;}

正常にコンパイルされましたが、""で囲まれていないため、そもそも正常に表示されません。

6. 5に加え、mixin内で""を追加するようにしてみる

6.scss
@mixin bgFontAwesome($content) {
    content: unquote("\"") + $content + unquote("\"");
}
.icon:before {@include bgFontAwesome(\f17b);}
6.css
.icon:before {content: "\f17b";}

正常にコンパイルされました!

$fa-var-android: \f17b; のように変数定義してやれば、引数に変数を渡しても動作しました

7. 引数に""を使う代わりにエスケープ\を外し、mixin内でエスケープを追加するようにしてみた

7.scss
@mixin bgFontAwesome($content) {
    // 引数に \ を追加し、全体を "" で囲みなおす
    content: unquote("\"") + unquote(str-insert($content, "\\", 1)) + unquote("\"");
}
.icon:before {@include bgFontAwesome("f17b");}
7.css
.icon:before {content: "\f17b";}

正常にコンパイルされました!

問題と対処法

contentの値としてそのまま出力する分には問題なく、変数や関数などsassの機能を挟むと生じることが分かりました。font-awesomeだからというわけではなく、Asciiコードが含まれる時に再現すると考えられます。

理由については既出のissuesで議論がされているので、そちらをご覧いただければと思います・・・^^;

対処法としては上記6, 7が使えそうです。ですが6のように""を使用しないのは、バージョンによってエラーが出る気がしないでもないので、7の方が安心かもしれません。。(もちろんunquote()メソッド等が使える前提ですが)

ただし6, 7いずれにせよ、せっかくfont-awesomeで定義されている$fa-var-android: "\f17b";のような変数を使用しないか、もしくは再定義しなければなりません。これがスマートではないと述べた理由になります。

終わりに

というわけで、もっと良い案がある、もしくは何か勘違いしていることがあればご指摘いただけると幸いでごわす。