A place to cache linked articles (think custom and personal wayback machine)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

index.html 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. <!doctype html><!-- This is a valid HTML5 document. -->
  2. <!-- Screen readers, SEO, extensions and so on. -->
  3. <html lang="fr">
  4. <!-- Has to be within the first 1024 bytes, hence before the `title` element
  5. See: https://www.w3.org/TR/2012/CR-html5-20121217/document-metadata.html#charset -->
  6. <meta charset="utf-8">
  7. <!-- Why no `X-UA-Compatible` meta: https://stackoverflow.com/a/6771584 -->
  8. <!-- The viewport meta is quite crowded and we are responsible for that.
  9. See: https://codepen.io/tigt/post/meta-viewport-for-2015 -->
  10. <meta name="viewport" content="width=device-width,initial-scale=1">
  11. <!-- Required to make a valid HTML5 document. -->
  12. <title>HTML with Superpowers (archive) — David Larlet</title>
  13. <meta name="description" content="Publication mise en cache pour en conserver une trace.">
  14. <!-- That good ol' feed, subscribe :). -->
  15. <link rel="alternate" type="application/atom+xml" title="Feed" href="/david/log/">
  16. <!-- Generated from https://realfavicongenerator.net/ such a mess. -->
  17. <link rel="apple-touch-icon" sizes="180x180" href="/static/david/icons2/apple-touch-icon.png">
  18. <link rel="icon" type="image/png" sizes="32x32" href="/static/david/icons2/favicon-32x32.png">
  19. <link rel="icon" type="image/png" sizes="16x16" href="/static/david/icons2/favicon-16x16.png">
  20. <link rel="manifest" href="/static/david/icons2/site.webmanifest">
  21. <link rel="mask-icon" href="/static/david/icons2/safari-pinned-tab.svg" color="#07486c">
  22. <link rel="shortcut icon" href="/static/david/icons2/favicon.ico">
  23. <meta name="msapplication-TileColor" content="#f7f7f7">
  24. <meta name="msapplication-config" content="/static/david/icons2/browserconfig.xml">
  25. <meta name="theme-color" content="#f7f7f7" media="(prefers-color-scheme: light)">
  26. <meta name="theme-color" content="#272727" media="(prefers-color-scheme: dark)">
  27. <!-- Documented, feel free to shoot an email. -->
  28. <link rel="stylesheet" href="/static/david/css/style_2021-01-20.css">
  29. <!-- See https://www.zachleat.com/web/comprehensive-webfonts/ for the trade-off. -->
  30. <link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_regular.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
  31. <link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_bold.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
  32. <link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_italic.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
  33. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_regular.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  34. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_bold.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  35. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_italic.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  36. <script>
  37. function toggleTheme(themeName) {
  38. document.documentElement.classList.toggle(
  39. 'forced-dark',
  40. themeName === 'dark'
  41. )
  42. document.documentElement.classList.toggle(
  43. 'forced-light',
  44. themeName === 'light'
  45. )
  46. }
  47. const selectedTheme = localStorage.getItem('theme')
  48. if (selectedTheme !== 'undefined') {
  49. toggleTheme(selectedTheme)
  50. }
  51. </script>
  52. <meta name="robots" content="noindex, nofollow">
  53. <meta content="origin-when-cross-origin" name="referrer">
  54. <!-- Canonical URL for SEO purposes -->
  55. <link rel="canonical" href="https://daverupert.com/2021/10/html-with-superpowers/">
  56. <body class="remarkdown h1-underline h2-underline h3-underline em-underscore hr-center ul-star pre-tick" data-instant-intensity="viewport-all">
  57. <article>
  58. <header>
  59. <h1>HTML with Superpowers</h1>
  60. </header>
  61. <nav>
  62. <p class="center">
  63. <a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
  64. <use xlink:href="/static/david/icons2/symbol-defs.svg#icon-home"></use>
  65. </svg> Accueil</a> •
  66. <a href="https://daverupert.com/2021/10/html-with-superpowers/" title="Lien vers le contenu original">Source originale</a>
  67. </p>
  68. </nav>
  69. <hr>
  70. <p>Earlier this year I spoke at An Event Apart’s Spring Summit and today I’m happy to share with you that talk called <em>HTML with Superpowers</em>, which is all about Web Components.</p>
  71. <p><a href="https://noti.st/davatron5000/k6N2LP/html-with-superpowers" class="button">View slides on Notist</a></p>
  72. <p>This talk had two major objectives. Firstly, In January 2021 I joined the <a href="https://www.w3.org/community/webcomponents/">W3C Web Components Community Group</a>, which is hoping to advance Web Components and raise awareness. It’s a worthwhile cause to get over some of Web Components’ historical marketing problems. I also get a chance to provide feedback on nascent stage proposals. I’m a fringe member in this group, but happy to escalate any questions or feedback you have.</p>
  73. <p>The second reason I wanted to talk about Web Components is that I feel there’s an education gap. I noticed that nearly all the people I know that love HTML, CSS, and Design Systems… they don’t use Web Components. It makes sense when you realize a lot of web component education targets JavaScript developers. Every <em>How-To Web Components</em> post on <a href="http://Dev.to">Dev.to</a> starts with the class-based JavaScript API. That’s great… if you like JavaScript. But if I’m 100% honest, if you already have a JS framework that works for you, I don’t see much point in switching. That’s an intense amount of sunk costs and organizational entropy to overcome. I wanted to write a talk that approaches Web Components from a different angle.</p>
  74. <p>Emulating <a href="https://speaking.adactio.com/87IIn1#sn3gBTn">Jeremy Keith’s pacing layers for the Web</a>, which emulates Stuart Brand’s pacing layers for architecture, I start with the slower layers of the Web. The layers unlikely to change from under you and then build up to the “<a href="https://www.youtube.com/watch?v=RFm9ClqlGuo">Jeremy Beremy</a>” velocity of JavaScript. That means starting with HTML, then talk about CSS, then talk about JavaScript.</p>
  75. <h2>Part 1: How to use Web Components with HTML</h2>
  76. <p>Let’s start with HTML. Let’s use Web Components that someone else built. No build tools. No NPM install blah blah. Copy and paste a script tag from the web like the old days. I walk through half a dozen examples on how to use Web Components to make interactive sites, reusable components, and even 3D realms using HTML and a humble <code>&lt;script&gt;</code> tag.</p>
  77. <p>My favorite is <a href="https://github.com/GoogleChromeLabs/two-up"><code>&lt;two-up&gt;</code> from Google Chrome Labs</a> which you can use in your code today to make one of those neat before/after picture sliders.</p>
  78. <pre><code class="language-html">&lt;two-up&gt;
  79. &lt;div&gt;&lt;img src="before.jpg" alt="before"&gt;&lt;/div&gt;
  80. &lt;div&gt;&lt;img src="after.jpg" alt="after"&gt;&lt;/div&gt;
  81. &lt;/two-up&gt;
  82. &lt;script src="path/to/two-up.js"&gt;&lt;/script&gt;
  83. </code></pre>
  84. <p>I love it because I didn’t have to code it myself. I didn’t have to fuss with absolute positioning, pointer events, nothing. It gives me a great effect with ~5 lines of HTML.</p>
  85. <h2>Part 2: How to style Web Components with CSS</h2>
  86. <p>In the second part of the talk we come face to face with the most frustrating part of Web Components… styling.</p>
  87. <p>Styling Web Components is the biggest foot gun of the entire Web Component system because it involves something called “Piercing the Shadow DOM”. The Shadow DOM is a boundary inside the component where no styles bleed in and no styles bleed out… but some styles do pass through! Why??!? This is figure-outable, but it’s not intuitive and can leave you with a sour first experience.</p>
  88. <pre><code class="language-css">/* This does not work */
  89. custom-alert button {
  90. background: pink;
  91. }
  92. </code></pre>
  93. <p>When some styles pass through the shadow boundary and some styles don’t, it creates a bit of a frustrating developer experience. A loss of agency. As a CSS professional, I’m used to having access to style nearly everything on the page. But Web Components break that social contract and there’s not even a mechanism to say “Hey, I’m an expert, let me style this.”</p>
  94. <p>I did the thing where I chucked a lot of CSS at a Web Component to see what sticks. We also walk through options like CSS Custom Properties and CSS Named Parts that you can add to your components to offer more customizable styling APIs.</p>
  95. <h2>Part 3: Build Web Components with JS</h2>
  96. <p>The final step, I sort of bring it all together and write a <code>&lt;custom-alert&gt;</code> component using Lit. It’s a hundred lines of code and I’d wager it’s half CSS. If I could redo the talk I’d probably rip out the styles and layer them in at the end.</p>
  97. <p>The biggest takeaway that I hope people get is that components have a lifecycle, like a React or Vue component. And there are micro-libraries that give you different flavors of Web Components to suit your niche aesthetics. They also have a bit of reactive component state built-in and I could probably cover that more better next time around. Point being… they’re probably a little bit better than the last time you checked them out.</p>
  98. <h2>tl;dr</h2>
  99. <p>I think if you were using Web Components before 2020 you were an early adopter and you probably have some scars to show for it. But in 2021, now that all modern browsers support Web Components, I think they’re worth investigating. They have one superpower that no other JavaScript framework offers called the Shadow DOM which is both powerful but frustrating. But another superpower — the power I’m most excited about — is that you can use them standalone without any frameworks, build tools, or package managers.</p>
  100. <p>And from there, if we have good, robust Web Components… I believe they can inform the Web Platform and we can get more native elements in the future.</p>
  101. <p>If you have questions, want to air grievances, or would like to know more about Web Components, hit me up on Twitter. I’m also putting together a workshop on Web Components so if that interests you or your company please reach out.</p>
  102. </article>
  103. <hr>
  104. <footer>
  105. <p>
  106. <a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
  107. <use xlink:href="/static/david/icons2/symbol-defs.svg#icon-home"></use>
  108. </svg> Accueil</a> •
  109. <a href="/david/log/" title="Accès au flux RSS"><svg class="icon icon-rss2">
  110. <use xlink:href="/static/david/icons2/symbol-defs.svg#icon-rss2"></use>
  111. </svg> Suivre</a> •
  112. <a href="http://larlet.com" title="Go to my English profile" data-instant><svg class="icon icon-user-tie">
  113. <use xlink:href="/static/david/icons2/symbol-defs.svg#icon-user-tie"></use>
  114. </svg> Pro</a> •
  115. <a href="mailto:david%40larlet.fr" title="Envoyer un courriel"><svg class="icon icon-mail">
  116. <use xlink:href="/static/david/icons2/symbol-defs.svg#icon-mail"></use>
  117. </svg> Email</a> •
  118. <abbr class="nowrap" title="Hébergeur : Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33184162340"><svg class="icon icon-hammer2">
  119. <use xlink:href="/static/david/icons2/symbol-defs.svg#icon-hammer2"></use>
  120. </svg> Légal</abbr>
  121. </p>
  122. <template id="theme-selector">
  123. <form>
  124. <fieldset>
  125. <legend><svg class="icon icon-brightness-contrast">
  126. <use xlink:href="/static/david/icons2/symbol-defs.svg#icon-brightness-contrast"></use>
  127. </svg> Thème</legend>
  128. <label>
  129. <input type="radio" value="auto" name="chosen-color-scheme" checked> Auto
  130. </label>
  131. <label>
  132. <input type="radio" value="dark" name="chosen-color-scheme"> Foncé
  133. </label>
  134. <label>
  135. <input type="radio" value="light" name="chosen-color-scheme"> Clair
  136. </label>
  137. </fieldset>
  138. </form>
  139. </template>
  140. </footer>
  141. <script src="/static/david/js/instantpage-5.1.0.min.js" type="module"></script>
  142. <script>
  143. function loadThemeForm(templateName) {
  144. const themeSelectorTemplate = document.querySelector(templateName)
  145. const form = themeSelectorTemplate.content.firstElementChild
  146. themeSelectorTemplate.replaceWith(form)
  147. form.addEventListener('change', (e) => {
  148. const chosenColorScheme = e.target.value
  149. localStorage.setItem('theme', chosenColorScheme)
  150. toggleTheme(chosenColorScheme)
  151. })
  152. const selectedTheme = localStorage.getItem('theme')
  153. if (selectedTheme && selectedTheme !== 'undefined') {
  154. form.querySelector(`[value="${selectedTheme}"]`).checked = true
  155. }
  156. }
  157. const prefersColorSchemeDark = '(prefers-color-scheme: dark)'
  158. window.addEventListener('load', () => {
  159. let hasDarkRules = false
  160. for (const styleSheet of Array.from(document.styleSheets)) {
  161. let mediaRules = []
  162. for (const cssRule of styleSheet.cssRules) {
  163. if (cssRule.type !== CSSRule.MEDIA_RULE) {
  164. continue
  165. }
  166. // WARNING: Safari does not have/supports `conditionText`.
  167. if (cssRule.conditionText) {
  168. if (cssRule.conditionText !== prefersColorSchemeDark) {
  169. continue
  170. }
  171. } else {
  172. if (cssRule.cssText.startsWith(prefersColorSchemeDark)) {
  173. continue
  174. }
  175. }
  176. mediaRules = mediaRules.concat(Array.from(cssRule.cssRules))
  177. }
  178. // WARNING: do not try to insert a Rule to a styleSheet you are
  179. // currently iterating on, otherwise the browser will be stuck
  180. // in a infinite loop…
  181. for (const mediaRule of mediaRules) {
  182. styleSheet.insertRule(mediaRule.cssText)
  183. hasDarkRules = true
  184. }
  185. }
  186. if (hasDarkRules) {
  187. loadThemeForm('#theme-selector')
  188. }
  189. })
  190. </script>
  191. </body>
  192. </html>