令我非常惊讶的是,HTML 从未有任何方法可以包含其他 HTML 文件。而且,地平线上似乎也没有任何东西可以解决这个问题。我指的是直接的包含,就像获取一段 HTML 并将其直接放到另一个 HTML 中一样。例如,整个互联网的大部分用例,所有页面都包含一个页眉和页脚
...
<body>
<include src="./header.html"></include>
Content
<include src="./footer.html"></include>
</body>
...
顺便说一句,那不是真的。我只是希望它是真的。
人们一直在寻求其他语言来为他们解决这个问题。从某种意义上说,它是 HTML 预处理。早在我们预处理 CSS 之前,我们就一直在使用工具来操作我们的 HTML。我们现在仍在这样做,因为包含的想法在世界上几乎每个网站上都很有用。
使用 PHP
你能改用 PHP 吗?
...
<body>
<?php include "./header.html" ?>
Content
<?php include "./footer.html" ?>
</body>
...
这将在服务器级别执行包含操作,使对它的请求发生在服务器上的文件系统级别,因此它应该比客户端解决方案快得多。
使用 Gulp
什么比服务器端包含更快?如果包含在它甚至在服务器上之前就被预处理了。 Gulp 有各种各样的处理器可以做到这一点。一个是 gulp-file-include。
它看起来像这样
...
<body>
@@include('./header.html')
Content
@@include('./footer.html')
</body>
...
你会像这样处理它
var fileinclude = require('gulp-file-include'),
gulp = require('gulp');
gulp.task('fileinclude', function() {
gulp.src(['index.html'])
.pipe(fileinclude({
prefix: '@@',
basepath: '@file'
}))
.pipe(gulp.dest('./'));
});
看起来这个特定的插件有一些花哨的功能,你可以在其中向包含项传递变量,从而可以创建小型数据驱动的组件。
使用 Grunt
这就是 grunt-bake 插件的作用。您将配置 Grunt 来处理您的 HTML
grunt.initConfig({
bake: {
your_target: {
files: {
"dist/index.html": "app/index.html",
}
}
}
});
然后你的 HTML 可以使用这种特殊的语法进行包含
...
<body>
<!--(bake header.html)-->
Content
<!--(bake footer.html)-->
</body>
...
使用 Handlebars
Handlebars 有部分。
你注册它们
Handlebars.registerPartial('myPartial', '{{name}}')
然后使用它们
{{> myPartial }}
它还有一些花哨的功能,允许评估和传递数据。您仍然需要一个处理器来运行它,可能是类似 gulp-handlebars 的东西。
说到使用花括号的模板语言……Mustache 也有它们。
使用 Pug
Pug 是一种 HTML 预处理器,它具有全新的 HTML 语法,更加简洁。 它有包含功能。
...
body
include ./header.html"
p Content
include ./footer.html"
...
然后你用类似 gulp-pug 的东西运行它。
使用 Nunjucks
我非常喜欢 Nunjucks! Nunjucks 有 包含。你会像这样做到
...
<body>
{% include "./header.html" %}
Content
{% include "./footer.html" %}
</body>
...
如果你把它放在一个名为index.njk
的文件中,你可以用一个简单的 Node 脚本将其处理成 index.html,如下所示
const nunjucks = require("nunjucks");
const fs = require("fs");
fs.writeFile("index.html", nunjucks.render("index.njk"), function(err, data) {
if (err) console.log(err);
console.log("Compiled the Nunjucks, captain.");
});
或者用类似 gulp-nunjucks 的东西处理它。
11ty 内置了 Nunjucks,以及迄今为止提到的许多其他内容。如果你真的在构建一个小网站,这可能对你有帮助。
使用 Ajax
假设你有……
<body>
<header></header>
Content.
<footer></footer>
</body>
您可以从各自的文件中获取页眉和页脚的内容,并将内容转储到其中。
fetch("./header.html")
.then(response => {
return response.text()
})
.then(data => {
document.querySelector("header").innerHTML = data;
});
fetch("./footer.html")
.then(response => {
return response.text()
})
.then(data => {
document.querySelector("footer").innerHTML = data;
});
说到 JavaScript……如果你使用任何 JavaScript 框架构建你的网站,通过组件构建是主要的工作,并且将你想要包含在其他文件中的部分分解出来应该不成问题。某种import Header from "./header.js";
和<Header />
是在 React 领域中的范畴。
使用 iframe
你可以这样做
<body>
<iframe src="./header.html"></iframe>
Content.
<iframe src="./footer.html"></iframe>
</body>
但是这些 iframe 中的内容不共享相同的 DOM,所以有点奇怪,更不用说加载速度慢且难以设置样式(因为 iframe 不知道其内容的高度)。
Scott Jehl 记录了一个很酷的想法:您可以让 iframe 将其自身的内容注入到父页面中,然后删除自身。
<body>
<iframe src="header.html" onload="this.before((this.contentDocument.body||this.contentDocument).children[0]);this.remove()"></iframe>
Content.
<iframe src="footer.html" onload="this.before((this.contentDocument.body||this.contentDocument).children[0]);this.remove()"></iframe>
</body>
Kolya Korruptis 这样写道,如果你的 HTML 文件包含 body 的第一个子元素以外的内容,此适配将包含更多内容
<iframe src="included.html" onload="this.insertAdjacentHTML('afterend', (this.contentDocument.body||this.contentDocument).innerHTML);this.remove()"></iframe>
使用 Jekyll
Jekyll 是一个基于 Ruby 的静态网站生成器,具有 包含。您将包含文件保存在/_includes/
文件夹中,然后
<body>
{% include header.html %}
Content.
{% include footer.html %}
</body>
Jekyll 非常重要,所以我在此处特别指出它,但是有 大量的静态网站生成器,我敢打赌其中任何一个都可以进行包含。
使用 Sergey
好的,我还要指出一个 SSG,因为它很新并且非常专注。 Sergey 具有 Web Components 样式的格式
<body>
<sergey-import src="header" />
Content.
<sergey-import src="footer" />
</body>
您将文件命名为header.html
和footer.html
,并将它们放在/includes/
中,然后当您运行它提供的 npm 脚本时,它将生成一个包含已处理包含项的构建。
使用 Apache SSI
Apache 是一款超级常见的 Web 服务器,可以 进行包含。您需要像这样操作
<body>
<!--#include file="./header.html" -->
Content
<!--#include file="./footer.html" -->
</body>
但是您需要正确的 Apache 配置才能允许这些操作。我尽力尝试创建一个可用的演示,但没有太多运气。
我尝试在 Apache 服务器上的文件夹中使用.htaccess
,并启用我认为正确的内容
Options +Includes
AddType text/html .html
AddOutputFilter INCLUDES .html
我相信有一种方法可以使其正常工作,如果您确实做到了,那么它无需任何其他依赖项就非常棒。
使用 CodeKit
仅限 Mac,但 CodeKit 有一个它处理的名为 Kit 的特殊语言,其中 90% 的重点是 HTML 包含。它使用特殊的 HTML 注释
...
<body>
<!-- @import "./header.html" -->
Content
<!-- @import "./footer.html" -->
</body>
...
使用 Dreamweaver
我的天哪
有很多方法,不是吗?
就像我在开头说的,我非常惊讶 HTML 本身没有直接解决这个问题。并不是说我认为对于性能来说,让<include>
语句在我们的代码中触发网络请求是一个好主意,但它似乎与平台一致。直接使用 ES6 导入而不进行打包并不总是好主意,但我们有它们。在 CSS 中@import
CSS 并不总是好主意,但我们有它。如果平台有本机语法,也许其他工具会以此为基础,就像 JavaScript 打包器支持 ES6 导入格式一样。
Webpack HTML 插件怎么样?我用它在我的作品集中,考虑到变量和包含,它做得非常出色!
笑一笑,但 Dreamweaver 模板是我最怀念的关于 2001 年左右 Web 开发的东西。简单易用,灵活,所见即所得的预览,没有脆弱的依赖项或奇怪的构建错误。
为了完整起见,我之前使用 jQuery 做过这个。(我确定它算作“使用 AJAX”,但仍然。)
哇,Dreamweaver 上榜了,但没有 SHTML,太可惜了。
如果你希望它感觉像原生,你也可以使用 pHTML。
https://github.com/phtmlorg/phtml-include
Apache SSI 不需要 HTML 文件使用 .shtml 扩展名吗?
默认扩展名是 .shtml,但如果你更喜欢坚持使用 .html,可以将此行添加到你的 .htaccess 文件中
AddHandler server-parsed .html
SSI:服务器端包含
服务器端包含 (SSI) 是基于 PERL 语言的命令,允许从服务器收集信息。PERL 和 CGI 从互联网诞生之初就存在,所有这些其他高级语言都基于 PERL 的功能。
其概念是使用服务器来收集和发布信息。这样你就不用处理浏览器版本问题了。被包含的内容在到达浏览器之前就被包含进来了,所以版本永远不会起作用。
大多数 UNIX 服务器都设置为运行 SSI。WindowsNT 基于服务器上的那些可能不得不使用 ASP 来获得很多这些效果,但在决定你无法运行这些命令之前先检查一下。你也许可以。
更多信息请查看
https://www.htmlgoodies.com/beyond/webmaster/article.php/3473341/SSI-The-Include-Command.htm
SSI 很长一段时间都是我的首选。我把它用在 Apache、IIS 和 Nginx 上。不过,你确实需要控制服务器才能保证配置。后来在 Grunt 时代,我使用了 Bake 和 Nunjuks。现在都是 React。让你想知道如果你的 include 标签从一开始就存在,React 是否会成为一件事……
NHTML 导入原本应该成为解决此问题的原始方法。导入是 Web Components 提案的一部分,但浏览器没有实现标准。
https://www.html5rocks.com/tutorials/webcomponents/imports/
实际上,你发布的第一个示例几乎是真实的。我在一个使用 Parcel 作为打包器的项目中使用了完全相同的语法。设置起来非常简单,你只需执行
parcel build index.html
即可。你可以使用
include virtual
而不是include file
来使服务器端包含工作。这是我关于此的文章
https://www.chromestatus.com/feature/5144752345317376 它实际上存在,但由于从未获得完全支持,因此将在 6 月份在 Chrome 中被删除。干杯。
HTML 导入非常酷,我知道它让很多人感到难过,因为它们基本上已经死了。
但同样,我 99% 确定它们从未打算像include那样将 HTML 的一部分简单地添加到另一个 HTML 文档中。
如果做电子邮件,请使用 MJML。https://mjml.io/documentation/#mj-include
导入没有得到 Mozilla 的完全支持,因为规范存在问题。
其中一个最大的问题是,你仍然需要编写 Javascript 才能使其工作——并且当你使用 Javascript 时,你也可以为自己的导入组件提供 polyfill。考虑到使用 Javascript 进行导入非常容易,并且考虑到社区对“最佳”方法存在分歧,Mozilla 认为最好采用渐进式 Web 方法,等待并观察社区如何发展。
我认为拒绝它们绝对是正确的决定。克里斯谈论的是更简单、更透明的东西,可以在不深入 Web Components 的情况下使用。
如果你正在运行像 varnish 这样的缓存服务器,那么你可以使用 esi。使用 esi,你不仅可以将你的网页构建为组件,而且组件可以位于不同的服务器上。
哇,很高兴看到有这么多方法可以包含文件……特别是带有自毁功能的 iframe 选项。
听说过框架、框架集吗?
你错过了“使用 Web Components”:https://www.github.com/gustafnk/h-include
还有
https://github.com/github/include-fragment-element
是的,有很多方法可以在服务器上预处理它。但不幸的是,HTML 标准中没有将此集成到语言本身的方法。这才是真正的问题。当然,你可以在服务器框架中做到这一点,当然,你也可以使用 AJAX 来做到这一点,当然,你也可以通过 Apache 的 hack 来做到这一点——但真正的东西仍然缺乏。你没有 HTML 语言内部的原生 HTML 导入。无法将两个页面组合成一个。这很遗憾。
我前几天想到了这一点,以及它在前端框架的组件驱动世界中有多重要。它将有助于可重用性和模块化,并且都是原生的。那会有多有趣?
不错。可能值得补充一点,PHP 选项也可以用作类似于 Grunt/Gulp 等的客户端技术。
据我所知,HTML 导入应该能够完成这项工作,并且它们实际上正在走向废弃的道路……
我非常确定 Jekyll 的
include
魔法是Liquid的功劳,所以如果你只需要这个功能,就不需要整个生成器。另一种很酷的方法是使用 Web Components。
定义一个自定义元素,例如
<my-header>
编写模板代码并包含 JavaScript。
我真的很喜欢它们
哇,很酷!
过去几年我一直在我的 NPM 脚本中使用 file-include,感觉非常不错,但最近我开始喜欢使用 Handlebars 和 Panini,就像 Foundation 在其高级构建选项中使用的那样。
工作组或供应商之间是否有关于为什么没有原生解决方案的讨论?
对于 Codekit Kit 语言包含,Prepros 支持 Mac 和 Windows 上的此功能。
使用 Gulp 或 Grunt 包含 HTML 的另一种方法是使用 processhtml 插件。语法使用 HTML 注释
它还具有根据环境包含不同文件的优势。例如,您可能希望在生产环境中使用最小化的 HTML。
仅供参考,要使 PHP include 选项正常工作,您需要告诉您的 Web 服务器将 .html 文件视为 PHP 文件进行处理。如何实现这一点在很大程度上取决于您的服务器设置,但无论如何,这都会对性能产生不利影响,因为以前您的服务器只是获取并返回文本文档,现在它必须生成一个 PHP 线程并将 HTML 视为 PHP 代码进行处理。即使对于像这样的简单任务,它也必然会消耗每个页面的更多 CPU/内存资源——即使您的页面根本不包含任何 PHP,它仍然会被 PHP 解析。
如果您使用的是 Apache,那么对于像这样的简单包含,SSI 是一个更好的选择。不确定您的问题是什么(尽管使用 .htaccess 仅在底层 Apache 配置允许的情况下才能工作),但我过去非常成功地使用过它。它经过高度优化,因此(根据我的经验)对性能的影响可以忽略不计。
喜欢这篇文章 Chris。这有点烦人,它可能会让我们的生活更轻松,可能 CMS 的使用量会大幅下降,我记得我用过 Drupal 或 WordPress 几十次,而不是仅仅使用 HTML,因为我当时处于两者之间,并不完全需要整个森林里的香蕉,但仍然缺少 HTML 提供的功能。此外,对于这样一个微小的项目来说,框架有点过头了……希望有一天……
干杯!
我将此用于页面顶部的简单菜单
适用于简单的页面。
您好 Chris,感谢您所有精彩的文章,我从中学到了很多东西!
您可能已经知道,可以使用您在示例顶部描述的语法:
<include src="path_to/partial_file.html></include>
使用 posthtml Include 插件。PostHTML 怎么样? https://github.com/posthtml/posthtml-include
我不好意思承认,我的作品集网站(我最初在 2002 年左右开发的,从那以后几乎没有更新过)使用了/正在使用 shtml。 https://www.yourhtmlsource.com/sitemanagement/includes.html
对我来说,设置和使用它就像您提到的用于标题和页脚一样非常容易。
使用 PWA 缓存标题/页脚。
您如何突出显示当前“选中”的顶级菜单?解析标题以获取当前 URL 并添加一个类?最好能看到它内置在一个 PWA 解决方案中。
我之前用过另一种方法。
首先 - 将文件保存为 .inc 扩展名。
其次 - 转到 Web 服务器并创建或更新对 .Inc 扩展名的支持,在本例中渲染引擎为 html。这也可以使用 ht.access 或 web.config 文件来完成。
请使用 npm 脚本!!
您还可以使用像 Smarty 这样的模板引擎。我认识的一些网店使用这种方法。
https://smarty.php.ac.cn/docs/en/language.function.include.tpl
是否有理由相信 HTML include 的性能会优于其他方法?我不确定为什么有人需要为静态 HTML 使用它。
在 ASP 时代,我们使用 SSI(服务器端包含)
SSI 发生了什么?
我们可以使用 CSS 吗?
p:first-child{
content:”在此处添加文本…”;
}
Twig!比 Handlebars/Mustache 更强大,但仍然非常易于使用(非常相似的语法)。
要在 Apache 上运行 SSI,您需要在 .htaccess 配置文件中使用以下内容
Options +Includes
AddHandler server-parsed .shtml
AddType text/html .shtml
AddOutputFilter INCLUDES .shtml
如果有人想解析常规的 .html 文件,最好使用 XBitHack(除非您在 Windows 上运行 Apache,当然)
XBitHack on
…以及
chmod +x somepage.html
….对于您要解析的文件。请记住:“此指令仅影响与 MIME 类型 text/html 关联的文件。”确保您的 Apache 安装实际安装并启用了 mod_include,以及 mod_expires 以避免在使用某些指令时出现 SSI 问题。
用不到 1kb 的 JavaScript 将包含功能引入 HTML
https://github.com/Paul-Browne/HTMLInclude
如果您想要一个原生替代方案,请参阅此讨论:https://github.com/whatwg/html/issues/2791
IIS 也能执行 SSI。多年来我一直在 Apache 和 IIS 上使用 SSI。IIS 中的实现更灵活:您可以使用相对路径访问文件树中较高级别的文件(../../../otherdirectory/file.shtm),而 Apache 需要为此使用绝对路径(/otherdirectory/file.shtml)
哦,天哪!非常感谢,我终于能够静态包含 HTML 片段了。Gulp 是我最喜欢的选项,并且运行完美。
非常喜欢 CodeKit 的
.kit
语言。我通过 Gulp 使用它…gulp-kit
。强烈推荐它用于简单的静态网站。过去也有一种叫做 shtml 的东西可以做到这一点。
完美!我设法使用您创建的 .htaccess 代码在 Apache 上立即使用 html include 运行它。我目前正在开发一个扁平网站,这非常有效!
document.write 对我来说很有效。没有库、框架或服务器端的东西。
你好
看来最初的问题还没有得到解答:是否有简单的方法在 HTML 文件中包含另一个 HTML 文件?我已经手写 HTML 代码 25 年了,所以我所做的事情非常基本,但足以满足我的需求和用户的需求。叫我老古董也行。;-)
但有人会认为,正如本主题开头提到的,这应该是 HTML 0.01 的一部分。
类似于“img src picture.gif”但用于 HTML 的东西。;-)
其次是提供具体的示例,而不是没有上下文的代码片段,因为人们假设每个人都知道暗示的?!#% 是什么。
我希望有类似“html src file.html”的功能,它基本上继承调用 HTML 文档的参数,从而像文本插入到该位置一样插入。本质上是从多个网页调用文本块,这样就不需要在主 HTML 文档中单独复制和维护它们。
谢谢,
—— sam