⚠この記事が公開されたのは 2020年7月3日で、内容が古く、間違っている可能性があります。
先日とあるサイトでGoogle Search Consoleの「ウェブに関する指標」を確認したところ、「CLSに関する問題」のレポートで不良が多数発生していることに気づきました。

CLS(Cumulative Layout Shift)とはUXのコアウェブバイタルの指標の一つで、ページの読み込み中に起こるレイアウトの移動量(がたつきの大きさ)を示します。

(キャンセルボタンを押そうとしたら読み込み中だったバナーが突然現れ、結果その分ボタンが下に移動してしまい、同意するボタンを誤って押してしまった図解です。似たような経験ありませんか?)
以下のページ内にある動画を見ていただければCLSの概要が掴めるかと思います。
web.dev – https://web.dev/cls/
詳しく調べたところページ上部に設置しているカルーセルのimg要素にheightを指定していないことが原因とわかりました。
対策としてはこのimg要素のheightを固定値にすればいいのですが、レスポンシブサイトの場合、srcsetを使用してアスペクト比の違う画像を差し替えている場合はwidth, heightの値は可変(%指定など)にする必要があり、固定値するとレスポンシブデザインに不都合が起きます。
そこでimgの親要素に画像のアスペクト比の値を設定することでimg要素のheightの値を固定することなくCLS対策することがきました。
【⚠追記】padding-top: calc();でアスペクト比を記述していたものをaspect-ratio:に変更しました。
<style>
.embed-responsive-variable-ratios picture {
display: block;
position: relative;
height: 0;
overflow: hidden;
}
.embed-responsive-variable-ratios picture img, .embed-responsive-variable-ratios picture source {
position: absolute;
top: 0;
left: 0;
width: 100%;
}
@media screen and (orientation: portrait) { /* 縦画面 */
.embed-responsive-variable-ratios picture {
aspect-ratio: 9 / 16; /* アスペクト比 9:16の場合 */
height: 100%;
}
}
@media screen and (orientation: landscape) { /* 横画面 */
.embed-responsive-variable-ratios picture {
aspect-ratio: 16 / 9; /* アスペクト比 16:9の場合 */
height: 100%;
}
}
</style>
<div class="embed-responsive-variable-ratios">
<picture>
<source media="(orientation: portrait)" srcset="https://placehold.jp/768x1366.png?text=縦画像(768x1366) 1x, https://placehold.jp/1536x2732.png?text=縦画像(1536x2732) 2x">
<source media="(orientation: landscape)" srcset="https://placehold.jp/1366x768.png?text=横画像(1366x768) 1x, https://placehold.jp/2732x1536.png?text=横画像(2732x1536) 2x">
<img src="https://placehold.jp/1366x768.png?text=横画像(1366x768)" alt="レスポンシブ画像">
</picture>
</div>
<style>
.embed-responsive-variable-ratios picture {
display: block;
position: relative;
height: 0;
overflow: hidden;
}
.embed-responsive-variable-ratios picture img, .embed-responsive-variable-ratios picture source {
position: absolute;
top: 0;
left: 0;
width: 100%;
}
@media screen and (orientation: portrait) { /* 縦画面 */
.embed-responsive-variable-ratios picture {
aspect-ratio: 9 / 16; /* アスペクト比 9:16の場合 */
height: 100%;
}
}
@media screen and (orientation: landscape) { /* 横画面 */
.embed-responsive-variable-ratios picture {
aspect-ratio: 16 / 9; /* アスペクト比 16:9の場合 */
height: 100%;
}
}
</style>
<div class="embed-responsive-variable-ratios">
<picture>
<source media="(orientation: portrait)" srcset="https://placehold.jp/768x1366.png?text=縦画像(768x1366) 1x, https://placehold.jp/1536x2732.png?text=縦画像(1536x2732) 2x">
<source media="(orientation: landscape)" srcset="https://placehold.jp/1366x768.png?text=縦画像(1366x768) 1x, https://placehold.jp/2732x1536.png?text=横画像(2732x1536) 2x">
<img src="https://placehold.jp/1366x768.png?text=縦画像(1366x768)" alt="レスポンシブ画像">
</picture>
</div>
See the Pen by 本田類二 (@curledtail_h) on CodePen.