Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
CA BASE NEXT でスクロールに 連動したUIを構築した話
Search
kubo-hide-kun
October 11, 2022
Programming
610
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
CA BASE NEXT でスクロールに 連動したUIを構築した話
kubo-hide-kun
October 11, 2022
More Decks by kubo-hide-kun
See All by kubo-hide-kun
ハイレベルな環境こそが最高である 科学的なお話
kubo_programmer
0
180
SQL Injection
kubo_programmer
0
130
IPアドレスとは何か?
kubo_programmer
0
3.9k
クライアント/サーバーシステム
kubo_programmer
0
16k
DHCPサーバ
kubo_programmer
0
3.5k
How to make Readable Slide
kubo_programmer
0
170
AtomicDesignの説明と所感
kubo_programmer
0
2k
Moonblock入門
kubo_programmer
3
1.4k
TCP/UDPの違い
kubo_programmer
4
6.2k
Other Decks in Programming
See All in Programming
LoopHub - ローカルで動く GitHub で、AI と共同開発
jugyo
1
550
AI に Inclusive UI を書かせよう — Design Rules Skill で Compose UI を作り直す
theoriatec2024
1
490
個人開発基盤をまるごとCloudflareに引っ越して爆速で総合的体験を向上させた話
tinykitten
0
190
数年滞っていたダークモード対応をおよそ2週間で完了させる
chigichan24
0
710
スマート反転とウェブアクセシビリティ
camiha
0
210
Kiroで創り、AgentCoreで繋ぐ!AWSで実践する「AI-DLC」から「AIエージェント統合」までの最新地図
licux
4
680
20260828_品質と開発生産性を両立させる、AI時代のE2Eテストの考え方
magicpod
0
210
WebMCP Challenge に星空観察アプリで参加した話
okajun35
0
170
cdk deploy JawsSonic #MARATHONしながらAWSリソースをデプロイしてみよう
akihisaikeda
2
130
技術的負債の返済は、AI時代の複利で効く投資 — 経営としての意思決定とその遂行
curekoshimizu
0
1.3k
大喜利で理解するLLM as a Judge / Understanding LLM-as-a-Judge through Ogiri
rockname
0
100
仕様駆動開発による爆速プロダクト開発 / Bakusoku Spec Driven Development
kobakei
0
110
Featured
See All Featured
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
32
4.8k
DevOps and Value Stream Thinking: Enabling flow, efficiency and business value
helenjbeal
1
380
Code Review Best Practice
trishagee
74
20k
Leveraging LLMs for student feedback in introductory data science courses - posit::conf(2025)
minecr
1
390
My Coaching Mixtape
mlcsv
0
310
How to optimise 3,500 product descriptions for ecommerce in one day using ChatGPT
katarinadahlin
PRO
3
3.8k
Typedesign – Prime Four
hannesfritz
42
3.2k
Rails Girls Zürich Keynote
gr2m
96
14k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
17k
Design of three-dimensional binary manipulators for pick-and-place task avoiding obstacles (IECON2024)
konakalab
0
590
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
254
22k
Conquering PDFs: document understanding beyond plain text
inesmontani
PRO
4
3.1k
Transcript
CA BASE NEXT でスクロールに 連動したUIを構築した話 ~ 発表者 : 窪田 ~
[名前] 窪田 秀哉 / クボ太郎 (2021年入社) [専門] React /
TypeScript [仕事] Marougeなどの複数の占いサービスを運用 [趣味] 知人にオススメされた漫画を読むこと。 今月、読み始めた作品: 「忘却バッテリー」「ハイパーインフレーション」「ドリフターズ」
1. CA BASE NEXT とは 2. スクロール連動UI a. 基本的な仕組み b.
安定して動かすための工夫 3. 告知
1. CA BASE NEXT とは 2. スクロール連動UI a. 基本的な仕組み b.
安定して動かすための工夫 3. 告知
“CA BASE NEXT” について
“CA BASE NEXT” (以下, ”CABN”) とは、 2022.7.27 ~ 2022.7.28 に開催に開催された
サイバーエージェントの 技術カンファレンス です。
自分は “LP開発チームのエンジニアメンバー” として CABNの運営に携わりました。 主に担当したのはスクロールに連動したUIの実装です。 「SANKOU!」「Web Clip Design」などの デザインまとめサイト にも掲載されました
🎉🎉
1. CA BASE NEXT とは 2. スクロール連動UI a. 基本的な仕組み b.
安定して動かすための工夫 3. 告知
【基本の仕組み】 パラパラ漫画 と同じ要領で、連続する複数枚の画像を高速で切り替えることで、 スクロールに連動して動画が動いてるように見せています。 CA BASE NEXT では ファーストビューで 141枚、エンドロールに
60枚 を使っています。
【パラパラ漫画機能を実現するために①】 このスクロール連動処理を行う上で大事になるのが、 スクロールの進捗状況 を インデックス番号(パラパラ漫画における何番目か) に変換する処理です. 例)進捗状況が全体の 10% であれば、 30枚目
の画像を表示する。 スクロール可能領域を基点としたブラウザの位置 = 表示領域のトップの位置を基点としたスクロール可能領域となるDOMの相対距離 * -1 window.addEventListener('scroll', () => { // ターゲットの上部から見た、スクロール量を取得 const positionTop = targetElm.getBoundingClientRect().top * -1; // スクロール可能領域の高さを取得 const scrollableHeight = targetElm.getBoundingClientRect().height; // スクロール可能領域を何%スクロールしたかを計算 const scrollFraction = positionTop / scrollableHeight; const frameIndex = Math.min( frameCount - 1, Math.floor(scrollFraction * frameCount) ); });
【パラパラ漫画機能を実現するために②】 取得したインデックス番号をもとに画像を描画します。 画像の描画は canvas の drawImage を使うことで実現します。 別案: ・videoタグの動画を進み具合にJSで操作する →
動画サイズが大きいと後半の内容の画質が悪くなる (再生しないとフレームをちゃんと読み込まない?) ・DOMを操作する → サイト自体がJSですごく重くなったので、見送り。 const img = await loadImage(framePaths[index]); const canvas = canvasRef.current; const context = canvas.getContext('2d'); // 中央寄せするための計算 (object-fix: cover; をJSで再現) const { offset, size } = calcCoverRect( { width: canvas.clientWidth, height: canvas.clientHeight }, { width: img.width, height: img.height } ); // 画質を落とさないための拡大率の計算 const scale = calcCanvasScale(canvas); requestAnimationFrame(() => { context.drawImage( img, offset.left * scale.x, offset.top * scale.y, size.width * scale.x, size.height * scale.y ); });
← 「青色」がウィンドウ。 「オレンジ」がスクロール可能領域。 「茶色」が表示されているDOM (ウィンドウ) これを駆使することで、
スクロールしてもパラパラ画面に相当するDOMを表示可能。 【パラパラ漫画機能を実現するために③】 次にスクロールしてもパラパラ漫画を表示し続けるためのCSSについて説明します。 やり方は表示したい要素(動画で言うと「茶色」のDOM)を画面目一杯に広げて、 position: fixed; もしくは position: sticky; をつけることで、 スクロールしても、特定の要素を表示し続けることができます。
基本の仕組みは先ほど説明した内容で十分ですが、 それだけだといくつか問題が発生するので、 その対応として自分が行った修正内容について解説していきます。
1. CA BASE NEXT とは 2. スクロール連動UI a. 基本的な仕組み b.
安定して動かすための工夫 3. 告知
【滑らかなアニメーションのための工夫】 素早くスクロールすると、画像フレームの切り替えに タイムラグ が生じてしまいます。 これは、新しい画像を表示する度に、画像のダウンロードを必要とするためです。 これを回避するために、スクロール前に あらかじめ画像をロード しておきます。 そうすれば、各フレームが既にダウンロードされてるので、 画像を滑らかにアニメーションすることができます。
const preloadImages = () => { currentFramePaths.forEach(loadImage); }; const loadImage = (src: string) => { return new Promise<HTMLImageElement>((resolve, reject) => { const img = new Image(); img.src = src; img.onload = () => resolve(img); img.onerror = () => reject(); }); };
【正常な描画ための工夫】 アクセスして数秒は画像の読み込みに時間がかかり、 パラパラ漫画の画像が何も表示されないという問題が発生しました。 これを解決するために最初の数フレームの画像は <link rel=”preload” … /> を使うことで、 HTMLが描画される時点で、最初の画像が読み込まれる状態を実現させる必要があります。
<NextHead> {alternateFrame.slice(0, 20).map((frame) => ( <React.Fragment key={frame.avif}> <link rel="preload" href={frame.avif} as="image" media="(min-width: 640px)" type="image/avif" /> </React.Fragment> ))} </NextHead>
【画像の軽量化のための工夫①】 パラパラ漫画のUIには必要となる画像枚数が多すぎるので、 avif , webP などの軽量な画像フォーマットにも対応しました。 html側であれば簡単に実現できますが、canvasで画像を表示しているので 、 JS側で「実行しているブラウザが各フォーマットに対応しているか」を確認するようにしています。 const
checkAvifSupport = (): Promise<boolean> => { return new Promise((resolve) => { const avif = new Image(); avif.src = 'data:image/avif;base64,...'; avif.onload = function () { const result = avif.width > 0 && avif.height > 0; resolve(result); }; avif.onerror = function () { resolve(false); }; }); }; const checkWebPSupport = (): Promise<boolean> => { return new Promise((resolve) => { const webP = new Image(); webP.src = 'data:image/webp;base64,...'; webP.onload = function () { const result = webP.width > 0 && webP.height > 0; resolve(result); }; webP.onerror = function () { resolve(false); }; }); }; ▼ webPが使えるか確認するメソッド ▼ avifが使えるか確認するメソッド この対応で jpg: 107MB → avif: 59MB (45%減)
【画像の軽量化のための工夫②】 スクロールの位置によって、画質の圧縮率を変更。 左の画像のように、背景が大きく写ってるタイミングは高画質。 右の画像のように、背景があまり描画されないタイミングは低画質にしています。 ▼ 高画質 ▼ 低画質
1. CA BASE NEXT とは 2. スクロール連動UI a. 基本的な仕組み b.
安定して動かすための工夫 3. 告知
CA BASE NEXT ではパラパラ漫画の機能を Reactで実現するために 600行 近く実装しています。 これをパラパラ漫画を実現したいと思う人が毎回書くのはツラいすぎるので、 今回、開発したロジックを OSS
として公開することにしました。 (会社から許可はもらっていますが、あくまで 個人名義のライブラリ です)
既にpublish済みですが、READMEが未整備です。 (進展があったら Twitter で告知するので、ぜひフォローお願いします🙏 → 今回のイベントのCompass から飛べます) デモサイトも開発中です。 (こちらも完成したら Twitter
で告知します) 【開発中のライブラリ】 ライブラリ①: スクロールの進捗状況を計算するカスタムフック。 ライブラリ②: 画像を渡すだけでパラパラ漫画機能を実現可能なコンポーネント。 window.addEventListener('scroll', () => { // ターゲットの上部から見た、スクロール量を取得 const positionTop = targetElm.getBoundingClientRect().top * -1; // スクロール可能領域の高さを取得 const scrollableHeight = targetElm.getBoundingClientRect().height; // スクロール可能領域を何%スクロールしたかを計算 const scrollFraction = positionTop / scrollableHeight; }); ▼ カスタムフックで提供するロジック
発表は以上です。 最後までお聞きいただき、ありがとうございました。 Presentation by クボ太郎 ( Twitter: @kubo_programmer )