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
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
現場で役立つ技術負債の効果的な返済方法
masuda220
PRO
9
4.7k
負債のメタファと2026年 / Debt Metaphor in Agentic Engineering Age 202609 Edition
twada
PRO
10
4.3k
beyond jj: config & tools ecosystem
indirect
0
5.4k
AIエージェントの一手は 誰も見ていない - Falco拡張OSS「Prempti」とeBPFで サーバーレス実行基盤を二層防御する
keitah
0
330
なぜ「決定性」が 決定的に重要なのか? Durable Execution 基盤の数理的理解 #serverlessjp / ServerlessDays Tokyo 2026
ytaka23
3
940
リアーキテクチャ後の障害ゼロを目指したShadow Testingの取り組み
nihonbuson
PRO
1
160
「ピッケル本」日本語版は4.0(第6版)が出版されるべき / pickaxe4-nagoyark05
kakutani
2
230
すぐできる衛星通信対応 あとは山奥に行くだけ
tatetate55
0
140
Oracle Cloud Network Path Analyzerを試してみた/I Tried Out Oracle Cloud Network Path Analyzer
masakiokuda
1
100
顧客に向き合う開発組織へ。リアーキテクチャとフィーチャーチーム化で挑む組織改革
safie
0
2.1k
AgentCore Runtime上にAgentic Coding基盤を構築・展開する際の設計ポイントと限界点 / Design considerations and limitations when building an agentic coding platform on AgentCore Runtime
har1101
5
500
Claude in Chrome 入門 / Introduction to Claude in Chrome
cielo1985
0
870
Featured
See All Featured
A brief & incomplete history of UX Design for the World Wide Web: 1989–2019
jct
2
510
SEO Brein meetup: CTRL+C is not how to scale international SEO
lindahogenes
2
2.9k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
31
3.4k
My Coaching Mixtape
mlcsv
0
320
Bridging the Design Gap: How Collaborative Modelling removes blockers to flow between stakeholders and teams @FastFlow conf
baasie
0
700
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
Producing Creativity
orderedlist
PRO
348
41k
So, you think you're a good person
axbom
PRO
2
2.2k
Designing Powerful Visuals for Engaging Learning
tmiket
1
570
Stop Working from a Prison Cell
hatefulcrawdad
274
21k
How to optimise 3,500 product descriptions for ecommerce in one day using ChatGPT
katarinadahlin
PRO
3
3.8k
Conquering PDFs: document understanding beyond plain text
inesmontani
PRO
4
3.1k
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 ศར
ϒϥβ࣮ݟΔͷ ͜Ε͕ॳΊͯͰͨ͠… ޡΓͳͲ͋Γ·ͨ͠Βɺ༏͘͠ڭ͍͑ͯͨͩ ͚Δͱ͍Ͱ͢
͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠