Repository with sources and generator of https://larlet.fr/david/ https://larlet.fr/david/
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 23KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  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>
  13. Injection
  14. — David Larlet</title>
  15. <script>
  16. function toggleTheme(themeName) {
  17. document.documentElement.classList.toggle(
  18. 'forced-dark',
  19. themeName === 'dark'
  20. )
  21. document.documentElement.classList.toggle(
  22. 'forced-light',
  23. themeName === 'light'
  24. )
  25. }
  26. const selectedTheme = localStorage.getItem('theme')
  27. if (selectedTheme !== 'undefined') {
  28. toggleTheme(selectedTheme)
  29. }
  30. </script>
  31. <!-- Documented, feel free to shoot an email. -->
  32. <link rel="stylesheet" href="/static/david/css/style_2024-03-09.css">
  33. <!-- See https://www.zachleat.com/web/comprehensive-webfonts/ for the trade-off. -->
  34. <link rel="preload"
  35. href="/static/david/css/fonts/century_supra_ot_a_regular.woff2"
  36. as="font"
  37. type="font/woff2"
  38. media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)"
  39. crossorigin>
  40. <link rel="preload"
  41. href="/static/david/css/fonts/century_supra_ot_a_bold.woff2"
  42. as="font"
  43. type="font/woff2"
  44. media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)"
  45. crossorigin>
  46. <link rel="preload"
  47. href="/static/david/css/fonts/century_supra_ot_a_italic.woff2"
  48. as="font"
  49. type="font/woff2"
  50. media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)"
  51. crossorigin>
  52. <link rel="preload"
  53. href="/static/david/css/fonts/century_supra_ot_b_regular.woff2"
  54. as="font"
  55. type="font/woff2"
  56. media="(prefers-color-scheme: dark)"
  57. crossorigin>
  58. <link rel="preload"
  59. href="/static/david/css/fonts/century_supra_ot_b_bold.woff2"
  60. as="font"
  61. type="font/woff2"
  62. media="(prefers-color-scheme: dark)"
  63. crossorigin>
  64. <link rel="preload"
  65. href="/static/david/css/fonts/century_supra_ot_b_italic.woff2"
  66. as="font"
  67. type="font/woff2"
  68. media="(prefers-color-scheme: dark)"
  69. crossorigin>
  70. <meta name="description" content="It’s fun to think of other possible uses… Perhaps you could pull in HTML modules along with their relevant CSS link. Or embed a tweet or code examples in documentation or a blog post. It could probably even be used to load and apply a regular rel=stylesheet link asynchronously, and at a low priority, which is otherwise surprisingly hard to do (note: I didn’t test this idea much to say for sure).">
  71. <!-- That good ol' feed, subscribe :). -->
  72. <link rel="alternate"
  73. type="application/atom+xml"
  74. title="Feed"
  75. href="/david/log/">
  76. <!-- Generated from https://realfavicongenerator.net/ such a mess. -->
  77. <link rel="apple-touch-icon"
  78. sizes="180x180"
  79. href="/static/david/icons2/apple-touch-icon.png">
  80. <link rel="icon"
  81. type="image/png"
  82. sizes="32x32"
  83. href="/static/david/icons2/favicon-32x32.png">
  84. <link rel="icon"
  85. type="image/png"
  86. sizes="16x16"
  87. href="/static/david/icons2/favicon-16x16.png">
  88. <link rel="manifest" href="/static/david/icons2/site.webmanifest">
  89. <link rel="mask-icon"
  90. href="/static/david/icons2/safari-pinned-tab.svg"
  91. color="#07486c">
  92. <link rel="shortcut icon" href="/static/david/icons2/favicon.ico">
  93. <meta name="msapplication-TileColor" content="#f7f7f7">
  94. <meta name="msapplication-config"
  95. content="/static/david/icons2/browserconfig.xml">
  96. <meta name="theme-color"
  97. content="#f7f7f7"
  98. media="(prefers-color-scheme: light)">
  99. <meta name="theme-color"
  100. content="#272727"
  101. media="(prefers-color-scheme: dark)">
  102. <!-- Is that even respected? Retrospectively? What a shAItshow…
  103. https://neil-clarke.com/block-the-bots-that-feed-ai-models-by-scraping-your-website/ -->
  104. <meta name="robots" content="noai, noimageai">
  105. <!-- To get attribution when linking on mastodon. -->
  106. <meta name="fediverse:creator" content="@david@larlet.fr">
  107. <style type="text/css">
  108. .tippy-content {
  109. min-width: 280px;
  110. padding: .5rem;
  111. font-size: calc(var(--fluid-0) * 0.8);
  112. font-family: var(--labor-font);
  113. letter-spacing: initial;
  114. text-align: left;
  115. }
  116. .tippy-content h3 {
  117. margin-top: 0;
  118. }
  119. .tippy-content h3 img {
  120. max-width: 2rem;
  121. max-height: 2rem;
  122. display: inline-block;
  123. }
  124. .tippy-content .tippy-links {
  125. display: flex;
  126. justify-content: space-around;
  127. }
  128. .tippy-content a {
  129. padding: .4rem;
  130. color: #F06048;
  131. }
  132. </style>
  133. <body data-instant-intensity="viewport-all">
  134. <article>
  135. <header>
  136. <hgroup>
  137. <h1>Injection</h1>
  138. <p>Le <time datetime="2024-02-19">19 février 2024</time></p>
  139. </hgroup>
  140. </header>
  141. <nav>
  142. <p>
  143. <a rel="prev"
  144. href="/david/2024/02/18/"
  145. title="Publication précédente : In·directions">← Précédent</a> •
  146. <a href="/david/" title="Aller à l’accueil" rel="up">Accueil</a>
  147. <a href="/david/recherche/"
  148. title="Aller à la page de recherche"
  149. rel="search" data-no-instant>Recherche</a>
  150. • <a rel="next"
  151. href="/david/2024/02/20/"
  152. title="Publication suivante : Véhicule">Suivant →</a>
  153. </p>
  154. </nav>
  155. <blockquote lang="en">
  156. <p>It’s fun to think of <mark>other possible uses…</mark> Perhaps you could pull in HTML modules along with their relevant CSS link. Or embed a tweet or code examples in documentation or a blog post. It could probably even be used to load and apply a regular <code>rel=stylesheet</code> link asynchronously, and at a low priority, which is otherwise surprisingly hard to do (note: I didn’t test this idea much to say for&nbsp;sure).</p>
  157. <p><cite><em><a data-link-domain="filamentgroup.com" href="https://www.filamentgroup.com/lab/html-includes/" hreflang="en"
  158. title="Consultation de l’article (anglais)">HTML Includes That Work Today</a>
  159. <a href="/david/cache/2024/88df28660094efbc5a13bb09d70dfea6/" hreflang="en"
  160. data-tippy data-description="Read this page on the Filament Group website"
  161. data-source="https://www.filamentgroup.com/lab/html-includes/"
  162. data-date="2024-02-19"
  163. data-favicon="https://www.filamentgroup.com/images/icons/favicon-32x32.png"
  164. data-domain="filamentgroup.com"
  165. ><svg xmlns="http://www.w3.org/2000/svg"
  166. width="24" height="24" viewBox="0 0 24 24" fill="none"
  167. stroke="currentColor" stroke-width="2" stroke-linecap="square"
  168. stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle>
  169. <path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"></path>
  170. <line x1="12" y1="17" x2="12.01" y2="17"></line>
  171. </svg>
  172. <span class="sr-only">[archive]</span></a></em></cite></p>
  173. </blockquote>
  174. <p>J’ai cette page ouverte dans un onglet depuis littéralement des années. C’est <a data-link-domain="blog.notmyidea.org" href="https://blog.notmyidea.org/">Alexis</a> qui me l’a rappelé en partageant <a data-link-domain="leanrada.com" href="https://leanrada.com/htmz/">htmz</a> aujourd’hui qui va un tout petit peu plus&nbsp;loin.</p>
  175. <p>Voilà le code en&nbsp;question&nbsp;:</p>
  176. <pre><code>&lt;iframe
  177. src=&quot;/static/david/2024/test-injection.html&quot;
  178. onload=&quot;
  179. this.before(
  180. (
  181. this.contentDocument.body||this.contentDocument
  182. ).children[0]
  183. );
  184. this.remove()
  185. &quot;
  186. hidden&gt;
  187. &lt;/iframe&gt;
  188. </code></pre>
  189. <p>En résumé, on prend le code l’<code>iframe</code> et on l’injecte au chargement dans le document en cours. Voici un exemple (pas sûr que ça fonctionne depuis un&nbsp;agrégateur…)&nbsp;:</p>
  190. <iframe src="/static/david/2024/test-injection.html" onload="this.before((this.contentDocument.body||this.contentDocument).children[0]);this.remove()" hidden></iframe>
  191. <p>J’ai ajouté l’attribut <code>hidden</code> à la proposition initiale pour éviter le flash. Si vous inspectez le code, vous constatez que le paragraphe précédent tout à fait classique alors qu’il s’agissait d’une <code>iframe</code> (sauf si vous avez une extension qui bloque les <code>iframe</code> bien sûr). Jusque là c’est <a data-link-domain="css-tricks.com" href="https://css-tricks.com/the-simplest-ways-to-handle-html-includes/" hreflang="en"
  192. title="Consultation de l’article (anglais)">une forme d’inclusion</a>
  193. <a href="/david/cache/2024/6bfc6bd7bc1d9158aa7f6591123e7f4b/" hreflang="en"
  194. data-tippy data-description="It's extremely surprising to me that HTML has never had any way to include other HTML files within it. Nor does there seem to be anything on the horizon that"
  195. data-source="https://css-tricks.com/the-simplest-ways-to-handle-html-includes/"
  196. data-date="2024-02-19"
  197. data-favicon="https://css-tricks.com/favicon.svg"
  198. data-domain="css-tricks.com"
  199. ><svg xmlns="http://www.w3.org/2000/svg"
  200. width="24" height="24" viewBox="0 0 24 24" fill="none"
  201. stroke="currentColor" stroke-width="2" stroke-linecap="square"
  202. stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle>
  203. <path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"></path>
  204. <line x1="12" y1="17" x2="12.01" y2="17"></line>
  205. </svg>
  206. <span class="sr-only">[archive]</span></a> mais rien de bien&nbsp;utile.</p>
  207. <p>Ce qui devient un peu plus fou serait de pouvoir injecter un <em>Web Component</em> de cette façon&#8239;! Le problème étant que le <code>this.remove()</code> est exécuté avant le chargement du script de l’<code>iframe</code>… et si on le retire on conserve cet élément <code>hidden</code> dans le document. Ce n’est pas critique mais ce n’est pas très élégant non plus, d’autant que cela signifie que le composant est défini et instancié deux&nbsp;fois.</p>
  208. <style>para-graph { background: paleturquoise; color: black; }</style>
  209. <iframe src="/static/david/2024/test-injection-web-component.html" onload= "this.before((this.contentDocument.body||this.contentDocument).children[0]);this.before(this.contentDocument.scripts[0])" hidden></iframe>
  210. <p>Il y a probablement des choses qui m’échappent mais il se fait&nbsp;tard.</p>
  211. <p><em>To be&nbsp;continued…</em></p>
  212. <a href="#hr-79" title="Lien vers cette section de la page"><hr id="hr-79" /></a>
  213. <p>Découvertes du jour&nbsp;: <a data-link-domain="MDN" href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base"><code>&lt;base&gt;</code></a> et <a data-link-domain="MDN" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis">globalThis</a>.</p>
  214. <p>Aussi, il n’est <a data-link-domain="github.com" href="https://github.com/django/django/commit/b7f500396e05cd1f0bb8901fce16e2d8393d2779">pas forcément indiqué</a> de générer une <code>SECRET_KEY</code> avec Django, il vaut mieux le faire en Python&nbsp;directement&nbsp;:</p>
  215. <pre><code>[depuis un shell]
  216. $ python3 -c 'import secrets; print(secrets.token_hex(100))'
  217. </code></pre>
  218. <a href="#hr-80" title="Lien vers cette section de la page"><hr id="hr-80" /></a>
  219. <blockquote lang="en">
  220. <p>So, what’s the fun of writing on the internet anymore? Well, if your aim is to be respected as an author, there’s probably not much fun to be had here at all. Don’t write online for fame and glory. Oblivion, obscurity and exploitation are all but guaranteed. Write here because <em>ideas</em> matter, not authorship. Write here because the more robots, pirates, and single-minded trolls swallow up cyberspace, <mark>the more we need independent writing in order to think new thoughts in the future</mark> — even if your words are getting dished up and plated by an&nbsp;algorithm.</p>
  221. <p><cite><em><a data-link-domain="jamesshelley.com" href="https://jamesshelley.com/blog/writing-on-the-internet.html" hreflang="en"
  222. title="Consultation de l’article (anglais)">What’s the fun in writing on the internet anymore?</a>
  223. <a href="/david/cache/2024/a005801f0e596f9ecb99037a992ecc1b/" hreflang="en"
  224. data-tippy data-description="The moment you release your words, you relinquish all control."
  225. data-source="https://jamesshelley.com/blog/writing-on-the-internet.html"
  226. data-date="2024-02-19"
  227. data-favicon="https://jamesshelley.com/images/favicon.png"
  228. data-domain="jamesshelley.com"
  229. ><svg xmlns="http://www.w3.org/2000/svg"
  230. width="24" height="24" viewBox="0 0 24 24" fill="none"
  231. stroke="currentColor" stroke-width="2" stroke-linecap="square"
  232. stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle>
  233. <path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"></path>
  234. <line x1="12" y1="17" x2="12.01" y2="17"></line>
  235. </svg>
  236. <span class="sr-only">[archive]</span></a></em></cite></p>
  237. </blockquote>
  238. <p>Rester (et alimenter la machine) ou quitter (et laisser l’espace à la&nbsp;machine).</p>
  239. <p>Je n’aime pas beaucoup la <a data-link-domain="maggieappleton.com" href="https://maggieappleton.com/ai-dark-forest" hreflang="en"
  240. title="Consultation de l’article (anglais)">métaphore de la forêt noire</a>
  241. <a href="/david/cache/2024/140458968f9f7da7d14e181d0a80e799/" hreflang="en"
  242. data-tippy data-description="Proving you're a human on a web flooded with generative AI content"
  243. data-source="https://maggieappleton.com/ai-dark-forest"
  244. data-date="2024-02-19"
  245. data-favicon="https://maggieappleton.com//images/favicon/favicon.ico"
  246. data-domain="maggieappleton.com"
  247. ><svg xmlns="http://www.w3.org/2000/svg"
  248. width="24" height="24" viewBox="0 0 24 24" fill="none"
  249. stroke="currentColor" stroke-width="2" stroke-linecap="square"
  250. stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle>
  251. <path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"></path>
  252. <line x1="12" y1="17" x2="12.01" y2="17"></line>
  253. </svg>
  254. <span class="sr-only">[archive]</span></a> ces temps-ci car j’apprécie un peu trop les forêts pour ça. J’aurais davantage l’impression de faire partie d’une haie alors qu’il y a beaucoup de monoculture aux alentours. Avec les double sens que cette méta·phore&nbsp;implique.</p>
  255. <nav>
  256. <p>
  257. <a href="/david/2024/apprentissage/"
  258. title="Liste de tous les articles 2024 associés à cette étiquette"
  259. rel="tag">#apprentissage</a>
  260. <a href="/david/2024/laboratoire/"
  261. title="Liste de tous les articles 2024 associés à cette étiquette"
  262. rel="tag">#laboratoire</a>
  263. <a href="/david/2024/web/"
  264. title="Liste de tous les articles 2024 associés à cette étiquette"
  265. rel="tag">#web</a>
  266. <a href="/david/2024/#tags" title="Liste de toutes les étiquettes 2024">tous ?</a>
  267. </p>
  268. </nav>
  269. <nav>
  270. <p>
  271. <a rel="prev"
  272. href="/david/2024/02/18/"
  273. title="Publication précédente : In·directions">← Précédent</a> •
  274. <a href="/david/2024/" title="Liste des publications récentes">↑ En 2024</a>
  275. • <a rel="next"
  276. href="/david/2024/02/20/"
  277. title="Publication suivante : Véhicule">Suivant →</a>
  278. </p>
  279. </nav>
  280. <form action="/david/recherche/" method="get">
  281. <fieldset>
  282. <legend>Recherche</legend>
  283. <label for="input-search">Termes de votre recherche :</label>
  284. <input id="input-search" type="search" name="s" aria-describedby="indexation-infos" required>
  285. <input type="submit" value="Chercher">
  286. <p id="indexation-infos">
  287. <small>
  288. Seuls les contenus de ces 8 dernières années sont indexés.
  289. </small>
  290. </p>
  291. </fieldset>
  292. </form>
  293. <aside>
  294. <theme-toggle></theme-toggle>
  295. </aside>
  296. </article>
  297. <hr>
  298. <footer>
  299. <p>
  300. <a href="/david/" title="Aller à l’accueil">Accueil</a>
  301. <a href="/david/log/" title="Accès au flux RSS">Suivre</a>
  302. <a href="http://larlet.com"
  303. title="Go to my English profile"
  304. data-instant>Pro</a>
  305. <a href="mailto:david%40larlet.fr" title="Envoyer un courriel">Email</a>
  306. <abbr title="Hébergeur : Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33184162340">Légal</abbr>
  307. </p>
  308. <template id="theme-selector">
  309. <form>
  310. <style type="text/css">
  311. fieldset div {
  312. text-align: center;
  313. }
  314. </style>
  315. <fieldset>
  316. <legend>Thème</legend>
  317. <div>
  318. <label>
  319. <input type="radio" value="auto" name="chosen-color-scheme" checked>
  320. Auto
  321. </label>
  322. <label>
  323. <input type="radio" value="dark" name="chosen-color-scheme">
  324. Foncé
  325. </label>
  326. <label>
  327. <input type="radio" value="light" name="chosen-color-scheme">
  328. Clair
  329. </label>
  330. </div>
  331. </fieldset>
  332. </form>
  333. </template>
  334. </footer>
  335. <script src="/static/david/js/instantpage-5.1.0.min.js" type="module"></script>
  336. <script>
  337. class ThemeToggle extends HTMLElement {
  338. constructor() {
  339. super()
  340. const themeSelectorTemplate = document.querySelector('#theme-selector')
  341. const form = themeSelectorTemplate.content.firstElementChild
  342. this.attachShadow({ mode: 'open' })
  343. this.shadowRoot.appendChild(form.cloneNode(true))
  344. }
  345. connectedCallback() {
  346. const form = this.shadowRoot.querySelector('form')
  347. form.addEventListener('change', (e) => {
  348. const chosenColorScheme = e.target.value
  349. localStorage.setItem('theme', chosenColorScheme)
  350. toggleTheme(chosenColorScheme)
  351. })
  352. const selectedTheme = localStorage.getItem('theme')
  353. if (selectedTheme && selectedTheme !== 'undefined') {
  354. form.querySelector(`[value="${selectedTheme}"]`).checked = true
  355. }
  356. }
  357. }
  358. const prefersColorSchemeDark = '(prefers-color-scheme: dark)'
  359. window.addEventListener('load', () => {
  360. let colorsLayer = undefined
  361. let hasDarkRules = false
  362. for (const styleSheet of Array.from(document.styleSheets)) {
  363. let mediaRules = []
  364. for (const layerRule of styleSheet.cssRules) {
  365. if (!(layerRule instanceof CSSLayerBlockRule)) {
  366. continue
  367. }
  368. if (layerRule.name === 'colors') {
  369. colorsLayer = layerRule
  370. }
  371. for (const cssRule of layerRule.cssRules) {
  372. if (cssRule.type !== CSSRule.MEDIA_RULE) {
  373. continue
  374. }
  375. // WARNING: Safari does not have/supports `conditionText`.
  376. if (cssRule.conditionText) {
  377. if (cssRule.conditionText !== prefersColorSchemeDark) {
  378. continue
  379. }
  380. } else {
  381. if (cssRule.cssText.startsWith(prefersColorSchemeDark)) {
  382. continue
  383. }
  384. }
  385. mediaRules = mediaRules.concat(Array.from(cssRule.cssRules))
  386. }
  387. }
  388. // WARNING: do not try to insert a Rule to a styleSheet you are
  389. // currently iterating on, otherwise the browser will be stuck
  390. // in a infinite loop…
  391. for (const mediaRule of mediaRules) {
  392. // Safari requires the `0` second parameter (even if default).
  393. colorsLayer.insertRule(mediaRule.cssText, 0)
  394. hasDarkRules = true
  395. }
  396. }
  397. if (hasDarkRules) {
  398. if ('customElements' in window && !customElements.get('theme-toggle')) {
  399. customElements.define('theme-toggle', ThemeToggle)
  400. }
  401. }
  402. })
  403. </script>
  404. <script src="/static/david/js/popper-2.11.8.min.js"></script>
  405. <script src="/static/david/js/tippy-bundle-6.3.7.umd.min.js"></script>
  406. <script>
  407. tippy('[data-tippy]', {
  408. content(reference) {
  409. reference.addEventListener('click', (e) => e.preventDefault())
  410. return `
  411. <h3 lang="fr">
  412. <img src="${reference.dataset.favicon}" loading="lazy">
  413. <a href="${reference.dataset.source}"
  414. >Article sur ${reference.dataset.domain}</a></h3>
  415. <p lang="${reference.hreflang}"><em>${reference.dataset.description}</em></p>
  416. <div class="tippy-links" lang="fr">
  417. <a href="${reference.href}">Archive au ${reference.dataset.date}</a>
  418. </div>
  419. `
  420. },
  421. allowHTML: true,
  422. interactive: true,
  423. delay: [150, 700],
  424. hideOnClick: false
  425. })
  426. </script>
  427. <script type="module">
  428. import { annotate } from '/static/david/js/rough-notation-0.5.1.esm.min.js'
  429. const markObserver = new IntersectionObserver((entries, observer) => {
  430. const computedStyle = getComputedStyle(document.documentElement)
  431. const markBackground = computedStyle.getPropertyValue('--mark-background')
  432. for (const entry of entries) {
  433. if (entry.intersectionRatio === 0) continue
  434. const markElement = entry.target
  435. markElement.style.backgroundColor = 'inherit'
  436. const annotation = annotate(
  437. markElement, {
  438. type: 'highlight',
  439. multiline: true,
  440. color: markBackground,
  441. // animate: !window.matchMedia('(prefers-reduced-motion: reduce)').matches
  442. animate: false
  443. }
  444. )
  445. annotation.show()
  446. observer.unobserve(markElement)
  447. }
  448. }, {threshold: 1.0})
  449. for (const markElement of document.querySelectorAll('mark')) {
  450. markObserver.observe(markElement)
  451. }
  452. </script>
  453. </body>
  454. </html>