CSS変数でbackground-imageを指定するとChromeとSafariで挙動が異なるのを解決する


Chrome と Safari で挙動が違う

CSS変数で background-image を指定したら Chrome と Safari で挙動が違ったので備忘録として残しておきます。

失敗した実装

下記のようにCSS変数を使って指定します。
https://xxx.xxx/test/ という URL で想定しています。

動作サンプル
https://sygnas.github.io/cssvar-sample/

/test/index.html
<link rel="stylesheet" href="./css/hoge.css">
<div class="imgbox" style="--img:url('../img/foo.jpg')"></div>
/test/css/hoge.css
.imgbox{
  background-image: var(--img);
}

結果

Chrome は表示されるが、Safari は表示されない。

問題点

相対パスで画像を指定した時、下記のような違いがあるようです。

Chrome : OK : CSSファイルを起点とした相対パスとして処理

https://xxx.xxx/test/css/hoge.css を起点とした ../img/foo.jpg
https://xxx.xxx/test/img/foo.jpg

Safari : NG : 表示URLを起点として処理

https://xxx.xxx/test/ を起点とした ../img/foo.jpg
https://xxx.xxx/img/foo.jpg

解決策① 絶対パス

絶対パスで指定する。
一番簡単な解決方法です。

/test/index.html
<div class="imgbox" style="--img:url('/test/img/foo.jpg')"></div>

しかし相対パスしか使えないパターンもあるので今回は別の方法を模索します。

解決策② HTML 側に CSS を記述

HTML 側に記述すれば Chrome、Safari どちらも問題ありません。

Vue や React ではコンポーネント内に CSS を書くことが多いのでこちらの方法もアリですね。
変則的ですが background-image の部分だけ HTML 側に書くという方法もあります。

/test/index.html
<link rel="stylesheet" href="./css/hoge.css">
<style>
.imgbox{
  background-image: var(--img);
}
</style>
<div class="imgbox" style="--img:url('./img/foo.jpg')"></div>
/test/css/hoge.css
.imgbox{
  /* background-position とか他の部分はここに書く */
  background-size: contain;
  background-position: center center;
  /* background-image: var(--img); */
}

おわり

CSS の挙動については Safari が IE のような立ち位置になりつつあり困りますね……。