Edited at

打倒slick! CSS Scroll Snap入門


はじめに

2, 3ヶ月ほど前、勧告候補である「CSS Scroll Snap Module Level 1」のプロパティ群が、Google Chromeで使用できるようになりました:tada:

いったいどんなことが出来るのか、気になります。そこで、さっそく使ってみました。この記事は、その際のメモです。

用意したものは、最新版のGoogle Chrome(バージョン: 70.0.3538.77)です。


CSS Scroll Snap とは

CSS Scroll Snap は、スクロール可能な領域内のスクロール位置を調整できる機能を提供してくれるようです。

私たちは、Webページから目的の内容を探し出すとき、スクロールをしながら、セクション内の文章を読みます。

そして、目的の内容が見つかると、スクロールを止めます。

その時に「あっ、スクロールしすぎちゃった。最初から読むためにスクロール位置を調整しなきゃ...。」なんてことがよく起こると思います。これは急いでいるときには特に煩わしい作業です。

そこで、そんな作業をしなくても済むように、CSS Scroll Snap を使うことが出来ます。これを使えば、スクロール操作が完了した後に、スクロール位置を指定した場所まで調整してくれるのです。


押さえておくべきプロパティ



  • scroll-snap-typeプロパティ


  • scroll-snap-alignプロパティ


  • scroll-paddingプロパティ


  • scroll-marginプロパティ

CSS Scroll Snapを使うなら、とりあえずこの4つを押さえておけば良いかな、と思います。


scroll-snap-typeプロパティ

scroll-snap-typeプロパティは、


  • スクロール位置の調整を行うかどうか

  • どの軸でスクロール位置を調整するか

  • どの程度厳密に調整するか

を指定します。

このプロパティは、スクロール可能な領域(スクロールコンテナ)に対して設定します。


スクロール位置の調整を行うかどうか

スクロール位置の調整を行わない場合、このプロパティにはnoneを設定します。これが初期値です。


どの軸でスクロール位置を調整するか



  • x:
    X 軸でスクロール位置の調整を有効にする


  • y:
    Y 軸でスクロール位置の調整を有効にする


  • block:
    ブロック軸でスクロール位置の調整を有効にする


  • inline:
    インライン軸でスクロール位置の調整を有効にする


  • both:
    X, Y 軸両方でスクロール位置の調整が行われる


どの程度厳密に調整するか



  • mandatory:
    スクロール位置を調整できる場合、スクロール位置が調整される


  • proximity:
    スクロール位置を調整でき、調整後のスクロール位置が現在位置から近い場合は、スクロール位置が調整される。そうでない場合、スクロール位置の調整は行われない。


使用例

これらの設定は結構重要なのですが、言葉だけでは伝わりにくい部分があるので、簡単な例を用意しました。

調整の厳密さに関する指定であるmandatoryproximityを並べて、比較できるようにしています。

最新版のGoogle Chromeであれば動作すると思うので、ぜひ実際に試してみてください(動作確認リンク)。

両方ぐりぐり弄っているとわかると思いますが、mandatoryでは絶対にスクロール位置の調整が行われるのに対して、proximityではスクロール位置の調整が行われない位置があります

<div class="container">

<div class="scroll-container">
<img src="http://placehold.jp/3d4070/ffffff/450x450.png?text=mandatory1" alt="">
<img src="http://placehold.jp/3d4070/ffffff/450x450.png?text=mandatory2" alt="">
<img src="http://placehold.jp/3d4070/ffffff/450x450.png?text=mandatory3" alt="">
</div>

<div class="scroll-container proximity">
<img src="http://placehold.jp/703d40/ffffff/450x450.png?text=proximity1" alt="">
<img src="http://placehold.jp/703d40/ffffff/450x450.png?text=proximity2" alt="">
<img src="http://placehold.jp/703d40/ffffff/450x450.png?text=proximity3" alt="">
</div>
</div>

.container {

display: flex;
}

.scroll-container {
display: flex;
flex-basis: 50%;
flex-direction: column;
overflow-y: scroll;
scroll-snap-type: y mandatory;
max-height: 100vh;
}

.proximity {
scroll-snap-type: y proximity;
}

img {
scroll-snap-align: start;
margin-bottom: 5px;
}


scroll-snap-alignプロパティ

scroll-snap-alignプロパティでは、


  • スクロール位置の調整を行うかどうか

  • スクロールコンテナ内の可視領域(スナップポート)にある要素をどのように配置するか

を指定します。

このプロパティは、スクロール可能な領域の子要素に対して設定します。


スクロール位置の調整を行うかどうか



  • none:
    noneを指定したコンテンツでは、スクロール位置の調整が行われない。つまり、スクロールが調整される場合、そのコンテンツの隣にあるコンテンツにスクロールされる。動作確認リンクを用意した。これを実行すると、2つ目のimg要素にスクロールが調整されないことがわかる


  • start:
    スクロールコンテナ内で可視領域にある要素の始端が、スクロールコンテナの始端に位置するように、スクロール位置が調整される


  • end:
    スクロールコンテナ内の可視領域にある要素の終端が、スクロールコンテナの終端に位置するように、スクロール位置が調整される


  • center:
    スクロールコンテナ内の可視領域にある要素の中央が、スクロールコンテナの中央に位置するように、スクロール位置が調整される


使用例

こちらも、言葉だけではいまいちわからないと思うので、例を用意しました(動作確認リンク)。

scroll-snap-alignプロパティに、start, end, centerを指定した時の比較をしています。

この例を実行してみるとわかると思いますが、startを指定すると、スクロールコンテナの上端にスクロール位置が調整されるようになります。center, endを指定した場合も、それぞれスクロールコンテナの中央、下端にスクロール位置が調整されます。

<div class="container">

<div class="scroll-container start">
<img src="http://placehold.jp/3d4070/ffffff/450x450.png?text=start1" alt="">
<img src="http://placehold.jp/3d4070/ffffff/250x250.png?text=start2" alt="">
<img src="http://placehold.jp/3d4070/ffffff/450x450.png?text=start3" alt="">
</div>

<div class="scroll-container end">
<img src="http://placehold.jp/3d4070/ffffff/450x450.png?text=end1" alt="">
<img src="http://placehold.jp/3d4070/ffffff/250x250.png?text=end2" alt="">
<img src="http://placehold.jp/3d4070/ffffff/450x450.png?text=end3" alt="">
</div>

<div class="scroll-container center">
<img src="http://placehold.jp/3d4070/ffffff/450x450.png?text=center2" alt="">
<img src="http://placehold.jp/3d4070/ffffff/250x250.png?text=center1" alt="">
<img src="http://placehold.jp/3d4070/ffffff/450x450.png?text=center3" alt="">
</div>
</div>

.container {

display: flex;
}

.scroll-container {
display: flex;
flex-basis: 33.3%;
flex-direction: column;
overflow-y: scroll;
scroll-snap-type: y mandatory;
max-height: 100vh;
}

img {
margin-bottom: 5px;
}

.start img {
scroll-snap-align: start;
}

.end img {
scroll-snap-align: end;
}

.center img {
scroll-snap-align: center;
}


scroll-paddingプロパティ

scroll-paddingプロパティは、


  • スクロールコンテナ内にpaddingを設定するかどうか

を指定できます。

scroll-paddingプロパティについては、例を使いながら説明をします。

たとえば、このような固定ヘッダーがあるページで、CSS Scroll Snapを使用した場合を考えます。

<div class="container">

<header></header>
<div class="scroll-container start">
<img src="http://placehold.jp/3d4070/ffffff/450x450.png?text=start1" alt="">
<img src="http://placehold.jp/3d4070/ffffff/250x250.png?text=start2" alt="">
<img src="http://placehold.jp/3d4070/ffffff/450x450.png?text=start3" alt="">
</div>
</div>

body{

margin:0;
}

.container {
display: flex;
}

header {
position: fixed;
width: 100vw;
height: 100px;
background: rgba(255,0,255,.3);
top: 0;
left: 0;
}

.scroll-container {
display: flex;
flex-direction: column;
overflow-y: scroll;
scroll-snap-type: y mandatory;
max-height: 100vh;
scroll-padding-top: 150px;
}

img {
margin-bottom: 5px;
}

.start img {
scroll-snap-align: start;
}

従来の方法であれば、padding-topを固定ヘッダーの高さ分設定することで、固定ヘッダーの部分に余白が作られ、コンテンツ全体が表示されるようになります。

しかし、CSS Scroll Snapを使用すると、padding-topを設定していても、スクロール位置を調整する際にpaddingを無視したスクロール位置の調整が行われます

こちらはpadding-topのみを設定したときの例です。一度スクロールすると、スクロール位置の調整が行われ、padding-top分を無視したスクロール位置の調整が行われることがわかると思います。

<div class="container">

<header></header>
<div class="scroll-container start">
<img src="http://placehold.jp/3d4070/ffffff/450x450.png?text=start1" alt="">
<img src="http://placehold.jp/3d4070/ffffff/250x250.png?text=start2" alt="">
<img src="http://placehold.jp/3d4070/ffffff/450x450.png?text=start3" alt="">
</div>
</div>

body {

margin: 0;
}

.container {
display: flex;
max-height: 100vh;
}

header {
position: fixed;
width: 100vw;
height: 100px;
background: rgba(255, 0, 255, 0.3);
top: 0;
left: 0;
}

.scroll-container {
display: flex;
flex-direction: column;
overflow-y: scroll;
scroll-snap-type: y mandatory;
max-height: 100vh;
padding-top: 100px;
}

img {
margin-bottom: 5px;
}

.start img {
scroll-snap-align: start;
}

この動作を防ぐために、scroll-paddingプロパティを使うことができます。

scroll-paddingプロパティを使うことで、スクロール位置の調整にもpaddingが考慮されるようになります。

scroll-paddingプロパティを使った時の動作はこのようになります

<div class="container">

<header></header>
<div class="scroll-container start">
<img src="http://placehold.jp/3d4070/ffffff/450x450.png?text=start1" alt="">
<img src="http://placehold.jp/3d4070/ffffff/250x250.png?text=start2" alt="">
<img src="http://placehold.jp/3d4070/ffffff/450x450.png?text=start3" alt="">
</div>
</div>

body {

margin: 0;
}

.container {
display: flex;
max-height: 100vh;
}

header {
position: fixed;
width: 100vw;
height: 100px;
background: rgba(255, 0, 255, 0.3);
top: 0;
left: 0;
}

.scroll-container {
display: flex;
flex-direction: column;
overflow-y: scroll;
scroll-snap-type: y mandatory;
max-height: 100vh;
padding-top: 100px;
scroll-padding-top: 100px;
}

img {
margin-bottom: 5px;
}

.start img {
scroll-snap-align: start;
}


scroll-marginプロパティ

scroll-marginプロパティは、


  • スクロールコンテナに対するmarginを設定するか

を指定できます。

(※このプロパティの動作については、十分に理解できていないので、この部分は改めて追記する予定です。)


ブラウザの対応状況

Can I use によると、Google Chrome, Safari はCSS Scroll Snapをサポートしているようですが、その他のブラウザでのサポートはまだ十分ではありません。また、現在の段階ではGoogle Chrome, Safari間の実装にも差異がある可能性が残っているため、注意が必要です。

以上。