服务热线
131-1198-7613
前言
史上最长的分享,编辑的时间表示感情稳固。今日早读文章须要你很长的时间阅读,由@ikeike443 和 @kiyoto01翻译分享。
正文从这最先~
这是一篇周全介绍 WebKit 和 Gecko 内部利用的入门文章,是以色列开发人员塔利·加希尔大量研究的成果。在过去的几年中,她查阅了所有公开发布的关于浏览器内部机制的数据(请参见资源),并花了许多时间来研读收集浏览器的源代码。她写道:
在 IE 占有 90% 市场份额的年月,我们除了把浏览器当成一个“黑箱”,什么也做不了。可是如今,开放源代码的浏览器拥有了过半的市场份额,因此,是时间来揭开机密的面纱,一探收集浏览器的内幕了。呃,里面只有数以百万行计的 C++ 代码 ...
塔利在她的网站上宣布了自己的研究成果,可是我们觉得它值得让更多的人来了解,所以我们在此从头整顿并宣布。
作为一名收集开发人员,进修浏览器的内部工作道理将有助于您作出更明智的决定,并大白那些最佳开发实践的个中缘由。尽管这是一篇相当长的文档,可是我们建议您花些时间来过细阅读;读完之后,您必定会觉得所费不虚。
保罗·爱丽诗 (Paul Irish),Chrome 浏览器开发人员事务部
简介
收集浏览器很或许是操纵最广的软件。在这篇入门文章中,我将会介绍它们的幕后工作道理。我们会了解到,从您在所在栏输入 google.com 直到您在浏览器屏幕上看到 Google 首页的整个过程中都发生了些什么。
我们要接头的浏览器
如今操纵的主流浏览器有五个:Internet Explorer、Firefox、Safari、Chrome 浏览器和 Opera。本文中以开放源代码浏览器为例,即 Firefox、Chrome 浏览器和 Safari(部门开源)。凭据 StatCounter 浏览器统计数据,如今(2011 年 8 月)Firefox、Safari 和 Chrome 浏览器的总市场占有率快要 60%。由此可见,如今开放源代码浏览器在浏览器市场中占有了很是结实的部门。
浏览器的紧张功能
浏览器的紧张功能就是向办事器发出请求,在浏览器窗口中展示您选择的收集资源。这里所说的资源日常是指 HTML 文档,也可所以 PDF、图片或其他的典范。资源的位置由用户操纵 URI(统一资源标示符)指定。
浏览器表白并表示 HTML 文件的方式是在 HTML 和 CSS 规范中指定的。这些规范由收集尺度化机关 W3C(万维网联盟)进行维护。
多年以来,各浏览器都没有完全坚守这些规范,同时还在开发自己独有的扩展程序,这给收集开发人员带来了严肃的兼容性标题。如今,大大都的浏览器都是或多或少地坚守规范。
浏览器的用户界面有许多彼此类似的元素,其中包含:
用来输入 URI 的所在栏
前进和撤退按钮
书签配置选项
用于刷新和禁止加载当前文档的刷新和禁止按钮
用于返回主页的主页按钮
希奇的是,浏览器的用户界面并没有任何正式的规范,这是多年来的最佳实践自然成长以及彼此之间彼此模拟的成果。HTML5 也没有定义浏览器必需具有的用户界面元素,但列出了一些通用的元素,例如所在栏、状况栏和工具栏等。当然,各浏览器也可以有自己独特的功能,好比 Firefox 的下载治理器。
浏览器的高层结构
浏览器的紧张组件为 (1.1):
用户界面 - 包含所在栏、前进/撤退按钮、书签菜单等。除了浏览器主窗口表示的您请求的页面外,其他表示的各个部门都属于用户界面。
浏览器引擎 - 在用户界面和呈现引擎之间传送指令。
呈现引擎 - 负责表示请求的内容。如果请求的内容是 HTML,它就负责阐明 HTML 和 CSS 内容,并将阐明后的内容表示在屏幕上。
收集 - 用于收集挪用,好比 HTTP 请求。其接口与平台无关,并为所有平台提供底层实现。
用户界面后端 - 用于绘制底子的窗口小部件,好比组合框和窗口。其公开了与平台无关的通用接口,而在底层操纵利用系统的用户界面方法。
Java 表白器。用于阐明和实施 Java 代码。
数据存储。这是持久层。浏览器须要在硬盘上保存各种数据,例如 Cookie。新的 HTML 规范 (HTML5) 定义了“收集数据库”,这是一个完整(可是简便)的浏览器内数据库。
浏览器的紧张组件
值得寄望的是,和大大都浏览器不同,Chrome 浏览器的每个标签页都别离对应一个呈现引擎实例。每个标签页都是一个自力的历程。
呈现引擎
呈现引擎的作用嘛...当然就是“呈现”了,也就是在浏览器的屏幕上表示请求的内容。
默认情况下,呈现引擎可表示 HTML 和 XML 文档与图片。通过插件(或浏览器扩展程序),还可以表示其他典范的内容;例如,操纵 PDF 查察器插件就能表示 PDF 文档。可是在本章中,我们将汇合介绍其紧张用途:表示操纵 CSS 花样化的 HTML 内容和图片。
呈现引擎
本文所接头的浏览器(Firefox、Chrome 浏览器和 Safari)是基于两种呈现引擎构建的。Firefox 操纵的是 Gecko,这是 Mozilla 公司“便宜”的呈现引擎。而 Safari 和 Chrome 浏览器操纵的都是 WebKit。
WebKit 是一种开放源代码呈现引擎,起初用于 Linux 平台,随后由 Apple 公司进行修改,从而支撑苹果机和 Windows。有关详情,请参阅 webkit.org。
主流程
呈现引擎一最先会从收集层获取请求文档的内容,内容的大小日常限制在 8000 个块以内。
然后进行如下所示的底子流程:
呈现引擎的底子流程
呈现引擎将最先阐明 HTML 文档,并将各标志逐个转化成“内容树”上的 DOM 节点。同时也会阐明外部 CSS 文件以及样式元素中的样式数据。HTML 中这些带有视觉指令的样式信息将用于创建另一个树结构:呈现树。
呈现树包含多个带有视觉属性(如颜色和尺寸)的矩形。这些矩形的排列序次就是它们将在屏幕上表示的序次。
呈现树构建完毕之后,进入“结构”处置惩罚处罚阶段,也就是为每个节点分配一个应出如今屏幕上的确切坐标。下一个阶段是绘制 - 呈现引擎会遍历呈现树,由用户界面后端层将每个节点绘制出来。
须要侧重指出的是,这是一个渐进的过程。为达到更好的用户体验,呈现引擎会力求尽快将内容表示在屏幕上。它不必等到整个 HTML 文档阐明完毕之后,就会最先构建呈现树和配置结构。在不绝吸取和处置惩罚处罚来自收集的此外内容的同时,呈现引擎会将部门内容阐明并表示出来。
主流程示例
WebKit 主流程
Mozilla 的 Gecko 呈现引擎主流程
从图 3 和图 4 可以看出,当然 WebKit 和 Gecko 操纵的术语略有不同,但集体流程是底子类似的。
Gecko 将视觉花样化元素组成的树称为“框架树”。每个元素都是一个框架。WebKit 操纵的术语是“呈现树”,它由“呈现对象”组成。对于元素的放置,WebKit 操纵的术语是“结构”,而 Gecko 称之为“重排”。对于连接 DOM 节点和可视化信息从而创建呈现树的过程,WebKit 操纵的术语是“附加”。有一个眇小的非语义不同,就是 Gecko 在 HTML 与 DOM 树之间尚有一个称为“内容槽”的层,用于生成 DOM 元素。我们会一一叙述流程中的每一部门:
阐明 - 综述
阐明是呈现引擎中很是重要的一个环节,因此我们要更深入地教学。首先,来介绍一下阐明。
阐明文档是指将文档转化成为居心义的结构,也就是可让代码大白和操纵的结构。阐明获得的成果每每是代表了文档结构的节点树,它称作阐明树或许语法树。
示例 - 阐明 2 + 3 - 1 这个表达式,会返回下面的树:
数学表达式树节点
语法
阐明是以文档所依照的语律例则(编写文档所用的语言或花样)为根本的。所有可以阐明的花样都必需对应确定的语法(由词汇和语律例则组成)。这称为与上下文无关的语法。人类语言并不属于这样的语言,因此无法用常规的阐明技术进行阐明。
阐明器和词法阐明器的组合
阐明的过程可以分成两个子过程:词法阐明和语法阐明。
词法阐明是将输入内容分割成大量标志的过程。标志是语言中的词汇,即组成内容的单元。在人类语言中,它相当于语言字典中的单词。
语法阐明是应用语言的语律例则的过程。
阐明器每每将阐明工作分给以下两个组件来处置惩罚处罚:词法阐明器(偶尔也称为标志生成器),负责将输入内容分解成一个个有用标志;而阐明器负责凭据语言的语律例则阐明文档的结构,从而构建阐明树。词法阐明器知道奈何将无关的字符(好比空格和换行符)星散出来。
从源文档到阐明树
阐明是一个迭代的过程。每每,阐明器会向词法阐明器请求一个新标志,并实施将其与某条语律例则进行匹配。如果发现了匹配规则,阐明器会将一个对应于该标志的节点添加到阐明树中,然后担当请求下一个标志。
如果没有规则可以匹配,阐明器就会将标志存储到内部,并担当请求标志,直至找到可与所有内部存储的标志匹配的规则。如果找不到任何匹配规则,阐明器就会激发一个很是。这意味着文档无效,包含语法错误。
翻译
许多时间,阐明树还不是最终产品。阐明每每是在翻译过程中操纵的,而翻译是指将输入文档转换成另一种花样。编译就是这样一个例子。编译器可将源代码编译成机器代码,详细过程是首先将源代码阐明身分析树,然后将阐明树翻译成机器代码文档。
编译流程
阐明示例
在图 5 中,我们通过一个数学表达式创建了阐明树。如今,让我们试着定义一个简朴的数学语言,用来演示阐明的过程。
词汇:我们用的语言可包含整数、加号和减号。
语法:
组成语言的语法单元是表达式、项和运算符。
我们用的语言可以包含尽情数目的表达式。
表达式的定义是:一个“项”接一个“运算符”,然后再接一个“项”。
运算符是加号或减号。
项是一个整数或一个表达式。
让我们阐明一下 2 + 3 - 1。
匹配语律例则的第一个子串是 2,而凭据第 5 条语律例则,这是一个项。匹配语律例则的第二个子串是 2 + 3,而凭据第 3 条规则(一个项接一个运算符,然后再接一个项),这是一个表达式。下一个匹配项已经到了输入的结束。2 + 3 - 1 是一个表达式,因为我们已经知道 2 + 3 是一个项,这样就合适“一个项接一个运算符,然后再接一个项”的规则。2 + + 不与任何规则匹配,因此是无效的输入。
词汇和语法的正式定义
词汇每每用正则表达式表示。
例如,我们的示例语言可以定义如下:
INTEGER :0|[1-9][0-9]*
PLUS :+
MINUS:-
正如您所看到的,这里用正则表达式给出了整数的定义。
语法每每操纵一种称为 BNF 的花样来定义。我们的示例语言可以定义如下:
expression :=term operation term
operation :=PLUS |MINUS
term :=INTEGER |expression
之前我们说过,如果语言的语法是与上下文无关的语法,就可以由常规阐明器进行阐明。与上下文无关的语法的直观定义就是可以完全用 BNF 花样表达的语法。有关正式定义,请参阅关于与上下文无关的语法的维基百科文章。
阐明器典范
有两种底子典范的阐明器:自上而下阐明器和自下而上阐明器。直观地来说,自上而下的阐明器从语法的高层结构出发,实施从中找到匹配的结构。而自下而上的阐明器从低层规则出发,将输入内容逐渐转化为语律例则,直至满足高层规则。
让我们来看看这两种阐明器会奈何阐明我们的示例:
自上而下的阐明器会从高层的规则最先:首先将 2 + 3 标识为一个表达式,然后将 2 + 3 - 1 标识为一个表达式(标识表达式的过程涉及到匹配其他规则,可是起点是第一流此外规则)。
自下而上的阐明器将扫描输入内容,找到匹配的规则后,将匹配的输入内容更换陈规则。如此担当更换,直到输入内容的最后。部门匹配的表达式保存在阐明器的仓库中。
这种自下而上的阐明器称为移位归约阐明器,因为输入在向右移位(设想有一个指针从输入内容的开头移动到最后),并且逐渐归约到语律例则上。
自动生成阐明器
有一些工具可以资助您生成阐明器,它们称为阐明器生成器。您只要向其提供您所用语言的语法(词汇和语律例则),它就会生成响应的阐明器。创建阐明器须要对阐明有深刻大白,而人工创建并优化阐明器并不是一件等闲的事情,所以阐明器生成器黑白常实用的。
WebKit 操纵了两种很是著名的阐明器生成器:用于创建词法阐明器的 Flex 以及用于创建阐明器的 Bison(您也或许遇到 Lex 和 Yacc 这样的别名)。Flex 的输入是包含标志的正则表达式定义的文件。Bison 的输入是采纳 BNF 花样的语言语律例则。
HTML 阐明器
HTML 阐明器的使命是将 HTML 标志阐明身分析树。
HTML 语法定义
HTML 的词汇和语法在 W3C 机关创建的规范中进行了定义。当前的版本是 HTML4,HTML5 正在处置惩罚处罚过程中。
非与上下文无关的语法
正如我们在阐明过程的简介中已经了解到的,语法可以用 BNF 等花样进行正式定义。
很遗憾,所有的常规阐明器都不实用于 HTML(我并不是开玩笑,它们可以用于阐明 CSS 和 Java)。HTML 并不能很等闲地用阐明器所需的与上下文无关的语法来定义。
有一种可以定义 HTML 的正规花样:DTD(Document Type Definition,文档典范定义),但它不是与上下文无关的语法。
这初看起来很希奇:HTML 和 XML 很是相似。有许多 XML 阐明器可以操纵。HTML 存在一个 XML 变体 (XHTML),那么有什么大的区别呢?
区别在于 HTML 的处置惩罚处罚更为“宽容”,它承诺您省略某些隐式添加的标志,偶尔还能省略一些起始或许结束标志等等。和 XML 严酷的语法不同,HTML 集体来看是一种“软性”的语法。
显然,这种看上去眇小的不同现实上却带来了庞大的影响。一方面,这是 HTML 如此流行的缘故因由:它能包容您的错误,简化收集开发。另一方面,这使得它很难编写正式的语法。概括地说,HTML 无法很等闲地通过常规阐明器阐明(因为它的语法不是与上下文无关的语法),也无法通过 XML 阐明器来阐明。
HTML DTD
HTML 的定义采纳了 DTD 花样。此花样可用于定义 SGML 族的语言。它包含所有承诺操纵的元素及其属性和层次结构的定义。如上文所述,HTML DTD 无法组成与上下文无关的语法。
DTD 存在一些变体。严酷模式完全坚守 HTML 规范,而其他模式可支撑以前的浏览器所操纵的标志。这样做的目的是确保向下兼容一些早期版本的内容。最新的严酷模式 DTD 可以在这里找到:www.w3.org/TR/html4/strict.dtd
DOM
阐明器的输出“阐明树”是由 DOM 元素和属性节点组成的树结构。DOM 是文档对象模型 (Document Object Model) 的缩写。它是 HTML 文档的对象表示,同时也是外部内容(例如 Java)与 HTML 元素之间的接口。
阐明树的根节点是“Document”对象。
DOM 与标志之间几乎是一一对应的关系。好比下面这段标志:
html
body
p
Hello World
/p
divimg src="example.png"//div
/body
/html
可翻译成如下的 DOM 树:
示例标志的 DOM 树
和 HTML 一样,DOM 也是由 W3C 机关指定的。请参见 www.w3.org/DOM/DOMTR。这是关于文档利用的通用规范。其中一个特定模块描摹针对 HTML 的元素。HTML 的定义可以在这里找到:www.w3.org/TR/2003/REC-DOM-Level-2-HTML-20030109/idl-definitions.html。
我所说的树包含 DOM 节点,指的是树是由实现了某个 DOM 接口的元素组成的。浏览器在详细的实现中会有一些供内部操纵的其他属性。
阐明算法
我们在之前章节已经说过,HTML 无法用常规的自上而下或自下而上的阐明器进行阐明。
缘故因由在于:
语言的宽容本质。
浏览器历来对一些常见的无效 HTML 用法采纳包容立场。
阐明过程须要不绝地反复。源内容在阐明过程中每每不会改变,可是在 HTML 中,剧本标志如果包含 document.write,就会添加额外的标志,这样阐明过程现实上就更改了输入内容。
因为不能操纵常规的阐明技术,浏览器就创建了自定义的阐明器来阐明 HTML。
HTML5 规范详细地描摹了阐明算法。此算法由两个阶段组成:标志化和树构建。
标志化是词法阐明过程,将输入内容阐明成多个标志。HTML 标志包含起始标志、结束标志、属性名称和属性值。
标志生成器识别标志,传达给树机关器,然后继承下一个字符以识别下一个标志;如此反复直到输入的结束。
HTML 阐明流程(摘自 HTML5 规范)
标志化算法
该算法的输出成果是 HTML 标志。该算法操纵状况机来表示。每一个状况吸取来自输入信息流的一个或多个字符,并凭据这些字符更新下一个状况。当前的标志化状况和树结构状况会影响进入下一状况的决定。这意味着,即使吸取的字符类似,对于下一个准确的状况也会产生不同的成果,详细取决于当前的状况。该算法相当复杂,无法在此详述,所以我们通过一个简朴的示例来资助大家大白其道理。
底子示例 - 将下面的 HTML 代码标志化:
html
body
Hello world
/body
/html
初始状况是数据状况。遇到字符 时,状况更改为“标志打开状况”。吸取一个 a-z 字符会创建“起始标志”,状况更改为“标志名称状况”。这个状况会不断保持到吸取 字符。在此时代吸取的每个字符城市附加到新的标志名称上。在本例中,我们创建的标志是 html 标志。
遇到 标志时,会发送当前的标志,状况改回“数据状况”。body 标志也会进行同样的处置惩罚处罚。如今 html 和 body 标志均已发出。如今我们回到“数据状况”。吸取到 Hello world 中的 H 字符时,将创建并发送字符标志,直到吸取 /body 中的 。我们将为 Hello world 中的每个字符都发送一个字符标志。
如今我们回到“标志打开状况”。吸取下一个输入字符 / 时,会创建 end tag token 并改为“标志名称状况”。我们会再次保持这个状况,直到吸取 。然后将发送新的标志,并回到“数据状况”。/html 输入也会进行同样的处置惩罚处罚。
对示例输入进行标志化
树构建算法
在创建阐明器的同时,也会创建 Document 对象。在树构建阶段,以 Document 为根节点的 DOM 树也会不绝进行修改,向其中添加各种元素。标志生成器发送的每个节点城市由树构建器进行处置惩罚处罚。规范中定义了每个标志所对应的 DOM 元素,这些元素会在吸取到响应的标志时创建。这些元素不单会添加到 DOM 树中,还会添加到开放元素的仓库中。此仓库用于矫正嵌套错误和处置惩罚处罚未关闭的标志。其算法也可以用状况机来描摹。这些状况称为“插入模式”。
让我们来看看示例输入的树构建过程:
html
body
Hello world
/body
/html
树构建阶段的输入是一个来自标志化阶段的标志序列。第一个模式是“initial mode”。吸取 HTML 标志后转为“before html”模式,并在这个模式下从头处置惩罚处罚此标志。这样会创建一个 HTMLHtmlElement 元素,并将其附加到 Document 根对象上。
然后状况将改为“before head”。此时我们吸取“body”标志。即使我们的示例中没有“head”标志,系统也会隐式创建一个 HTMLHeadElement,并将其添加到树中。
如今我们进入了“in head”模式,然后转入“after head”模式。系统对 body 标志进行从头处置惩罚处罚,创建并插入 HTMLBodyElement,同时模式转变为“in body”。
如今,吸取由“Hello world”字符串生成的一系列字符标志。吸取第一个字符时会创建并插入“Text”节点,而其他字符也将附加到该节点。
吸取 body 结束标志会触发“after body”模式。如今我们将吸取 HTML 结束标志,然后进入“after after body”模式。吸取到文件结束标志后,阐明过程就此结束。
示例 HTML 的树构建
阐明结束后的利用
在此阶段,浏览器会将文档标注为交互状况,并最先阐明那些处于“deferred”模式的剧本,也就是那些应在文档阐明完成后才实施的剧本。然后,文档状况将配置为“完成”,一个“加载”事故将随之触发。
您可以在 HTML5 规范中查察标志化和树构建的完整算法
浏览器的容错机制
您在浏览 HTML 网页时从来不会看到“语法无效”的错误。这是因为浏览器会矫正任何无效内容,然后担当工作。
以下面的 HTML 代码为例:
html
mytag
/mytag
div
p
/div
Really lousy HTML
/p
/html
在这里,我已经违反了许多语律例则(“mytag”不是尺度的标志,“p”和“div”元素之间的嵌套有误等等),可是浏览器仍然会准确地表示这些内容,并且毫无牢骚。因为有大量的阐明器代码会矫正 HTML 网页作者的错误。
不同浏览器的错误处置惩罚处罚机制相当平等,但令人称奇的是,这种机制并不是 HTML 当前规范的一部门。和书签治理以及前进/撤退按钮一样,它也是浏览器在多年成长中的产品。许多网站都普遍存在着一些已知的无效 HTML 结构,每一种浏览器城市实施通过和其他浏览器一样的方式来修复这些无效结构。
HTML5 规范定义了一部门这样的要求。WebKit 在 HTML 阐明器类的开头诠释中对此做了很好的概括。
阐明器对标志化输入内容进行阐明,以构建文档树。如果文档的花样准确,就直接进行阐明。
遗憾的是,我们不得不处置惩罚处罚许多花样错误的 HTML 文档,所以阐明器必需具备必定的容错性。
我们至少要能够处置惩罚处罚以下错误情况:
显着不能在某些外部标志中添加的元素。在此情况下,我们应该关闭所有标志,直到呈现禁止添加的元素,然后再到场该元素。
我们不能直接添加的元素。这很或许是网页作者健忘添加了其中的一些标志(或许其中的标志是可选的)。这些标签或许包含:HTML HEAD BODY TBODY TR TD LI(尚有漏掉的吗?)。
向 inline 元素内添加 block 元素。关闭所有 inline 元素,直到呈现下一个较高级的 block 元素。
如果这样仍然无效,可关闭所有元素,直到可以添加元素为止,或许忽略该标志。
让我们看一些 WebKit 容错的示例:
操纵了 /br 而不是 br
有些网站操纵了 /br 而不是 br。为了与 IE 和 Firefox 兼容,WebKit 将其与 br 做同样的处置惩罚处罚。
代码如下:
if(t-isCloseTag(brTag)m_document-inCompatMode()){
reportError(MalformedBRError);
t-beginTag =true;
}
请寄望,错误处置惩罚处罚是在内部进行的,用户并不会看到这个过程。
离散表格
离散表格是指位于其他表格内容中,但又不在任何一个单元格内的表格。
好比以下的示例:
table
table
trtdinner table/td/tr
/table
trtdouter table/td/tr
/table
WebKit 会将其层次结构更改为两个同级表格:
table
trtdouter table/td/tr
/table
table
trtdinner table/td/tr
/table
代码如下:
if(m_inStrayTableContent localName ==tableTag)
popBlock(tableTag);
WebKit 操纵一个仓库来保存当前的元素内容,它会从外部表格的仓库中弹出内部表格。如今,这两个表格就酿成了同级关系。
嵌套的表单元素
如果用户在一个表单元素中又放入了另一个表单,那么第二个表单将被忽略。
代码如下:
if(!m_currentFormElement){
m_currentFormElement =newHTMLFormElement(formTag,m_document);
}
过于复杂的标志层次结构
代码的诠释已经说得很清晰了。
示例网站 www.liceo.edu.mx 嵌套了约 1500 个标志,全都来自一堆 b 标志。我们只承诺最多 20 层同典范标志的嵌套,如果再嵌套更多,就会所有忽略。
bool HTMLParser::allowNestedRedundantTag(constAtomicStringtagName)
{
unsigned i =0;
for(HTMLStackElem*curr =m_blockStack;
i cMaxRedundantTagDepth curr curr-tagName ==tagName;
curr =curr-next,i++){}
returni !=cMaxRedundantTagDepth;
}
放错位置的 html 或许 body 结束标志
同样,代码的诠释已经说得很清晰了。
支撑花样很是糟糕的 HTML 代码。我们从不关闭 body 标志,因为一些愚蠢的网页会在现实文档结束之前就关闭。我们通过挪用 end() 来实施关闭利用。
if(t-tagName ==htmlTag ||t-tagName ==bodyTag )
return;
所以网页作者须要寄望,除非您想作为背面课本出如今 WebKit 容错代码段的示例中,不然还请编写花样准确的 HTML 代码。
CSS 阐明
还记得简介中阐明的概念吗?和 HTML 不同,CSS 是上下文无关的语法,可以操纵简介中描摹的各种阐明器进行阐明。毕竟上,CSS 规范定义了 CSS 的词法和语法。
让我们来看一些示例:
词法语法(词汇)是针对各个标志用正则表达式定义的:
comment /*[^*]**+([^/*][^*]**+)*/
num [0-9]+|[0-9]*"."[0-9]+
nonascii [200-377]
nmstart [_a-z]|{nonascii}|{escape}
nmchar [_a-z0-9-]|{nonascii}|{escape}
name {nmchar}+
ident {nmstart}{nmchar}*
“ident”是标识符 (identifier) 的缩写,好比类名。“name”是元素的 ID(通过“#”来引用)。
语法是采纳 BNF 花样描摹的。
ruleset
:selector [','S*selector ]*
'{'S*declaration [';'S*declaration ]*'}'S*
;
selector
:simple_selector [combinator selector |S+[combinator?selector ]?]?
;
simple_selector
:element_name [HASH |class|attrib |pseudo ]*
|[HASH |class|attrib |pseudo ]+
;
class
:'.'IDENT
;
element_name
:IDENT |'*'
;
attrib
:'['S*IDENT S*[['='|INCLUDES |DASHMATCH ]S*
[IDENT |STRING ]S*]']'
;
pseudo
:':'[IDENT |FUNCTION S*[IDENT S*]')']
;
表白:这是一个规则集的结构:
div.error ,a.error {
color:red;
font-weight:bold;
}
div.error 和 a.error 是选择器。大括号内的部门包含了由此规则集应用的规则。此结构的正式定义是这样的:
ruleset
:selector [','S*selector ]*
'{'S*declaration [';'S*declaration ]*'}'S*
;
这表示一个规则集就是一个选择器,或许由逗号和空格(S 表示空格)分隔的多个(数目可选)选择器。规则集包含了大括号,以及其中的一个或多个(数目可选)由分号分隔的声明。“声明”和“选择器”将由下面的 BNF 花样定义。
关于本文
译者:@ikeike443 和 @kiyoto01
原文:https://www.html5rocks.com/zh/tutorials/internals/howbrowserswork/
2024-03-20
网页设计,是根据企业希望向浏览者传递的信息(包括产品、服务、理念、文化),进行网站功能策划,然后进行···
2024-03-19
网页设计,是根据企业希望向浏览者传递的信息(包括产品、服务、理念、文化),进行网站功能策划,然后进行···
2024-03-19
网页设计,是根据企业希望向浏览者传递的信息(包括产品、服务、理念、文化),进行网站功能策划,然后进行···
2024-03-19
网页设计,是根据企业希望向浏览者传递的信息(包括产品、服务、理念、文化),进行网站功能策划,然后进行···