Pourquoi HTML ne peut-il pas, à lui seul, prendre en charge une fonctionnalité d’« include » ?
(frontendmasters.com)- Le besoin d’éviter de répéter le même header sur plusieurs pages est fondamental, mais HTML ne dispose pas d’une balise include native pour le gérer directement
- Les développeurs résolvent ce même problème via des solutions de contournement comme JavaScript
fetch, des directives serveur, des générateurs de sites statiques, des langages de templates, des langages backend ou des Web Components <iframe>est la méthode la plus proche d’un HTML pur, mais elle convient mal à cet usage en raison de problèmes de performance, d’accessibilité et d’utilisabilité, et reste globalement peu naturelle- CSS peut importer du CSS et JavaScript peut importer du JavaScript, mais HTML ne peut pas importer de HTML, ce qui donne l’impression de fragiliser la cohérence de la plateforme web
- L’impact sur le preload scanner, les décalages de mise en page liés au chargement asynchrone, les includes imbriqués ou circulaires, l’augmentation des requêtes, les restrictions de domaine et une demande possiblement insuffisante restent des obstacles à la standardisation
Un besoin fondamental : réutiliser des fragments HTML répétés
- Le problème apparaît lorsqu’il faut insérer le même header dans trois pages :
index.html,about.htmletcontact.html - Au lieu de copier le même code trois fois, il est naturel de vouloir créer le header une seule fois puis l’inclure dans plusieurs pages
- Quand le nombre de pages monte à des milliers, ce n’est plus seulement une question de confort, mais de prévention de la duplication de code
De nombreuses solutions existent déjà
- Il est déjà possible de récupérer et d’insérer des fragments HTML via divers outils et couches de la pile
- En JavaScript, on peut récupérer du HTML avec
fetchpuis l’insérer avecinsertAdjacentElement - Il existe aussi les anciennes directives serveur Server Side Includes
- On peut le gérer avec des fonctionnalités de générateurs de sites statiques comme Jekyll include
- Des task runners comme gulp-include peuvent aussi être utilisés
- Les langages de templates comme Handlebars partials proposent généralement une fonctionnalité d’include
- Des langages backend peuvent aussi générer du HTML dynamiquement, comme
includeen PHP - Il existe également des approches fondées sur des Web Components dédiés à l’include
- En JavaScript, on peut récupérer du HTML avec
<iframe>est techniquement une façon de charger un autre document HTML avec du HTML seul, mais pour cet usage, ses problèmes de performance, d’accessibilité et d’utilisabilité sont importants- On peut aussi choisir de ne pas utiliser d’include du tout, en s’appuyant sur de puissantes fonctions de rechercher/remplacer
Et pourtant, rien dans HTML lui-même
- Toutes les méthodes ci-dessus ne consistent pas à « récupérer du HTML avec une balise HTML et l’insérer à cet emplacement »
- De la même manière que
<img>récupère une image et l’insère là où elle est déclarée, HTML ne propose pas de balise déclarative directe du type « récupérer ce HTML et l’insérer ici » - La question a aussi été discutée dans ShopTalk Show, notamment avec Jake Archibald et Dave Rupert
Un décalage avec l’évolution habituelle de la plateforme web
- Les standards du web et les navigateurs ont souvent tendance à intégrer à la plateforme des besoins que les développeurs résolvent déjà de manière répétée
- Pour la gestion des dates, longtemps confiée à des bibliothèques JavaScript tierces, on a vu apparaître Temporal
- Pour les transitions entre pages auparavant gérées par des frameworks, il y a désormais la View Transition API
- Pour le positionnement sûr des éléments, domaine historiquement couvert par des bibliothèques, on voit arriver le CSS anchor positioning
- Alors que presque tous les sites web ont besoin de réutiliser des fragments HTML et recourent chacun à des outils non standard différents, l’absence d’un include HTML ressemble à un vide assez inhabituel
Pourquoi un include HTML a du mal à devenir un standard
- Du point de vue des navigateurs et de l’écosystème, un include HTML implique plusieurs contraintes
- Il pourrait casser le preload scanner et nuire aux performances web
- S’il devait être asynchrone, cela pourrait provoquer des secousses visuelles ou des sauts de mise en page pendant le chargement
- Cela pourrait introduire une complexité qui nuit à la simplicité ou à la pureté de HTML
- La gestion des includes imbriqués et des includes circulaires pourrait être difficile
- Les hébergeurs web pourraient s’y opposer en raison de l’augmentation du nombre de requêtes
- Contrairement aux images, au CSS ou au JavaScript, le HTML pourrait nécessiter des restrictions plus strictes lorsqu’il est chargé depuis un autre domaine
- Il peut exister d’autres problèmes non listés ici
- En pratique, la demande réelle pour cette fonctionnalité n’est peut-être pas si forte
- Il s’agit moins d’apporter une réponse définitive que d’explorer les raisons possibles pour lesquelles HTML ne peut pas inclure directement du HTML
1 commentaires
Avis de Hacker News
Historiquement, HTML était une application de SGML, et SGML permettait les includes
On pouvait définir une nouvelle « entity », et en créer une de type « system » permettait de la référencer plus tard pour qu’elle soit substituée. SGML était complexe, et plusieurs tentatives ont cherché à simplifier HTML ; cette fonctionnalité a alors été retirée au passage
La balise en question semble inclure ou intégrer une autre page HTML. Page HTML intégrée : https://www.w3schools.com/tags/tag_object.asp
https://en.wikipedia.org/wiki/Billion_laughs_attack
C’est un terrier dans lequel je suis tombé à la fin des années 90, et dont je ne suis toujours pas sorti
J’étais webmaster du site d’Analog Science Fiction, et créer des tonnes de pages statiques avec le même en-tête et la même barre latérale me rendait fou. En cherchant, j’ai découvert les includes côté serveur d’Apache, ce qui m’a permis de faire du DRY avant même de connaître le terme. Certains disent qu’un iframe suffit, mais ce n’est pas le cas. Un iframe ne s’agrandit pas pour s’adapter à la taille du contenu, et les solutions côté serveur nécessitent un serveur. Je ne vois pas pourquoi il ne pourrait pas exister une méthode simple côté client, et c’est une question qui mérite d’être envisagée maintenant qu’on corrige beaucoup d’irritants du développement web
Quand j’ai commencé à fabriquer du « web stuff » avec un ami au milieu des années 90, le concept de DRY nous paraissait simplement naturel. À l’époque, notre FAI en accès commuté n’interdisait pas l’usage de
.htaccessdans l’espace web utilisateur, ce qui permettait d’activer les includes côté serveur, et plus tard nous avons aussi trouvé comment activer CGI. J’ai même écrit en Perl un webshell rudimentaire pour explorer la machine du serveur webC’est une petite bibliothèque de 10 Ko qui ajoute à HTML des fonctionnalités essentielles, comme l’import dynamique dans du HTML statique
https://caniuse.com/iframe-seamless
Ce qui m’a toujours agacé avec les frames, c’est qu’elles essayaient d’être trop intelligentes. Quand je faisais clic droit puis actualiser, je ne voulais pas recharger uniquement le HTML de la frame. Je comprends l’intention de mettre cela en cache séparément, mais les frames et le cache sont censés résoudre deux problèmes différents ; en les mélangeant, les deux sont devenus bancals. À mon avis, un include HTML devrait se comporter de la manière la plus bête possible. Il suffit de coller le texte inclus à l’endroit de l’include, et que le navigateur reçoive le texte résultant. Si l’on veut mettre en cache séparément la même navigation sur toutes les pages, on peut ajouter des attributs de cache et résoudre ce problème indépendamment. On peut toujours me convaincre qu’un include devrait faire davantage, mais ce comportement bête n’est pas un bug, c’est une fonctionnalité
Cette proposition de fonctionnalité s’appelait HTML Imports et a été créée dans le cadre des travaux sur les Web Components
Elle était décrite ainsi : « HTML Imports are a way to include and reuse HTML documents in other HTML documents », et le document de planification se trouve sur https://www.w3.org/TR/html-imports/
Mais ces raisons sont presque des non-raisons qui n’expliquent rien en pratique. Cette fonctionnalité est demandée depuis 20 ans, et il existe toutes sortes d’implémentations en shim faites avec des scripts, des moteurs backend, etc. ; il est donc difficile de croire que la demande soit faible. Le refus des fournisseurs n’explique pas non plus pourquoi ils sont allés jusqu’à revenir sur des implémentations qui existaient déjà. L’argument des « implications de sécurité » est également étrange, puisqu’on peut déjà récupérer du HTML cross-origin avec une balise script et faire un
document.write(). Pourquoi un script qui faitdocument.write()serait-il acceptable, alors qu’une balise HTML faisant la même chose deviendrait un gros problème ? Je comprends la préoccupation de sécurité visant à empêcher, par exemple, de cloner instantanément la page d’accueil de Google, mais cela semble facile à résoudre avec CORS[1] https://frontendmasters.com/blog/seeking-an-answer-why-cant-...
Le HTML devrait être importé et affiché à un endroit précis du document, alors que HTML Imports ne permettait pas de le faire sans JavaScript. Pour plus de détails, voir https://github.com/whatwg/html/issues/2791#issuecomment-3112...
De mémoire, après l’import il fallait instancier le template avec JavaScript ; ce n’était pas simplement une balise unique et toute simple
Netscape 4 disposait de cette fonctionnalité sous forme d’inflow layer
https://web.archive.org/web/19970630074729fw_/http://develop...
https://web.archive.org/web/19970630094813fw_/http://develop...
SRCavait tendance à provoquer pas mal de crashs, et la fonctionnalité a vite été retiréeJe me souviens m’être amusé avec dans la bêta, mais elle avait disparu dans la version finale
Le nom de cette fonctionnalité est transclusion
https://en.wikipedia.org/wiki/Transclusion
Elle faisait partie du Project Xanadu et était à l’origine considérée comme une fonctionnalité importante de l’hypertexte. MediaWiki, en particulier, utilise abondamment la transclusion, et les wikis donnent parfois l’impression d’être la forme la plus pure de l’hypertexte
https://en.wikipedia.org/wiki/Federated_Wiki
Mais cela n’a jamais vraiment décollé
Dans Xanadu, on pouvait transclure dans un autre document seulement un extrait d’un document. Pour faire cela en HTML, il faut une réponse côté CSS. Dans certains cas, on peut déterminer et résoudre quelles propriétés doivent rester cohérentes entre le document hôte, le document invité et l’invité intégré dans l’hôte, mais dans le cas général ce n’est pas clair. Avec une simple approche par balise, le document invité devrait être conçu pour vivre dans l’environnement CSS que l’hôte lui impose. Une autre réponse simple est le Shadow DOM, qui permet généralement à l’invité d’appliquer ses propres styles sans affecter le reste du document. Même dans ce cas, je pense que l’hôte pourrait quand même ajouter quelques styles pour ajuster l’invité
J’ai l’impression que c’est ce que les vrais framesets essayaient de faire il y a longtemps. Je parle des framesets de l’époque HTML 4, pas des iframes
Au moins, l’agrandissement automatique fonctionnait bien, et l’utilisateur pouvait aussi redimensionner à sa convenance. Les frames ont été beaucoup critiquées [1], mais elles ont été utilisées avec succès là où elles étaient utiles, comme dans la documentation de l’API Java [2]. Si elles ont fini par disparaître, c’est, à mon avis, parce qu’elles manquaient trop de souplesse pour les designers. C’était suffisant pour des pages d’information, mais les barres de défilement grossières et le découpage limité de l’écran ne répondaient pas aux attentes des designers. Aujourd’hui, les framesets tels quels ne fonctionneraient probablement pas bien sur mobile, il est donc trop tard pour les ressusciter
[1] <https://www.nngroup.com/articles/why-frames-suck-most-of-the...> - Il est amusant de constater qu’une grande partie de ce contenu ne s’applique plus vraiment, et que tous les problèmes reprochés aux frames existent aujourd’hui sur le Web sous des formes encore plus désordonnées
[2] <https://www.eeng.dcu.ie/~ee553/ee402notes/html/figures/JavaD...>
Les liens profonds étaient impossibles, si bien que les personnes arrivant via un favori, Google ou des moteurs de recherche plus anciens tombaient sur une page sans navigation ; on essayait de contourner cela avec JavaScript, mais cela ne donnait pas une bonne expérience
La fonctionnalité « include » est considérée comme quelque chose traité côté serveur, c’est-à-dire en dehors du navigateur web
HTML est côté client et, en réalité, ce n’est pas un langage de programmation mais une syntaxe de balisage. Comme le dit l’article, ce problème est déjà résolu. Ce que les étudiants en webdesign découvrent en premier en apprenant PHP, c’est
include, et dans la plupart des CMS,includedevient un partial de template expliqué dès le début de la documentation. Il n’y a pas vraiment besoin de rendreincludepossible avec HTML seul. HTML est un format de représentation et ne fait rien d’intéressant sans CSS ni JSEn fait, HTML possède déjà des versions pires avec les frames et les iframes. L’équivalent côté client du server-side include s’intègre naturellement à ce que les gens font avec HTML
On pourrait probablement le coder avec des éléments personnalisés, et je serais plutôt surpris s’il n’existait pas déjà un dépôt similaire sur GitHub
Il existe déjà du contenu chargé de manière asynchrone, comme les images ou le contenu en bas de page. Dire que « HTML n’est pas un langage de programmation mais une syntaxe de balisage » relève presque du flamebait : c’est un langage déclaratif interprété par différents moteurs de navigateur
Si l’on parle de style, c’est CSS qui se charge de la présentation
Il y a deux options. La première consiste à le traiter au moment du parsing HTML, donc avant la création du DOM, mais cela nécessite une requête synchrone au serveur pour l’include, ce qui n’est pas souhaitable. La seconde consiste, après la création du DOM, à faire apparaître un élément donné dans le DOM, à charger un fragment de manière asynchrone, puis à remplacer cet élément DOM par le fragment externe ; mais cela neutralise les mécanismes existants de validation de la structure du DOM. Cela dit, le moteur Sciter l’a implémenté avec la première stratégie. Le HTML de Sciter provient généralement de ressources locales de l’application ou du système de fichiers, si bien que le coût des requêtes de fragments supplémentaires est négligeable
https://docs.sciter.com/docs/HTML/html-include
Comme d’autres l’ont dit, un include HTML pose plusieurs problèmes
Si
main.htmlinclutchild/include1.html, et qu’à l’intérieur dechild/include1.htmlil y a un liensrc="include2.html", où l’utilisateur doit-il aller quand il clique ? S’il va versinclude2.html, il s’agira probablement, d’après son nom, d’une page prévue pour l’include, donc il manquera le reste ; s’il va versmain.html, comment indiquer cette fois qu’il faut utiliserinclude2.htmlet noninclude1.html? À l’inverse,article1.html,article2.htmletarticle3.htmlpourraient chacun inclureheader.html,footer.htmletnavi.html, mais alors, pour modifier globalement la structure de tous les articles, il faudrait modifier tous les articles. Si l’on veut ajoutercomments.htmlà tous les articles, on finit par vouloir régénérer les pages avec un template, et à ce stade l’include dans le navigateur n’est plus nécessaire. Il y a aussi le problème du header qui doit connaître le titre, ou du footer qui doit connaître les liens précédent/suivant ; il faut alors un moyen d’échanger des informations entre les includes, et l’on revient finalement à la génération de pages. À bien y regarder, l’include HTML risque d’être pratiquement inutile dans la plupart des usagesDeux cas d’usage différents sont mélangés ici. L’un est la réutilisation de fragments, l’autre une île autonome intégrable. Le second est déjà pris en charge par iframe, il ne reste donc qu’à résoudre le premier
include2.htmlperdrait le reste s’applique tout autant aux autres includesSi l’utilisateur clique sur un lien
src="include.css", ce sera le bazar. Cela peut convenir à des données statiques, des images, du CSS ou du contenu HTML statiqueIl existe une issue ouverte à ce sujet au WHATWG. Elle est aussi mentionnée dans la section commentaires de l’article de blog
Client side include feature for HTML
https://github.com/whatwg/html/issues/2791
HTML a eu des includes, puis ils ont perdu en popularité
Le terme réel « include » désigne une fonctionnalité XML, et c’est aussi cette fonctionnalité que l’article souhaite. HTML avait une autre approche, antérieure à XML : les frames. Comme les frames faisaient beaucoup plus que les includes XML, HTML n’a pas obtenu cette fonctionnalité séparément. Les frames sont tombées en disgrâce pour plusieurs raisons : mauvais usages, sécurité, accessibilité, etc.
J’aime toujours les utiliser de temps en temps, mais il faut une étape de compilation qui les évalue avant de les transmettre à l’utilisateur ou au navigateur