Repository with sources and generator of https://larlet.fr/david/ https://larlet.fr/david/
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

index.html 24KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  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>
  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>Technique — David Larlet</title>
  13. <meta name="description" content="Cette fois promis c’est l’album de la maturité.">
  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="#f0f0ea">
  24. <meta name="msapplication-config" content="/static/david/icons2/browserconfig.xml">
  25. <meta name="theme-color" content="#f0f0ea">
  26. <!-- Documented, feel free to shoot an email. -->
  27. <link rel="stylesheet" href="/static/david/css/style_2020-06-19.css">
  28. <!-- See https://www.zachleat.com/web/comprehensive-webfonts/ for the trade-off. -->
  29. <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>
  30. <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>
  31. <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>
  32. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_regular.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  33. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_bold.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  34. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_italic.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  35. <script type="text/javascript">
  36. function toggleTheme(themeName) {
  37. document.documentElement.classList.toggle(
  38. 'forced-dark',
  39. themeName === 'dark'
  40. )
  41. document.documentElement.classList.toggle(
  42. 'forced-light',
  43. themeName === 'light'
  44. )
  45. }
  46. const selectedTheme = localStorage.getItem('theme')
  47. if (selectedTheme !== 'undefined') {
  48. toggleTheme(selectedTheme)
  49. }
  50. </script>
  51. <body class="remarkdown h1-underline h2-underline h3-underline hr-center ul-star pre-tick" data-instant-intensity="viewport-all">
  52. <article>
  53. <header>
  54. <h1>Technique</h1>
  55. </header>
  56. <nav>
  57. <p class="center">
  58. <a rel="prev" href="/david/2020/02/21/" title="Publication précédente : Service">←</a> •
  59. <a href="/david/" title="Aller à l’accueil">🏠</a>
  60. • <a rel="next" href="/david/2020/03/20/" title="Publication suivante : Rédemption">→</a>
  61. </p>
  62. </nav>
  63. <hr>
  64. <main>
  65. <p><em>Cette fois promis c’est l’album de la maturité.</em></p>
  66. <h2 id="une-suite">Une suite ? <a href="#une-suite" title="Ancre vers cette partie">#</a></h2><p>Vous avez été nombreux (comprendre, environ deux) à me demander s’il y avait une suite à <a href="/david/blog/2016/minimalisme-esthetique/">Minimalisme et esthétique</a> puis <a href="/david/blog/2016/simplicite-defaut/">Simplicité par défaut</a> et comme les trilogies vont toujours mieux par trois, vous pouvez considérer ce qui suit comme <em>mon</em> cheminement personnel ces quatre dernières années.</p>
  67. <p>L’état de l’art en matière de développement web n’a pas vraiment l’air d’être allé vers davantage de simplicité, de minimalisme et encore moins d’esthétisme au cours de cet intervalle. <em>C’est peu de le dire, enfin l’écrire.</em> Ce qui a changé par contre, c’est mon expérience — d’aucuns appelleraient ça vieillesse — et mon envie d’échapper à cela en fuyant les produits et donc équipes qui mettent la technique avant les utilisateur·ice·s.</p>
  68. <p>Je vous divulgâche le résultat tout de suite : je me sens plus apaisé sur ce plan là. La présence de <a href="https://ronan.amicel.net/">Ronan</a> dans mon <a href="/david/blog/2019/faire-equipe/">équipe actuelle</a> n’est pas étrangère à ce sentiment mais le choix des technologies employées me donne <em>aussi</em> un sentiment de contrôle salutaire.</p>
  69. <hr />
  70. <p>En guise d’introduction aussi, j’ai conscience d’être dans un <a href="http://scopyleft.fr/">environnement</a> <a href="https://beta.gouv.fr/">extrêmement</a> <a href="http://larlet.com/">privilégié</a> me permettant d’avoir la liberté suffisante pour être en capacité de faire ces choix. C’est loin d’être anodin dans l’exploration qui suit.</p>
  71. <h2 id="le-probleme">Le problème <a href="#le-probleme" title="Ancre vers cette partie">#</a></h2>
  72. <blockquote lang="en">
  73. <p>Eventually, I settled on a list of questions I would ask myself for each problem as it arose. I found that asking these questions, in order, helped me make the best decision possible:</p>
  74. <ol>
  75. <li>Is this really a problem?</li>
  76. <li>Does the problem need to be solved?</li>
  77. <li>Does the problem need to be solved now?</li>
  78. <li>Does the problem need to be solved by me?</li>
  79. <li>Is there a simpler problem I can solve instead?</li>
  80. </ol>
  81. <p>Each question is designed to reveal something about the problem that allows you to go to the next step, or if you’re lucky, <mark>just avoid the problem altogether</mark>.</p>
  82. <p><cite><em><a href="https://humanwhocodes.com/blog/2020/02/how-i-think-about-solving-problems/">How I think about solving problems</a></em> (<a href="/david/cache/2020/bdc65ed9d2657f45d13d97186072b415/">cache</a>)</cite></p>
  83. </blockquote>
  84. <p>C’est le principal fléau de notre industrie : tenter de résoudre des problèmes là où il n’y a pas de besoin. Le solutionnisme technologique ne devrait être que la dernière option mais cela serait mauvais pour le <em>business</em>. Alors on met des paillettes pour faire passer la pilule et encaisser le chèque en fin de mois.</p>
  85. <p>Vous connaissez le fameux <cite>« Je vous écris une longue lettre parce que je n’ai pas le temps d’en écrire une courte »</cite> de Blaise Pascal, il se trouve que cela s’applique aussi à l’élaboration d’un produit. Les solutions frugales coûtent parfois autant (si ce n’est plus !) que les usines à gaz. Cela prend du temps de comprendre une problématique, cela prend du temps d’échanger avec des utilisateur·ice·s, cela prend du temps de déterminer quelles sont les fonctionnalités qui ne sont pas/plus utiles. <strong>Cela prend du temps de produire des choses im·pertinentes.</strong></p>
  86. <p>En contrepartie, elles permettent d’économiser sur le long terme en réduisant la maintenance, le périmètre de support et l’exploitation du produit. En se focalisant sur la pertinence, on conserve une application à échelle humaine. Autant dans l’usage que dans la conception.</p>
  87. <hr />
  88. <p>Mon contentement est grand lorsque je suis surpris par la résilience du code auquel je contribue. J’ai soudain l’impression d’avoir pas trop mal fait les choses. C’est assez rare pour être célébré comme il se doit.</p>
  89. <h2 id="javascript">JavaScript <a href="#javascript" title="Ancre vers cette partie">#</a></h2>
  90. <blockquote lang="en">
  91. <p>The performance tradeoff isn’t about <em>where</em> the bottleneck is. It’s about <em>who</em> has to carry the burden. It’s one thing for a developer to push the burden onto a server they control. It’s another thing entirely to expect visitors to carry that load when connectivity and device performance isn’t a constant.</p>
  92. <p>Developer productivity is a great metric, but it can’t be isolated from the larger ecosystem. With Ruby, the tradeoff works because nothing is externalized, and it’s barely even a tradeoff these days. But with large front-end JavaScript frameworks, things aren’t just slow. If that JavaScript isn’t able to be loaded for a variety of reasons, sites don’t just become a little slower. <mark>They break entirely.</mark></p>
  93. <p><cite><em><a href="https://garrettdimon.com/2020/visitors-developers-or-machines/">Visitors, Developers, or Machines</a></em> (<a href="/david/cache/2020/af5d5f52466dfc2f59718294faa07418/">cache</a>)</cite></p>
  94. </blockquote>
  95. <p>Je ne peux pas parler de technique et de Web sans parler de JavaScript et de ce que l’on fait subir à chaque personne qui visite une page. Les compromis qui sont fait actuellement sont propres à un contexte qui donne une ascendance aux riches développeurs et développeuses qui peuvent se permettre <a href="https://hankchizljaw.com/wrote/honesty-is-the-best-policy/">avec leur matériel récent</a> (<a href="/david/cache/2020/195a2ecd81fa25a7cf43248b809bf724/">cache</a>) de faire des pages tout saufs <em>réact</em>ives pour le reste du monde. Ma machine <a href="/david/stream/2015/07/19/">a bientôt cinq ans</a> et se trouve être limite inutilisable pour du développement web, <strong>comment ose-t-on ?</strong></p>
  96. <p>Je trouve cela terrible, autant en terme de (non)empathie que de consommation de ressources si l’on considère les coûts de manière globale et transverse. Cela a de quoi <a href="https://www.matuzo.at/blog/why-543kb-keep-me-up-at-night/">m’empêcher de dormir aussi</a> (<a href="/david/cache/2020/fc97310297178a549eab5c5f9e8a334f/">cache</a>), déporter une grande partie de la complexité et du calcul du côté du navigateur s’avère être contre-productif <em>dans une majorité des cas</em>.</p>
  97. <blockquote lang="en">
  98. <p>HTTP 262 JAVASCRIPT UNNECESSARILY REQUIRED; the content is available but you’d better have a good CPU and 15 seconds of free time before the first pixel gets painted</p>
  99. <p><cite>Taudry Hepburn <a href="https://twitter.com/tabatkins/status/1232065732034191360">sur Twitter</a></cite></p>
  100. </blockquote>
  101. <p>On ne peut pas non plus parler de technologie sans son usage et ce n’est pas tant JavaScript que ce qui est fait avec qui m’importune. En tant que développeur, c’est mon quotidien d’apprendre à m’adapter et je sens bien que je pourrais devenir un peu moins incompétent sur le sujet <em>mais</em> c’est en tant qu’usager que je n’en peux plus. Manque de résilience, réduction des performances, tentative de prise de contrôle de mon navigateur et je n’évoque même pas tout ce qui essaye de consigner mes moindres clics.</p>
  102. <p>Heureusement que les navigateurs implémentent un <em>mode lecteur</em> qui rend certains sites juste… lisibles. Je ne compte plus le nombre de fois où je suis carrément obligé d’aller supprimer un nœud du <abbr title="Document Object Model">DOM</abbr> à la main (!) pour pouvoir afficher une page web. Fâcheux.</p>
  103. <hr />
  104. <p>Aujourd’hui, lorsque la <a href="http://vanilla-js.com/">vanille</a> ne me suffit plus, j’utilise <a href="https://stimulusjs.org/">StimulusJS</a> que je trouve être la moins mauvaise solution. On garde du <abbr title="HyperText Markup Language">HTML</abbr> propre et interprétable ce qui facilite l’amélioration progressive. C’est relativement léger compte tenu de l’aide que ça m’apporte pour structurer mon code. Et c’est suffisamment limité pour me permettre de prendre conscience de mon erreur lorsque j’essaye de mettre trop de logique dans le navigateur.</p>
  105. <h2 id="transmission">Transmission <a href="#transmission" title="Ancre vers cette partie">#</a></h2>
  106. <blockquote>
  107. <p>Aucun code n’a changé ma vie.</p>
  108. <p><cite><em>via Mastodon, publication privée</em></cite></p>
  109. </blockquote>
  110. <p>On touche ici du doigt une chose qui me semble être essentielle, le fait de savoir écouter <em>et</em> aussi de prendre la parole pour accompagner et montrer avec une petite lanterne que d’autres voies sont possibles. Qu’il y a un autre niveau de plaisir à rendre disponibles des outils utiles et relativement frugaux.</p>
  111. <p>Aucun code n’a changé ma vie mais le fait de partager mes réflexions dessus a eu des conséquences non négligeables. Que ce soit sur cet espace ou lors de conférences ou par courriel ou en échangeant avec des collègues ou autres. Chaque échange est une occasion de me faire changer et <em>en même temps</em> de faire changer mon interlocuteur·ice.</p>
  112. <p>Sans l’imposer, raconter une voie qui pourrait résonner chez l’autre. Sans prétention autre que celle de dire que cela existe, que certaines utopies ne sont pas si inaccessibles.</p>
  113. <blockquote>
  114. <p>L’avan­tage c’est qu’a­vec l’ex­pé­rience, norma­le­ment, vous pouvez appor­ter plus que votre code. Le péri­mètre n’a aucune raison d’être iden­tique avec les années.</p>
  115. <p><cite><em><a href="https://n.survol.fr/n/vieux-developpeur-pas-manager">Vieux développeur, pas manager</a></em> (<a href="/david/cache/2020/874765e437a144748e9438d272b1177a/">cache</a>)</cite></p>
  116. </blockquote>
  117. <p>Exactement, vous pouvez accompagner d’autres personnes, participer à la conception du produit, interviewer des utilisateur·ice·s, et pleins d’autres trucs auxquels je ne pense pas. Si ça se trouve, vous commencez à suffisamment vous connaître pour prendre du recul au bon moment afin de ne pas devenir un goulot d’étranglement ou tout simplement vous protéger.</p>
  118. <p><em>Tout cela a de la valeur.</em></p>
  119. <h2 id="tendance">Tendance <a href="#tendance" title="Ancre vers cette partie">#</a></h2>
  120. <blockquote>
  121. <p>tiens, une question pour les vieux réacs : quelle est la dernière chose tendance que vous trouvez utile ?</p>
  122. <p><cite><em>via <abbr title="Internet Relay Chat">IRC</abbr></em></cite></p>
  123. </blockquote>
  124. <p><strong>Alléger.</strong> Proposer un <a href="http://blog.danieljanus.pl/2019/10/07/web-of-documents/">web de documents</a> (<a href="/david/cache/2020/31652af3fd4757154c51aadcbe9ffb39/">cache</a>) lorsqu’il est possible. Fuir ce qui ressemble à de <a href="https://adactio.com/journal/16404">l’hydratation (?!)</a> (<a href="/david/cache/2020/911b72ae5d6e140268adf8591aae7df3/">cache</a>) ou toute autre fausse bonne idée réduisant l’accessibilité (et les performances mais c’est pour moi un pléonasme).</p>
  125. <p>Prendre le temps d’expliquer pourquoi vous avez fait ces choix dans ce contexte particulier. Partager le fait que l’on peut faire des choses chouettes en utilisant des « <a href="https://mcfunley.com/choose-boring-technology">boring technologies</a> (<a href="/david/cache/2020/6723325d9229f986f6b77cc5ff6d3ef2/">cache</a>) », que la valeur n’est pas forcément là. Se méfier aussi de ce qui semble <em>boring</em> mais <a href="https://daverupert.com/2020/02/html-the-inaccessible-parts/">n’est pas pour autant trivial</a> (<a href="/david/cache/2020/a70068c881eba36604b2f4f8aec54670/">cache</a>) ou bien toujours <a href="https://css-tricks.com/why-is-css-frustrating/">incompris par beaucoup</a> (<a href="/david/cache/2020/afb9fa99e3c43324fbe57b416562b8f9/">cache</a>).</p>
  126. <p>On peut courir après la technologie, c’est plaisant une heure par-ci par-là pour découvrir de nouveaux paysages. De temps en temps même un petit marathon pour rester en forme. Mais à force d’être focalisé sur les prochains pas, j’en étais arrivé à perdre de vue l’intérêt du chemin. Un périple au service de <em>ma</em> vision de l’utilité.</p>
  127. <hr />
  128. <p>Je suis conscient que je me tire peut-être une balle dans le pied en énonçant toutes ces frustrations publiquement. Ou peut-être que cela me permettra au contraire d’entrer en contact avec des personnes qui partagent cette approche. On verra bien, n’hésitez pas à me contacter pour échanger là-dessus.</p>
  129. <h2 id="docker">Docker <a href="#docker" title="Ancre vers cette partie">#</a></h2>
  130. <blockquote lang="en">
  131. <p>Code must run behind at least three levels of virtualization now. Code that runs on bare metal is unnecessarily performant.</p>
  132. <p><cite><em><a href="https://medium.com/swlh/how-is-computer-programming-different-today-than-20-years-ago-9d0154d1b6ce">How is computer programming different today than 20 years ago?</a></em> (<a href="/david/cache/2020/4bf3df418cd5d6e14bc6e1b2bda9b12d/">cache</a>)</cite></p>
  133. </blockquote>
  134. <p>La critique est acerbe et juste. J’en suis à refuser des projets car l’empilement de technologies me semble être trop bancal pour ne pas risquer de faire tout tomber sans comprendre ce qu’il s’est passé.</p>
  135. <p>Et je ne parle même pas de la charge mentale associée à toute cette pile technique qui détourne de l’intérêt principal d’un produit. Ni du surcoût pour chaque nouvelle personne souhaitant participer (en dépit de la promesse inverse !). Ou du besoin d’avoir une machine récente pour que tout puisse tourner tellement il y a de couches accumulées.</p>
  136. <blockquote lang="en">
  137. <p>So here’s the counterargument: Integrated systems are good. Integrated developers are good. Being able to wrap your mind around the whole application, and have developers who are able to make whole features, is good! The road to madness and despair lays in specialization and compartmentalization.</p>
  138. <p><cite><em><a href="https://m.signalvnoise.com/integrated-systems-for-integrated-programmers/">Integrated systems for integrated programmers</a></em> (<a href="/david/cache/2020/ef5d670c8473add5c3e43f8d4db2eed0/">cache</a>)</cite></p>
  139. </blockquote>
  140. <p>Je ne veux pas que ma connaissance soit « virtualisée », je ne veux pas que mon application devienne une boîte noire, je ne produis pas de l’électroménager. <strong>J’ai parfois l’impression de me battre contre ma propre prolétarisation.</strong> Suis-je un <a href="/david/stream/2018/06/15/">Luddite</a> moderne de penser cela ?</p>
  141. <h2 id="mudita">Mudita <a href="#mudita" title="Ancre vers cette partie">#</a></h2>
  142. <blockquote lang="en">
  143. <p>What enough means for me, only concerns me, and should only be compared to myself: where I’m actually at versus where I’m working to get to. As in, am I presently happy or do I assume I’ll be happier in the future, and if so, why?</p>
  144. <p>Enough is the antithesis of unchecked growth because growth encourages mindless consumption and enough requires constant questioning and awareness. Enough is when we reach the upper bound of what’s required.</p>
  145. <p><cite><em><a href="https://pjrvs.com/enough">Enough</a></em> (<a href="/david/cache/2020/f61e3ce56d0360e061f4b22e0bb20e47/">cache</a>)</cite></p>
  146. </blockquote>
  147. <p>Toutes ces réflexions sont très personnelles. Vous pouvez être à un niveau différent de prise de conscience — et c’est très sain. Vous pouvez aussi avoir des contraintes beaucoup plus fortes où d’autres choix seraient beaucoup plus valides. Pour ma part, <strong>je pense avoir assez d’outils pour continuer des expériences utiles où le facteur limitant n’est pas technique.</strong> Et si jamais il le devient, je serais ravi de savoir qu’il y a des personnes différentes qui sont prêtes à relever ces défis.</p>
  148. <blockquote lang="en">
  149. <p>In Sanskrit, there’s a term called <em>mudita</em>, and there’s no equivalent word in English. Essentially, it means to have sympathetic or unselfish joy for others—<mark>regardless of where they’re at in their own lives</mark>. Really, if we spend less time envying or assuming that others think less of us because they’re in a different place than we are, then it becomes easier to focus on what’s important to ourselves.</p>
  150. <p><cite><em>Ibid.</em></cite></p>
  151. </blockquote>
  152. <p>Chacun sa route, chacun son chemin. Passe le <a href="/david/blog/2019/flux-rss/">flux RSS</a> à ton voisin (ou ta voisine).</p>
  153. </main>
  154. <nav>
  155. <p class="center">
  156. <a rel="prev" href="/david/2020/02/21/" title="Publication précédente : Service">←</a> •
  157. <a href="/david/2020/" title="Liste des publications récentes">↑</a>
  158. • <a rel="next" href="/david/2020/03/20/" title="Publication suivante : Rédemption">→</a>
  159. </p>
  160. </nav>
  161. </article>
  162. <hr>
  163. <footer>
  164. <p>
  165. <a href="/david/" title="Aller à l’accueil">🏠</a> •
  166. <a href="/david/log/" title="Accès au flux RSS">🤖</a> •
  167. <a href="http://larlet.com" title="Go to my English profile" data-instant>🇨🇦</a> •
  168. <a href="mailto:david%40larlet.fr" title="Envoyer un courriel">📮</a> •
  169. <abbr title="Hébergeur : Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33184162340">🧚</abbr>
  170. </p>
  171. <template id="theme-selector">
  172. <form>
  173. <fieldset>
  174. <legend>Thème</legend>
  175. <label>
  176. <input type="radio" value="auto" name="chosen-color-scheme" checked> Auto
  177. </label>
  178. <label>
  179. <input type="radio" value="dark" name="chosen-color-scheme"> Foncé
  180. </label>
  181. <label>
  182. <input type="radio" value="light" name="chosen-color-scheme"> Clair
  183. </label>
  184. </fieldset>
  185. </form>
  186. </template>
  187. </footer>
  188. <script src="/static/david/js/instantpage-5.1.0.min.js" type="module" defer></script>
  189. <script type="text/javascript">
  190. function loadThemeForm(templateName) {
  191. const themeSelectorTemplate = document.querySelector(templateName)
  192. const form = themeSelectorTemplate.content.firstElementChild
  193. themeSelectorTemplate.replaceWith(form)
  194. form.addEventListener('change', (e) => {
  195. const chosenColorScheme = e.target.value
  196. localStorage.setItem('theme', chosenColorScheme)
  197. toggleTheme(chosenColorScheme)
  198. })
  199. const selectedTheme = localStorage.getItem('theme')
  200. if (selectedTheme && selectedTheme !== 'undefined') {
  201. form.querySelector(`[value="${selectedTheme}"]`).checked = true
  202. }
  203. }
  204. const prefersColorSchemeDark = '(prefers-color-scheme: dark)'
  205. window.addEventListener('load', () => {
  206. let hasDarkRules = false
  207. for (const styleSheet of Array.from(document.styleSheets)) {
  208. let mediaRules = []
  209. for (const cssRule of styleSheet.cssRules) {
  210. if (cssRule.type !== CSSRule.MEDIA_RULE) {
  211. continue
  212. }
  213. // WARNING: Safari does not have/supports `conditionText`.
  214. if (cssRule.conditionText) {
  215. if (cssRule.conditionText !== prefersColorSchemeDark) {
  216. continue
  217. }
  218. } else {
  219. if (cssRule.cssText.startsWith(prefersColorSchemeDark)) {
  220. continue
  221. }
  222. }
  223. mediaRules = mediaRules.concat(Array.from(cssRule.cssRules))
  224. }
  225. // WARNING: do not try to insert a Rule to a styleSheet you are
  226. // currently iterating on, otherwise the browser will be stuck
  227. // in a infinite loop…
  228. for (const mediaRule of mediaRules) {
  229. styleSheet.insertRule(mediaRule.cssText)
  230. hasDarkRules = true
  231. }
  232. }
  233. if (hasDarkRules) {
  234. loadThemeForm('#theme-selector')
  235. }
  236. })
  237. </script>
  238. </body>
  239. </html>