window の scroll イベントがうまく取れない

JavaScript でスクロールイベントをトリガーにする処理を書いたのですが、うまく動かなかったので調査しました。よく考えてみると当たり前な原因だったのですが、少し手間取ったので記事として残しておこうと思います。

結論から言うと、 window.onscroll は viewport の領域をスクロールした際に発生するということです。viewport とはブラウザの表示エリアです。内側の div タグ等に overflow: auto; を指定してスクロールバーを出しても、それは window ではなくそのタグのイベントとして拾わなければならないという事ですね。

画面の一部分の div タグとかなら視覚的にわかるのですが、今回は body タグにスクロールバーが出ていたのですぐに気が付けませんでした。見た目でスクロールバーの位置が viewport なのか body なのか判断が付かなかったのです。

以下にサンプルを載せます。ボタンを押すたびに、スクロールバーを出す場所を html (viewport) と body で切り替えるように作りました。わかりやすいように body と html の間に空間を設けています。

$(window).on(‘scroll’, func) でも $(document).on(‘scroll’, func) でも同じ動きをするようです。

そもそもですが body タグをスクロールさせるっていうデザインに問題がある気がしてきました。W3C の CSS 2.2「11.1.1 Overflow: the ‘overflow’ property」の章を見ると、overflow に関しては body にあてたものも viewport に反映するようなことを書いてあります(CSS 3 でも変わってなさそうです)。その通りであれば body にスクロールバーは出ないはずですが、html と body タグ両方に overflow (と幅高さ) を指定している場合は、デザイナーが意図して付けたものだとブラウザが解釈しているのか、それぞれ別のスクロールバーを出してくれるようです。

自前で書いたスクリプトなら window ではなく body からイベントをとればいいのですが、ライブラリとかだと window で固定になっていたりします。コンテンツ全体のスクロールはやはり viewport (ルートタグ) にしないと色々不具合がでそうなので、他のタグで全部コンテンツを囲ってスクロールバーを出す実装は避けた方がよさそうです。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください