Firefox(<49)でもbackground-position-xしたい!~CSS Variablesで再現する


追記(2017/10/17)

Firefox 49ではbackground-position-xが正式サポートされるようになったので、以下のようなワークアラウンドは不要となっています。

以下、昔の内容をそのまま残しています

2次元的にスプライト画像を並べているような場面で便利なbackground-position-x/-yですが、正式なプロパティではなく、IE・Edge・Webkit系では動きますが、Firefoxでは対応していません。

もちろん、background-position x y;とするのが正式ですし、SCSSなどを使えばまとめて生成してしまうこともできなくはないのですが、「CSS Variables」という新規格を使った面白い解決法を見つけたので、それについてまとめてみます。

なお、CSS Variablesの対応ブラウザは少し前からのFirefoxと最新のWebkit/Blink系で、MS系が非対応なので、「これを使って積極的に何か組む」にはまだ向いていません。

カスタムプロパティの宣言

CSS Variablesでのカスタムプロパティは、--abc: value;のような形で、ふつうのCSSプロパティと同様に宣言します。最初はハイフン2つで、残りのプロパティ名では大文字・小文字の区別があります。

そして、このカスタムプロパティも他のCSSプロパティ同様に、継承されます。

カスタムプロパティの継承
:root{
  --hoge: 2px;
}

ul{
  --hoge: 10px;
}

このように書いた場合、ulの外では--hoge: 2px;に、中では--hoge: 10px;になります。このように継承することが、使う分には重要なポイントとなってきます。

カスタムプロパティを使う

カスタムプロパティは、他のCSSプロパティのとして、var(カスタムプロパティ名)として使うことができます。なお、Sassの変数とは違って、セレクタやプロパティに使うことはできません。また、--hoge: 2;の時に、margin-left: var(--hoge)pxと書いても、margin-left: 2 pxのようにみなされてうまく動きません(もちろん、margin-left: calc( var(--hoge) * 1px)のようにすることはできます)。

そして、この変数展開は、要素ごとにその要素に適用されたカスタムプロパティで行います。

サンプルCSS
:root { --color: blue; }
div { --color: green; }
#alert { --color: red; }
* { color: var(--color); }
上のCSSを適用した結果
<p>:rootそのままの青色</p>
<div>divには緑色が指定されています</div>
<div id='alert'>
  #alertに指定された赤色
  <p>外側の#alertから継承した赤色</p>
</div>

継承関係はCSSそのままということで、ここもSassの変数と異なります。

実践(background-position-x/-yの再現)

ということで、2×3に並べたスプライトを考えてみます。

元のCSS
#parent a.buttons{
  /* サイズ指定や画像置換など */
  background-position-y: 0;
}

#parent a#foo{
  background-position-x: 0;
}
#parent a#bar{
  background-position-x: -80px;
}
#parent a#baz{
  background-position-x: -160px;
}

#parent a:hover{
  background-position-y: -30px;
}

これをCSS Variablesでも表してみると、

適用後
#parent{
  /* 変数のデフォルト指定 */
  --bgX: 0;
  --bgY: 0;
}

#parent a.buttons{
  /* サイズ指定や画像置換など */
  background-position-y: 0;
  background-position: var(--bgX) var(--bgY);
}

#parent a#foo{
  background-position-x: 0;
}
#parent a#bar{
  background-position-x: -80px;
  --bgX:-80px;
}
#parent a#baz{
  background-position-x: -160px;
  --bgX:-160px;
}

#parent a:hover{
  background-position-y: -30px;
  --bgY: -30px;
}

と、再現することができます。

参考資料