Warum unterstützt HTML allein keine `include`-Funktion?
(frontendmasters.com)- Der Wunsch, auf mehreren Seiten nicht denselben Header zu wiederholen, ist naheliegend, aber HTML hat kein natives Include-Tag, das dies direkt erledigt
- Entwickler haben dasselbe Problem mit Workarounds wie JavaScript
fetch, Server-Direktiven, statischen Site-Generatoren, Template-Sprachen, Backend-Sprachen und Web Components gelöst <iframe>ist die Methode, die reinem HTML am nächsten kommt, eignet sich dafür aber wegen Performance-, Accessibility- und Usability-Problemen nicht und wirkt insgesamt unbeholfen- CSS kann CSS importieren und JavaScript kann JavaScript importieren, aber HTML kann kein HTML importieren, wodurch die Konsistenz der Web-Plattform brüchig wirkt
- Auswirkungen auf den Preload-Scanner, Layout-Verschiebungen durch asynchrones Laden, verschachtelte oder zyklische Includes, mehr Requests, Domain-Beschränkungen und möglicherweise zu geringe Nachfrage bleiben Hürden für eine Standardisierung
Der grundlegende Wunsch, wiederkehrende HTML-Fragmente wiederzuverwenden
- Das Problem zeigt sich, wenn in
index.html,about.htmlundcontact.htmlderselbe Header eingebaut werden muss - Statt denselben Code dreimal zu kopieren, liegt es nahe, den Header einmal zu erstellen und ihn auf mehreren Seiten zu includen
- Wenn die Zahl der Seiten in die Tausende geht, ist das nicht mehr nur Bequemlichkeit, sondern ein Problem der Vermeidung von Codeduplikaten
Viele vorhandene Lösungswege
- HTML-Fragmente zu laden und einzufügen ist bereits mit vielen Tools und auf verschiedenen Ebenen möglich
- JavaScript kann HTML mit
fetchladen und mitinsertAdjacentElementeinfügen - Es gibt auch alte Webserver-Direktiven wie Server Side Includes
- Statische Site-Generatoren bieten dafür Funktionen wie Jekyll include
- Auch Task-Runner wie gulp-include lassen sich dafür nutzen
- Template-Sprachen wie Handlebars partials stellen in der Regel Include-Funktionen bereit
- Backend-Sprachen können HTML auch dynamisch erzeugen, etwa mit PHPs
include - Es gibt sogar Ansätze mit Web Components, die speziell für Includes gedacht sind
- JavaScript kann HTML mit
<iframe>ist technisch zwar ein Weg, nur mit HTML anderes HTML zu laden, bringt für diesen Einsatzzweck aber große Probleme bei Performance, Accessibility und Usability mit sich- Man kann auch ganz auf Includes verzichten und stattdessen auf leistungsfähiges Suchen und Ersetzen setzen
Ausgerechnet in HTML selbst fehlt es
- Keine der genannten Methoden bedeutet: „Ein HTML-Tag lädt HTML und setzt es genau an diese Stelle ein“
- So wie
<img>ein Bild lädt und an dieser Position platziert, gibt es in HTML kein direktes deklaratives Tag nach dem Muster „Lade dieses HTML und füge es hier ein“ - Auch in der ShopTalk Show wurde diese Frage unter anderem mit Jake Archibald und Dave Rupert diskutiert
Wo das vom bisherigen Verlauf der Web-Plattform abweicht
- Web-Standards und Browser übernehmen häufig Aufgaben als Plattform-Feature, die Entwickler zuvor immer wieder selbst lösen mussten
- Für den bisherigen Einsatz von Third-Party-JavaScript bei Datumsverarbeitung gibt es inzwischen Temporal
- Auf Anforderungen an Seitenübergänge, die zuvor Frameworks übernommen haben, reagiert die View Transition API
- In Bereiche, die früher Bibliotheken für die sichere Platzierung von Elementen abdeckten, ist CSS anchor positioning vorgedrungen
- Wenn fast jede Website HTML-Fragmente wiederverwenden muss und dafür jeweils andere nicht standardisierte Werkzeuge einsetzt, wirkt das Fehlen eines HTML-Include wie eine ungewöhnliche Lücke
Warum HTML-Include schwer zum Standard werden dürfte
- Aus Sicht von Browsern und Ökosystem bringt HTML-Include mehrere Belastungen mit sich
- Es könnte den Preload-Scanner beeinträchtigen und damit die Web-Performance verschlechtern
- Wenn es asynchron funktionieren müsste, könnte das während des Ladens zu Layout-Verschiebungen oder springenden Inhalten führen
- Es würde zusätzliche Komplexität schaffen, die die Einfachheit oder Reinheit von HTML beeinträchtigen könnte
- Die Behandlung verschachtelter und zyklischer Includes könnte schwierig sein
- Webhosting-Anbieter könnten wegen der steigenden Zahl von Requests Einwände haben
- Anders als bei Bildern, CSS und JavaScript könnten für HTML strengere Beschränkungen nötig sein, wenn Inhalte von anderen Domains geladen werden
- Es könnte noch weitere Probleme geben, die hier nicht aufgeführt sind
- Möglicherweise ist die tatsächliche Nachfrage nach dieser Funktion gar nicht so groß
- Statt einer endgültigen Antwort geht es eher um eine Erkundung der Gründe, warum HTML HTML nicht direkt includen kann
1 Kommentare
Meinungen auf Hacker News
HTML war historisch eine Anwendung von SGML, und SGML konnte Includes
Man konnte neue „Entities“ definieren, und wenn man eine „System“-Entity anlegte, konnte sie später referenziert und ersetzt werden. SGML war komplex, daher gab es mehrere Versuche, HTML zu vereinfachen, und dabei fiel auch diese Funktion heraus.
Das betreffende Tag sieht so aus, als könne es eine andere HTML-Seite einbinden oder embedden. Eingebettete HTML-Seite: https://www.w3schools.com/tags/tag_object.asp
https://en.wikipedia.org/wiki/Billion_laughs_attack
Das war Ende der 90er ein Rabbit Hole, in das ich geraten bin, und ich bin immer noch nicht herausgekommen
Ich war Webmaster der Website von Analog Science Fiction, und weil ich Unmengen statischer Seiten mit demselben Header und derselben Sidebar erstellen musste, wurde ich fast verrückt. Bei der Recherche stieß ich auf Apache-Server-Side Includes, und noch bevor ich den Begriff DRY kannte, konnte ich damit DRY arbeiten. Manche sagen, iframes reichten aus, aber das tun sie nicht. iframes wachsen nicht passend zur Inhaltsgröße mit, und serverseitige Lösungen brauchen einen Server. Ich verstehe nicht, warum es keine einfache clientseitige Methode geben sollte, und jetzt, wo viele Ärgernisse der Webentwicklung behoben werden, ist das eine Frage, die man erwägen sollte.
Als ich Mitte der 90er mit einem Freund anfing, „Web stuff“ zu bauen, war das DRY-Konzept einfach intuitiv klar. Unser damaliger Dial-up-ISP blockierte
.htaccessim Benutzer-Webspace nicht, sodass wir Server-Side Includes einschalten konnten, und später fanden wir auch heraus, wie man CGI aktiviert. Ich schrieb sogar eine primitive Webshell in Perl, um die Webserver-Box zu erkunden.Eine kleine 10-KB-Bibliothek, die HTML um Kernfunktionen wie dynamische Imports von statischem HTML ergänzt.
https://caniuse.com/iframe-seamless
Was mich an Frames immer gestört hat, war, dass sie zu schlau sein wollten. Wenn ich per Rechtsklick aktualisierte, wollte ich nicht nur das Frame-HTML neu laden. Ich verstehe die Absicht, getrennt zu cachen, aber Frames und Caches sollten unterschiedliche Probleme lösen; indem man beides vermischte, wurde beides halbgar. Meiner Ansicht nach sollte ein HTML-Include so dumm wie möglich funktionieren. Es sollte den Include-Text an der Include-Position einfügen, und der Browser bekommt den daraus resultierenden Text. Wenn man dieselbe Navigation auf jeder Seite separat cachen möchte, kann man Cache-Attribute hinzufügen und dieses Problem unabhängig lösen. Man kann mich vielleicht davon überzeugen, dass ein Include mehr leisten sollte, aber dummes Verhalten ist kein Bug, sondern ein Feature.
Dieser Feature-Vorschlag hieß HTML Imports und entstand als Teil der Arbeit an Web Components
Es gab die Beschreibung „HTML Imports are a way to include and reuse HTML documents in other HTML documents“, und das Planungsdokument steht unter https://www.w3.org/TR/html-imports/.
Allerdings sind solche Gründe eher Nicht-Gründe, die in der Praxis nichts erklären. Dieses Feature wurde 20 Jahre lang immer wieder gefordert, und es gibt alle möglichen Shim-Implementierungen mit Skripten, Backend-Engines und Ähnlichem; da ist es schwer zu glauben, die Nachfrage sei gering. Auch die Ablehnung durch Anbieter erklärt nicht, warum sie so weit ging, bereits vorhandene Implementierungen zurückzudrehen. Auch „Sicherheitsauswirkungen“ ist merkwürdig, denn man kann bereits mit einem script-Tag Cross-Origin-HTML laden und
document.write()ausführen. Ich frage mich, warum es in Ordnung ist, wenn ein Skriptdocument.write()macht, aber ein HTML-Tag, das dasselbe tut, ein großes Problem sein soll. Sicherheitsbedenken, etwa dass man die Google-Startseite spontan klonen könnte, verstehe ich, aber das ließe sich offenbar leicht mit CORS lösen.[1] https://frontendmasters.com/blog/seeking-an-answer-why-cant-...
HTML müsste an einer bestimmten Stelle im Dokument importiert und angezeigt werden, aber HTML Imports konnten das ohne JavaScript nicht. Details siehe https://github.com/whatwg/html/issues/2791#issuecomment-3112...
Soweit ich mich erinnere, musste man nach dem Import ein Template per JavaScript instanziieren; es war also nicht einfach nur ein simples einzelnes Tag.
Netscape 4 hatte diese Funktion als inflow layer
https://web.archive.org/web/19970630074729fw_/http://develop...
https://web.archive.org/web/19970630094813fw_/http://develop...
SRC-Attributs ziemlich häufig zu Crashes, und die Funktion wurde bald wieder entferntIch erinnere mich, in der Beta damit herumgespielt zu haben; in der finalen Version war sie verschwunden
Der Name dieser Funktion ist Transklusion (transclusion)
https://en.wikipedia.org/wiki/Transclusion
Sie war Teil von Project Xanadu und galt ursprünglich als wichtige Funktion von Hypertext. Besonders MediaWiki nutzt Transklusion in großem Umfang, und manchmal fühlt sich ein Wiki wie die reinste Form von Hypertext an
https://en.wikipedia.org/wiki/Federated_Wiki
Wirklich durchgesetzt hat es sich aber nicht
In Xanadu konnte man nur einen Ausschnitt eines Dokuments in ein anderes Dokument transkludieren. Um das in HTML zu machen, bräuchte man eine Antwort auf die CSS-Frage. In bestimmten Situationen lässt sich entscheiden, welche Eigenschaften zwischen Host-Dokument, Gast-Dokument und dem im Host eingebetteten Gast konsistent sein sollen, und das entsprechend lösen; im allgemeinen Fall ist es aber unklar. Bei einem einfachen Tag-Ansatz müsste das Gast-Dokument so gestaltet sein, dass es in der vom Host bereitgestellten CSS-Umgebung lebt. Eine andere einfache Antwort ist Shadow DOM: Damit kann der Gast im Großen und Ganzen seine eigenen Styles anwenden, ohne den Rest des Dokuments zu beeinflussen. Auch in diesem Fall könnte der Host meiner Meinung nach einige Styles einbringen, um den Gast anzupassen
Ich frage mich, ob nicht genau das schon vor langer Zeit ein ordentliches frameset leisten sollte. Nicht iframe, sondern frameset aus der HTML-4-Zeit
Zumindest funktionierte die automatische Größenanpassung gut, und Nutzer konnten die Größe auch nach Wunsch ändern. Es gab viel Kritik an Frames [1], aber in nützlichen Bereichen wie der Java-API-Dokumentation [2] wurden sie erfolgreich eingesetzt. Dass sie letztlich verschwanden, lag meiner Meinung nach daran, dass sie Designern zu wenig Flexibilität boten. Für Informationsseiten reichte es, aber die groben Scrollbars und die eingeschränkte Bildschirmaufteilung erfüllten die Anforderungen von Designern nicht. Heute würden unveränderte framesets auf Mobilgeräten vermutlich nicht gut funktionieren, also ist es zu spät, sie wiederzubeleben
[1] <https://www.nngroup.com/articles/why-frames-suck-most-of-the...> – Interessant ist, dass vieles darin heute nicht mehr gilt und dass alle bei Frames bemängelten Probleme im heutigen Web in noch chaotischerer Form existieren
[2] <https://www.eeng.dcu.ie/~ee553/ee402notes/html/figures/JavaD...>
Deep Linking war unmöglich, sodass Leute, die über Lesezeichen, Google oder frühere Suchmaschinen kamen, auf einer Seite ohne Navigation landeten; man versuchte, das mit JavaScript zu umgehen, aber daraus wurde keine gute Experience
Die „include“-Funktion wird als etwas betrachtet, das serverseitig, also außerhalb des Webbrowsers, verarbeitet wird
HTML ist clientseitig und im Grunde keine Programmiersprache, sondern eine Markup-Syntax. Wie im Artikel gesagt wird, ist dieses Problem bereits gelöst. Webdesign-Studierende begegnen
includemeist zum ersten Mal, wenn sie PHP lernen, und in den meisten CMS wirdincludeals Template-Partial schon früh in der Dokumentation erklärt. Es gibt keinen besonderen Bedarf,includenur mit HTML möglich zu machen. HTML ist ein Darstellungsformat und macht ohne CSS und JS nichts InteressantesTatsächlich gibt es in HTML mit Frames und Iframes bereits schlechtere Versionen davon. Ein clientseitiges Gegenstück zu Server-Side Includes würde sich natürlich in das einfügen, was Menschen mit HTML tun
Vermutlich ließe sich das mit Custom Elements umsetzen, und ich wäre eher überrascht, wenn es auf GitHub kein ähnliches Repository gäbe
Es gibt bereits Inhalte, die asynchron geladen werden, etwa Bilder oder Inhalte weiter unten auf der Seite. Die Aussage „HTML ist keine Programmiersprache, sondern Markup-Syntax“ grenzt an Flamebait; es ist eine deklarative Sprache, die von Browser-Engines interpretiert wird
Wenn es um Styling geht, ist dafür CSS zuständig
Es gibt zwei Möglichkeiten. Erstens während des HTML-Parsings, also vor der DOM-Erzeugung; dafür wären synchrone Requests an den Server nötig, was für Includes unerwünscht ist. Zweitens nach der DOM-Erzeugung: Ein bestimmtes Element erscheint im DOM, ein Fragment wird asynchron geladen und dieses DOM-Element wird durch das externe Fragment ersetzt. Das hebelt jedoch die bestehenden Mechanismen zur Validierung der DOM-Struktur aus. Die Sciter-Engine hat es allerdings mit der ersten Strategie implementiert. Da Sciters HTML normalerweise aus lokalen App-Ressourcen oder dem Dateisystem stammt, sind die Kosten für zusätzliche Fragment-Anfragen vernachlässigbar
https://docs.sciter.com/docs/HTML/html-include
Bei HTML-Includes gibt es, wie andere gesagt haben, mehrere Probleme
Wenn
main.htmlchild/include1.htmleinbindet und es inchild/include1.htmleinen Linksrc="include2.html"gibt: Wohin soll der Nutzer beim Klicken gelangen? Wenn es zuinclude2.htmlgeht, fehlt dort dem Namen nach vermutlich der Rest der Seite; wenn es zumain.htmlgeht, wie gibt man dann an, dass diesmalinclude2.htmlstattinclude1.htmlverwendet werden soll? Umgekehrt könntenarticle1.html,article2.html,article3.htmljeweilsheader.html,footer.html,navi.htmleinbinden; dann müsste man aber alle Artikel ändern, wenn man die globale Artikelstruktur ändern will. Wenn man allen Artikelncomments.htmlhinzufügen will, möchte man am Ende die Seiten doch wieder aus Templates generieren, und an diesem Punkt braucht man kein Browser-Include mehr. Außerdem entstehen Probleme, wenn der Header den Titel kennen muss oder der Footer Vorher-/Weiter-Links kennen muss; man braucht eine Möglichkeit, Informationen zwischen Includes auszutauschen, und landet schließlich wieder bei der Seitengenerierung. Bei genauerem Hinsehen ist HTML-Include für die meisten Einsatzzwecke wahrscheinlich praktisch nutzlosHier werden zwei unterschiedliche Use Cases vermischt. Der eine ist Wiederverwendung von Fragmenten, der andere eine einbettbare unabhängige Insel. Letzteres wird bereits von Iframes abgedeckt, also muss nur Ersteres gelöst werden
include2.htmlden Rest verliert, gilt genauso für andere IncludesWenn ein Nutzer auf einen Link
src="include.css"klickt, wird es ebenfalls chaotisch. Für statische Daten, Bilder, CSS und statische HTML-Inhalte kann es aber in Ordnung seinBei WHATWG gibt es dazu ein offenes Issue. Es wird auch im Kommentarbereich des Blogbeitrags erwähnt
Client side include feature for HTML
https://github.com/whatwg/html/issues/2791
HTML hatte Includes, und sie sind aus der Mode gekommen
Der eigentliche Begriff „include“ stammt aus XML, und genau diese Funktion wünscht sich der Artikel. HTML hatte vor XML einen anderen Ansatz, nämlich Frames. Frames leisteten sehr viel mehr als XML-Includes, deshalb bekam HTML diese Funktion nicht separat. Frames verloren wegen Missbrauch, Sicherheit, Barrierefreiheit und anderer Probleme an Popularität
Ich nutze sie gelegentlich immer noch gern, aber man braucht eine Kompilierungsphase, die sie auswertet, bevor man das Ergebnis an Nutzer oder Browser weitergibt