フルページスクリーンショットとDOMとCSSと
about me
Pasta-K / @pastak
京都で主にJavaScriptを書いて暮らしています
京都サンガF.C.サポーター
Kyoto.jsオーガナイザー
Kyoto.js 21の宣伝
https://gyazo.com/5950af5b958b0c9385404f698ddef51a https://kyotojs.connpass.com/event/311584/
イタリアのローマのJavaScriptコミュニティRomaJSよりコミュニティマネージャーをされているMatteo Manchiさんが京都に旅行に来られるそうなので、それに合わせて開催します!!!!!MatteoさんにはReact NativeについてとRomaJSやイタリアにおけるJavaScriptコミュニティについてトークをして頂きます!
良ければ、東京にお住まいの皆さんも観光がてらどうぞ
3月13日なので、まだ桜とか咲いてなくて(桜の時期などのハイシーズンと比べると)空いてるかも
今日の話
フルページのスクリーンショットを撮影する際のDOM操作について
ではDOMスクリプティングを通じて、色んな要素のアニメーションを止めたり、要素をそれっぽく見えなくしたりしているという話だった
似たような困り事がスクリーンショット撮影という文脈であるので紹介します
知見紹介というは、困りごと紹介という感じです
スライドを作ってから気付きましたが、あんまりDOMの話出てきません
Gyazoのブラウザ拡張
https://gyazo.com/374192db0f58c1949ac25c030575af8b https://chromewebstore.google.com/detail/gyazo-share-new-screensho/ffdaeeijbbijklfcpahbghahojgfgebo
Webページのスクリーンショットを撮影してアップロードする機能を提供している
DOM要素にフィットするような選択UIを提供して、その要素を撮影できる機能もある
こっちの方がDOM DOMトークスっぽいが、こっちはまぁそれなりにやるだけという感じだったので割愛
DEMO
フルページスクリーンショットを撮るために必要なこと
現在の表示領域の外にあるものを撮影する必要がある
ウェブページの全体をスクリーンショットを撮る
表示領域の外まではみ出ている要素の全貌を撮影する
browser.tabs.captureVisibleTab()
Firefoxだけoptionでrectやscaleを指定できるが…
表示領域内のスクリーンショットしか取得できないので、scrollToなどでスクロールさせて順次撮影していく手法を採用している
スクロールさせながら1枚ずつ撮影していくので、素朴にやると、position:fixedやposition:stickyな要素がずっと付いてくるなどの困難がある
ところで
Devtoolでもスクリーンショットを撮れる
https://gyazo.com/b35c2f9c6e8f6d6daa3c3d24b4a68916
chrome.debugger.sendCommandでPage.captureScreenshotコマンドをcaptureBeyondViewport: trueをプロパティとして付与して与えればブラウザ拡張でも同様の結果を取得できる
撮ってみましょう
https://gyazo.com/983666b9eb110729e845647767a6d814
Viewportの外も撮れている
デモ2
結果
今見ているものと同じものが撮影できるわけではない
よく見ると今表示しているものと広告が異なる
ヘッダー部分読込中になっている
Tweet埋め込みなど、遅れてのレンダリングが必要な要素が表示されない
広告が初期位置で固定されて映り込んでいる
整理
browser.tabs.captureVisibleTab()
スクロールしていきながらスクリーンショットを撮影し、canvasで合成していく
スクロールすると遅延読み込みされるような要素もそれなりにレンダリングされた状態で撮影できることがある
スクロールしないといけないので、縦に長いウェブページなどだと時間が掛かる
Page.captureScreenshotコマンド
Viewportの外の要素も撮影できる
見ているものがそのまま撮れるわけではない
Viewportに近づいたタイミングでレンダリングされる要素などは空白になる
共通
画面下にくっついてる要素などの扱いがムズい
どういうDOM操作をすると良いのか?
position: fixedやposition: stickyをなんとかする
→ position: absoluteに一時的にすれば良いと思っているが……
現状これは入れている
ヘッダーや付いてくるサイドバーみたいなのはなんとかなる
画面下に表示されている要素(広告など)はそのままその位置に表示されてしまう
1ページ目の表示領域の下部に重なっている部分を撮影できない
position: fixedだと付いてくることを利用して、スクロールを若干ズラして、その部分の画像を別途取得して合成する?(結構高級な操作に感じる…)
そもそも本当に隠して良いのか?
position: fixedかつbottom: 0の要素をどこに配置するか問題
ページの一番下?
どういうDOM操作をすると良いのか?
遅延読み込みされる要素どうする?
撮影前にloading=lazyを剥がして回る?
剥がして回って且つ一度全体をViewportに入れるとIntersection Observer APIなんかを使っている要素も発火させられる?
その他
カルーセルなどのアニメーション止めた方が良い?
重要度はそんなに高くない?
scrollイベントに何かが引っ掛けられているとスクロールさせられなかったりする
GCPのダッシュボードのようにwindow.scrollToだけでは操作できないような構造のウェブページも増えてきている
overflow:scrollとかを使って2カラム構成になっているなど
まとめ
スクリーンショットを撮るために要素をどう固定するか
どのようにレンダリング結果を取得するか
難しいなぁと思って日々暮らしているので、良いアイデアや知見がある人助けてください
DOMの話が少なくてすいません……