2 Punkte von GN⁺ 2025-05-05 | 1 Kommentare | Auf WhatsApp teilen
  • 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.html und contact.html derselbe 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
  • <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

 
GN⁺ 2025-05-05
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.

    • Mit XHTML gab es kurz einen Umweg über XML, und XML hat XInclude, aber es ist keine Pflichtfunktion.
    • Interessantes Referenzmaterial, ich werde dazu noch weiter recherchieren
      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
    • Das ist für sich genommen eine vollständige Angriffsfläche
      https://en.wikipedia.org/wiki/Billion_laughs_attack
    • Das gab es auch in DTD, das in HTML 4 und früher sowie in XML verwendet wurde, und es stammt vermutlich aus SGML.
  • 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.

    • Server-Side Includes waren großartig
      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 .htaccess im 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.
    • Aus diesem Grund habe ich https://htmx.org lieben gelernt
      Eine kleine 10-KB-Bibliothek, die HTML um Kernfunktionen wie dynamische Imports von statischem HTML ergänzt.
    • Der Punkt „iframe wächst nicht passend zum Inhalt mit“ war tatsächlich ursprünglich geplant
      https://caniuse.com/iframe-seamless
    • Selbst in Netscape von 1996 konnte man so etwas tun. Ich betreibe immer noch einen Website-Server, der diese Methode verwendet
      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.
    • Die beste Lösung ist, mit einer Template-Engine statische Dokumente zu erzeugen.
  • 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/.

    • Das passt zu den im Kommentar [1] des Artikels genannten Gründen wie mangelnder Nachfrage und fehlender Begeisterung der Anbieter
      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 Skript document.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 Imports gingen in eine ähnliche Richtung, waren aber nicht dasselbe wie die Funktion, von der der Blogbeitrag spricht
      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...
    • Fairerweise muss man sagen, dass es ziemlich komplex war
      Soweit ich mich erinnere, musste man nach dem Import ein Template per JavaScript instanziieren; es war also nicht einfach nur ein simples einzelnes Tag.
    • Laut https://caniuse.com/imports gab es das in Firefox zumindest hinter einem Einstellungs-Flag.
    • HTML Imports waren deutlich komplexer als das Include, das dieser Artikel fordert.
  • Netscape 4 hatte diese Funktion als inflow layer
    https://web.archive.org/web/19970630074729fw_/http://develop...
    https://web.archive.org/web/19970630094813fw_/http://develop...

    • Soweit ich weiß, führte das Ändern des SRC-Attributs ziemlich häufig zu Crashes, und die Funktion wurde bald wieder entfernt
      Ich erinnere mich, in der Beta damit herumgespielt zu haben; in der finalen Version war sie verschwunden
    • Ich habe mich immer gefragt, warum der Name ILAYER war; jetzt weiß ich es
  • 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

    • Ward Cunningham, der Erfinder des Wiki, versuchte einmal, ein Transklusion-zuerst-Wiki zu bauen, in dem jeder seinen eigenen Wiki-Bereich hat und Transklusion sozial genutzt wird
      https://en.wikipedia.org/wiki/Federated_Wiki
      Wirklich durchgesetzt hat es sich aber nicht
    • Echte Transklusion bedeutet meiner Ansicht nach noch mehr als das
      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...>

    • Das Problem von framesets war viel grundlegender
      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 include meist zum ersten Mal, wenn sie PHP lernen, und in den meisten CMS wird include als Template-Partial schon früh in der Dokumentation erklärt. Es gibt keinen besonderen Bedarf, include nur mit HTML möglich zu machen. HTML ist ein Darstellungsformat und macht ohne CSS und JS nichts Interessantes

    • Die Aussage „include ist eine serverseitige Funktion“ ist kein Argument dafür, dass es kein clientseitiges Include geben sollte
      Tatsä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
    • Es wirkt seltsam, weil eine HTML-Datei Skripte, Fonts, Bilder, Videos, Styles usw. einbinden kann, aber kein HTML einbinden kann
      Vermutlich ließe sich das mit Custom Elements umsetzen, und ich wäre eher überrascht, wenn es auf GitHub kein ähnliches Repository gäbe
    • Dass viele Studierende darüber zu PHP kommen, stimmt. Trotzdem frage ich mich, warum es nicht als simples Tag geht
      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
    • Ich stimme dem Gesagten zu, aber HTML ist kein Darstellungsformat, sondern eine Dokumentbeschreibungssprache
      Wenn es um Styling geht, ist dafür CSS zuständig
    • Die Aussage „include ist serverseitig“ stimmt. Serverseitiges Include ist völlig natürlich, clientseitiges Include bedeutet aber, dass der Client das ursprüngliche DOM zu einem für ihn nicht vorhersehbaren Zeitpunkt verändern können müsste
      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.html child/include1.html einbindet und es in child/include1.html einen Link src="include2.html" gibt: Wohin soll der Nutzer beim Klicken gelangen? Wenn es zu include2.html geht, fehlt dort dem Namen nach vermutlich der Rest der Seite; wenn es zu main.html geht, wie gibt man dann an, dass diesmal include2.html statt include1.html verwendet werden soll? Umgekehrt könnten article1.html, article2.html, article3.html jeweils header.html, footer.html, navi.html einbinden; dann müsste man aber alle Artikel ändern, wenn man die globale Artikelstruktur ändern will. Wenn man allen Artikeln comments.html hinzufü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 nutzlos

    • Das sind alles lösbare Probleme, für die es ziemlich klare Lösungen gibt
      Hier 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
    • Die Include-Logik, nach der include2.html den Rest verliert, gilt genauso für andere Includes
      Wenn 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 sein
  • Bei 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

    • Anders als Framesets wurden XML-Includes anscheinend nie wirklich von vielen Browsern, vielleicht sogar von keinem der großen Browser, ordentlich unterstützt
      Ich nutze sie gelegentlich immer noch gern, aber man braucht eine Kompilierungsphase, die sie auswertet, bevor man das Ergebnis an Nutzer oder Browser weitergibt