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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  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>Stupeur et tremblements : comment faire fuir les développeuses expérimentées. (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. <!-- Is that even respected? Retrospectively? What a shAItshow…
  28. https://neil-clarke.com/block-the-bots-that-feed-ai-models-by-scraping-your-website/ -->
  29. <meta name="robots" content="noai, noimageai">
  30. <!-- Documented, feel free to shoot an email. -->
  31. <link rel="stylesheet" href="/static/david/css/style_2021-01-20.css">
  32. <!-- See https://www.zachleat.com/web/comprehensive-webfonts/ for the trade-off. -->
  33. <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>
  34. <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>
  35. <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>
  36. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_regular.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  37. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_bold.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  38. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_italic.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  39. <script>
  40. function toggleTheme(themeName) {
  41. document.documentElement.classList.toggle(
  42. 'forced-dark',
  43. themeName === 'dark'
  44. )
  45. document.documentElement.classList.toggle(
  46. 'forced-light',
  47. themeName === 'light'
  48. )
  49. }
  50. const selectedTheme = localStorage.getItem('theme')
  51. if (selectedTheme !== 'undefined') {
  52. toggleTheme(selectedTheme)
  53. }
  54. </script>
  55. <meta name="robots" content="noindex, nofollow">
  56. <meta content="origin-when-cross-origin" name="referrer">
  57. <!-- Canonical URL for SEO purposes -->
  58. <link rel="canonical" href="https://www.duchess-france.fr/coup%20de%20gueule/sexisme/2023/03/06/stupeur-et-trembements.html">
  59. <body class="remarkdown h1-underline h2-underline h3-underline em-underscore hr-center ul-star pre-tick" data-instant-intensity="viewport-all">
  60. <article>
  61. <header>
  62. <h1>Stupeur et tremblements : comment faire fuir les développeuses expérimentées.</h1>
  63. </header>
  64. <nav>
  65. <p class="center">
  66. <a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
  67. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-home"></use>
  68. </svg> Accueil</a> •
  69. <a href="https://www.duchess-france.fr/coup%20de%20gueule/sexisme/2023/03/06/stupeur-et-trembements.html" title="Lien vers le contenu original">Source originale</a>
  70. </p>
  71. </nav>
  72. <hr>
  73. <p>Étant bien à l’aise dans mon poste actuel, j’avais commencé à demander à passer à l’échelon technique supérieur 🪜.
  74. J’en ai discuté avec mon manager, il m’a partagé les critères pour l’étape suivante et j’ai rempli un document qui montre que sur tous les points j’ai le niveau. On en a discuté et il est rapidement arrivé à la conclusion que de toute façon je faisais déjà le travail du poste au dessus, donc il allait soutenir ma promotion à la prochaine fournée.
  75. <strong>Moi j’étais toute contente: “Youpi, enfin une entreprise dans laquelle j’ai mes chances !”.</strong>
  76. Les processus de promotion sont souvent annuels, ou biannuels et je savais bien qu’il me fallait un peu de patience.</p>
  77. <p>Vient un jour de réunion générale ou tout d’un coup surgit un slide pour féliciter les personnes fraîchement promues et là, comme dirait Amélie Nothomb: <strong>stupeur et tremblement</strong> ! Ça me frappe immédiatement: j’aurais dû être sur ce slide ! Que s’est-il passé ?</p>
  78. <h1 id="une-grande-parenthèse-dans-le-passé">Une grande parenthèse dans le passé</h1>
  79. <p>Je fais une grande parenthèse.
  80. J’ai dans mes premières années en tant que développeuse subi une période de harcèlement moral. Par des développeurs misogynes qui se sont ligués contre moi pour pouvoir mieux être promus, et ils ont réussi.
  81. Ils m’ont dénigrée auprès des managers sans que j’en sache rien, ils s’amusaient à changer des parties de l’application au dernier moment pour que la partie que je développais ne fonctionne plus lors des démonstrations.
  82. Quand j’entrais dans la pièce où ils étaient pour discuter projet, ils se taisaient et m’ignoraient.
  83. Ils sont allés jusqu’à s’attribuer certaines de mes réalisations.
  84. Et quand, n’ayant aucune écoute côté management, j’ai osé dire par email à l’équipe tant bien que mal que ça ne pouvait pas continuer…
  85. On m’a juste reproché d’écrire un email, et ignoré totalement le fond.
  86. A noter qu’évidemment le plus toxique et misogyne dans l’histoire c’était le développeur qui visait une carrière technique.
  87. Il a continué pendant des années derrière à évincer toute concurrence d’autant plus violemment si cette concurrence était racisée et/ou féminine.
  88. <strong>Un cas somme toute classique de “oui c’est des gens toxiques mais bon ils sont performants alors on les laisse faire”.</strong></p>
  89. <p>J’ai mis plus d’un an à comprendre que le problème ce n’était pas moi, grâce à beaucoup de témoignages du genre “oui mais bon avec eux tu avais aucune chance, t’es une femme”.
  90. Grâce aussi au fait qu’en changeant de poste, sans vraiment changer ma façon de faire, je suis tout d’un coup passée de “développeuse toute nulle” à “développeuse super forte je te veux dans mon équipe”.
  91. Et grâce aux histoires misogynes et racistes qui ont continué après moi, au vu et au su de tout le monde, en toute impunité.
  92. <strong>Il m’a fallu plusieurs années pour mettre les mots harcèlement moral</strong> - plus d’années que la durée de prescription de 5 ans.
  93. Je me suis informée et formée sur les biais, y compris les biais sexistes, et aussi le conditionnement social.
  94. J’ai gravi des échelons, choisissant soigneusement les personnes avec qui j’allais travailler, évitant à tout prix des personnes que j’estimais à risque pour moi.
  95. Ça m’a peut-être fermé des opportunités, peut-être pas je ne saurai jamais.
  96. Mais ça m’a mise sur le qui-vive un peu permanent.
  97. La “safe place” ce n’est pas un concept marketing de recrutement pour moi, mais une nécessité.</p>
  98. <p>Pourquoi cette parenthèse ? Simplement pour expliquer que comme je m’étais déjà confrontée à un mur de sexisme crasse, j’avais depuis beaucoup appris sur les mécanismes de mise à l’écart des femmes et des personnes sous représentées.
  99. <strong>Et pourtant, je n’ai rien pu faire pour empêcher ce second gros mur que j’ai pris dans la face.</strong></p>
  100. <h1 id="de-retour-vers-stupeur-et-tremblements">De retour vers “stupeur et tremblements”</h1>
  101. <p>Suite à cette réunion générale avec l’absence visible - uniquement par moi - de mon nom sur la liste des personnes promues, je suis revenue vers mon manager avec un document écrit, expliquant que je ne comprenais pas et avec la liste factuelle des raisons qui font que j’aurais dû avoir cette promotion.
  102. On se voit en face à face rapidement: il était embêté et furieux. Il avait bien présenté mon nom à la réunion de promotions, mais son supérieur se serait braqué, sans raisons.
  103. Et depuis il essayait tant bien que mal d’obtenir des réponses sur la justification de la non promotion, mais n’en avait aucune.
  104. <strong>Moi ni une ni deux: un refus de promotion sans aucune justification, ce n’est pas normal !!</strong>
  105. Je saisis les RH, explique mon cas et mon désarroi.
  106. Je glisse au passage que toutes les personnes promues ces deux dernières années sont des hommes, et que j’ai des doutes de biais sexistes.
  107. Je partage aussi que je trouve ça d’autant plus injuste que j’arrive au même niveau de compétences alors j’ai eu à travailler tout en gérant les enfants pendant le covid, alors que la plupart des développeurs autour de moi étaient soit sans enfant, soit avec la mère sans emploi, par choix ou cause covid, qui gérait la maison et les enfants.
  108. Je reçois en retour la garantie qu’il va y avoir une enquête…
  109. Puis j’attends, pas forcément les bras croisés.</p>
  110. <p>Parmi les personnes promues, il y avait un homme avec qui le courant passait bien : ça tombe bien il venait d’être promu au niveau que je visais !
  111. Après l’avoir félicité, je lui demande “Dis moi, quelles étapes tu as dû suivre pour ta promotion ?”.
  112. Sa réponse me laisse sans voix: “Basiquement j’ai juste demandé, j’ai expliqué pourquoi et voilà quoi”.</p>
  113. <p>Ah… 🤯</p>
  114. <p>Suite à tout ça, j’ai du mal à me concentrer au travail.
  115. A un moment dans un point de synchronisation entre développeurs, je m’excuse auprès des collègues et je leur explique qu’on m’a refusé la promotion, et que ça me perturbe beaucoup dans mon travail.
  116. Le développeur le plus expérimenté de l’équipe me confirme que notre manager lui avait demandé et qu’il avait validé que j’avais le niveau.
  117. Deux autres développeurs expriment en privé leur indignation et leur désaccord aussi avec la non promotion, et me donnent leur précieux soutien.
  118. <strong>Je me dis que les RH vont gérer, j’y crois encore.</strong>
  119. Sur ce, mon manager démissionne, je crois être la goutte qui a fait déborder le vase, mais je ne le saurai jamais.</p>
  120. <p>Les jours passent, et je me retrouve dans une réunion “face à face” avec le supérieur de mon manager.
  121. Situation que je voulais éviter mais bon, je reste professionnelle, je prends mon courage à deux mains et j’y vais quand même, ne sachant pas trop à quoi m’attendre.
  122. Et là surprise…. Il me sort le texte que j’avais rédigé avec mon manager.
  123. Moment de gêne, puis il me dit qu’il est désolé que j’ai été impactée.
  124. Je reste sans voix: “Impactée ??” Il m’explique qu’effectivement mon manager a proposé mon nom en fin de réunion, mais qu’ils n’avaient plus le temps et que de toute façon mon manager s’est braqué.
  125. Globalement il met tout sur le dos de mon manager, ce dernier n’étant plus dans l’entreprise, c’est un peu l’excuse toute trouvée.
  126. Il me dit vaguement que je manque de visibilité, ce à quoi je commence à lui exposer toutes les réalisations que j’ai faites, incluant des talks en public et enregistrés donc facilement consultables.
  127. Il me coupe rapidement, non c’est pas ça.
  128. Je ne suis pas assez visible de lui.
  129. Il m’explique aussi que le document que j’ai dûment rempli ne sert à rien, de toute façon c’est lui qui décide.
  130. <strong>Il m’explique aussi au passage que je ne peux pas me comparer aux autres personnes qui ont le niveau du dessus, parce que certains d’entre eux - tous des hommes au passage - ont eu la promotion alors qu’ils ne la méritaient pas.</strong></p>
  131. <p>Les bras m’en tombent.</p>
  132. <p>Donc des hommes qui ne méritent pas la promotion l’ont, et moi pour qui on est incapable de me dire ce qu’il manque je ne l’ai pas ?
  133. Et ça ne choque que moi dans cette entreprise ?</p>
  134. <p><strong>Heureusement, j’avais commencé à chercher du soutien auprès de quelques Duchess, elles ont été formidables et m’ont beaucoup aidée, je les remercie vraiment très fort. 💖</strong></p>
  135. <p>Les RH reviennent, la bouche en coeur “bon c’est bon on a vérifié, c’est pas du sexisme”.</p>
  136. <p>Et voilà c’est tout. 😲</p>
  137. <p>Avoir un refus de promotion sans aucune justification écrite n’a pas l’air de les gêner.
  138. Que plusieurs hommes aient obtenu la promotion sans vraiment avoir le niveau ne les fait pas réagir non plus.
  139. Dans ma tête, un refus de promotion sans justification était limite illégal, et s’il n’est pas possible de justifier le refus c’est donc bien que la promotion est due, non ? Je m’attendais à ce qu’iels reprennent mon dossier, avec la liste des réalisations, des justifications et me fassent au moins un retour de ce qu’il manque à mon travail.
  140. Non rien…. Rien sur quoi travailler ou se projeter.
  141. Mission impossible: il ne me manque rien mais je n’ai pas ce qu’il faut.</p>
  142. <p>Pire encore, quand j’essaye d’évoquer les biais inconscients que nous avons toutes et tous et qui desservent les femmes notamment dans la carrière, parce que je pense alors très fortement que c’est le mécanisme en œuvre, je me heurte à un mur d’incompréhension totale.
  143. “Mais non, <strong>moi je ne fais aucune différence entre les hommes et les femmes !</strong>”
  144. <strong>C’est tellement faux cette phrase</strong>, c’est la base de l’ouverture à la diversité: on a toutes et tous des biais sexistes, racistes, validistes, grossophobes et j’en passe.
  145. L’accepter c’est la première étape obligatoire pour progresser en tant que société.</p>
  146. <p><strong>C’est vraiment violent, en plus du sentiment de discrimination, que d’avoir à faire à des personnes qui n’ont pas le vocabulaire ni les concepts.</strong>
  147. C’est très bien expliqué dans la conférence <a href="https://mixitconf.org/2022/violence-hermeneutique-comment-eviter-le-malaise-">Violence hermeneutique</a>.</p>
  148. <h1 id="dépitée-je-me-lève-et-je-me-casse">Dépitée, je me lève et je me casse</h1>
  149. <p>Un nouveau manager est désigné, à peu près au courant de ma situation.
  150. Son point de vue: ok on va travailler à ma promotion à partir de maintenant, par contre après avoir échangé avec les RHs il vaut mieux éviter les derniers mois parce que j’ai été un peu agressive.
  151. Je perds donc un an à un an et demi et je recommence à zéro ?
  152. Tout ça parce qu’un supérieur “ne le sent pas” ?
  153. Je suis victime d’erreurs de management et d’incompétences et c’est moi qui paye les pots cassés ?
  154. Et je suis agressive quand j’exprime mon vécu de discrimination ?
  155. Sérieusement ?</p>
  156. <p>J’ai posé ma démission le jour suivant, quitte à recommencer de zéro autant recommencer ailleurs !</p>
  157. <p><img src="https://www.duchess-france.fr/assets/2023/03/2023-03-08-stupeur-et-tremblements/plafond-de-verre-2.jpeg" alt=" Image d'une femme coincée sous un plafond de verre. La direction lui dit &quot;Le plafond de verre c'est notre plancher, alors ne le cassez pas.&quot;"></p>
  158. <h1 id="je-suis-fatiguée-de-tout">Je suis fatiguée…. de tout</h1>
  159. <p>Heurter un second mur en connaissance de cause est d’autant plus brutal et plus violent.
  160. Je commence à réaliser que je n’ai absolument aucun moyen de me protéger de cette violence, je peux juste espérer avoir de la chance et arrêter de tomber sur des personnes toxiques faussement ouvertes à la diversité.
  161. <strong>Isabelle Collet</strong> en parle dans son livre <strong>“les oubliées du numérique”</strong> de cette chance, ou pas, de ne jamais croiser une ou des personnes qui vont bloquer la carrière des femmes.
  162. Mon cas personnel confirme en tout cas son étude.</p>
  163. <p><img src="https://www.duchess-france.fr/assets/2023/03/2023-03-08-stupeur-et-tremblements/journee-de-la-femme.jpeg" alt=" Image avec deux femmes qui disent &quot;Nous voulons l'égalité salariale entre hommes et femmes!&quot;. L'homme derrière le bureau répond &quot;Une journée de la femme par an, ça ne vous suffit plus ?&quot;"></p>
  164. <p>Je suis fatiguée que notre industrie n’ouvre pas les yeux sur ce qui se passe <strong>malgré les nombreuses études chiffrées et sérieuses.</strong>
  165. Je suis fatiguée que la plupart des hommes, développeurs comme managers, <strong>ne se sentent pas concernés.</strong>
  166. De mes collègues, seuls deux d’entre eux m’ont soutenue, les autres ont juste tourné les yeux ailleurs en attendant que ça passe.
  167. Je suis fatiguée que les entreprises ne fassent pas leur devoir de formation et d’information aux biais sexistes, et ne mettent pas grand chose en place pour se prémunir des différences de traitements.</p>
  168. <ul>
  169. <li>
  170. <p>Dire à une femme qu’elle est agressive quand elle est assertive ?
  171. ✅ Un grand classique du sexisme ordinaire.</p>
  172. </li>
  173. <li>
  174. <p>Demander dix fois plus de compétences et pinailler sur la moindre chose pour éviter de donner une promotion à une femme ?
  175. ✅ Un grand classique du sexisme ordinaire et du plafond de verre.</p>
  176. </li>
  177. <li>
  178. <p>“Ne pas le sentir” mais sans vraiment de raisons factuelles ?
  179. ✅ Un grand classique du sexisme ordinaire.</p>
  180. </li>
  181. </ul>
  182. <p>Je suis fatiguée d’essayer de trouver ma voie dans une industrie qui fait tout pour me mettre des bâtons dans les roues, je suis fatiguée de voir que mes collègues masculins cherchent à tricher pour finir au plus vite les formations “diversité et inclusion”.
  183. Je suis fatiguée de ne pas pouvoir avoir de discussion un peu avancée sur le paternalisme, les biais, le sexisme, le féminisme parce que la plupart des personnes, des RH aux développeurs en passant par toutes les strates de management, <strong>refusent massivement d’apprendre le vocabulaire et les concepts.</strong>
  184. Je suis fatiguée des entreprises qui sous couvert “d’oeuvrer pour la diversité en général, pas que le gender gap” ne font en fait aucune action en faveur des femmes alors que c’est bien plus facile à mesurer et potentiellement bénéfique aussi pour les autres catégories de personnes sous représentées.</p>
  185. <p>Et je suis fatiguée de <strong>cette société qui est incapable de croire les femmes.</strong>
  186. Combien faudra t-il encore de vidéos ou témoignage où un homme se retrouve, volontairement ou par accident, à la place d’une femme ?
  187. Pour se rendre compte qu’en fait oui c’est violent ce que vivent les femmes et que ce qu’elles dénoncent c’est vrai et systémique.</p>
  188. <p><strong>Je ne peux m’empêcher de penser que si j’avais été un homme ma carrière serait plus avancée aujourd’hui, mon salaire supérieur et ma santé mentale bien meilleure.</strong></p>
  189. <p>Et pourtant j’adore le code, créer des applications, maintenir des applications.
  190. Mais à quel prix pour ma santé puis-je faire un métier que j’aime ?</p>
  191. <h1 id="trouverai-je-un-jour-ma-place-dans-cette-industrie-qui-au-fond-ne-souhaite-pas-vraiment-mon-succès-">Trouverai-je un jour ma place dans cette industrie qui, au fond, ne souhaite pas vraiment mon succès ?</h1>
  192. </article>
  193. <hr>
  194. <footer>
  195. <p>
  196. <a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
  197. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-home"></use>
  198. </svg> Accueil</a> •
  199. <a href="/david/log/" title="Accès au flux RSS"><svg class="icon icon-rss2">
  200. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-rss2"></use>
  201. </svg> Suivre</a> •
  202. <a href="http://larlet.com" title="Go to my English profile" data-instant><svg class="icon icon-user-tie">
  203. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-user-tie"></use>
  204. </svg> Pro</a> •
  205. <a href="mailto:david%40larlet.fr" title="Envoyer un courriel"><svg class="icon icon-mail">
  206. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-mail"></use>
  207. </svg> Email</a> •
  208. <abbr class="nowrap" title="Hébergeur : Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33184162340"><svg class="icon icon-hammer2">
  209. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-hammer2"></use>
  210. </svg> Légal</abbr>
  211. </p>
  212. <template id="theme-selector">
  213. <form>
  214. <fieldset>
  215. <legend><svg class="icon icon-brightness-contrast">
  216. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-brightness-contrast"></use>
  217. </svg> Thème</legend>
  218. <label>
  219. <input type="radio" value="auto" name="chosen-color-scheme" checked> Auto
  220. </label>
  221. <label>
  222. <input type="radio" value="dark" name="chosen-color-scheme"> Foncé
  223. </label>
  224. <label>
  225. <input type="radio" value="light" name="chosen-color-scheme"> Clair
  226. </label>
  227. </fieldset>
  228. </form>
  229. </template>
  230. </footer>
  231. <script src="/static/david/js/instantpage-5.1.0.min.js" type="module"></script>
  232. <script>
  233. function loadThemeForm(templateName) {
  234. const themeSelectorTemplate = document.querySelector(templateName)
  235. const form = themeSelectorTemplate.content.firstElementChild
  236. themeSelectorTemplate.replaceWith(form)
  237. form.addEventListener('change', (e) => {
  238. const chosenColorScheme = e.target.value
  239. localStorage.setItem('theme', chosenColorScheme)
  240. toggleTheme(chosenColorScheme)
  241. })
  242. const selectedTheme = localStorage.getItem('theme')
  243. if (selectedTheme && selectedTheme !== 'undefined') {
  244. form.querySelector(`[value="${selectedTheme}"]`).checked = true
  245. }
  246. }
  247. const prefersColorSchemeDark = '(prefers-color-scheme: dark)'
  248. window.addEventListener('load', () => {
  249. let hasDarkRules = false
  250. for (const styleSheet of Array.from(document.styleSheets)) {
  251. let mediaRules = []
  252. for (const cssRule of styleSheet.cssRules) {
  253. if (cssRule.type !== CSSRule.MEDIA_RULE) {
  254. continue
  255. }
  256. // WARNING: Safari does not have/supports `conditionText`.
  257. if (cssRule.conditionText) {
  258. if (cssRule.conditionText !== prefersColorSchemeDark) {
  259. continue
  260. }
  261. } else {
  262. if (cssRule.cssText.startsWith(prefersColorSchemeDark)) {
  263. continue
  264. }
  265. }
  266. mediaRules = mediaRules.concat(Array.from(cssRule.cssRules))
  267. }
  268. // WARNING: do not try to insert a Rule to a styleSheet you are
  269. // currently iterating on, otherwise the browser will be stuck
  270. // in a infinite loop…
  271. for (const mediaRule of mediaRules) {
  272. styleSheet.insertRule(mediaRule.cssText)
  273. hasDarkRules = true
  274. }
  275. }
  276. if (hasDarkRules) {
  277. loadThemeForm('#theme-selector')
  278. }
  279. })
  280. </script>
  281. </body>
  282. </html>