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
Chrome の marquee 要素が 優秀だった話
Search
tsuyoshi wada
March 29, 2018
Technology
5.2k
8
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Chrome の marquee 要素が 優秀だった話
marquee の深みに迫ります。
tsuyoshi wada
March 29, 2018
More Decks by tsuyoshi wada
See All by tsuyoshi wada
技術面からみる パフォーマンス改善 / Frontrend Vol.13 Dec 19th, 2018
tsuyoshiwada
7
1.4k
Yarn + CI + GitHub で挑む npm パッケージの定期更新
tsuyoshiwada
3
1.8k
Other Decks in Technology
See All in Technology
OAuth SPIFFE Client Authentication(OAuth/OIDC Numa (Immersion) Workshop 2026)
oidfj
PRO
0
340
EMの役割で 変わったこと・変わらなかったこと
sansantech
PRO
0
190
RapidCopy2 Matrix I/Oエンジンによるファイルコピーソフトウェアの設計と実装
kengosawa2
1
480
AI駆動開発はどこまで来たのか? ファインディの最新実態調査で読み解く現在地 Devin Con Tokyo
akiratom
4
1.9k
紙 to デジタル
ichien178
0
350
NANDでも描画したい!
nichica906
3
810
:syncing_time:
sksat
3
840
Windows の互換機能 - 古いプログラムはなぜ動作できるのか
murachiakira
PRO
0
120
Introduction to Bill One Development Engineer
sansan33
PRO
0
480
名刺メーカーDevグループ 紹介資料
sansan33
PRO
0
1.2k
【5分でわかる】セーフィー エンジニア向け会社紹介
safie_recruit
0
54k
「ミスを許さない手順書」を作ってみた 〜 個人的にはこれ以上できることはあまりなさそう/20260827-ssmjp-operation-procedure-update
opelab
12
8.9k
Featured
See All Featured
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
17k
How To Stay Up To Date on Web Technology
chriscoyier
790
250k
Lightning Talk: Beautiful Slides for Beginners
inesmontani
PRO
2
650
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
12
1.3k
GitHub's CSS Performance
jonrohan
1033
470k
Claude Code どこまでも/ Claude Code Everywhere
nwiizo
67
57k
The browser strikes back
jonoalderson
0
1.6k
Bash Introduction
62gerente
615
220k
Rebuilding a faster, lazier Slack
samanthasiow
85
9.6k
Discover your Explorer Soul
emna__ayadi
2
1.3k
Automating Front-end Workflow
addyosmani
1369
210k
A brief & incomplete history of UX Design for the World Wide Web: 1989–2019
jct
2
490
Transcript
Chrome ͷ marquee ཁૉ͕ ༏लͩͬͨ 2018-03-29 / Meguro.es #14 @wadackel
ࣗݾհ @wadackel / Θͩ ͭΑ͠ tsuyoshiwada https://blog.wadackel.me • Go Ͱ
CHANGELOG δΣωϨʔλ࡞ͬͨΓ • Storybook ͱ Puppeteer ͰεΫϦʔϯγϣοτࡱͬͨΓ • CyberAgent, Inc. Ͱಇ͍͍ͯͨΓ͠·͢
·ͣ࢝Ίʹ͓அΓͰ͕͢…
marquee ཁૉطʹ ഇࢭ͞Ε͍ͯΔͨΊ Θͳ͍Α͏ʹ͠·͠ΐ͏ օ͞Μ͝ଘͷ௨Γ 00000002 ਓੜ ͷ-5 8FMDPNF৺͔Βܴ
marquee ཁૉͷ͓͞Β͍ HTML ্ͰςΩετ͕εΫϩʔϧ͢ΔྖҬΛ ࡞Δɻࢦఆͨ͠ଐੑʹԠͯ͡ɺςΩετ͕Ξ χϝʔγϣϯ͠ͳ͕ΒϨϯμϦϯά͞ΕΔɻ ʮ͍ͭ͜……ಈͧ͘ʂʯ
͔͜͜Β͕ຊɻ marquee in Chrome ͷ Ͳ͕͜༏लͳͷ ʁ
Chrome ͱ Firefox Ͱ marquee ͷಈ࡞Λൺֱͯ͠Έ·͠ΐ͏ https://developer.mozilla.org/ja/docs/Web/HTML/Element/marquee MDN web docs
ͷ DEMO
Firefox ʮΧΫΧΫʯ ͱ ςΩετ͕εΫϩʔϧ͞ΕΔ
Chrome Կނ͔ ʮψϧψϧʯ ͱಈ͘
͜ΕԿʹʁ
Ͳ͏ͤ Chrome ͷ ϨϯμϦϯάΤϯδϯ͕༏लͱ͔ ͦΜͳͰ͠ΐʁ
ͱɺࡶͳղऍͰࡁ·ͣ͞ʹ ϒϥβͷιʔείʔυΛ ͬͯΈΔ
·ͣ Firefox ͷ ϨΠΞτΤϯδϯͰ͋Δ Gecko ͔Β
Ξχϝʔγϣϯ͕։࢝͞Εͯ ͍ΔͩΖ͏෦ <method name="start" exposeToUntrustedContent="true"> <body> <![CDATA[ if (this.runId ==
0) { var myThis = this; var lambda = function myTimeOutFunction(){myThis._doMove(false);} this.runId = window.setTimeout(lambda, this._scrollDelay - this._deltaStartStop); this._deltaStartStop = 0; } ]]> </body> </method> ࢀߟNP[JMMBHFDLPMBZPVUTUZMFYCMNBSRVFFYCMNBSRVFFYNM
Ξχϝʔγϣϯ͕։࢝͞Εͯ ͍ΔͩΖ͏෦ <method name="start" exposeToUntrustedContent="true"> <body> <![CDATA[ if (this.runId ==
0) { var myThis = this; var lambda = function myTimeOutFunction(){myThis._doMove(false);} this.runId = window.setTimeout(lambda, this._scrollDelay - this._deltaStartStop); this._deltaStartStop = 0; } ]]> </body> </method> ࢀߟNP[JMMBHFDLPMBZPVUTUZMFYCMNBSRVFFYCMNBSRVFFYNM setTimeout() Λͬͯ _doMove() Λݺͼग़ͯ͠Δ
_doMove() ΛͬͯΈΔ <method name="_doMove"> <parameter name="aResetPosition"/> <body> <![CDATA[ // ...
εΫϩʔϧҐஔͷࢉग़ϩδοΫ (͍ͷͰলུ) if ((this._direction == "up") || (this._direction == "down")) { this.outerDiv.scrollTop = this.newPosition; } else { this.outerDiv.scrollLeft = this.newPosition; } // ... ͦͷଞॲཧ ]]> </body> </method> ࢀߟNP[JMMBHFDLPMBZPVUTUZMFYCMNBSRVFFYCMNBSRVFFYNM
_doMove() ΛͬͯΈΔ <method name="_doMove"> <parameter name="aResetPosition"/> <body> <![CDATA[ // ...
εΫϩʔϧҐஔͷࢉग़ϩδοΫ (͍ͷͰলུ) if ((this._direction == "up") || (this._direction == "down")) { this.outerDiv.scrollTop = this.newPosition; } else { this.outerDiv.scrollLeft = this.newPosition; } // ... ͦͷଞॲཧ ]]> </body> </method> ࢀߟNP[JMMBHFDLPMBZPVUTUZMFYCMNBSRVFFYCMNBSRVFFYNM ཁૉͷ scrollTop, scrollLeft ʹ ࢉग़ͨ͠࠲ඪΛࢦఆ͍ͯ͠Δ
ૉͳ࣮͕ͩʮΧΫΧΫʯ ͢Δͷೲಘͷ༰ • setTimeout() ͰϧʔϓΛൃੜͤͯ͞Ξχϝʔγϣϯͤͯ͞Δ - ϧʔϓͱϒϥβͷ࠶ඳըλΠϛϯά͕Ұக͠ͳ͍ • ֤ϧʔϓͰͷ࠲ඪΛٻΊͯ scrollTop,
scrollLeft ʹೖ͠Ҡಈ͍ͤͯ͞Δ - ϨΠΞτͷ࠶ܭࢉ͕ൃੜ͢Δ ※ಈ࡞͕ JS Ͱ࣮͞Ε͍ͯͨͷ͕ɺݸਓతʹҙ֎ͩͬͨ
Ͱຊ໋
Chrome վΊ Chromium ͷ ࣮Λ͘
Ξχϝʔγϣϯ͕։࢝͞Εͯ ͍ΔͩΖ͏ίʔυ෦ void HTMLMarqueeElement::start() { if (continue_callback_request_id_) return; RequestAnimationFrameCallback* callback
= new RequestAnimationFrameCallback(this); continue_callback_request_id_ = GetDocument().RequestAnimationFrame(callback); } ࢀߟDISPNJVNUIJSE@QBSUZ8FC,JU4PVSDFDPSFIUNM)5.-.BSRVFF&MFNFOUDQQ
Ξχϝʔγϣϯ͕։࢝͞Εͯ ͍ΔͩΖ͏ίʔυ෦ void HTMLMarqueeElement::start() { if (continue_callback_request_id_) return; RequestAnimationFrameCallback* callback
= new RequestAnimationFrameCallback(this); continue_callback_request_id_ = GetDocument().RequestAnimationFrame(callback); } ࢀߟDISPNJVNUIJSE@QBSUZ8FC,JU4PVSDFDPSFIUNM)5.-.BSRVFF&MFNFOUDQQ requestAnimationFrame Λ ͬͯΔͬΆ͍!!
֤ඳըϑϨʔϜͷॲཧΛ ͬͯΈΔ void HTMLMarqueeElement::ContinueAnimation() { // ... લॲཧ (͍ͷͰলུ) AnimationParameters
parameters = GetAnimationParameters(); int scroll_delay = scrollDelay(); int scroll_amount = scrollAmount(); // ... ࣮ࡍʹ࠲ඪΛద༻ͨ͠Γͯ͠Δ (͍ͷͰলུ) } ࢀߟDISPNJVNUIJSE@QBSUZ8FC,JU4PVSDFDPSFIUNM)5.-.BSRVFF&MFNFOUDQQ
֤ඳըϑϨʔϜͷॲཧΛ ͬͯΈΔ void HTMLMarqueeElement::ContinueAnimation() { // ... લॲཧ (͍ͷͰলུ) AnimationParameters
parameters = GetAnimationParameters(); int scroll_delay = scrollDelay(); int scroll_amount = scrollAmount(); // ... ࣮ࡍʹ࠲ඪΛద༻ͨ͠Γͯ͠Δ (͍ͷͰলུ) } ࢀߟDISPNJVNUIJSE@QBSUZ8FC,JU4PVSDFDPSFIUNM)5.-.BSRVFF&MFNFOUDQQ ԿΒΞχϝʔγϣϯ༻ͷ ύϥϝʔλΛ࡞͍ͬͯΔ
AnimationParameters ͷ ੜʹഭΔ HTMLMarqueeElement::GetAnimationParameters() { AnimationParameters parameters; Metrics metrics =
GetMetrics(); // ... ͍ͨΊলུ!! parameters.transform_begin = CreateTransform(-metrics.content_width); parameters.transform_end = CreateTransform(metrics.marquee_width); // ... ͍ͨΊলུ!! } ࢀߟDISPNJVNUIJSE@QBSUZ8FC,JU4PVSDFDPSFIUNM)5.-.BSRVFF&MFNFOUDQQ
AnimationParameters ͷ ੜʹഭΔ HTMLMarqueeElement::GetAnimationParameters() { AnimationParameters parameters; Metrics metrics =
GetMetrics(); // ... ͍ͨΊলུ!! parameters.transform_begin = CreateTransform(-metrics.content_width); parameters.transform_end = CreateTransform(metrics.marquee_width); // ... ͍ͨΊলུ!! } ࢀߟDISPNJVNUIJSE@QBSUZ8FC,JU4PVSDFDPSFIUNM)5.-.BSRVFF&MFNFOUDQQ Transform?? Λ࡞͍ͬͯΔΆ͍
͞Βʹ͞Βʹ CreateTransform ʹഭΔ AtomicString HTMLMarqueeElement::CreateTransform(double value) const { char axis
= IsHorizontal() ? 'X' : 'Y'; return String::Format("translate%c(", axis) + String::NumberToStringECMAScript(value) + "px)"; } ࢀߟDISPNJVNUIJSE@QBSUZ8FC,JU4PVSDFDPSFIUNM)5.-.BSRVFF&MFNFOUDQQ
͞Βʹ͞Βʹ CreateTransform ʹഭΔ AtomicString HTMLMarqueeElement::CreateTransform(double value) const { char axis
= IsHorizontal() ? 'X' : 'Y'; return String::Format("translate%c(", axis) + String::NumberToStringECMAScript(value) + "px)"; } ࢀߟDISPNJVNUIJSE@QBSUZ8FC,JU4PVSDFDPSFIUNM)5.-.BSRVFF&MFNFOUDQQ CSS ϓϩύςΟͰ͋Δ Transform ͷΛੜͯͨ͠
ͦͷଞɺ ιʔείʔυΛݟͯ ؾ͍͕ͮͨ…
ཁૉͷੜॲཧ void HTMLMarqueeElement::DidAddUserAgentShadowRoot(ShadowRoot& shadow_root) { auto* style = HTMLStyleElement::Create(GetDocument(), CreateElementFlags());
style->setTextContent( ":host { display: inline-block; overflow: hidden;" "text-align: initial; white-space: nowrap; }" ":host([direction=\"up\"]), :host([direction=\"down\"]) { overflow: " "initial; overflow-y: hidden; white-space: initial; }" ":host > div { will-change: transform; }"); shadow_root.AppendChild(style); Element* mover = HTMLDivElement::Create(GetDocument()); shadow_root.AppendChild(mover); mover->AppendChild( HTMLSlotElement::CreateUserAgentDefaultSlot(GetDocument())); mover_ = mover; } ࢀߟDISPNJVNUIJSE@QBSUZ8FC,JU4PVSDFDPSFIUNM)5.-.BSRVFF&MFNFOUDQQ
ShadowRoot Β Slot ཁૉΒ ݟ֮͑ͷ͋Δهड़͕ࢁʂ
ੜ͞ΕΔཁૉͷΠϝʔδ <marquee> #shadow-root <style> :host { display: inline-block; overflow: hidden;
text-align: initial; white-space: nowrap; } :host([direction="up"]), :host([direction="down"]) { overflow: initial; overflow-y: hidden; white-space: initial; } :host > div { will-change: transform; } </style> <!-- ҎԼͷ div ͕ transform ϓϩύςΟͰΞχϝʔγϣϯ͢Δ --> <div> <slot></slot> </div> </marquee>
ࢥ͍͖ͬΓ Web Components
Chromium ͷ marquee ࣮ ૾ΑΓϞμϯͩͬͨ… • ෦࣮ Web Components ͩͬͨ…!!
• requestAnimationFrame ʹΑΔ࠶ඳըλΠϛϯάͷ࠷దԽ - ϧʔϓͱϒϥβͷ࠶ඳըλΠϛϯά͕Ұக • ֤ϧʔϓͰͷ࠲ඪ CSS ͷ transform ϓϩύςΟͰཧ͞Ε͍ͯͨ - ϨΠΞτͷ࠶ܭࢉ͕ى͖ͳ͍ ✨
·ͱΊ
͍ʹ͑͠ͷཁૉࢥ͍ͷ΄͔ Ϟμϯͳٕज़Ͱಈ࡞͍ͯͨ͠ • ShadowDOM ʹΑΔελΠϧͷӅṭ • requestAnimationFrame ʹΑΔΞχϝʔγϣϯͷ੍ޚ • will-change
ΛͬͨΞχϝʔγϣϯͷ࠷దԽ • transform/translate Λͬͨ࠲ඪҠಈ (ඳըෛՙ࠷దԽ) • ීஈͷ Web ϑϩϯτΤϯυ։ൃʹ௨͡Δٕज़Ͱ ߏ͞Ε͍ͯͨ • ͋͘·Ͱ Chromium ͷதͰͶ
ϒϥβͷ࣮Λ͘ͷ ҙ֎ͱָ͍͠!! • C++ ॻ͚ͳͯ͘ɺงғؾͰԿͱͳ͘ॻ͍ͯ͋Δ͜ͱ͕͔Δ • ίϝϯτͦͦ͜͜ॻ͔Ε͍ͯΔͷͰ • ΤσΟλΛ׆༻͢Δ -
$ ctags --languages=C++ ͰλάΛ࡞ͬͯ… - vim Ͱఆٛδϟϯϓͯ͠ιʔείʔυ㓢͢Δͱָ • ripgrep Έ͍ͨͳߴͳ grep ସπʔϧ༗༻ • https://cs.chromium.org ศར
ϒϥβ࣮ݟΔͷ ͜Ε͕ॳΊͯͰͨ͠… ޡΓͳͲ͋Γ·ͨ͠Βɺ༏͘͠ڭ͍͑ͯͨͩ ͚Δͱ͍Ͱ͢
͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠