とあるサイトで、「狭い画面で表示するとSVG画像のせいで横スクロールバーが出てしまう」というよくあるアレがあって。
すぐ直せると思ってたら、意外と根が深かったという話。
あらすじ
そのサイトではVitePressを使ってて、このようにSVGが利用されてた。
<script setup>
import MySVG from "./path/to/my.svg?component";
</script>
<div class="Container">
<MySVG />
</div>
セオリー通りなら、svg
要素にwidth: 100%; height: auto;
するだけで終わりなはず。
だがそうしてみても、意図通りに表示されない。スクロールバーは消えたけど、中身が見切れてる。なんで?というところから調査スタート。
?component
とは
まず、?component
って何やねん!っていうのが最初に思ったこと。
どうやらこれは、vite-svg-loader
というVue用のViteのプラグインが暗躍してるものだった。
jpkleemans/vite-svg-loader: Vite plugin to load SVG files as Vue components https://github.com/jpkleemans/vite-svg-loader
このプラグインを使うと、SVGをそのままコンポーネントとして展開できつつ、SVGOで最適化もあわせて行われるとのこと。
<script setup>
import MySVG from "./path/to/my.svg?raw";
</script>
<div class="Container">
<div v-html="MySVG"></div>
</div>
つまりこれに似た雰囲気のことができつつ、各種Props(といってもclass
とかstyle
とかref
とか?)を流し込めるって感じ。
(ちなみに、この?raw
はVite本体の機能)
犯人はSVGO
で、このとき内部的にSVGOを使ってSVGの最適化をやるらしいが、そこでなんとviewBox
が消されてた。
なのでその結果、SVGの枠の中の表示だけが見切れるという結果になってたというわけ。
仕組みとしては単純明快ではあるものの、これはどうやらかなり根が深い問題だったらしく・・。
Remove the
removeViewBox
plugin from the default plugins list by JohnAlbin · Pull Request #1461 · svg/svgo https://github.com/svg/svgo/pull/1461
なんとこのPRは2021年のもの!
そこから時が流れ・・・2024年になってやっとマージされたけど、メジャーバージョンで反映するわってことで未だにRCなステータスという。
Release v4.0.0-rc.0 · svg/svgo https://github.com/svg/svgo/releases/tag/v4.0.0-rc.0
ワークアラウンド
まず考えたは、先述のとおりv-html
でお茶を濁す方法。
SVGOで最適化したい内容にもよるとは思うけど、事前にSVGを用意する時点で最適化しておけばいい。
もしくは、SVGOのオプションを上書きする方法。
svgLoader({
svgoConfig: {
plugins: [
{
name: "preset-default",
params: {
overrides: {
removeViewBox: false,
},
},
},
],
}
})
いっそのこと使わないという手もあるか。
svgLoader({
svgo: false
})
まあ、個人的にはこの手のプラグイン自体あまり好きじゃないし、なくても特に困ることはなさそうだったので、v-html
で済ませた。
余計なレイヤーは無いにこしたことはない。