12
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

html新要素「portals」による新しい無限スクロール

Posted at

動作デモ

google検索にて、ページをスクロールすると、次のページが下からニュッっと出てきます。出てきたページをそのままスクロールし続けると、そのページに遷移します。
ezgif-5-f94ab8347027.gif

この記事の目的

本記事では、google検索でportalsによる無限スクロールを試し、portalsの可能性と現在の問題点を共有出来れば良いなと思っています。
portals流行ってくれ!!

portalsとはなんぞや

Webページの中に別のWebページを埋め込むためのhtml要素として、iframeがあります。portalsではiframeのように、埋め込んだWebページにシームレスに遷移することが出来ます。事前にページをロードすることが出来るので、例えば、遷移する際にページ全体が一瞬真っ白になる現象を防げます。SPAのページ遷移でも同じようなことが出来ますが、htmlの標準仕様として実装出来る点が優れていると思います。

現在portalsはドラフト状態です。現在の仕様はWICGの仕様書1で見れます。
今はChrome Canaryでしか動きませんし、まだ仕様も決まりきっていませんが、今後HTMLの標準仕様となれば、他のhtml要素と同じように一般的に使用されることが予想されます。

portalsについては、こちらの記事2が詳しいです。私もこの記事でportalsを知りました。

動作の前提

今回は、以下の条件でportalsによる無限スクロールを動かします。

  • portalsは現状Chrome Canaryでのみ動く。
  • google検索でのみ動く。汎用的に動くわけでは無い。
  • chrome拡張機能として作った。

また、portalsを動かすにはCanary版でフラグをつけて起動する必要があります。詳しくはこの記事2を参考にして下さい。
以下引用

Mac: open -a Google\ Chrome\ Canary --args --enable-features=Portals
Windows: ショートカットを右クリック、リンク先に --args -enable-features=Portals のオプションを付けて起動。
Linux: Canary は Linux ではサポートされていません。代替として Chromium をご利用ください。

無限スクロールの実装

ソースコードはgithubに上げています。git cloneして、Chrome Canaryに拡張機能として追加すると動かせます。

主にスクロールの位置を判定して、portalの表示・非表示を行っているだけです。表示方法はちょっと工夫していて、下からニュッっと出すために、空の領域(emptyArea)をportalの上に置いています。

script.js
window.onload = function() {
  // もし Portal が利用できるプラットフォームであれば...
  if (!'HTMLPortalElement' in window) return alert('portalが無効です。')

  // google検索でだけ動かす
  if (!window.location.href.includes('google')) return

  main()
}

function main() {
  // portalをページに追加
  nextPagePortal = document.createElement('portal')
  nextPagePortal.classList.add('portal')
  nextLink = document.getElementsByClassName('cur')[0].nextElementSibling
  nextPagePortal.src = nextLink.getElementsByTagName('a')[0].href

  // portalとemptyAreaをwrapする、スクロール領域
  scrollArea = document.createElement('div')
  scrollArea.classList.add('scroll')

  // portalの表示を下にずらすためのempty領域
  emptyArea = document.createElement('div')
  emptyArea.classList.add('empty')

  // 一番下までスクロールしたらportalがappendされる
  window.onscroll = function() {
    const scrollTop = document.documentElement.scrollTop || document.body.scrollTop
    if (scrollTop >= document.body.offsetHeight - window.innerHeight) {
      document.body.appendChild(scrollArea)
      scrollArea.appendChild(emptyArea)
      scrollArea.appendChild(nextPagePortal)
      scrollArea.style.display = 'block'
    }
  }

  scrollArea.onscroll = function() {
    // 上に戻ったらportal非表示
    if (this.scrollTop <= 0) {
      this.style.display = 'none'
    }
    // スクロールし終えたらactivate
    if (this.scrollTop >= window.innerHeight) {
      nextPagePortal.activate()
    }
  }
}

style.css
.portal {
  width: 100vw;
  height: 100vh;
}

.scroll {
  position: fixed;
  top: 0;
  height: 100vh;
  width: 100vw;
  z-index: 10000;
  overflow-y: scroll;
}

.empty {
  height: 100vh;
  width: 100vw;
}

portalsの現在の問題点

無限に再帰する

portalはsrc属性で参照するhtmlを指定しますが、それ自身が追加されているページを指定することも可能です。
例えば、A.html<portal src="A.html">を追加することが出来ます。すると、DOMツリーは以下のように無限に再帰します。

A.html
<html>
  ...
  <portal src="A.html">
    #document
      <html>
        ...
        <portal src="A.html">
          #document
            <html>
              ....

上の例は自己参照ですが、相互参照(A.htmlとB.htmlがportalsで参照し合うような場合)や、今回行った無限スクロールの場合でも同じ現象が起きます。

今回はこれを防ぐために、ページを一番下までスクロールしてからDOMツリーにportalを追加しています。portalsの売りはシームレスな遷移なので、初めはwindow.onloadのタイミングで追加していましたが、上記の問題にぶつかったので追加タイミングを変えました。3

また、これはiframeでも起きうる問題ですが、iframeでは特定回数以上の入れ子になるとストップしてくれるようです4

Activateした後、historyが消える

activateされた後、戻るボタンなどで前のページに戻れない。ちなみに今回実装した無限スクロールも、前のページに戻ることは出来ない。これを解決するには、仕様の変更を待つしかない、、、かな。

おわりに

portals流行ってくれ!

  1. Portals https://wicg.github.io/portals/
    draft spec。暫定の仕様書。

  2. 話題の Portals を使った画面遷移 UX の未来 https://blog.uskay.io/article/002-hands-on-portals
    これを見てportalsを知りました。具体的な実装があり、非常に参考になりました。 2

  3. portalsにはメッセージをやり取りするためのインターフェースが用意されています。window.portalHostで自身がPortal として利用されているかの判定が可能らしいです。「自身がportalsとして利用されている場合は、新たなportalをDOMツリーに追加しない」とすれば、無限に再帰するのを防げるかもしれません。

  4. ブラウザの実装に依る。chromeで試したところ、iframeは3層以上でストップする仕様だった。この辺りは気になったので、WICGのgithubで質問してみました。https://github.com/WICG/portals/issues/108

12
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?