要素のheightの値を固定しないCLS対策

CLS
⚠この記事が公開されたのは 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.