戏说HTML5

戏说HTML5

2015/12/23 · HTML5 ·
HTML5

原文出处:
木的树的博客   

如果有非技术人员问你,HTML5是什么,你会怎么回答?

 

新的HTML规范。。。

给浏览器提供了牛逼能力,干以前不能干的事。。。(确切地说应该是给浏览器规定了许多新的接口标准,要求浏览器实现牛逼的功能。。。
这里感谢红枫一叶)

给浏览器暴露了许多新的接口。。。

加了很多新的效果。。。

问的人其实并不明白他想问的真正问题,回答的人貌似明白,但又好像少了点什么。牛逼的能力、新的接口、炫酷的效果,首先回答的人自己就是晕晕乎乎。什么是HTML、什么是CSS、什么是DOM、什么是JavaScript,大部分的前端开发每天都在用这些,但很少会有人去思考一下他们之间的关系。

首先,HTML的全称是超文本标记语言,是一种标记形式的计算机语言。将这种标记语言给专门的解析器,就能够解析出一定的界面效果。浏览器就是专门解析这种标记语言的解析器。我们说他最终的效果是在屏幕上展示出特定的界面,那么浏览器肯定要把一个个的标记转换成内部的一种数据结构,这种数据结构便是DOM元素。比如,一个<a>标签在浏览器内部的世界中就是一个HTMLAnchorElement类型的一个实例。

一个HTML文件就好比用超文本标记语言写的一篇文章,文章通常是有结构的,在浏览器眼里它就是DOM。DOM描述了一系列层次化的节点树。(但这时候的DOM还是存在于浏览器内部是C++语言编写的)

 

随着历史的发展,当人们不在满足简单的显示文本,对于某些文本需要特殊强调或者给添加特殊格式的需求,慢慢的冒了出来。面对人们需要控制显示效果的需求,最先想到的也最简单的方式就是加标记。加一些样式控制的标记。这时候就出现了像<font>、<center>这种样式控制的标记。但是这样一来,所有的标记就会分为两大类:一种是说我是什么,一种是说我怎么显示。这还不是大问题,标记简单,但是浏览器要解析标记可就不那么简单了。想一想,这样干的话DOM也就要分成两大类,一类属于描述元素的DOM节点,一类属于描述显示效果的DOM节点。一个DOM节点可能代表一个元素,也可能是代表一种显示效果。怎么看都觉得别扭呀。

最后人们决定废弃样式标签,给元素标签添加一个style特性,style特性控制元素的样式(最初的样式声明语法肯定很简单)。原来的样式标签的特性,现在变成了样式特性的语法,样式标记变成了样式特性。这样逻辑上就清晰多了。那么问题来了:

  • 一篇文章如果修辞过多,必然会引起读者的反感。如果把元素和显示效果都放在一个文件中,必然不利于阅读。
  • 如果有10个元素都需要一个效果,是不是要把一个style重复写十遍呢
  • 父元素的设置效果对子元素有没有影响,让不让拼爹
  • 。。。。。。。。。

类似的问题肯定有很多,所以出来了CSS,层叠样式表,带来了css规则、css选择器、css声明、css属性等,这样以来就解决了以上痛点。标记语言这层解决了,但是浏览器就不能干坐着玩耍了,必然得提供支持。所以浏览器来解析一个静态html文件时,遍历整个html文档生成DOM树,当所有样式资源加载完毕后,浏览器开始构建呈现树。呈现树就是根据一系列css声明,经历了层叠之后,来确定一个个个DOM元素应该怎么绘制。这时候其实页面上还没有显示任何界面,渲染树也是浏览器内存里面的一种数据结构。渲染树完成之后,开始进行布局,这就好比已经知道一个矩形的宽高,现在要在画布量一量该画在哪,具体占多大地方。这个过程完了之后就是绘制的过程,然后我们便有了我们看到的显示界面了。

给标记加点效果的问题解决了,历史的车轮又开始前进了。慢慢的人们不再满足简单的显示效果,人们希望来点交互。那个时候写HTML的大部分并不懂软件开发,开玩笑嘛,我一写活动页的你让我用C++?C++干这事的确是高射炮打蚊子——大材小用。那正规军不屑干的事就交给游击队吧,这时候网景公司开发出了JavaScript语言,那时候的JavaScript根本没有现在这么火,一土鳖脚本语言,哪像现在这么牛逼哄哄统一宇宙。

JavaScript本是运行在浏览器的语言,HTML文本是静态的,不可能让JavaScript修改静态文件,但可以跟浏览器内部打交道。可是这个时候的DOM并不是今天的DOM,他们是C++对象,要么把JavaScript转换成C++指令操作这些C++对象,要么把这些C++对象包装成JavaScript原生对象。历史选择了后者,这时候也就标志着现代DOM的正式诞生。不过历史有时候会出现倒退,历史上总会出现几个奇葩,比如IE,IE奇葩他全家,包括Edge!

马克思是个江湖骗子,但恩格斯是个好同志。自然辩证法与历史唯物主义是好东西。从历史的角度我们可以看到。CSS、DOM、JavaScript的出现于发展最终的源头都在HTML,超文本标记语言。人们对web的需求最终都汇集在HTML上。所以只要历史产生新的需求,最终的变化都首先发生在HTML规范上。

当交互性不能在满足人们需求时,web迎来了新的需求:webapp。要迎合新的需求,首先要改变的就是HTML规范,这个时候已有的HTML4.0,已经无法满足人们日益增长的需求,所以HTML5迎着历史的需求,经过八年的艰苦努力,终于在2014年正式定稿!HTML5肯定是要加入新标签,然对于传统HTML而言,HTML5算是一个叛逆。所有之前的版本对于JavaScript接口的描述都不过三言两语,主要篇幅都用于定义标记,与JavaScript相关内容一概交由DOM规范去定义。而HTML5规范,则围绕着如何使用新增标记定义了大量JavaScript
API(所以其中有一些API是与DOM重叠,定义了浏览器应该支持的DOM扩展,由此可以看到HTML5也必定不是HTML的最终版)。

 

后记——
本文只是一个旁观者以线性的方式来翻阅HTML的发展史,但历史更像是晴空上突然的晴天霹雳,一声过后,有人哀嚎遍野,有人高歌入云。以此纪念曾红极一时的Silverlight、Flex,以此纪念广大一线开发者活到老学到老的不懈精神、曾经耗费的精力、曾经逝去的青春。

1 赞 1 收藏
评论

图片 1

转载自web fundamental

构建对象模型

浏览器渲染页面前需要先构建 DOM 和 CSSOM 树。因此,我们需要确保尽快将
HTML 和 CSS 都提供给浏览器。

  • 字节 → 字符 → 标记 → 节点 → 对象模型。
  • HTML 标记转换成文档对象模型 (DOM);CSS 标记转换成 CSS 对象模型
    (CSSOM)。DOM 和 CSSOM 是独立的数据结构。
  • Chrome DevTools Timeline可以捕获和检查 DOM 和 CSSOM
    的构建和处理开销。

文档对象模型 (DOM)

<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link href="style.css" rel="stylesheet">
    <title>Critical Path</title>
  </head>
  <body>
    <p>Hello web performance students!</p>
    <div><img src="awesome-photo.jpg"></div>
  </body>
</html>

一个包含一些文本和一幅图片的普通 HTML 页面,浏览器如何处理此页面?

HTML解析器输出的树是由DOM元素和属性节点组成的,它是HTML文档的对象化描述,也是HTML元素与外界(如Javascript)的接口。DOM与标签有着几乎一一对应的关系。

 图片 2 

  1. 转换: 浏览器从磁盘或网络读取 HTML
    的原始字节,并根据文件的指定编码(如 UTF-8)将它们转换成各个字符。
  2. Tokenizing: 浏览器将字符串转换成 W3C HTML5
    标准规定的各种tokens,例如,“<html>”、“<body>”,以及其他尖括号内的字符串。每个token都具有特殊含义和一组规则。
  3. 词法分析: 发出的标记转换成定义其属性和规则的“对象”。
  4. DOM 构建: 最后,由于 HTML
    标记定义不同标记之间的关系(一些标记包含在其他标记内),创建的对象链接在一个树数据结构内,此结构也会捕获原始标记中定义的父项-子项关系:HTML 对象是 body 对象的父项,bodyparagraph对象的父项,依此类推。

整个流程最终输出是页面的文档对象模型
(DOM),浏览器对页面进行的所有进一步处理都会用到它。

浏览器每次处理 HTML
标记时,都会完成以上所有步骤:将字节转换成字符,确定tokens,将tokens转换成节点,然后构建
DOM 树。这整个流程可能需要一些时间才能完成,有大量 HTML
需要处理时更是如此。

 图片 3

如果您打开 Chrome DevTools
并在页面加载时记录时间线,就可以看到执行该步骤实际花费的时间。在上例中,将一堆
HTML 字节转换成 DOM 树大约需要 5
毫秒。对于较大的页面,这一过程需要的时间可能会显著增加。创建流畅动画时,如果浏览器需要处理大量
HTML,这很容易成为瓶颈。

DOM
树捕获文档标记的属性和关系,但并未告诉我们元素在渲染后呈现的外观。那是
CSSOM 的责任。

CSS 对象模型 (CSSOM)

在浏览器构建这个简单页面的 DOM 过程中,在文档的 head 中遇到了一个 link
标记,该标记引用一个外部 CSS
样式表:style.css。由于预见到需要利用该资源来渲染页面,它会立即发出对该资源的请求,并返回以下内容:

body { font-size: 16px }
p { font-weight: bold }
span { color: red }
p span { display: none }
img { float: right }

我们本可以直接在 HTML 标记内声明样式(内联),但让 CSS 独立于 HTML
有利于我们将内容和设计作为独立关注点进行处理:设计人员负责处理
CSS,开发者侧重于 HTML,等等。

与处理 HTML 时一样,我们需要将收到的 CSS
规则转换成某种浏览器能够理解和处理的东西。因此,我们会重复 HTML
过程,不过是为 CSS 而不是 HTML:

 图片 4

CSS 字节转换成字符,接着转换成tokens和节点,最后链接到一个称为“CSS
对象模型”(CSSOM) 的树结构:

 图片 5

CSSOM
为何具有树结构?为页面上的任何节点对象计算最后一组样式时,浏览器都会先从适用于该节点的最通用规则开始(例如,如果该节点是
body 元素的子元素,则应用所有 body
样式),然后通过应用更具体的规则以递归方式优化计算的样式。

以上面的 CSSOM 树为例进行更具体的阐述。任何置于 body
元素内span 标记中的文本都将具有 16 像素字号,并且颜色为红色
。font-size 指令从 body 向下级层叠至 span。不过,如果某个 span
标记是某个段落 (p) 标记的子项,则其内容将不会显示。

Also, note that the above tree is not the complete CSSOM tree and only
shows the styles we decided to override in our
stylesheet.每个浏览器都提供一组默认样式(也称为“User Agent
样式”),即我们的样式只是override这些默认样式。

要了解 CSS 处理所需的时间,可以在 DevTools
中记录时间线并寻找“Recalculate Style”事件:unlike DOM parsing, the
timeline doesn’t show a separate “Parse CSS” entry, and instead captures
parsing and CSSOM tree construction, plus the recursive calculation of
computed styles under this one event.

 图片 6

我们的小样式表需要大约 0.6 毫秒的处理时间,影响页面上的 8 个元素 —
虽然不多,但同样会产生开销。不过,这 8 个元素从何而来呢?将 DOM 与 CSSOM
关联在一起的是渲染树。

渲染树构建、布局及绘制

CSSOM 树和 DOM
树合并成渲染树,然后用于计算每个可见元素的布局,并输出给绘制流程,将像素渲染到屏幕上。优化上述每一个步骤对实现最佳渲染性能至关重要。

浏览器根据 HTML 和 CSS 输入构建了 DOM 树和 CSSOM 树。
不过,它们是彼此完全独立的对象,分别capture文档不同方面的信息:一个描述内容,另一个则是描述需要对文档应用的样式规则。我们该如何将两者合并,让浏览器在屏幕上渲染像素呢?

  • DOM 树与 CSSOM
    树合并后形成渲染树,它只包含渲染网页所需的节点。遍历每个DOM树中的node节点,在CSSOM规则树中寻找当前节点的样式,生成渲染树。
  • 布局计算每个对象的精确位置和大小。
  • 最后一步是绘制,使用最终渲染树将像素渲染到屏幕上。

 图片 7

第一步是让浏览器将 DOM 和 CSSOM
合并成一个“渲染树”,网罗网页上所有可见的 DOM
内容,以及每个节点的所有 CSSOM 样式信息。

 图片 8

为构建渲染树,浏览器大体上完成了下列工作:

  1. 从 DOM 树的根节点开始遍历每个可见节点。
    • 某些节点不可见(例如脚本标记、元标记等),因为它们不会体现在渲染输出中,所以会被忽略。
    • 某些节点通过 CSS 隐藏,因此在渲染树中也会被忽略。例如 span
      节点上设置了“display: none”属性,所以也不会出现在渲染树中。
  2. 遍历每个可见节点,为其找到适配的 CSSOM
    规则并应用它们。从选择器的右边往左边开始匹配,也就是从CSSOM树的子节点开始往父节点匹配。
  3. Emit visible nodes with content and their computed styles.

注: visibility: hidden 与 display:
none 是不一样的。前者隐藏元素,但元素仍占据着布局空间(即将其渲染成一个空框),而后者
(display: none)
将元素从渲染树中完全移除,元素既不可见,也不是布局的组成部分。

最终输出的渲染同时包含了屏幕上的所有可见内容及其样式信息。有了渲染树,我们就可以进入“布局”阶段。

到目前为止,我们计算了哪些节点应该是可见的以及它们的计算样式,但我们尚未计算它们在设备视口内的确切位置和大小—这就是“布局”阶段,也称为“reflow”。

为弄清每个对象在网页上的确切大小和位置,浏览器从渲染树的根节点开始进行遍历。让我们考虑一个简单的实例:

<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>Critial Path: Hello world!</title>
  </head>
  <body>
    <div style="width: 50%">
      <div style="width: 50%">Hello world!</div>
    </div>
  </body>
</html>

以上网页的正文包含两个嵌套 div:第一个(父)div
将节点的显示尺寸设置为视口宽度的 50%,父 div 包含的第二个
div宽度为其父项的 50%,即视口宽度的 25%。

 图片 9

 

布局流程的输出是一个“盒模型”,它会精确地捕获每个元素在视口内的确切位置和尺寸:所有相对测量值都转换为屏幕上的绝对像素。

最后,既然我们知道了哪些节点可见、它们的computed
styles以及几何信息,我们终于可以将这些信息传递给最后一个阶段:将渲染树中的每个节点转换成屏幕上的实际像素。这一步通常称为”painting”
or “rasterizing.”。

Chrome DevTools
可以帮助我们对上述所有三个阶段的耗时进行深入的了解。让我们看一下最初“hello
world”示例的布局阶段:

 图片 10

The “Layout” event captures the render tree construction, position, and
size calculation in the Timeline.

When layout is complete, the browser issues “Paint Setup” and “Paint”
events, which convert the render tree to pixels on the screen.

执行渲染树构建、布局和绘制所需的时间将取决于文档大小、应用的样式,以及运行文档的设备:文档越大,浏览器需要完成的工作就越多;样式越复杂,绘制需要的时间就越长(例如,单色的绘制开销“较小”,而阴影的计算和渲染开销则要“大得多”)。

下面简要概述了浏览器完成的步骤:

  1. 处理 HTML 标记并构建 DOM 树。
  2. 处理 CSS 标记并构建 CSSOM 树。
  3. 将 DOM 与 CSSOM 合并成一个渲染树。
  4. 根据渲染树来布局,以计算每个节点的几何信息。
  5. 将各个节点绘制到屏幕上。

如果 DOM 或 CSSOM
被修改,需要再执行一遍以上所有步骤,以确定哪些像素需要在屏幕上进行重新渲染。

Optimizing the critical rendering path is the process of minimizing
the total amount of time spent performing steps 1 through 5 in the above
sequence.
Doing so renders content to the screen as quickly as
possible and also reduces the amount of time between screen updates
after the initial render; that is, achieve higher refresh rates for
interactive content.

阻塞渲染的 CSS

默认情况下,CSS
被视为阻塞渲染的资源(但不阻塞html的解析),这意味着浏览器将不会渲染任何已处理的内容,直至
CSSOM
构建完毕请务必精简CSS,尽快提供它,并利用媒体类型和查询来解除对渲染的阻塞,以缩短首屏的时间。

在渲染树构建中,要求同时具有
DOM 和 CSSOM 才能构建渲染树。这会给性能造成严重影响:HTML
CSS 都是阻塞渲染的资源。 HTML 显然是必需的,因为如果没有
DOM,就没有可渲染的内容,但 CSS 的必要性可能就不太明显。如果在 CSS
不阻塞渲染的情况下尝试渲染一个普通网页会怎样?

  • 默认情况下,CSS 被视为阻塞渲染的资源。
  • 我们可以通过媒体类型和媒体查询将一些 CSS 资源标记为不阻塞渲染。
  • 浏览器会下载所有 CSS 资源,无论阻塞还是不阻塞。

没有 CSS 的网页实际上无法使用。所以浏览器将阻塞渲染,直至 DOM 和 CSSOM
全都准备就绪。

CSS
是阻塞渲染的资源。需要将它尽早、尽快地下载到客户端,以便缩短首次渲染的时间。

如果有一些 CSS
样式只在特定条件下(例如显示网页或将网页投影到大型显示器上时)使用,又该如何?如果这些资源不阻塞渲染,该有多好。

可以通过 CSS“媒体类型”和“媒体查询”来解决这类情况:

<link href=”style.css” rel=”stylesheet”>
<link href=”print.css” rel=”stylesheet” media=”print”>
<link href=”other.css” rel=”stylesheet” media=”(min-width: 40em)”>

媒体查询由媒体类型以及零个或多个检查特定媒体特征状况的表达式组成。例如,第一个样式表声明未提供任何媒体类型或查询,因此它适用于所有情况。也就是说它始终会阻塞渲染。第二个样式表则不然,它只在打印内容时适用—或许您想重新安排布局、更改字体等等,因此在网页首次加载时,该样式表不需要阻塞渲染。最后一个样式表声明提供了由浏览器执行的“媒体查询”:符合条件时,样式表会生效,浏览器将阻塞渲染,直至样式表下载并处理完毕。

通过使用媒体查询,我们可以根据特定用例(比如显示或打印),也可以根据动态情况(比如屏幕方向变化、尺寸调整事件等)定制外观。声明样式表时,请密切注意媒体类型和查询,因为它们将严重影响关键渲染路径的性能。

让我们考虑下面这些实例:

<link href=”style.css”    rel=”stylesheet”>
<link href=”style.css”    rel=”stylesheet” media=”all”>
<link href=”portrait.css” rel=”stylesheet”
media=”orientation:portrait”>
<link href=”print.css”    rel=”stylesheet” media=”print”>

  • 第一个声明阻塞渲染,适用于所有情况。
  • 第二个声明同样阻塞渲染:“all”是默认类型,和第一个声明实际上是等效的。
  • 第三个声明具有动态媒体查询,将在网页加载时计算。根据网页加载时设备的方向,portrait.css
    可能阻塞渲染,也可能不阻塞渲染。
  • 最后一个声明只在打印网页时应用,因此网页在浏览器中加载时,不会阻塞渲染。

最后,“阻塞渲染”仅是指浏览器是否需要暂停网页的首次渲染,直至该资源准备就绪。无论媒寻是否命中,浏览器都会下载上述所有的CSS样式表,只不过不阻塞渲染的资源对当前媒体不生效罢了。

Copyright @ 2015-2019 ca88 版权所有
网站地图xml地图