Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
ABEMA における CriticalCSS の活用例
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
Co9xs
April 28, 2023
Programming
200
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
ABEMA における CriticalCSS の活用例
2023/04/28 Muddy Web #5
Co9xs
April 28, 2023
More Decks by Co9xs
See All by Co9xs
注目のアーキテクチャ、JAMstackってなんだろう? / What-is-JAMstack
co9xs
1
160
Other Decks in Programming
See All in Programming
Pythonの実行はどこまで賢くなったのか? CPythonとPyPyから見る最適化のしくみ
curekoshimizu
4
2.8k
20260828_品質と開発生産性を両立させる、AI時代のE2Eテストの考え方
magicpod
0
160
変化を抱擁するドキュメントの作り方 - ビジネスルール駆動開発がもたらす、コードとの新しい関係
ioki
2
110
AI駆動開発にグラフDBを重ねてみた
satoshi256kbyte
2
750
ソフトウェアエンジニアにとっての生成AI - 特性を知って使い倒す / generative ai for software enginner
kishida
7
2.3k
【デモ】Kiroで体験する仕様駆動開発|設計からコーディングまでAIと進める開発フロー
cmkudo
0
580
自分的「カンファレンスの楽しみ方」
syumai
0
190
Go 1.27からのGODEBUG / Go 1.27 リリースパーティ #go127party
mazrean
0
320
AWS Step Functions 大規模並列の壁を越える / jaws-sonic-2026-niigata-step-functions
kasacchiful
PRO
0
380
Foundry Localでエージェント開発
seosoft
0
140
Gmail/Google DriveをトリガーにAIエージェントを動かそう! / Run AI agents with Gmail/Google Drive as triggers!
har1101
3
470
【DroidKaigi 2026】「アクセシビリティを利用するとき、 アクセシビリティもまたこちらを利用している」 〜マルウェアによる攻撃と防衛について〜
halunoyo
0
410
Featured
See All Featured
[RailsConf 2023] Rails as a piece of cake
palkan
59
7k
How Fast Is Fast Enough? [PerfNow 2025]
tammyeverts
3
870
Raft: Consensus for Rubyists
vanstee
141
7.7k
Highjacked: Video Game Concept Design
rkendrick25
PRO
1
450
Design in an AI World
tapps
1
300
SEO Brein meetup: CTRL+C is not how to scale international SEO
lindahogenes
1
2.9k
Evolving SEO for Evolving Search Engines
ryanjones
0
280
Code Reviewing Like a Champion
maltzj
528
40k
Redefining SEO in the New Era of Traffic Generation
szymonslowik
1
400
Facilitating Awesome Meetings
lara
57
7.1k
Balancing Empowerment & Direction
lara
6
1.3k
Testing 201, or: Great Expectations
jmmastey
46
8.3k
Transcript
ABEMA における CriticalCSS の活用例 2023/04/28 Muddy Web #5
自己紹介 藤嶋 稜(ふじしま りょう) 株式会社サイバーエージェント 2022 年新卒入社 Web フロントエンドエンジニア@ 株式会社AbemaTV
@Co9xsR
ABEMA における Critical CSS の活用例 目次 Critical CSS の仕組みのおさらい ABEMA
における Critical CSS の実践例 Muddy な対応が必要だった例 現状の課題 まとめ
Critical CSS の仕組みのおさらい ブラウザはページ表示の前に CSS を読み込む必要がある = CSS ファイルは rendering
block resource である ページに必要な CSS だけを先に読み込むことで、初期表示をブロックするよ うな読み込み時間を減らすことができる = Web Vitals の LCP の改善などにつ ながる
Critical CSS の仕組みのおさらい Critical CSS 適用前 ページに必要ない CSS の読み込みも待つ必要がある <head>
<meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>html served from backend server</title> <!-- 全てのページで必要な CSS を head で読み込む --> <link rel="stylesheet" href="/path/to/main.css" /> </head> <body> <!-- 実際に必要なのはこのコンポーネントに対する CSS だけ --> <div class="awesome-component">This is awesome component</div> </body>
Critical CSS の仕組みのおさらい Critical CSS 適用後 ページにあるコンポーネントに必要な CSS だけ先に読み込む <head>
<meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>html served from backend server</title> <!-- 初期表示に必要な CSS だけを inline で読み込む --> <style> .awesome-component { color: red; padding: 8px; } </style> </head> <body> <div class="awesome-component">This is awesome component</div> <!-- 全ての CSS は body の最後 = ページの描画後に読み込む --> <link rel="stylesheet" href="/path/to/main.css" /> </body>
ABEMA における Critical CSS の実践例 abema-web の全体設計イメージ バックエンドチームが管理している Go のマイクロサービス群
Web チームが管理している Node.js の BFF 層 gRPC 経由で各マイクロサービスを呼び出し、クライアントアプリケーシ ョンが期待する形に変換する 変換したデータをもとに HTML を組み立てて serve する クライアントの React アプリケーションは HTML を受け取り hydration する
ABEMA における Critical CSS の実践例 1. SSR サーバーの Docker イメージのビルド、コンテナの起動
2. ヘッドレスブラウザで Critical CSS の抽出を行い JSON に保存 3. サーバーから HTML を serve する際は JSON ファイルから利用 これらのステップが各環境のデプロイワークフローで行われる
ABEMA における Critical CSS の実践例 1. SSR サーバーの Docker イメージのビルド、コンテナの起動
2. ヘッドレスブラウザで Critical CSS の抽出を行い JSON に保存 3. サーバーから HTML を serve する際は JSON ファイルから利用 ビルド時に CircleCI の workspace [※1] に保存していたコードを利用 通常の環境で使っている SSR サーバーの Dockerfile を一部上書きして利用する SSR 時に gRPC 経由で呼び出す各マイクロサービスの向き先を独自のモックサーバーにする ページとして出現する可能性のあるコンポーネントを全て表示させる必要があるので独自 のモックデータを使いたい(詳細は後述) ※1 https://circleci.com/docs/ja/workspaces/
ABEMA における Critical CSS の実践例 1. SSR サーバーの Docker イメージのビルド、コンテナの起動
2. ヘッドレスブラウザで Critical CSS の抽出を行い JSON に保存 3. サーバーから HTML を serve する際は JSON ファイルから利用 penthouse [※1] というライブラリを利用している 内部的には puppeteer を利用して chromium 経由でページにアクセス 全体の CSS ファイル main.css からページに表示されている HTML のクラス名を基に抽出 CSS の抽出結果が含まれる JSON も CircleCI の workspace に保存 ※1 https://github.com/pocketjoso/penthouse
ABEMA における Critical CSS の実践例 PostCSS で必ず抽出対象に含めたい CSS ファイルを parse
してセレクタの一覧を取得し、そ れを forceInclude オプションに指定 画面外のはずの footer などの要素に CSS が当たっていないことでなぜか CLS が悪化してい たらしい const penthouse = require("penthouse"); const criticalCss = await penthouse({ url: `http://0.0.0.0:3000${path}`, forceInclude: isMobile ? mobileForceIncludeSelectors : desktopForceIncludeSelectors, });
ABEMA における Critical CSS の実践例 1. SSR サーバーの Docker イメージのビルド、コンテナの起動
2. ヘッドレスブラウザで Critical CSS の抽出を行い JSON に保存 3. サーバーから HTML を serve する際は JSON ファイルから利用 // JSON から対象の CSS を文字列として取得 const criticalCss = shouldEnableCriticalCss && criticalCssName ? manifest[`${criticalCssName}-${isMobile ? "mobile" : "desktop"}`] ?? null : null; // backend から返す html の head に埋め込む <CssLoader manifest={manifest} isMobile={isMobile} criticalCss={criticalCss} position="head" />
Muddy な対応が必要だった例 新規画面実装後... QA 「dev 環境でリロードすると一瞬画面が崩れます!」 ぼく「ローカルで動いてたはずでは?? 😇」
Muddy な対応が必要だった例 penthouse による抽出結果のデバッグ CI で実行される Critical CSS 抽出処理をローカルで実行 実際に撮影されるスクリーンショットを出力して、何が足りないのかを検証する
結果、モックサーバーに対象の gRPC メソッドが追加されておらず、そもそも SSR に失敗 していることが判明 const penthouse = require("penthouse"); const criticalCss = await penthouse({ url: `http://0.0.0.0:3000${path}`, forceInclude: isMobile ? mobileForceIncludeSelectors : desktopForceIncludeSelectors, screenshots: { basePath: `./_screenshots/${name}-${platform}`, type: "jpeg", }, });
モックサーバーに gRPC のメソッドとモックデータを追加後... 「SSR は成功するようになったけど CLS が酷い 🤔」
Muddy な対応が必要だった例 モックデータの追加 同一ページで出現する可能性のあるコンポーネントが全て出るようなモックデータを作る パターン A の CSS ⊆ パターン
B の CSS の場合はパターン B で CSS を抽出する必要がある 例: ABEMA Web 版におけるシリーズページ(パターン A 、パターン B )
現状の課題 マイクロサービス側への新規 gRPC メソッドの追加とモックサーバー側の更新が連動しておら ず、手動で追加する必要がある 結果、新規画面を一通り実装し dev で確認するまで Critical CSS
の抽出に失敗しているこ とに気づかなかった 😇 proto ファイルから TypeScript の型定義を生成する仕組み自体は整備されているので、そ れを利用してモックデータの追加をやりやすくしたい 同一ページでも条件によって全く異なる CSS が適用される場合は、モックデータで事前抽出 するアプローチに限界がある 実際のページへのアクセスごとに動的生成するなどの対応が必要?🤔
まとめ ABEMA における Critical CSS 抽出の仕組み自体は配属前から整備されていた が、チームメンバーが普段触る機会がなくデバッグが難しい状態 デバッグ方法などの知見をドキュメント化してチームに共有できたのは良かっ た 課題もかなり見つかったので改善策も見つけていきたい
ご清聴ありがとうございました!
None