让 HTML 网页打印自己的源代码 - HTML的 Quine 程序实现

简介: Quine 程序是指一个能够输出自身代码的计算机程序。在这篇文章中,我们将用HTML代码来实现一个Quine程序。我们把这个任务分成两步,首先让`<head>`标签中的内容显示出来,然后显示元素的标签

Quine 程序是指一个能够输出自身代码的计算机程序。Quine 程序的实现是计算机科学中一个有趣的问题,不同语言中有不同的实现方式,常见的技巧包括代码注入、字符串插值或反射等。实现 Quine 程序可以帮助我们对平常所使用的编程语言产生更深入的理解。

在这篇文章中,我们将用HTML代码来实现一个Quine程序。严格意义上讲,HTML并不是一门编程语言,但我们同样可以让一个HTML网页打印出自己的全部源代码。我们把这个任务分成两步,首先让<head>标签中的内容显示出来,然后让所有的html元素都显示出自己的标签。

1. head 标签中的内容打印

我们首先写一段简单的HTML,其中包括了两个<p>段落和一个<a>标签。

<html>
<head>
  <title>HTML Quine</title>
</head>
<body>
  <p>这个网页显示了自己的源代码</p>
  <p>灵感来源于
    <a href="https://www.youtube.com/watch?v=6avJHaC3C2U">这个讲座</a>
  </p>
</body>
</html>

运行页面效果如图所示:

frame_chrome_mac_dark (32).png

现在我们来思考一下:通常网页中展示的都是<body>标签中的内容,要显示网页的所有源代码意味着<head>标签中的内容也要被展示出来,这要怎么办呢?

大家回想一下浏览器渲染页面的过程,第一步叫做“根据HTML代码构建DOM树”,也就是说其实<head>标签的内容也是在DOM树中的,我们不妨打开浏览器控制台验证一下这一点。

image.png

那为什么<head>标签的内容不会被展示出来呢?我们接着顺着浏览器引擎的渲染过程往下走,接下来它会解析页面的CSS文件,我们这个网页没有任何自定义的CSS,但是浏览器本身是有自带的CSS的,这个叫做 user agent stylesheet,是浏览器给我们的网页提供的一套默认的CSS。不同浏览器的这套样式会有所不同,例如 chrome 就会有一个默认的网页内边距,所以我们才会需要 reset-css 这样的解决方案来磨平这些默认样式的差异。

而我们的 <head> 标签的内容没有被显示出来其实也正是这个 user agent stylesheet 搞的鬼。在控制台中选中 <head> 标签,我们可以通过右侧(或者下方)的 styles 面板来看浏览器最终计算得出的该元素的样式规则。

image.png

可以看到正是user agent stylesheet让我们的head标签display: none,所以才啥也看不见。那如果我们把它改成 display: block 呢?(点击上面的element.style那一栏可以添加自定义的样式,这也是一个 debug 的好方法)

image.png

还是啥也没有!但这是因为<title>也被设置为display: none了。我们再把<title>元素也改为display: block试试。

image.png

真的出现了!那么我们只要把让<head>中的所有元素显示出来的样式代码添加到HTML中就可以完成第一步了。为了方便,我们直接通过通配符来让所有的元素都display: block即可。同时,为了让打印出来的源代码更像代码,我们还设置了一个等宽字体。

<style>
    * {
    
     display: block; font-family: monospace; }
</style>

2. 打印元素标签和属性

现在我们距离成功打印网页的源代码只差了标签文本的显示了。HTML的标签起到了标记文本的作用,并不会作为网页本身的文本呈现,所以要把它们显示出来只能自己手动添加了。我们要做的就是想办法在网页中的每一个元素前后的显示它们的标签文本。emm...在元素的前后添加东西,这不就是beforeafter伪元素吗!以 <p> 标签的显示为例:

p::before {
   
    content: '<p>'; } p::after {
   
    content: '</p>'; }

frame_chrome_mac_dark (37).png
可以看到两个段落的 <p> 标签都显示出来了。同理,我们只需要枚举我们的网页中包含的所有标签就可以把完整的网页源代码打印出来了。

html::before {
   
    content: "<html>"; }
html::after {
   
    content: "</html>"; }

head::before {
   
    content: "<head>"; }
head::after {
   
    content: "</head>"; }

title::before {
   
    content: "<title>"; }
title::after {
   
    content: "<\title>"; }

style::before {
   
    content: "<style>"; }
style::after {
   
    content: "<\/style>"; }

body::before {
   
    content: "<body>"; }
body::after {
   
    content: "</body>"; }

p::before {
   
    content: "<p>"; }
p::after {
   
    content: "</p>"; }

a::before {
   
    content: "<a>" }
a::after {
   
    content: "</a>" }

frame_chrome_mac_dark (33).png

可以看到我们已经把源代码成功显示出来了,但还有几个地方不太符合预期。

首先是<a>标签的href属性没有显示出来,我们可以通过attr函数来获取href属性的内容,再把它拼接到a标签的before文本中。

a::before {
   
    content: "<a href='" attr(href)  "'>"; }

image.png

第二是<style>的内容被挤到了一行里面,没有像我们输入时那样格式化地展示。这是因为HTML解析时会默认忽略源代码中的换行符和空格,我们可以通过white-space: pre-wrap这条规则来让它保留源代码中的空白。

style {
   
    white-space: pre-wrap; }

第三是<body>标签的内容和<head>标签对的不是很齐,还记得我刚刚说过chrome会有一个默认的网页内边距吗,这就是它干的好事!因为正常情况下HTML网页显示的都是<body>标签的内容,所以这个默认的margin就是加在<body>标签身上的,我们把它清除一下就行了。

body {
   
    margin: 0; }

此时的页面效果如图所示:
frame_chrome_mac_dark (35).png

最后还有一个问题是<html>的闭合标签不知所踪,其实是因为它被放到了页面的底部,要滚动一下才能看到。我们可以通过把<html>元素的高度减小来解决这个问题。同时为了让页面更美观一点,我们再给它加上一个16px的内边距。

html {
   
    margin: 16px; height: 1%; }

frame_chrome_mac_dark (36).png

大功告成!我们写的这个HTML网页完完整整地打印出了自己的源代码,并且也保留了原有的代码缩进和换行。最终完整的代码如下:

<html>
<head>
  <title>HTML Quine</title>
  <style>
    * {
    
     display: block; font-family: monospace; }

    html {
    
     margin: 16px; height: 1%; }
    html::before {
    
     content: "<html>"; }
    html::after {
    
     content: "</html>"; }

    head::before {
    
     content: "<head>"; }
    head::after {
    
     content: "</head>"; }

    title::before {
    
     content: "<title>"; }
    title::after {
    
     content: "<\title>"; }

    style {
    
     white-space: pre-wrap; }
    style::before {
    
     content: "<style>"; }
    style::after {
    
     content: "<\/style>"; }

    body {
    
     margin: 0; }
    body::before {
    
     content: "<body>"; }
    body::after {
    
     content: "</body>"; }

    p::before {
    
     content: "<p>"; }
    p::after {
    
     content: "</p>"; }

    a::before {
    
     content: "<a href='" attr(href)  "'>"; }
    a::after {
    
     content: "</a>" }
  </style>
</head>
<body>
  <p>这个网页显示了自己的源代码</p>
  <p>灵感来源于
    <a href="https://www.youtube.com/watch?v=6avJHaC3C2U">这个讲座</a>
  </p>
</body>
</html>

总结

  1. <head>标签的内容没有显示出来是因为浏览器自定义的样式表隐藏了其内容,我们可以自定义样式覆盖浏览器定义的规则,就可以让其显示出来。
  2. 元素标签的显示可以通过伪元素实现,元素属性的内容可以通过attr函数获取并展示。

本文作者wzkMaster,如果对你有帮助的话欢迎点赞收藏~

相关文章
|
9天前
|
存储 移动开发 JavaScript
网页 HTML 自动播放下一首音乐
在 HTML5 中实现自动播放下一首音乐,通过管理音乐列表、操作音频元素和监听事件完成。创建包含多个音乐链接的列表,使用 `&lt;audio&gt;` 元素加载音乐,监听 `ended` 事件,在当前音乐结束时自动播放下一首。示例代码展示了如何使用 JavaScript 实现这一功能,确保无缝切换音乐。
|
4月前
|
存储 移动开发 前端开发
HTML基础知识:构建网页的基石
【10月更文挑战第11天】HTML基础知识:构建网页的基石
296 0
|
27天前
|
存储 JavaScript 算法
(html在线预览cad图纸插件)网页CAD绘制条形码、二维码的教程
本文介绍了如何在mxcad中绘制条形码和二维码。对于条形码,首先根据应用场景选择合适的编码标准(如CODE39、EAN13等),通过编码规则将数据转换为二进制,并利用`McDbHatch`绘制条和空的组合,同时支持自定义实体及属性管理。 对于二维码,因其能存储更多信息且具备更强纠错能力,采用开源库QRCode.js进行编码处理,再通过`McDbHatch`绘制黑白矩阵,同样封装成自定义实体以便管理和扩展。文中还给出了完整的绘制流程与效果展示,包括创建二维码对象、设置参数、调用绘制方法以及最终的效果图。整个过程体现了灵活运用API与第三方库来实现复杂图形绘制的能力。
|
28天前
|
前端开发
“弘五四,耀青春”程序创意获奖作品【html+css】
本作品以“青春筑梦,共创未来”为主题,采用动态龙元素展现青春活力与创新精神。页面设计简洁明快,色彩协调,突显年轻人积极向上的风貌。作品内容包括获奖截图、名字《时代扬新帆》及源代码分享。特别说明:禁止用于商业活动,可用于比赛和作业等开源场景。最后,作者表达了对五四精神的致敬与传承,强调了青春活力和创造力的重要性,并感谢评委和支持者。 **获奖感言摘录:** “获得这个奖项,对我们团队来说,既是认可也是激励。我们将继续努力,不断优化产品,为用户带来更好的体验,为社会贡献更多价值。”
32 2
|
2月前
HTML在线扫雷游戏网页源码
HTML在线扫雷游戏网页源码是一款基于HTML+CSS+JavaScript开发的在线扫雷小游戏单页源码,为用户提供了一个无需安装即可在浏览器中直接玩的扫雷游戏。该游戏的源码不仅包含了完整的游戏逻辑,还具备丰富的界面设计和用户交互功能,使得玩家能够轻松上手并享受扫雷带来的乐趣。
99 22
|
2月前
|
数据采集 前端开发 数据挖掘
利用 html_table 函数轻松获取网页中的表格数据
本文介绍了如何使用 R 语言中的 `html_table` 函数结合代理 IP 技术,轻松提取网页表格数据并规避反爬机制。通过设置代理和请求头,示例代码展示了如何从 58 同城采集租房信息并保存为 CSV 文件。该方法适用于需要频繁采集数据的场景,确保数据采集的高效和稳定性。
107 2
利用 html_table 函数轻松获取网页中的表格数据
|
5月前
|
JavaScript 前端开发 容器
用HTML DOM实现有条件地渲染网页元素(上)
用HTML DOM实现有条件地渲染网页元素(上)
|
5月前
|
存储 JavaScript 前端开发
用HTML DOM实现有条件地渲染网页元素(下)
用HTML DOM实现有条件地渲染网页元素(下)
|
4月前
|
数据安全/隐私保护 C++
【HTML】构建网页的基石
本文介绍了HTML的基本概念和常用标签,包括HTML文件的基本结构、常见标签(如标题、段落、换行、图片、超链接等)、表格与表单的使用方法,以及无语义标签div和span的特性。通过具体示例展示了如何在VS Code中快速生成HTML框架及各标签的应用场景,帮助初学者快速掌握HTML的基础知识。
83 1
【HTML】构建网页的基石
|
5月前
|
Web App开发 前端开发 JavaScript
HTML/CSS/JS学习笔记 Day3(HTML--网页标签 下)
HTML/CSS/JS学习笔记 Day3(HTML--网页标签 下)

热门文章

最新文章