重读HTML

初识HTML

来看看维基百科的解释。
HTML(超文本标记语言——HyperText Markup Language)是构成 Web 世界的一砖一瓦。它定义了网页内容的含义和结构。除 HTML 以外的其它技术则通常用来描述一个网页的表现与展示效果(如 CSS),或功能与行为(如 JavaScript)。

“超文本”(hypertext)是指连接单个网站内或多个网站间的网页的链接。链接是网络的一个基本方面。只要将内容上传到互联网,并将其与他人创建的页面相链接,你就成为了万维网的积极参与者。

HTML 使用“标记”(markup)来注明文本、图片和其他内容,以便于在 Web 浏览器中显示。HTML 标记包含一些特殊“元素”如 <head>,<title>,<body>,<header>,<footer>,<article>,<section>,<p>,<div>,<span>,<img>,<aside>,<audio>,<canvas>,<datalist>,<details>,<embed>,<nav>,<output>,<progress>,<video>等等等等。

HTML 元素大体分14类

  1. 主根元素 html
  2. 文档元数据 meta;title;head...;
  3. 分区根元素 body
  4. 内容分区 main;section;address...
  5. 文本内容
  6. 内联文本语义
  7. 图片和多媒体
  8. 内嵌内容
  9. 脚本
  10. 编辑标识
  11. 表格内容
  12. 表单
  13. 交互元素
  14. Web 组件
    参考MDN文档

关于 meta 标签的一些用法

<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<!-- 默认使用最新浏览器 -->
<meta http-equiv="Cache-Control" content="no-siteapp">
<!-- 不被网页(加速)转码 -->
<meta name="robots" content="index,follow">
<!-- 搜索引擎抓取 -->
<meta name="renderer" content="webkit">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui">
<meta name="apple-mobile-web-app-capable" content="yes">
<!-- 删除苹果默认的工具栏和菜单栏 -->
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<!-- 设置苹果工具栏颜色 -->

<!-- 忽略浏览器自动识别数字为电话号码 -->
<meta name="format-detection" content="telephone=no">
<meta name="format-detection" content="date=no">
<meta name="format-detection" content="address=no">
<!-- 忽略浏览器自动识别邮箱账号 -->
<meta name="format-detection" content="email=no">
关闭iOS上的内容识别
<meta name="renderer" content="webkit|ie-comp|ie-stand">
对于多核浏览器,控制浏览器以哪种类型内核来显示,好像是 360 浏览器首先主导的


怎么使用

1.HTML 标签里的元素名不区分大小写

例如,<title>标签可以写成 <Title><TITLE>或以任何其他方式。以下的几种写法都是可以的。

	<div>我是div</div>
    <DIV>我是DIV</DIV>
    <div>我是DIV</DIV>
2. 闭合标签

大家都知道 html 元素都是使用start tag 开始,end tag结束。但是。。。

  1. 只有start tag
<body>
    <div>1-我是div
    <Div>2-我是DIV
</body>

在这里插入图片描述
会自动生成一个闭合end tag。同时,如果后继还有一个没有end tag的元素,会产生一个树状的结构依次布局。如上图。
第二种情况:

<body>
    <div>我是 开合标签 DIV</DIV>
    <div>1-我是div
    <Div>2-我是DIV
    <div>我是 开合标签 DIV</DIV>
</body>

在这里插入图片描述
会依次 生成一个子标签。
2. 只有end tag

<body>
    我是文字
    <div>我是div</div>
    <div>我是DIV</DIV>
    我是DIV-1</DIV>
    我是DIV-2</div>
    <DIV>我是DIV</DIV>
</body>

在这里插入图片描述
把只有end tag当作普通的文字处理。

3.非闭合标签

以 hr 为例:

<body>
    </hr>
    <hr>qq</hr>
    </hr>
    <hr>
    <hr />
</body>

在这里插入图片描述
<hr>、<hr /><hr>qq<hr />;均有效果,注意 <hr>qq<hr />会在文字上产生一个横线。而</hr>没有效果。

语义化标签

一个整体结构的语义类标签

<body>
  <header>
    <nav>
      ……
    </nav>
  </header>
  <aside>
    <nav>
      ……
    </nav>
  </aside>
  <section>……</section>
  <section>……</section>
  <section>……</section>
  <footer>
    <address>……</address>
  </footer>
</body>

优点是:
1)语义类标签对开发者更为友好,使用语义类标签增强了可读性,即便是在没有CSS的时候,开发者也能够清晰地看出网页的结构,也更为便于团队的开发和维护。
2)除了对人类友好之外,语义类标签也十分适宜机器阅读。它的文字表现力丰富,更适合搜索引擎检索(SEO),也可以让搜索引擎爬虫更好地获取到更多有效信息,有效提升网页的搜索量,并且语义类还可以支持读屏软件,根据文章可以自动生成目录等等
3)自然语境的补充
4)结构化文档的分级

语法

一个问题衍生出来:HTML5 为什么只需要写 <!DOCTYPE HTML>

HTML5 不基于 SGML,因此不需要对DTD进行引用,但是需要doctype来规范浏览器的行为(让浏览器按照它们应该的方式来运行);

而HTML4.01基于SGML,所以需要对DTD进行引用,才能告知浏览器文档所使用的文档类型。

基本语法

首先,HTML作为SGML的子集,它遵循SGML的基本语法:包括标签、转义等。
SGML还规定了一些特殊的节点类型,在我们之前的DOM课程中已经讲过几种节点类型,它们都有与之对应的HTML语法,我们这里复习一下:

标签语法

标签语法产生元素,我们从语法的角度讲,就用“标签”这个术语,我们从运行时的角度讲,就用“元素”这个术语。
HTML中,用于描述一个元素的标签分为开始标签、结束标签和自闭合标签。开始标签和自闭合标签中,又可以有属性。

  • 开始标签:<tagname>

    • 带属性的开始标签: <tagname attributename="attributevalue">
  • 结束标签:</tagname>

  • 自闭合标签:<tagname />

HTML中开始标签的标签名称只能使用英文字母。
这里需要重点讲一讲属性语法,属性可以使用单引号、双引号或者完全不用引号,这三种情况下,需要转义的部分都不太一样。
属性中可以使用文本实体(后文会介绍)来做转义,属性中,一定需要转义的有下面几种。

  • 无引号属性:<tab> <LF> <FF> <SPACE> &五种字符。
  • 单引号属性:' &两种字符。
  • 双引号属性:\" &两种字符。

一般来说,灵活运用属性的形式,是不太用到文本实体转义的。

文本语法

在HTML中,规定了两种文本语法,一种是普通的文本节点,另一种是CDATA文本节点。
文本节点看似是普通的文本,但是,其中有两种字符是必须做转义的:<&
如果我们从某处拷贝了一段文本,里面包含了大量的 <&,那么我们就有麻烦了,这时候,就轮到我们的CDATA节点出场了。
CDATA也是一种文本,它存在的意义是语法上的意义:在CDATA节点内,不需要考虑多数的转义情况。
CDATA内,只有字符组合]]>需要处理,这里不能使用转义,只能拆成两个CDATA节点。

注释语法

HTML注释语法以<!--开头,以-->结尾,注释的内容非常自由,除了-->都没有问题。
如果注释的内容一定要出现 -->,我们可以拆成多个注释节点。

ProcessingInstruction语法(处理信息)

ProcessingInstruction多数情况下,是给机器看的。HTML中规定了可以有ProcessingInstruction,但是并没有规定它的具体内容,所以可以把它视为一种保留的扩展机制。对浏览器而言,ProcessingInstruction 的作用类似于注释。
ProcessingInstruction 包含两个部分,紧挨着第一个问号后,空格前的部分被称为“目标”,这个目标一般表示处理 ProcessingInstruction 的程序名。
剩余部分是它的文本信息,没有任何格式上的约定,完全由文档编写者和处理程序的编写者约定。

DTD(文档类型定义)

现在我们来讲一下DTD,DTD的全称是Document Type Defination,也就是文档类型定义。SGML用DTD来定义每一种文档类型,HTML属于SGML,在HTML5出现之前,HTML都是使用符合SGML规定的DTD。
如果你是一个上个时代走过来的前端,一定还记得HTML4.01有三种DTD。分别是严格模式、过渡模式和frameset模式。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

严格模式的DTD规定了HTML4.01中需要的标签。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

过渡模式的DTD除了html4.01,还包含了一些被贬斥的标签,这些标签已经不再推荐使用了,但是过渡模式中仍保留了它们。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">

frameset结构的网页如今已经很少见到了,它使用frameset标签把几个网页组合到一起。
众所周知,HTML中允许一些标签不闭合的用法,实际上这些都是符合SGML规定的,并且在DTD中规定好了的。但是,一些程序员喜欢严格遵守XML语法,保证标签闭合性,所以,HTML4.01又规定了XHTML语法,同样有三个版本:
版本一

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

版本二

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

版本三

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">

其实你看看就知道,这些复杂的DTD写法并没有什么实际作用(浏览器根本不会用SGML引擎解析它们),因此,到了HTML5,干脆放弃了SGML子集这项坚持,规定了一个简单的,大家都能记住的DTD:

<!DOCTYPE html>

但是,HTML5仍然保留了HTML语法和XHTML语法。

文本实体

不知道你注意到没有,HTML4.01的DTD里包含了一个长得很像是URL的东西,其实它是真的可以访问的——但是W3C警告说,禁止任何浏览器在解析网页的时候访问这个URL,不然W3C的服务器会被压垮。我相信很多好奇的前端工程师都把它下载下来打开过。
这是符合SGML规范的DTD,我们前面讲过,SGML的规范十分复杂,所以这里我并不打算讲SGML(其实我也不会),但是这不妨碍我们了解一下DTD的内容。这个DTD规定了HTML包含了哪些标签、属性和文本实体。其中文本实体分布在三个文件中:HTMLsymbol.ent HTMLspecial.ent和HTMLlat1.ent。
所谓文本实体定义就是类似以下的代码:

&lt;
&nbsp;
&gt;
&amp;

每一个文本实体由&开头,由;结束,这属于基本语法的规定,文本实体可以用#后跟一个十进制数字,表示字符Unicode值。除此之外这两个符号之间的内容,则由DTD决定。
我这里数了一下,HTML4.01的DTD中,共规定了255个文本实体,在如下位置:
https://www.w3school.com.cn/tags/html_ref_symbols.html

浏览器是如何解析请求回来的HTML代码,DOM树又是如何构建的?

在这里插入图片描述

解析代码

1.词(token)是如何被拆分的
首先我们来看看一个非常标准的标签,会被如何拆分:
<p class="a">text text text</p>
如果我们从最小有意义单元的定义来拆分,第一个词(token)是什么呢?显然,作为一个词(token),整个p标签肯定是过大了(它甚至可以嵌套)。
那么,只用p标签的开头是不是合适吗?我们考虑到起始标签也是会包含属性的,最小的意义单元其实是“<p” ,所以“ <p” 就是我们的第一个词(token)。
我们继续拆分,可以把这段代码依次拆成词(token):
• <p“标签开始”的开始;
• class=“a” 属性;
• > “标签开始”的结束;
• text text text 文本;
</p>标签结束。
2.状态机
在这里插入图片描述
举个例子:
区分 “< ”和 “非<”:
• 如果获得的是一个非<字符,那么可以认为进入了一个文本节点;
• 如果获得的是一个<字符,那么进入一个标签状态。
当然了,我们这里的分析比较粗略,真正完整的HTML词法状态机,比我们描述的要复杂的多。
不过当我们在标签状态时,则会面临着一些可能性。
• 比如下一个字符是“ ! ” ,那么很可能是进入了注释节点或者CDATA节点。
• 如果下一个字符是 “/ ”,那么可以确定进入了一个结束标签。
• 如果下一个字符是字母,那么可以确定进入了一个开始标签。
• 如果我们要完整处理各种HTML标准中定义的东西,那么还要考虑“ ? ”“% ”等内容。

构建DOM树

在这里插入图片描述
前面我们的词(token)中,以下两个是需要成对匹配的:
• tag start
• tag end
一个简单的构建DOM树过程:
• 栈顶元素就是当前节点;
• 遇到属性,就添加到当前节点;
• 遇到文本节点,如果当前节点是文本节点,则跟文本节点合并,否则入栈成为当前节点的子节点;
• 遇到注释节点,作为当前节点的子节点;
• 遇到tag start就入栈一个节点,当前节点就是这个节点的父节点;
• 遇到tag end就出栈一个节点(还可以检查是否匹配)。
执行顺序 思路,有点像leetcode的有效的括号。下面有个简单的视频做演示。

https://www.yuque.com/presbyter/ysvc23/bpo4b2#97b884e1

栈构造 DOM 树的全过程

参考

  1. 现代浏览器工作原理
  2. 重学前端(winter):极客时间
  3. 浏览器工作原理与实践 (李兵):极客时间
  4. MDN
  5. Web Fundamentals
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值