質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
スクロール

スクロールとは、ディスプレイスクリーン上において連続的にコンテンツが滑っていくことを指します。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

3回答

318閲覧

スクロール中に対象の要素が見えたらサイドナビをセレクト状態にしたい

bonbonbo

総合スコア0

スクロール

スクロールとは、ディスプレイスクリーン上において連続的にコンテンツが滑っていくことを指します。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

0クリップ

投稿2020/05/12 01:54

編集2020/05/12 02:02

前提・実現したいこと

サイドナビのあるページを作成中です。
スクロールした際、サイドバーを固定して追従するようにしたのですが
要素が見えたらサイドナビも連動してセレクトしているように実装したいです。

発生している問題・エラーメッセージ

スクロールした際セレクトにはなるのですが、複数選択されているように見えてしまいます。

該当のソースコード

Javascript

1//コンテンツ領域の要素id 2var navList = [ 3 document.getElementById("a"), 4 document.getElementById("b"), 5 document.getElementById("c"), 6 document.getElementById("d"), 7 document.getElementById("e"), 8 document.getElementById("f"), 9 document.getElementById("g"), 10 document.getElementById("h"), 11 document.getElementById("i") 12] 13 14let height = window.innerHeight; 15 16function sideNav() { 17 for (i = 0; i < navList.length; i++ ){ 18 19 let rect = navList[i].getBoundingClientRect(); 20 let scrollTop = window.pageYOffset || document.documentElement.scrollTop; 21 let topPos = rect.top + scrollTop; 22 23     //サイドナビid 24 let nav = document.getElementById("FnNav-" + (i+1)); 25 26 let position = topPos - height; 27 let position_bottom = topPos + height; 28 29 if( scrollTop > position && scrollTop < position_bottom ) { 30 nav.classList.add('ExSelected'); 31 } else { 32 nav.classList.remove('ExSelected'); 33 } 34 } 35 36} 37window.addEventListener('scroll', sideNav); 38 39

試したこと

nav.classList.add('ExSelected')の前に if (i - 1){ nav.classList.remove('ExSelected') } を追記してみましたエラーがおきました

nav.classList.add('ExSelected')の前に if (nav.classList.contains('ExSelected')){ nav.classList.remove('ExSelected') } を追記してみましたがスクロールしてみると全てのセレクトが外れてしまう。

補足情報(FW/ツールのバージョンなど)

jQueryは使用せずに実装したいです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Lhankor_Mhy

2020/05/12 03:35

「複数選択されているように見えてしまいます」とのことですが、それは全てが選択されているのですか? それとも「ひとつ前のものも選択されている」などの法則がありそうですか?
bonbonbo

2020/05/12 03:39

スクロールするうちに一つ前のものと二つ前のものまで選択されたままになってしまっています。
guest

回答3

0

自己解決

position_bottom の計算が間違っており、

let position_bottom = position + rect.height;

に修正したところ動きました !

投稿2020/05/12 05:03

bonbonbo

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

js

1 if( scrollTop > position && scrollTop < position_bottom ) {

↑この部分ですが、

js

1 let position = topPos - height; 2 let position_bottom = topPos + height;

↑を代入すると、↓と等価です。

js

1 if( scrollTop > topPos - height && scrollTop < topPos + height ) {

さらに、↓を代入すると、

js

1 let topPos = rect.top + scrollTop;

↓となります。

js

1 if( scrollTop > rect.top + scrollTop - height && scrollTop < rect.top + scrollTop + height ) {

↑は両辺に同じものがありますから、消して移項すると、↓になります。

js

1 if( height > rect.top && height > -rect.top ) {

height >= 0 なのは自明ですから、これはつまり、↓と概ね同義と考えていいでしょう。

js

1 if( height > Math.abs( rect.top ) ) {

さて、この式の意味を考えてみてください。
rect.topは、その要素のスクロール画面上端からの位置です。
heightは、その要素の高さです。
ということは、height > Math.abs( rect.top )は、つまり、「スクロール画面上端からその要素の高さ分だけ上にあるか、スクロール画面上端からその要素の高さ分だけ下にあるか、その間にあるか」ということです。

ここで、heightが2000pxでスクロール画面の高さが1000pxだとすると、その要素がスクロール画面の下端からさらに1000px下、つまり画面外にある時に条件が成立することになります。

これは、 bonbonboさんの想定と異なるのではないでしょうか?

投稿2020/05/12 05:02

Lhankor_Mhy

総合スコア36074

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

要素が見えたらサイドナビも連動してセレクトしているように実装したい

対象の要素が「どのように」見えたら要望の結果にするのか、細かい「条件付け」を考えてみてはどうでしょう。

例) qiita の toc(topics of content/tables of content) に似た挙動

qiitaのページを操作して感じ取れる要件です。

  1. 画面の上端から 一定範囲にある heading 要素で判定している?
  2. 判定した heading と同じ toc のリストを着色している?

「セレクト(選択)」と表現されていますが、視覚上は着色に過ぎません。
フォーカスされた状態ではないなど、表示と操作とは別で考えるのも改善のポイントと思います。

複数選択されている

ブラウザに複数の範囲が同時に表示されているのであればそうなって当然です。
なので、更に細かい条件付けをしているのが qiita のような toc 実装です。


蛇足ですが、長文コンテンツのページにおける TOC は様々な実装があります。

メタ情報とセマンティック・ウェブ に見られるように、Heading の右にある TOC アイコンでメニューを表示するようなタイプが先駆けだったように思います。

投稿2020/05/12 04:34

編集2020/05/12 04:48
AkitoshiManabe

総合スコア5432

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問