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

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

新規登録して質問してみよう
ただいま回答率
85.35%
JavaScript

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

Q&A

解決済

2回答

3632閲覧

JavaScript IntersectionObserverの挙動がおかしいです

退会済みユーザー

退会済みユーザー

総合スコア0

JavaScript

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

0グッド

0クリップ

投稿2021/04/05 16:47

編集2021/04/06 00:45

前提・実現したいこと

色分けされたsectionが画面に入ったことを探知し、表示領域が100%ならば、
入ったidを表示するものを作っています
threshold:1で全て入りきったら表示されるはずのところが、
なぜかs1が2回、s2が取得されなかったりと
おかしな挙動をします
スクロールバーを掴んでスクロールさせるのと、
マウスホイールでスクロールさせた場合の挙動も違います

どのように制御すれば、できますでしょうか?

IntersectionObserver
上記URLを参考に組んでいます
threshold:1にしてるにも関わらず初回ロード時にs1が表示されるのもおかしいです

該当のソースコード

<style> body,html{ height:100%; } </style> <script> let options = { root:document.querySelector("#aaa"), threshold:1 } window.onload=function(){ const observer = new IntersectionObserver((entries) => { if (entries[0].intersectionRatio == 0) { return; }else{ alert(entries[0].target.id); } }, options); s=document.querySelectorAll('.section'); sl=s.length; for(i=0;i<sl;i++){ observer.observe(s[i]); } } </script> <div id="aaa" style="width:100%;height:100%;overflow-y:scroll;"> <section id="s1" class="section" style="width:100%;height:100%;background:red"></section> <section id="s2" class="section" style="width:100%;height:100%;background:green"></section> <section id="s3" class="section" style="width:100%;height:100%;background:blue"></section> </div>

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

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

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

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

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

Lhankor_Mhy

2021/04/06 01:14

コードとご質問の内容があっていないように思えるのですが、実際のコードはまた違うものなのですか?
退会済みユーザー

退会済みユーザー

2021/04/06 01:16

どの辺に相違がありますでしょうか? 現時点での実際のコードになります
Lhankor_Mhy

2021/04/06 01:24

そうなのですね。では、それが原因なのかもしれないですね。 検討してみます。
Lhankor_Mhy

2021/04/06 01:31

「スクロールバーを掴んでスクロールさせるのと、 マウスホイールでスクロールさせた場合の挙動も違います」とのことですが、試してみたところ、違いがわかりませんでした。 具体的にはどのように違いますか?
退会済みユーザー

退会済みユーザー

2021/04/06 03:30

マウスホイールによるアラートの表示順 s1 ↓ s1 ↓ s3 スクロールバーによる操作 s1 ↓ s1 ↓ s2(緑の画面で止めたら出ます) ↓ s2 ↓ s3 上記になります Firefox最新版です
Lhankor_Mhy

2021/04/06 03:32

s2でアラートを表示させるのはけっこう大変じゃありませんか? 何度か試しましたが、成功しませんでした。
退会済みユーザー

退会済みユーザー

2021/04/06 03:36

スクロールバーをつまんでですよね? 大変じゃありません
退会済みユーザー

退会済みユーザー

2021/04/06 03:40

何度かやりましたら、出ない事が多いです たまたま数回が偶然に出てたんですね
Lhankor_Mhy

2021/04/06 03:44

そうなんですね。私は一度も出ませんでした。 きっと私が不器用なのでしょう。
guest

回答2

0

ベストアンサー

なぜかs1が2回、s2が取得されなかったり

s2が取得されないのは、yambejpさんのご回答の通りです。
s1が2回取得されるのは、intersectionRatiothresholdの値を通過した時に発火するからです。intersectionRatioが1から0.99に変化すると発火します。


スクロールバーを掴んでスクロールさせるのと、 マウスホイールでスクロールさせた場合の挙動も違います

問題が再現しませんでした。


threshold:1にしてるにも関わらず初回ロード時にs1が表示されるのもおかしいです

IntersectionObserverに登録された時に発火する仕様です。


コメントを受けて追記

s2が発火するかどうかについては、ユーザーの操作次第になりますが。

js

1 window.onload = function () { 2 3 // document.querySelector("#aaa")が取得できないので移動 4 let options = { 5 root: document.querySelector("#aaa"), 6 threshold: 1 7 } 8 9 const observer = new IntersectionObserver((entries) => { 10 if (entries[0].intersectionRatio != 1) { // 条件式変更 11 return; 12 } else { 13 alert(entries[0].target.id); 14 } 15 }, options); 16 17 // 1pxだけスクロールする(ロード時対策) 18 observer.root.scrollTo(0, 1); 19 20 s = document.querySelectorAll('.section'); 21 sl = s.length; 22 for (i = 0; i < sl; i++) { 23 observer.observe(s[i]); 24 } 25 }

投稿2021/04/06 02:19

編集2021/04/06 04:09
Lhankor_Mhy

総合スコア36960

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

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

退会済みユーザー

退会済みユーザー

2021/04/06 03:26 編集

理解が及ばず、すみません もしよろしければ、正常に動作するであろうコードを提示いただけませんでしょうか? 自分で考えろでしたら、シカトしていただいてかまいません
Lhankor_Mhy

2021/04/06 03:28 編集

qazaoさんの想定している「正常な動作」をご提示ください。 yambejpさんのご回答の通り、余裕のない設定ですと発火しないことが多くなると思います。
退会済みユーザー

退会済みユーザー

2021/04/06 03:36

100%領域は無理とのことですのでそれを考慮した正常な動作ですが 初期ロードでs1を出さず、緑画面に入ってs2 青画面でs3 青画面のs3から緑画面でs2 赤画面でs1と出したいと思っております
Lhankor_Mhy

2021/04/06 03:52

初期ロードでs1を出さないのは、実際にs1が全て表示されている以上、単純なコードでは対処が難しそうですね。
退会済みユーザー

退会済みユーザー

2021/04/06 03:55

初期ロードでs1は出さないというのは、難しいのでしたら、除外していただいてかまいません
Lhankor_Mhy

2021/04/06 04:18

以下は、細かい話なので、読まなくてもいいです。 ・entries[0] で決め打ちしてるのがもやもやする(動くけど) ・document.querySelector("#aaa") を getElementById にしないのがもやもやする(動くけど) ・intersectionRatio を isIntersecting にしないのがもやもやする(動くけど)
退会済みユーザー

退会済みユーザー

2021/04/06 05:02

s2が発火しないことを確認いたしました これは不完全なコードだと思うのですが?
退会済みユーザー

退会済みユーザー

2021/04/06 05:04

これでは私が最初に提示したコードよりも、マシになってる程度で、 しっかり動くものではありません
Lhankor_Mhy

2021/04/06 05:06

100%は無理、ということは許容されたと理解していましたが、違いましたか?
退会済みユーザー

退会済みユーザー

2021/04/06 05:06

私はあなたほど知識がありません 有識者のあなたですら、IntersectionObserverが扱いづらいというのであれば、 別の手法を考えます
Lhankor_Mhy

2021/04/06 05:20

IntersectionObserverが扱いづらい、ということはないですが、100%にこだわりがあり、ホイール操作でも「緑画面で覆われた瞬間に発火させたい」ということであれば、IntersectionObserver は向いていないのかもしれませんね。 妥協ができないのであれば、「別の手段」もいいかもしれないです。 または、IntersectionObserver にスクロールスナップを組み合わせると、上手くいくかもしれないです。スクロールの振る舞いが変わってしまいますが。 https://coliss.com/articles/build-websites/operation/css/usecase-of-css-scroll-snap.html
退会済みユーザー

退会済みユーザー

2021/04/06 05:22 編集

スクロールスナップは考えていました 逆に難しくなるのかなとも思っていました
退会済みユーザー

退会済みユーザー

2021/04/06 05:25

<style> body,html{ height:100%; } .scroll_snap_parent{ scroll-snap-type: y mandatory; } section{ scroll-snap-align: start; } </style> <script> window.onload = function () { // document.querySelector("#aaa")が取得できないので移動 let options = { root: document.querySelector("#aaa"), threshold: 1 } const observer = new IntersectionObserver((entries) => { if (entries[0].intersectionRatio != 1) { // 条件式変更 return; } else { alert(entries[0].target.id); } }, options); // 1pxだけスクロールする(ロード時対策) observer.root.scrollTo(0, 1); s = document.querySelectorAll('.section'); sl = s.length; for (i = 0; i < sl; i++) { observer.observe(s[i]); } } </script> <div id="aaa" class="scroll_snap_parent" style="width:100%;height:100%;overflow-y:scroll;"> <section id="s1" class="section" style="width:100%;height:100%;background:red"></section> <section id="s2" class="section" style="width:100%;height:100%;background:green"></section> <section id="s3" class="section" style="width:100%;height:100%;background:blue"></section> </div>
退会済みユーザー

退会済みユーザー

2021/04/06 05:26

ばっちり動きました。 感謝いたします。
Lhankor_Mhy

2021/04/06 05:26

既にご検討されていましたか。それは失礼しました。 では、あとは、スクロールイベントを拾って……、という古典的な実装しかないような気がしますね。 スクロールイベントであれば、ある程度の粒度で発火するので、上手くいくかもしれません。 (それでも、ある程度の閾値が必要になりそうな気もしますが)
退会済みユーザー

退会済みユーザー

2021/04/06 05:27

>スクロールの振る舞いが変わってしまいますが。 どう変わりますか? 正常に動作しておりますが
Lhankor_Mhy

2021/04/06 05:27

上手くいきましたか。 ご解決されて何よりです。
Lhankor_Mhy

2021/04/06 05:28

途中でスクロールを停止できないのではないかな、と思いますが、正常に動作しているのであれば問題ないと思います。
退会済みユーザー

退会済みユーザー

2021/04/06 05:31

総合的な観点からIntersectionObserverは使うべきでないと考えたほうがいいでしょうか?
Lhankor_Mhy

2021/04/06 05:35

目的に合わないのであれば、使わない方がいいのではないでしょうか。 目的に合うのであれば、お使いになられた方が楽ですし、パフォーマンスも上がります。
退会済みユーザー

退会済みユーザー

2021/04/06 05:40 編集

目的は合致しますがブラウザによるバグがあったら嫌です
退会済みユーザー

退会済みユーザー

2021/04/06 05:39

IntersectionObserverに関する資料が、日本人ユーザーから全然発信されていないのはなぜですか?!
退会済みユーザー

退会済みユーザー

2021/04/06 05:44

やりたいことはscroll smoothです 古いやり方で皆さんやってるからですか? わざわざIntersectionObserverとかいうのを使う必要がない!ってことでしょうか?
退会済みユーザー

退会済みユーザー

2021/04/06 05:44

回答よろしくお願いいたします
Lhankor_Mhy

2021/04/06 05:52

> 目的は合致しますがブラウザによるバグがあったら嫌です IntersectionObserver を使った方が、バグは起きにくいだろうと思います。 今回のように、1pxのズレも許さないような動作を求める場合は IntersectionObserver は向いていない、ということかと思います。 --- > IntersectionObserverに関する資料が、日本人ユーザーから全然発信されていないのはなぜですか?! そんなことはないと思いますが…… https://qiita.com/tags/intersectionobserver 不足していると思われるのであれば、Qiitaなどでqazaoさんが発信すればいいのではないですか? --- > やりたいことはscroll smoothです 「scroll smooth」でググったところ、一番上に出てきたのがこれです。 https://developer.mozilla.org/ja/docs/Web/CSS/scroll-behavior これをしたかったのですか? それであれば、CSSだけで解決しそうですね。 おっしゃるとおり、IntersectionObserver は使う必要ないです。
退会済みユーザー

退会済みユーザー

2021/04/07 00:22

scroll smoothはまったく別モノでした。すみません。 IntersectionObserverは使えてると思うのですがAndroid Chromeだと無反応なんですが、 なぜでしょうか?
Lhankor_Mhy

2021/04/07 00:33

すいません、当方は Android をテストする環境がないです。 別質問を立てられた方が速いかもしれないです。
guest

0

scrollで完全に100%一致した瞬間を取るのはかなりシビアです
慎重に合わせればいけないことはないですが100%から少しバッファを取ったほうがよいでしょう

投稿2021/04/06 00:35

yambejp

総合スコア116730

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

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

退会済みユーザー

退会済みユーザー

2021/04/06 00:41

誰も解決できないのかと思っていたところに、回答ありがとうございます threshold:0.5としてもタイミングがずれており、不自然な動作となっております また、マウスホイールとスクロールバーをつまんだ移動で動作が違う原因もわかりません どなたかわかる方引き続きお願いいたします
yambejp

2021/04/06 02:08

スクロールはドット単位ですべてイベントを発生させているわけではないので 完全に100%に一致させるのはむずかしいという話です。 intersectionRatioなどで許容範囲を調整するのがベターです
退会済みユーザー

退会済みユーザー

2021/04/06 03:26

>intersectionRatioなどで許容範囲を調整 よくわからないのですがintersectionRatioで許容範囲は設定できるのでしょうか? もしよろしければ、正常に動作するであろうコードを提示いただけませんでしょうか? 自分で考えろでしたら、シカトしていただいてかまいません
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問