🐷
【CSS】スムーススクロールの実践
本記事の目的
この記事では、
- スムーススクロールを使ったレイアウトをCSS だけで実現する
ことを目的とし、コードを通してポイントをまとめます。
完成したレイアウトは、以下のようになります。
結論:コードのポイントまとめ
- アニメーション防止には、
:focus-within
を設定する - フォーカスを当てたい遷移先のHTML要素には、
tabindex
属性を付ける -
@media(prefers-reduced-motion: no-preference)
で、「視差効果を減らす」設定を有効化できる - 解決できない問題点がある
- スクロールスピードの調整
- イージングが聞かない
- サイト内全てのアンカーに反映される
- 他のページから飛んできたとき、一度ヘッダーまで戻り、スムーススクロールが実行される。
- リンクが付く
レイアウトの実装
HTML
<body>
<header class="header commonGrid">
<nav class="header-nav grid12">
<ul>
<li><a href="#about_anchor">About</a></li>
<li><a href="#product_anchor">Product</a></li>
<li><a href="#news_anchor">News</a></li>
</ul>
</nav>
</header>
<section id="about_anchor" tabindex="-1" class="about commonGrid">
<div class="grid12">
<div class="text">
<h2>About</h2>
<p>あああああああああああああああああああ<br>
あああああああああああああああああああああ<br>
<br>
あああああああああああああ<br>
ああああああああああああああああ
<br><br>
ああああああああああ
</p>
</div>
<figure>
<img src="images/test2.jpg" alt="">
</figure>
</div>
</section>
<section id="product_anchor" tabindex="-1" class="product commonGrid">
<div class="grid12">
<div class="text">
<h2>Product</h2>
<p>あああああああああああああああああああ<br>
あああああああああああああああああああああ<br>
<br>
あああああああああああああ<br>
ああああああああああああああああ
<br><br>
ああああああああああ
</p>
</div>
<figure>
<img src="images/test3.jpg" alt="">
</figure>
</div>
</section>
<section id="news_anchor" tabindex="-1" class="news commonGrid">
<div class="grid12">
<div class="text">
<h2>News</h2>
<p>あああああああああああああああああああ<br>
あああああああああああああああああああああ<br>
<br>
あああああああああああああ<br>
ああああああああああああああああ
<br><br>
ああああああああああ
</p>
</div>
<figure>
<img src="images/test4.jpg" alt="">
</figure>
</div>
</section>
</body>
CSS
@charset "UTF-8";
/* スムーススクロール */
@media (prefers-reduced-motion: no-preference) {
html:focus-within {
scroll-behavior: smooth;
}
}
/* 基本 */
body {
color: #222222;
font-family: sans-serif;
line-height: 1.5;
}
* {
margin: 0;
padding: 0;
list-style: none;
}
a {
color: inherit;
text-decoration: none;
}
h2 {
font-size: 32px;
margin-bottom: 30px;
line-height: 1.8;
}
p {
font-size: 20px;
line-height: 1.8;
}
img {
width: 100%;
height: 100%;
object-fit: cover;
max-width: 100%;
vertical-align: bottom;
}
/* パーツグリッド */
.commonGrid {
display: grid;
grid-template-columns: minmax(8vw, 1fr) minmax(auto, 1088px) minmax(8vw, 1fr);
}
.commonGrid>* {
grid-column: 2;
}
/* 12分割グリッド */
.grid12 {
display: grid;
grid-template-columns: repeat(12, 1fr);
column-gap: 16px;
}
.grid12>* {
grid-column: 1 / -1;
}
/* ヘッダー */
.header.commonGrid {
height: 100vh;
background-image: url(images/test1.jpg);
background-size: cover;
background-position: center center;
}
.header-nav ul {
grid-column: 9 / -1;
display: grid;
column-gap: 40px;
color: #ffffff;
font-size: 18px;
margin-top: 39px;
}
.header-nav ul>li {
grid-row: 1;
}
/* About */
.about.commonGrid {
height: 100vh;
align-items: center;
}
.about .text {
grid-column: 8 / span 6;
grid-row: 1;
}
.about figure {
grid-column: span 6;
grid-row: 1;
}
/* Product */
.product.commonGrid {
height: 100vh;
background-color: #222222;
align-items: center;
}
.product .text {
grid-column: span 6;
grid-row: 1;
color: #ffffff;
}
.product figure {
grid-column: 8 / span 6;
grid-row: 1;
}
/* News */
.news.commonGrid {
height: 100vh;
align-items: center;
}
.news .text {
grid-column: 8 / span 6;
grid-row: 1;
}
.news .text h2 {
grid-row: 1;
}
.news .text p {
grid-row: 1;
}
.news figure {
grid-column: span 6;
grid-row: 1;
}
ポイント
コードのポイントは、下記の記事を参考に作成しています。
詳しく知りたい方は、一度ご覧ください。
ページ検索でのアニメーション防止
コードの下記の部分です。
html:focus-within {
scroll-behavior: smooth;
}
html要素に :focus-within
を付けることで、ページ検索によるアニメーションを防止できます。
この:focus-within
は、その要素 または 子孫要素にフォーカスがあれば、実行する動作になっています。
しかし、:focus-within
だけでは、Chrome・Firefox ブラウザでは動作されません。
そのため、フォーカスを当てたい遷移先のHTML要素に tabindex
属性を付けます。
コードの下記の部分です。
<section id="about_anchor" tabindex="-1" class="about partsGrid">
...
</section>
<section id="product_anchor" tabindex="-1" class="product partsGrid">
...
</section>
<section id="news_anchor" tabindex="-1" class="news partsGrid">
...
</section>
これにより、正常な動作を保ちながら、ページ検索でのアニメーションを防止できます。
「視差効果を減らす」設定がオンのときの無効化
コードの下記の部分です。
/* mediaの部分 */
@media (prefers-reduced-motion: no-preference) {
html:focus-within {
scroll-behavior: smooth;
}
}
このメディアクエリにより、「視差効果を減らす」設定のとき、必要不可欠でないアニメーションを無効化できます。
prefers-reduced-motion
は、「余計な動きを最小化する」設定を検出します。
no-preference
は、「ユーザーが設定を行っていない場合」を検出する値です。
つまり no-preference
を指定することで、ユーザーが「視差効果を減らす」を設定しているなら、アニメーションを無効化する動作ができます。
※「ユーザーが設定している場合」を検出する値は、reduce
です。
解決できていない問題点
上記が解決しても、CSSでのスムーススクロールには以下の欠点が存在します。
- スクロールスピードの調整
- イージングが聞かない
- サイト内全てのアンカーに反映される
- 他のページから飛んできたとき、一度ヘッダーまで戻り、スムーススクロールが実行される。
- リンクが付く
結論
- アニメーション防止には、
:focus-within
を設定する - フォーカスを当てたい遷移先のHTML要素には、
tabindex
属性を付ける -
@media(prefers-reduced-motion: no-preference)
で、「視差効果を減らす」設定を有効化できる - 解決できない問題点がある
- スクロールスピードの調整
- イージングが聞かない
- サイト内全てのアンカーに反映される
- 他のページから飛んできたとき、一度ヘッダーまで戻り、スムーススクロールが実行される。
- リンクが付く
CSS と JS の使い分けになりそうです。
参考資料
Discussion