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 30KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. <!doctype html><!-- This is a valid HTML5 document. -->
  2. <!-- Screen readers, SEO, extensions and so on. -->
  3. <html lang="en">
  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>The Simplest Ways to Handle HTML Includes (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://css-tricks.com/the-simplest-ways-to-handle-html-includes/">
  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>The Simplest Ways to Handle HTML Includes</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://css-tricks.com/the-simplest-ways-to-handle-html-includes/" title="Lien vers le contenu original">Source originale</a>
  70. <br>
  71. Mis en cache le 2024-02-19
  72. </p>
  73. </nav>
  74. <hr>
  75. <p>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 addresses it. I’m talking about straight up <em>includes</em>, like taking a chunk of HTML and plopping it right into another. For example the use case for much of the entire internet, an included header and footer for all pages:</p>
  76. <pre rel="HTML" class="wp-block-csstricks-code-block language-markup" data-line=""><code markup="tt">...
  77. &lt;body&gt;
  78. &lt;include src="./header.html"&gt;&lt;/include&gt;
  79. Content
  80. &lt;include src="./footer.html"&gt;&lt;/include&gt;
  81. &lt;/body&gt;
  82. ...</code></pre>
  83. <p>That’s not real, by the way. I just wish it was.</p>
  84. <p><span id="more-286228"></span></p>
  85. <p>People have been looking to other languages to solve this problem for them forever. It’s HTML preprocessing, in a sense. Long before we were preprocessing our CSS, we were using tools to manipulate our HTML. And we still are, because the idea of includes is useful on pretty much every website in the world.</p>
  86. <h3 class="wp-block-heading" id="h-use-php"><a href="#aa-use-php" aria-hidden="true" class="aal_anchor" id="aa-use-php"><svg aria-hidden="true" class="aal_svg" version="1.1" viewbox="0 0 16 16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Use PHP</h3>
  87. <p>Can you use PHP instead?</p>
  88. <pre rel="PHP" class="wp-block-csstricks-code-block language-javascript" data-line=""><code markup="tt">...
  89. &lt;body&gt;
  90. &lt;?php include "./header.html" ?&gt;
  91. Content
  92. &lt;?php include "./footer.html" ?&gt;
  93. &lt;/body&gt;
  94. ...</code></pre>
  95. <p>This will perform the include at the server level, making the request for it happen at the file system level on the server, so it should be far quicker than a client-side solution.</p>
  96. <h3 class="wp-block-heading" id="h-use-gulp"><a href="#aa-use-gulp" aria-hidden="true" class="aal_anchor" id="aa-use-gulp"><svg aria-hidden="true" class="aal_svg" version="1.1" viewbox="0 0 16 16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Use Gulp</h3>
  97. <p>What’s even faster than a server-side include? If the include is preprocessed before it’s even on the server. <a href="https://gulpjs.com/" rel="noopener">Gulp</a> has a variety of processors that can do this. One is <a href="https://www.npmjs.com/package/gulp-file-include" rel="noopener">gulp-file-include</a>.</p>
  98. <p>That would look like this:</p>
  99. <pre rel="HTML" class="wp-block-csstricks-code-block language-markup" data-line=""><code markup="tt">...
  100. &lt;body&gt;
  101. @@include('./header.html')
  102. Content
  103. @@include('./footer.html')
  104. &lt;/body&gt;
  105. ...</code></pre>
  106. <p>And you’d process it like:</p>
  107. <pre rel="JavaScript" class="wp-block-csstricks-code-block language-javascript" data-line=""><code markup="tt">var fileinclude = require('gulp-file-include'),
  108. gulp = require('gulp');
  109. gulp.task('fileinclude', function() {
  110. gulp.src(['index.html'])
  111. .pipe(fileinclude({
  112. prefix: '@@',
  113. basepath: '@file'
  114. }))
  115. .pipe(gulp.dest('./'));
  116. });</code></pre>
  117. <p>Looks like this particular plugin has fancy features where you can pass in variables to the includes, making it possible to make little data-driven components.</p>
  118. <h3 class="wp-block-heading" id="h-use-grunt"><a href="#aa-use-grunt" aria-hidden="true" class="aal_anchor" id="aa-use-grunt"><svg aria-hidden="true" class="aal_svg" version="1.1" viewbox="0 0 16 16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Use Grunt</h3>
  119. <p>This is what the <a href="https://www.npmjs.com/package/grunt-bake" rel="noopener">grunt-bake</a> plugin does. You’d configure Grunt to process your HTML:</p>
  120. <pre rel="JavaScript" class="wp-block-csstricks-code-block language-javascript" data-line=""><code markup="tt">grunt.initConfig({
  121. bake: {
  122. your_target: {
  123. files: {
  124. "dist/index.html": "app/index.html",
  125. }
  126. }
  127. }
  128. });</code></pre>
  129. <p>Then your HTML can use this special syntax for includes:</p>
  130. <pre rel="HTML" class="wp-block-csstricks-code-block language-markup" data-line=""><code markup="tt">...
  131. &lt;body&gt;
  132. &lt;!--(bake header.html)--&gt;
  133. Content
  134. &lt;!--(bake footer.html)--&gt;
  135. &lt;/body&gt;
  136. ...</code></pre>
  137. <h3 class="wp-block-heading" id="h-use-handlebars"><a href="#aa-use-handlebars" aria-hidden="true" class="aal_anchor" id="aa-use-handlebars"><svg aria-hidden="true" class="aal_svg" version="1.1" viewbox="0 0 16 16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Use Handlebars</h3>
  138. <p>Handlebars <a href="https://handlebarsjs.com/partials.html" rel="noopener">has partials</a>.</p>
  139. <p>You register them:</p>
  140. <pre rel="JavaScript" class="wp-block-csstricks-code-block language-javascript" data-line=""><code markup="tt">Handlebars.registerPartial('myPartial', '{{name}}')</code></pre>
  141. <p>Then use them:</p>
  142. <pre rel="HTML" class="wp-block-csstricks-code-block language-markup" data-line=""><code markup="tt">{{&gt; myPartial }}</code></pre>
  143. <p>There is also fancy features of this that allow for evaluation and passing data. You’ll still need a processor to run it, probably something like <a href="https://www.npmjs.com/package/gulp-handlebars" rel="noopener">gulp-handlebars</a>.</p>
  144. <p>Speaking of templating languages which make use of curly braces… Mustache <a href="https://github.com/janl/mustache.js#include-templates" rel="noopener">has them, too</a>.</p>
  145. <h3 class="wp-block-heading" id="h-use-pug"><a href="#aa-use-pug" aria-hidden="true" class="aal_anchor" id="aa-use-pug"><svg aria-hidden="true" class="aal_svg" version="1.1" viewbox="0 0 16 16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Use Pug</h3>
  146. <p><a href="https://pugjs.org/" rel="noopener">Pug</a> is an HTML preprocessor that has a whole new syntax for HTML that is a bit more terse. <a href="https://pugjs.org/language/includes.html" rel="noopener">It’s got includes though</a>.</p>
  147. <pre rel="Pug" class="wp-block-csstricks-code-block language-none" data-line=""><code markup="tt">...
  148. body
  149. include ./header.html"
  150. p Content
  151. include ./footer.html"
  152. ...</code></pre>
  153. <p>Then you run it with something like <a href="https://www.npmjs.com/package/gulp-pug" rel="noopener">gulp-pug</a>.</p>
  154. <h3 class="wp-block-heading" id="h-use-nunjucks"><a href="#aa-use-nunjucks" aria-hidden="true" class="aal_anchor" id="aa-use-nunjucks"><svg aria-hidden="true" class="aal_svg" version="1.1" viewbox="0 0 16 16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Use Nunjucks</h3>
  155. <p><a href="https://css-tricks.com/killer-features-of-nunjucks/">I love me some Nunjucks!</a> <a href="https://mozilla.github.io/nunjucks/" rel="noopener">Nunjucks</a> has <a href="https://mozilla.github.io/nunjucks/templating.html#include" rel="noopener">includes</a>. You’d do it like this:</p>
  156. <pre rel="HTML" class="wp-block-csstricks-code-block language-markup" data-line=""><code markup="tt">...
  157. &lt;body&gt;
  158. {% include "./header.html" %}
  159. Content
  160. {% include "./footer.html" %}
  161. &lt;/body&gt;
  162. ...</code></pre>
  163. <p>If you put that in a file called <code>index.njk</code>, you could process it with a simple Node script into index.html like this:</p>
  164. <pre rel="JavaScript" class="wp-block-csstricks-code-block language-javascript" data-line=""><code markup="tt">const nunjucks = require("nunjucks");
  165. const fs = require("fs");
  166. fs.writeFile("index.html", nunjucks.render("index.njk"), function(err, data) {
  167. if (err) console.log(err);
  168. console.log("Compiled the Nunjucks, captain.");
  169. });</code></pre>
  170. <p>Or process it with something like <a href="https://www.npmjs.com/package/gulp-nunjucks" rel="noopener">gulp-nunjucks</a>.</p>
  171. <p>11ty has <a href="https://www.11ty.io/docs/languages/nunjucks/" rel="noopener">Nunjucks built-in</a>, along with many of the other mentioned so far. Might be good for you if you’re actually building a little site.</p>
  172. <h3 class="wp-block-heading" id="h-use-ajax"><a href="#aa-use-ajax" aria-hidden="true" class="aal_anchor" id="aa-use-ajax"><svg aria-hidden="true" class="aal_svg" version="1.1" viewbox="0 0 16 16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Use Ajax</h3>
  173. <p>Say you had…</p>
  174. <pre rel="HTML" class="wp-block-csstricks-code-block language-markup" data-line=""><code markup="tt">&lt;body&gt;
  175. &lt;header&gt;&lt;/header&gt;
  176. Content.
  177. &lt;footer&gt;&lt;/footer&gt;
  178. &lt;/body&gt;</code></pre>
  179. <p>You could fetch the contents for the header and footer from respective files and dump the contents in.</p>
  180. <pre rel="JavaScript" class="wp-block-csstricks-code-block language-javascript" data-line=""><code markup="tt">fetch("./header.html")
  181. .then(response =&gt; {
  182. return response.text()
  183. })
  184. .then(data =&gt; {
  185. document.querySelector("header").innerHTML = data;
  186. });
  187. fetch("./footer.html")
  188. .then(response =&gt; {
  189. return response.text()
  190. })
  191. .then(data =&gt; {
  192. document.querySelector("footer").innerHTML = data;
  193. });</code></pre>
  194. <p>Speaking of JavaScript… If you’re building your site using a JavaScript framework of just about any kind, building through components is kind of the main deal there and breaking parts you want to include in other files should be no problem. Some kind of <code>import Header from "./header.js";</code> and <code>&lt;Header /&gt;</code> is the territory you’d be in in React land.</p>
  195. <h3 class="wp-block-heading" id="h-use-iframes"><a href="#aa-use-iframes" aria-hidden="true" class="aal_anchor" id="aa-use-iframes"><svg aria-hidden="true" class="aal_svg" version="1.1" viewbox="0 0 16 16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Use iframes</h3>
  196. <p>You could do this:</p>
  197. <pre rel="HTML" class="wp-block-csstricks-code-block language-markup" data-line=""><code markup="tt">&lt;body&gt;
  198. &lt;iframe src="./header.html"&gt;&lt;/iframe&gt;
  199. Content.
  200. &lt;iframe src="./footer.html"&gt;&lt;/iframe&gt;
  201. &lt;/body&gt;</code></pre>
  202. <p>But the content in those iframes does not share the same DOM, so it’s a bit weird, not to mention slow and awkward to style (since iframes don’t know the heights of their contents).</p>
  203. <p><a href="https://www.filamentgroup.com/lab/html-includes/" rel="noopener">Scott Jehl documented a cool idea</a> though: You can have the iframe inject the content of itself onto the parent page then remove itself.</p>
  204. <pre rel="HTML" class="wp-block-csstricks-code-block language-markup" data-line=""><code markup="tt">&lt;body&gt;
  205. &lt;iframe src="header.html" onload="this.before((this.contentDocument.body||this.contentDocument).children[0]);this.remove()"&gt;&lt;/iframe&gt;
  206. Content.
  207. &lt;iframe src="footer.html" onload="this.before((this.contentDocument.body||this.contentDocument).children[0]);this.remove()"&gt;&lt;/iframe&gt;
  208. &lt;/body&gt;</code></pre>
  209. <p>Kolya Korruptis wrote in with this adaptation which will include more than the first child of the body in case your HTML file has that:</p>
  210. <pre rel="HTML" class="wp-block-csstricks-code-block language-markup" data-line=""><code markup="tt">&lt;iframe src="included.html" onload="this.insertAdjacentHTML('afterend', (this.contentDocument.body||this.contentDocument).innerHTML);this.remove()"&gt;&lt;/iframe&gt;</code></pre>
  211. <h3 class="wp-block-heading" id="use-jekyll"><a href="#aa-use-jekyll" aria-hidden="true" class="aal_anchor" id="aa-use-jekyll"><svg aria-hidden="true" class="aal_svg" version="1.1" viewbox="0 0 16 16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Use Jekyll</h3>
  212. <p><a href="https://jekyllrb.com/" rel="noopener">Jekyll</a> is a Ruby-based static site generator with <a href="https://jekyllrb.com/docs/includes/" rel="noopener">includes</a>. You keep your includes in the <code>/_includes/</code> folder, then:</p>
  213. <pre rel="HTML" class="wp-block-csstricks-code-block language-markup" data-line=""><code markup="tt">&lt;body&gt;
  214. {% include header.html %}
  215. Content.
  216. {% include footer.html %}
  217. &lt;/body&gt;</code></pre>
  218. <p>Jekyll is a big one, so I’m calling it out here, but there are <a href="https://www.staticgen.com/" rel="noopener">a ton of static site generators</a> and I’d wager any of them can do includes.</p>
  219. <h3 class="wp-block-heading" id="use-sergey"><a href="#aa-use-sergey" aria-hidden="true" class="aal_anchor" id="aa-use-sergey"><svg aria-hidden="true" class="aal_svg" version="1.1" viewbox="0 0 16 16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><a href="https://css-tricks.com/the-simplest-ways-to-handle-html-includes/#use-sergey"></a>Use Sergey</h3>
  220. <p>OK, I’ll call out one more SSG because it’s new and super focused. <a href="https://sergey.cool/" rel="noopener">Sergey</a> has a web components style format:</p>
  221. <pre rel="HTML" class="wp-block-csstricks-code-block language-markup" data-line=""><code markup="tt">&lt;body&gt;
  222. &lt;sergey-import src="header" /&gt;
  223. Content.
  224. &lt;sergey-import src="footer" /&gt;
  225. &lt;/body&gt;</code></pre>
  226. <p>You’d name the files <code>header.html</code> and <code>footer.html</code> and put them in <code>/includes/</code> and then it’ll make a build with the includes processed when you run the npm script it has you do.</p>
  227. <h3 class="wp-block-heading" id="use-apache-ssi"><a href="#aa-use-apache-ssi" aria-hidden="true" class="aal_anchor" id="aa-use-apache-ssi"><svg aria-hidden="true" class="aal_svg" version="1.1" viewbox="0 0 16 16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><a href="https://css-tricks.com/the-simplest-ways-to-handle-html-includes/#use-apache-ssi"></a>Use Apache SSI</h3>
  228. <p>Apache, a super duper common web server, can <a href="https://httpd.apache.org/docs/2.4/mod/mod_include.html" rel="noopener">do includes</a>. You do it like this:</p>
  229. <pre rel="HTML" class="wp-block-csstricks-code-block language-markup" data-line=""><code markup="tt">&lt;body&gt;
  230. &lt;!--#include file="./header.html" --&gt;
  231. Content
  232. &lt;!--#include file="./footer.html" --&gt;
  233. &lt;/body&gt;</code></pre>
  234. <p>But you need the right Apache configuration to allow stuff. I tried my best to get a working demo going but didn’t have much luck.</p>
  235. <p>I tried using <code>.htaccess</code> within a folder on an Apache server and flipping on what I thought was the right stuff:</p>
  236. <pre rel="HTAccess" class="wp-block-csstricks-code-block language-none" data-line=""><code markup="tt">Options +Includes
  237. AddType text/html .html
  238. AddOutputFilter INCLUDES .html</code></pre>
  239. <p>I’m sure there is some way to get it working though, and if you do, it’s kinda neat that it needs zero other dependencies.</p>
  240. <h3 class="wp-block-heading" id="use-codekit"><a href="#aa-use-codekit" aria-hidden="true" class="aal_anchor" id="aa-use-codekit"><svg aria-hidden="true" class="aal_svg" version="1.1" viewbox="0 0 16 16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><a href="https://css-tricks.com/the-simplest-ways-to-handle-html-includes/#use-codekit"></a>Use CodeKit</h3>
  241. <p>Mac only, but CodeKit has <a href="https://codekitapp.com/help/kit/" rel="noopener">a special language called Kit</a> it processes where 90% of the point of it is HTML includes. It uses special HTML comments:</p>
  242. <pre rel="HTML" class="wp-block-csstricks-code-block language-markup" data-line=""><code markup="tt">...
  243. &lt;body&gt;
  244. &lt;!-- @import "./header.html" --&gt;
  245. Content
  246. &lt;!-- @import "./footer.html" --&gt;
  247. &lt;/body&gt;
  248. ...</code></pre>
  249. <h3 class="wp-block-heading" id="use-dreamweaver"><a href="#aa-use-dreamweaver" aria-hidden="true" class="aal_anchor" id="aa-use-dreamweaver"><svg aria-hidden="true" class="aal_svg" version="1.1" viewbox="0 0 16 16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><a href="https://css-tricks.com/the-simplest-ways-to-handle-html-includes/#use-dreamweaver"></a>Use Dreamweaver</h3>
  250. <p>Lol jk. But it <a href="https://helpx.adobe.com/dreamweaver/using/server-side-includes.html" rel="noopener">really is a thing</a>. <a href="http://shop.pixelmill.com/support/al0/kb101502.htm" rel="noopener">DWTs</a>, baby.</p>
  251. <h3 class="wp-block-heading" id="holy-crap"><a href="#aa-holy-crap" aria-hidden="true" class="aal_anchor" id="aa-holy-crap"><svg aria-hidden="true" class="aal_svg" version="1.1" viewbox="0 0 16 16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><a href="https://css-tricks.com/the-simplest-ways-to-handle-html-includes/#holy-crap"></a>Holy Crap</h3>
  252. <p>That’s a lot of ways, isn’t it?</p>
  253. <p>Like I said at the top, it’s very surprising to me that HTML itself hasn’t addressed this directly. Not that I think it would be a great idea for performance to have <code>&lt;include&gt;</code> statements that trigger network requests all over our code, but it seems in-line with the platform. Using ES6 imports directly without bundling isn’t a great idea always either, but we have them. <code>@import</code>ing CSS within CSS isn’t a great idea always, but we have it. If the platform had a native syntax, perhaps other tooling would key off that, much like JavaScript bundlers support the ES6 import format.</p>
  254. </article>
  255. <hr>
  256. <footer>
  257. <p>
  258. <a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
  259. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-home"></use>
  260. </svg> Accueil</a> •
  261. <a href="/david/log/" title="Accès au flux RSS"><svg class="icon icon-rss2">
  262. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-rss2"></use>
  263. </svg> Suivre</a> •
  264. <a href="http://larlet.com" title="Go to my English profile" data-instant><svg class="icon icon-user-tie">
  265. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-user-tie"></use>
  266. </svg> Pro</a> •
  267. <a href="mailto:david%40larlet.fr" title="Envoyer un courriel"><svg class="icon icon-mail">
  268. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-mail"></use>
  269. </svg> Email</a> •
  270. <abbr class="nowrap" title="Hébergeur : Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33184162340"><svg class="icon icon-hammer2">
  271. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-hammer2"></use>
  272. </svg> Légal</abbr>
  273. </p>
  274. <template id="theme-selector">
  275. <form>
  276. <fieldset>
  277. <legend><svg class="icon icon-brightness-contrast">
  278. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-brightness-contrast"></use>
  279. </svg> Thème</legend>
  280. <label>
  281. <input type="radio" value="auto" name="chosen-color-scheme" checked> Auto
  282. </label>
  283. <label>
  284. <input type="radio" value="dark" name="chosen-color-scheme"> Foncé
  285. </label>
  286. <label>
  287. <input type="radio" value="light" name="chosen-color-scheme"> Clair
  288. </label>
  289. </fieldset>
  290. </form>
  291. </template>
  292. </footer>
  293. <script src="/static/david/js/instantpage-5.1.0.min.js" type="module"></script>
  294. <script>
  295. function loadThemeForm(templateName) {
  296. const themeSelectorTemplate = document.querySelector(templateName)
  297. const form = themeSelectorTemplate.content.firstElementChild
  298. themeSelectorTemplate.replaceWith(form)
  299. form.addEventListener('change', (e) => {
  300. const chosenColorScheme = e.target.value
  301. localStorage.setItem('theme', chosenColorScheme)
  302. toggleTheme(chosenColorScheme)
  303. })
  304. const selectedTheme = localStorage.getItem('theme')
  305. if (selectedTheme && selectedTheme !== 'undefined') {
  306. form.querySelector(`[value="${selectedTheme}"]`).checked = true
  307. }
  308. }
  309. const prefersColorSchemeDark = '(prefers-color-scheme: dark)'
  310. window.addEventListener('load', () => {
  311. let hasDarkRules = false
  312. for (const styleSheet of Array.from(document.styleSheets)) {
  313. let mediaRules = []
  314. for (const cssRule of styleSheet.cssRules) {
  315. if (cssRule.type !== CSSRule.MEDIA_RULE) {
  316. continue
  317. }
  318. // WARNING: Safari does not have/supports `conditionText`.
  319. if (cssRule.conditionText) {
  320. if (cssRule.conditionText !== prefersColorSchemeDark) {
  321. continue
  322. }
  323. } else {
  324. if (cssRule.cssText.startsWith(prefersColorSchemeDark)) {
  325. continue
  326. }
  327. }
  328. mediaRules = mediaRules.concat(Array.from(cssRule.cssRules))
  329. }
  330. // WARNING: do not try to insert a Rule to a styleSheet you are
  331. // currently iterating on, otherwise the browser will be stuck
  332. // in a infinite loop…
  333. for (const mediaRule of mediaRules) {
  334. styleSheet.insertRule(mediaRule.cssText)
  335. hasDarkRules = true
  336. }
  337. }
  338. if (hasDarkRules) {
  339. loadThemeForm('#theme-selector')
  340. }
  341. })
  342. </script>
  343. </body>
  344. </html>