¿Por qué HTML por sí solo no puede soportar una función de `include`?
(frontendmasters.com)- La necesidad de no repetir el mismo header en varias páginas es básica, pero HTML no tiene una etiqueta nativa de include para manejarlo directamente
- Los desarrolladores han resuelto el mismo problema con vías alternativas como JavaScript
fetch, directivas del servidor, generadores de sitios estáticos, lenguajes de plantillas, lenguajes backend y Web Components <iframe>es el método más cercano a HTML puro, pero no encaja bien para este uso por temas de rendimiento, accesibilidad y usabilidad, y en general resulta incómodo- CSS puede importar CSS y JavaScript puede importar JavaScript, pero HTML no puede importar HTML, lo que hace que parezca romperse la consistencia de la plataforma web
- El impacto en el preload scanner, los saltos de layout por carga asíncrona, los includes anidados o circulares, el aumento de solicitudes, las restricciones de dominio y la posible falta de demanda siguen siendo barreras para su estandarización
La necesidad básica de reutilizar fragmentos repetidos de HTML
- El problema se hace evidente cuando hay que poner el mismo header en tres páginas:
index.html,about.htmlycontact.html - En vez de copiar el mismo código tres veces, lo natural es querer crear el header una sola vez e incluirlo en varias páginas
- Si el sitio crece a miles de páginas, ya no se trata solo de comodidad, sino de evitar la duplicación de código
Las distintas soluciones que ya existen
- Traer e insertar fragmentos de HTML ya es posible en varias herramientas y capas
- Con JavaScript se puede traer HTML usando
fetche insertarlo coninsertAdjacentElement - También existen las antiguas Server Side Includes
- Se puede resolver con funciones de generadores de sitios estáticos como Jekyll include
- También pueden usarse task runners como gulp-include
- Los lenguajes de plantillas como Handlebars partials por lo general ofrecen funciones de include
- Los lenguajes backend también pueden generar HTML dinámicamente, como
includede PHP - Incluso existe un enfoque con Web Component dedicado a includes
- Con JavaScript se puede traer HTML usando
<iframe>es técnicamente una forma de traer otro HTML usando solo HTML, pero para este caso tiene grandes problemas de rendimiento, accesibilidad y usabilidad- También existe la opción de no usar includes y confiar en una buena función de buscar y reemplazar
Pero en HTML en sí no existe
- Todos los métodos anteriores no son realmente una forma de “traer este HTML e insertarlo aquí con una sola etiqueta HTML”
- Así como
<img>trae una imagen y la coloca en ese lugar, HTML no tiene una etiqueta declarativa directa que diga “trae este HTML y ponlo aquí” - En ShopTalk Show también se discutió esta misma pregunta con Jake Archibald y Dave Rupert, entre otros
Un punto que choca con la dirección que ya ha tomado la plataforma web
- Los estándares web y los navegadores muchas veces terminan absorbiendo como funciones nativas cosas que los desarrolladores ya resolvían repetidamente por su cuenta
- En el caso del manejo de fechas, donde antes se usaba JavaScript de terceros, apareció Temporal
- Para la necesidad de transiciones entre páginas que antes resolvían los frameworks, surgió la View Transition API
- En el terreno de las librerías usadas para posicionar elementos de forma segura, llegó CSS anchor positioning
- Casi todos los sitios web necesitan reutilizar fragmentos de HTML y cada uno lo resuelve con herramientas no estándar distintas, así que la ausencia de HTML include parece un vacío inusual
Por qué es difícil que HTML include se vuelva un estándar
- Desde la perspectiva del navegador y del ecosistema, HTML include trae varias cargas
- Puede romper el preload scanner y afectar negativamente el rendimiento web
- Si tuviera que ser asíncrono, podría generar una experiencia con saltos o parpadeos en la interfaz mientras carga
- Podría introducir una complejidad que afecta la simplicidad o pureza de HTML
- Los includes anidados y los includes circulares podrían ser difíciles de manejar
- Los proveedores de hosting web podrían oponerse por el aumento en la cantidad de solicitudes
- A diferencia de imágenes, CSS o JavaScript, HTML podría requerir restricciones más estrictas al cargarse desde otros dominios
- Puede haber otros problemas no incluidos en esta lista
- En la práctica, quizá la demanda real por esta función no sea tan grande
- Más que una respuesta definitiva, se trata de una exploración de razones sobre por qué HTML no puede incluir HTML directamente
1 comentarios
Opiniones de Hacker News
Históricamente, HTML era una aplicación de SGML, y SGML sí permitía includes.
Se podían definir nuevas “entities”, y si se creaba una entity “system”, luego se podía referenciar para que fuera sustituida. SGML era complejo, así que hubo varios intentos de simplificar HTML, y en ese proceso también se eliminó esta función.
Esa etiqueta parece incluir o embeber otra página HTML. Página HTML embebida: https://www.w3schools.com/tags/tag_object.asp
https://en.wikipedia.org/wiki/Billion_laughs_attack
Fue una madriguera en la que caí a fines de los 90 y de la que todavía no he salido.
Era webmaster del sitio web de Analog Science Fiction, y estaba volviéndome loco creando montones de páginas estáticas con el mismo header y la misma barra lateral. Investigando, descubrí los server-side includes de Apache, y pude hacer las cosas de forma DRY incluso antes de conocer el término DRY. Algunos dicen que con iframe basta, pero no basta. Un iframe no se expande para ajustarse al tamaño del contenido, y las soluciones del lado del servidor requieren un servidor. No sé por qué no debería existir un método simple del lado del cliente, y ahora que se están corrigiendo muchas molestias del desarrollo web, es una pregunta que vale la pena considerar.
Cuando a mediados de los 90 empecé a hacer “web stuff” con un amigo, el concepto de DRY simplemente se entendía de forma natural. En esa época, nuestro ISP de dial-up no bloqueaba el uso de
.htaccessen el espacio web de los usuarios, así que pudimos activar server-side includes, y más tarde descubrimos cómo activar también CGI. Incluso escribí una web shell rudimentaria en Perl para explorar la máquina del servidor web.Es una pequeña biblioteca de 10 KB que le agrega a HTML funciones esenciales como imports dinámicos de HTML estático.
https://caniuse.com/iframe-seamless
Lo que siempre me molestó de los frames es que intentaban ser demasiado inteligentes. Cuando hacía clic derecho y recargaba, no quería que solo se volviera a cargar el HTML del frame. Entiendo la intención de cachearlo por separado, pero los frames y la caché deberían resolver problemas distintos, y al mezclarlos dejaron ambos a medias. Creo que un include de HTML debería comportarse de la forma más tonta posible. Basta con pegar el texto incluido en la ubicación del include y que el navegador reciba el texto resultante. Si quieres cachear por separado la misma navegación en todas las páginas, se puede agregar un atributo de caché y resolver ese problema de manera independiente. Se podría convencerme de que un include debería hacer más cosas, pero el comportamiento tonto no es un bug, es una función.
Esta propuesta de función se llamaba HTML Imports y se creó como parte del trabajo en Web Components.
Se describía como “HTML Imports are a way to include and reuse HTML documents in other HTML documents”, y el documento del plan está en https://www.w3.org/TR/html-imports/.
Pero esas razones se acercan más a no-razones que en realidad no explican nada. Esta función se ha pedido durante 20 años, y hay todo tipo de implementaciones shim hechas con scripts, motores de backend, etc.; cuesta creer que la demanda sea baja. El rechazo de los vendors tampoco explica por qué fue tan fuerte como para revertir implementaciones que ya existían. Lo de las “implicaciones de seguridad” también es raro, porque ya se puede traer HTML de otro origen con una etiqueta script y hacer
document.write(). Me pregunto por qué está bien que un script hagadocument.write(), pero que una etiqueta HTML haga lo mismo sería un gran problema. Entiendo la preocupación de seguridad de impedir cosas como clonar al vuelo la página principal de Google, pero eso parece resolverse fácilmente con CORS.[1] https://frontendmasters.com/blog/seeking-an-answer-why-cant-...
El HTML debería importarse y mostrarse en una ubicación específica del documento, pero HTML Imports no podía hacer eso sin JavaScript. Para más detalles, ver https://github.com/whatwg/html/issues/2791#issuecomment-3112....
Según recuerdo, después de importar había que instanciar la plantilla con JavaScript, y no era simplemente una sola etiqueta sencilla.
Netscape 4 tenía esta función como inflow layer
https://web.archive.org/web/19970630074729fw_/http://develop...
https://web.archive.org/web/19970630094813fw_/http://develop...
SRCera bastante propenso a crashear, y la función se eliminó poco despuésRecuerdo haber jugado con eso en la beta, pero en la versión final ya había desaparecido
El nombre de esta función es transclusión (transclusion)
https://en.wikipedia.org/wiki/Transclusion
Formaba parte de Project Xanadu y originalmente se consideraba una función importante del hipertexto. En particular, MediaWiki usa la transclusión de forma amplia y, a veces, una wiki se siente como la forma más pura del hipertexto
https://en.wikipedia.org/wiki/Federated_Wiki
Pero no logró despegar realmente
En Xanadu se podía transcluir en otro documento solo un extracto parcial de un documento. Para hacer esto en HTML, hace falta una respuesta sobre CSS. En ciertos casos se puede resolver decidiendo qué propiedades mantener consistentes entre el documento anfitrión, el documento invitado y el invitado incrustado dentro del anfitrión, pero en el caso general no está claro. Si fuera un enfoque simple basado en etiquetas, el documento invitado tendría que estar diseñado para vivir dentro del entorno CSS que el anfitrión le haya puesto. Otra respuesta simple es Shadow DOM, que en general permite que el invitado aplique sus propios estilos sin afectar al resto del documento. Incluso en este caso, creo que el anfitrión podría agregar algunos estilos para ajustar al invitado
Creo que esto era lo que hace mucho intentaba hacer un frameset bien implementado. No me refiero a iframe, sino al frameset de la época de HTML 4
Al menos la expansión automática de tamaño funcionaba bien y el usuario también podía ajustarlo al tamaño que quisiera. Hubo muchas críticas a los frames [1], pero se usaron con éxito en lugares donde eran útiles, como la documentación de la API de Java [2]. Creo que al final desaparecieron porque les faltaba demasiada flexibilidad para los diseñadores. Para páginas de información eran suficientes, pero las barras de desplazamiento toscas y la división limitada de la pantalla no satisfacían las necesidades de los diseñadores. Hoy, un frameset tal cual probablemente no funcionaría bien en móvil, así que ya es demasiado tarde para revivirlo
[1] <https://www.nngroup.com/articles/why-frames-suck-most-of-the...> - Es interesante que mucho de lo que dice ahí ya no aplica, y que todos los problemas señalados en los frames existen en la web actual de formas más desordenadas
[2] <https://www.eeng.dcu.ie/~ee553/ee402notes/html/figures/JavaD...>
Como no permitía deep linking, quienes llegaban por un marcador, por Google o por buscadores anteriores caían en una página sin navegación, y aunque se intentaba esquivarlo con JavaScript, no daba una buena experiencia
Se considera que la función “include” se procesa del lado del servidor, es decir, fuera del navegador web
HTML es del lado del cliente y, en realidad, no es un lenguaje de programación sino una sintaxis de marcado. Como dice el artículo, este problema ya está resuelto. Lo primero que suelen ver los estudiantes de diseño web al aprender PHP es
include, y en la mayoría de los CMSincludese convierte en un partial de plantilla y se explica al comienzo de la documentación. No hay una necesidad particular de hacer posibleincludesolo con HTML. HTML es un formato de presentación y, sin CSS y JS, no hace cosas interesantesDe hecho, HTML ya tiene versiones peores: frames e iframes. La contraparte del lado del cliente de un include del lado del servidor encaja de manera natural con lo que la gente hace con HTML
Probablemente se podría programar con elementos personalizados, y me sorprendería que no hubiera un repositorio similar en GitHub
También hay contenido que ya se carga de forma asíncrona, como imágenes o contenido en la parte inferior de la pantalla. Decir que “HTML no es un lenguaje de programación sino una sintaxis de marcado” se acerca bastante a un flamebait; es un lenguaje declarativo interpretado por cada motor de navegador
Si hablamos de styling, la presentación la maneja CSS
Hay dos opciones. La primera es hacerlo durante el parseo de HTML, es decir, antes de crear el DOM, pero no es deseable porque requeriría una solicitud síncrona al servidor para el include. La segunda es que, después de crear el DOM, un elemento específico aparezca en el DOM, se cargue un fragmento de forma asíncrona y luego se reemplace ese elemento del DOM por el fragmento externo, pero eso inutiliza el mecanismo existente de validación de la estructura del DOM. Sin embargo, en el motor Sciter lo implementaron con la primera estrategia. Como el HTML de Sciter normalmente proviene de recursos locales de la app o del sistema de archivos, el costo de solicitar fragmentos adicionales es despreciable
https://docs.sciter.com/docs/HTML/html-include
Como dijeron otros, HTML include tiene varios problemas
Si
main.htmlincluyechild/include1.html, y dentro dechild/include1.htmlhay un enlacesrc="include2.html", ¿a dónde debería ir el usuario al hacer clic? Si va ainclude2.html, por el nombre parece una página pensada para include, así que le faltará el resto; y si va amain.html, ¿cómo se indica que esta vez debe usarinclude2.htmlen lugar deinclude1.html? A la inversa, también se podría hacer quearticle1.html,article2.htmlyarticle3.htmlincluyan cada unoheader.html,footer.htmlynavi.html, pero entonces, si se quiere cambiar globalmente la estructura de todos los artículos, habría que modificar todos los artículos. Si se quiere agregarcomments.htmla todos los artículos, al final se vuelve a querer generar las páginas con plantillas, y en ese punto ya no se necesita un include en el navegador. También aparecen problemas como que el header necesite conocer el título o el footer necesite conocer los enlaces anterior/siguiente, y se necesita una forma de pasar información entre includes; al final se vuelve a la generación de páginas. Si se analiza, es muy probable que HTML include sea prácticamente inútil para la mayoría de los usosAquí se están mezclando dos casos de uso distintos. Uno es la reutilización de fragmentos y el otro es una isla independiente embebible. Lo segundo ya lo manejan los iframes, así que solo habría que resolver lo primero
include2.htmlpierde el resto se aplica igual a otros includesSi el usuario hace clic en un enlace
src="include.css", todo sería un desastre. Puede estar bien para datos estáticos, imágenes, CSS y contenido HTML estáticoHay un issue abierto relacionado con esto en WHATWG. También se menciona en la sección de comentarios del post
Client side include feature for HTML
https://github.com/whatwg/html/issues/2791
HTML tuvo includes y perdieron popularidad
El término real “include” es una función de XML, y eso es lo que desea el artículo. HTML tenía otro enfoque anterior a XML, que eran los frames. Como los frames hacían mucho más que un include de XML, HTML no obtuvo esa función por separado. Los frames perdieron popularidad por varios problemas, como mal uso, seguridad y accesibilidad
Todavía me gusta usarlo de vez en cuando, pero hace falta una etapa de compilación que lo evalúe antes de pasarlo al usuario o al navegador