display:noneな画像のダウンロードを避けるために
公開:
更新:
img
要素で読み込む画像は、CSSでdisplay: none
が指定されていたとしてもダウンロードされることはご存知かと思います。
それをどうにかしたいという話です。
前提として、画面サイズに応じたデザインの変更による画像表示の切り替えを想定しているわけではありません。
それにも対応できますが、使いにくいと思います。
結論から言うと「 大量の小さな画像が配置されたウェブページを作っていましたが、それらの大半はユーザーが操作しない限り表示されないUIでした。 デモを作ってありますので、確認してみましょう。 デモページで開発者ツールを開き、ネットワークパネルを見てもらうと分かるように、ページを開いた時点で画像がダウンロードされています。 ご存知のように、CSSの ともかく、背景画像にすれば そこで デモをご覧ください。 開発者ツールのネットワークパネルを見ると、ボタンを押下して しかし しかし、2021年5月現在、スラッシュ後の文字列に対応している環境はBlinkエンジンのみです。GeckoやWebkitでは使用できません。 対応している環境、たとえばGoogle Chromeを使って読み上げてみると、ちゃんと画像であることを伝えてくれます。 対処方法としては、替わりに 両者を比較するデモをご覧ください。 また、 レスポンシブ画像はCSSの これはあくまでも それでもいいです。 わたしが使ったケースとしては、タブが20個あるタブUIで、そのコンテンツはリンク集であり、各リンクに小さな画像がついているというものでした。 ほとんどの場合、url()
関数を指定したcontent
プロパティをインラインスタイルで指定する」、これだけです。なんでこんなことをしたかったのか
表示されるかどうか分からない画像をダウンロードさせるのもイマイチな気がして、ダウンロードを遅らせたかったというのが理由です。通常の
img
指定display: none
になっているのは親要素ですが、自身につけても変わりません。p {
display: none;
padding: 10px;
overflow: auto;
resize: both;
background-color: gainsboro;
}
img {
display: block;
max-width: 100%;
height: auto;
}
<button id="button">画像を表示する</button>
<div id="container" class="container">
<img src="./long-tailed-blue.jpg"
class="image"
width="2048"
height="1536"
alt="写真:ウラナミシジミ">
</div>
<script>
const button = document.querySelector('#button');
button.addEventListener('click', function() {
const container = document.querySelector('#container');
container.style.display = 'block';
this.disabled = true;
});
</script>
これを、ボタンが押下されて.container
がdisplay: block
になったときにダウンロードさせたいというわけです。表示されてからダウンロードを開始する
background-image
で指定された背景画像は、対象がdisplay: none
になっているとダウンロードされません。
これはbackground-image
というより<image>
型で扱われるリソースがそうなっているのではないかと思うのですが、ちょっとソースが分かりませんでした。CSS Images Moduleあたりかなと思ったんですが、仕様ではなく実装のほうなのかもしれません。display: none
のときにダウンロードされないようにはできるのですが、非常に不便です。
背景画像を使うということは、該当要素のサイズ指定が必要になりますが、そのためには画像のサイズを知っていなければなりません。content
プロパティによる要素置換を使います。
画像として扱う要素がimg
からdiv
になっている以外は同じです。<div id="container" class="container">
<div style="content: url(./long-tailed-blue.jpg)"
class="image">
</div>
</div>
display: none
な.cotainer
がdisplay: block
になって初めて画像がダウンロードされているのが分かります。.cotainer
をリサイズすると、それに合わせて画像になっているdiv
のサイズも変わります。これはimg
要素で読み込んだときと同じ動作です。読み上げ対応
content
プロパティに<image>
型が指定された要素は、アクセシビリティツリー上では画像として扱われます。
開発者ツールで確認してみてください。
こういう点では問題ありません。div
にはalt
属性が使えませんので、代替テキストが指定できません。
この問題に対しては、次のように解決されることが望ましいでしょう。content: url(./long-tailed-blue.jpg) / "写真:ウラナミシジミ"
content
プロパティ値の/
(スラッシュ)で区切ったあとの文字列は代替テキストとなります。
構文的には次のようなものです。(2021年5月17日版 Editor’s Draft)normal | none | [ <content-replacement> | <content-list> ] [/ [ <string> | <counter> ]+ ]?
そうではない環境では、不正なCSSとしてcontent
プロパティ自体が無視され、画像すら表示されません。aria-label
を使うことでしょう。<div style="content: url(./long-tailed-blue.jpg)"
class="image"
aria-label="写真:ウラナミシジミ">
</div>
このデモを使って開発者ツールを確認すると、ここまでの説明がわかりやすいかと思います。問題点
img
要素ではありませんので、width
またはheight
属性が使えません。つまり、画像のロードが完了しないとレイアウトが完了しません。
ただし、そのような場合は画像のサイズが分かっていることが前提ですので、CSSで指定すればいいでしょう。.image {
max-width: 100%;
height: auto;
}
<div style="
content: url(./long-tailed-blue.jpg);
aspect-ratio: 2048 / 1536;
"
class="image"
aria-label="写真:ウラナミシジミ">
</div>
img
要素ではないことから、loading
属性が使えません。
そもそもこの方法を採用するのは特殊なケースかと思いますので、ビューポート外の画像を遅延ロードさせたいなら普通にimg
要素を使ったほうがいいのではないかと思います。image-set()
関数を使えば解決できそうです。div
ですので、コンテキストメニューが画像用のものにはなりません。
その点は解決できないでしょう。loading="lazy"
じゃ駄目なの?
ただ、現在はWebkitで使えないことは念頭に置いておく必要があるでしょう。
https://bugs.webkit.org/show_bug.cgi?id=196698がWebkitの対象バグです。まとめ
タブUIの中身というものは、表示されるかどうか不明という意味では代表的なものかもしれません。
他にはdetails
要素でしょうか。img
要素を使うべきだと思いますが、このような方法もあると知っていれば役に立つことがあるかもしれません。