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
AIにシークレットを見せない、WSL2で安全な開発環境
yazm
0
320
AI コーディングと人間の認知スループット / CTO Night & Day 2026 Morning Session / AI Coding and Human Cognitive Throughput
prog893
5
1.4k
「私が一番顧客に詳しい」を捨てる~ 全員が一次情報に精通する開発チームをつくり、PMが次のボトルネックへ染み出すまで
kaminashi
0
200
PHPカンファレンス関西の招待状 / Invitation to PHP Conference Kansai
ykanoh
0
220
Persisting Massive Data with Rails ~Designing for 60 billion rows, and fighting the bottlenecks~ Railsで挑む大量データ永続化 〜600億件を永続化するための設計とボトルネックとの戦い〜
occhi
0
750
Benchmarking Disaggregated Serving on vLLM + Dynamo with a Real Coding-Agent Workload
nttcom
1
210
実践!Cloud Run ハンズオン!! / Cloud Run handson
y0hgi
2
300
Railsで挑む大量データ永続化 〜600億件を永続化するための設計とボトルネックとの戦い〜
occhi
1
990
Claude の新機能を、 出た日に触って社内に届けるまで
rfdnxbro
1
200
Optunaの最新リリースv5.0について
pfn
PRO
0
120
フロントエンドカンファレンス関西2026 - 速すぎるUIに、待ち時間を
teamlab
PRO
0
210
ウォンテッドリーの最近のプロダクトと技術の紹介
stomk
0
290
Featured
See All Featured
Why Mistakes Are the Best Teachers: Turning Failure into a Pathway for Growth
auna
0
330
How to optimise 3,500 product descriptions for ecommerce in one day using ChatGPT
katarinadahlin
PRO
3
3.9k
Winning Ecommerce Organic Search in an AI Era - #searchnstuff2025
aleyda
2
2.2k
Navigating Weather and Climate Data
rabernat
0
560
Darren the Foodie - Storyboard
khoart
PRO
4
4k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
35
2.9k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
17k
Principles of Awesome APIs and How to Build Them.
keavy
128
18k
GitHub's CSS Performance
jonrohan
1033
470k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
35
2.6k
The Illustrated Guide to Node.js - THAT Conference 2024
reverentgeek
1
570
The State of eCommerce SEO: How to Win in Today's Products SERPs - #SEOweek
aleyda
2
12k
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 ศར
ϒϥβ࣮ݟΔͷ ͜Ε͕ॳΊͯͰͨ͠… ޡΓͳͲ͋Γ·ͨ͠Βɺ༏͘͠ڭ͍͑ͯͨͩ ͚Δͱ͍Ͱ͢
͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠