整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

一文读懂HTML和CSS的关系


eb开发是一个很依赖经验的领域,然而这对初学者很不友好。

知识一旦脱离了应用场景就会变得晦涩、空洞,且知识本身也满足“二八定律”,“抓大放小”是提高学习效率的关键。

下文向大家介绍了HTML和CSS之间的关系。内容选自《HTML 5与CSS 3核心技法(全彩)》一书。本书主线清晰,讲解简洁,并提供在线效果演示效果,非常适合小白上手!


1 HTML是骨架

很难想象一个人在桌前对着一块砧板坐一夜,隔一会儿就噼里啪啦敲几下,一会儿哭一会儿笑,是一种什么景象。事实上,在猫眼中我们就是这样的。只不过我们面对的是一块会发光的“砧板”而已。但为什么这块“板子”如此吸引人?“上网”到底是在做什么?

获取信息。

重点在“信息”,一种看不见摸不着却真实存在的东西。无论“1 + 1 = 2”这段字符显示得多么粗糙,都不会影响它传递了完整的信息,以及这条信息的内在逻辑是正确的,不是吗?HTML就是用来盛放最核心的内容——信息。

所以,在CSS和JavaScript出现之前,HTML就出现了。这是必然的,因为如果连最核心的信息都无法有效传递,那围绕着它的一切装饰物和附属品都是毫无意义的。

除满足承载核心信息的需求外,HTML还解决了一个重要的问题——将信息结构化。

试想有这样一篇文章:

背影

我说道:“爸爸,你走吧。”他望车外看了看,说:“我买几个橘子去。你就在此地,不要走动。”我看那边月台的栅栏外有几个卖东西的等着顾客。走到那边月台,须穿过铁道,须跳下去又爬上去。父亲是一个胖子,走过去自然要费事些。我本来要去的,他不肯,只好让他去。我看见他戴着黑布小帽,穿着黑布大马褂,深青布棉袍,蹒跚地走到铁道边,慢慢探身下去,尚不大难。可是他穿过铁道,要爬上那边月台,就不容易了。他用两手攀着上面,两脚再向上缩;他肥胖的身子向左微倾,显出努力的样子。

评论

王花花 大概,天底下的父亲,老去的样子都有些共同的特质吧

李拴蛋 我们都不愿意承认他老了

刘备备 想吃橘子...

此时上面的信息基本没有结构,只能通过断行或缩进尽可能让内容更易读,编辑时的状态就是其最终的显示效果。

HTML就派上了用场,见下方的代码:

代码

<artcle>

<h1>背影</h1>

<p>

我说道:“爸爸,你走吧。”他望车外看了看,说:“我买几个橘子去。你就在此地,不要走动。”我看那边月台的栅栏外有几个卖东西的等着顾客。走到那边月台,须穿过铁道,须跳下去又爬上去。父亲是一个胖子,走过去自然要费事些。我本来要去的,他不肯,只好让他去。我看见他戴着黑布小帽,穿着黑布大马褂,深青布棉袍,蹒跚地走到铁道边,慢慢探身下去,尚不大难。可是他穿过铁道,要爬上那边月台,就不容易了。他用两手攀着上面,两脚再向上缩;他肥胖的身子向左微倾,显出努力的样子。

</p>

</artcle>

<section id="comment-list">

<div class="title">评论</div>

<div class="comment">

<strong class="username">王花花</strong>

<span class="content">大概,天底下的父亲,老去的样子都有些共同的特质吧</span>

</div>

<divclass="comment">

<strong class="username">李拴蛋</strong>

<span class="content">我们都不愿意承认他老了</span>

</div>

<div class="comment">

<strong class="username">刘备备</strong>

<span class="content">想吃橘子...</span>

</div>

</section>

一头雾水没关系,后面我们会细说每一个部分。总之这段内容给人感觉反而更繁琐。但繁琐是代价,重要的是现在这段信息有结构了。这就意味着计算机可以通过结构的规律将其显示得更便于阅读(甚至是交互)。

以下是不加任何装饰性内容直接让浏览器呈现的结果:

效果


这是纯HTML在没有引入任何装饰时的显示效果。很明显,即便是这样也比纯文字状态易读了许多。但注意,HTML本身没有样式,字体大小和粗细有变化的原因是浏览器的默认样式起了作用,与HTML没有关系。而重点就在这里,这意味着我们可以基于这个结构设计自己的页面效果,见下方的示例。

代码

<style>

body { font-family: 'Microsoft YaHei', sans-serif; }

#comment-list { background: #f0f0f0; padding: 10px; border: 1px solid #ccc; margin-top: 25px; }

#comment-list .comment { margin-top: 10px; margin-bottom: 10px; }

#comment-list .title {

color: #777; font-size: 1.1rem; padding-bottom: 5px;

border-bottom: 1px solid #ccc;

}

</style>

<artcle>

<h1>背影</h1>

<p>

我说道:“爸爸,你走吧。”他望车外看了看,说:“我买几个橘子去。你就在此地,不要走动。”我看那边月台的栅栏外有几个卖东西的等着顾客。走到那边月台,须穿过铁道,须跳下去又爬上去。父亲是一个胖子,走过去自然要费事些。我本来要去的,他不肯,只好让他去。我看见他戴着黑布小帽,穿着黑布大马褂,深青布棉袍,蹒跚地走到铁道边,慢慢探身下去,尚不大难。可是他穿过铁道,要爬上那边月台,就不容易了。他用两手攀着上面,两脚再向上缩;他肥胖的身子向左微倾,显出努力的样子。

</p>

</artcle>

<section id="comment-list">

<div class="title">评论</div>

<div class="comment">

<strong class="username">王花花</strong>

<span class="content">大概,天底下的父亲,老去的样子都有些共同的特质吧</span>

</div>

<div class="comment">

<strong class="username">李拴蛋</strong>

<span class="content">我们都不愿意承认他老了</span>

</div>

<div class="comment">

<strong class="username">刘备备</strong>

<span class="content">想吃橘子...</span>

</div>

</section>

效果

这里只是举了一个小示例。你可以轻而易举地让页面的风格千变万化,进而让用户体验有所差异(或差距)。“千变万化”因CSS灵活、强大,“轻而易举”因HTML简洁、有序。结构的力量!

CSS是皮肤

一个充满活力的生态是不满足于现状的。人们在适应了便利地浏览核心信息之后,就会想方设法改进浏览的体验。比如,让自己的博客以多栏显示,以便在视觉上区分不同板块;修改字体颜色,以便强调一些重要信息等。

起初的做法是——准备几种特殊的标签,专门用于样式的指定。涉及布局的地方,如果没有特殊标签就直接用表格布局。以下没有任何样式的状态(以下代码均不需要看懂):

代码

<h1>标题</h1>
<p>
从前有座山,山里有个庙,庙里...

</p>

效果


此时的页面结构下。

如果想让标题居中,则需要给其添加元素<center>,见下方的示例。

代码

<center>
<h1>标题</h1>
</center>
<p>
从前有座山,山里有个庙,庙里...
</p>

效果

此时的页面结构如下。

居中标题的目的确实达到了,但是有一个很大的问题:如果我改变主意了,不想让其居中了,那么我还得再去将<center>元素去掉。这对于简单的页面确实可行,但如果是复杂的页面,这种做法的工作量就是噩梦,因为每个地方都得修改,无论是对齐方式、颜色、背景色,还是大的布局都必须通过修改结构才能完成。这种做法的最大问题是可维护性太差,很多时候为了一种样式要修改很多不必要的结构,枯燥、重复、削足适履的工作太多,基本上写一次就再也不想改了。

这个问题亟待解决,而且解决方案还要兼容现有规则。现有规则是什么?HTML的语法及结构。不过既然HTML已经有结构了,为什么不好好利用呢?

以前面示例中的文章页面为例,如果我们想更改标题,是否可以先统一选中所有标题,然后说明想要什么样式规则呢?就像下面这样:

所有h1 元素听着

对齐方式 居中。

字体颜色 黑色。

如果想将所有段落字体放大,则像下面这样:

所有p 元素听着

字体大小 150%。

这种方式的确很高效!同时这个规则与HTML语法无关,相当于另一种语言。这样结构和样式就不会互相影响,结构是结构,样式是样式,两者隔离开了。如果想修改样式,则完全不需要劳HTML大驾,只需要修改样式文件即可,更便于管理和维护。这就是CSS,只不过其语法更简洁。

下面以修改标题对齐方式为例:

h1 { /* 所有h1 元素听着 */

text-align: center; /* 对齐方式 居中 */

}

通过批量选择和处理,极大地提高了开发效率,降低了维护成本,四两拨千斤。

(完)


图书推荐


《HTML 5与CSS 3核心技法(全彩)》

表严肃 著

本书能够为自学Web开发初学者建立一套HTML与CSS的核心知识框架,同时借助丰富的示例让初学者有一个愉悦、轻松的学习过程。

想从事前端开发的,可将本书作为学习的起点。正从事前端开发的,可将本书作为速查的手册。

家好,我是皮皮。

前言

对于前端来说,HTML 都是最基础的内容。

今天,我们来了解一下 HTML 和网页有什么关系,以及与 DOM 有什么不同。通过本讲内容,你将掌握浏览器是怎么处理 HTML 内容的,以及在这个过程中我们可以进行怎样的处理来提升网页的性能,从而提升用户的体验。


一、浏览器页面加载过程

不知你是否有过这样的体验:当打开某个浏览器的时候,发现一直在转圈,或者等了好长时间才打开页面……

此时的你,会选择关掉页面还是耐心等待呢?

这一现象,除了网络不稳定、网速过慢等原因,大多数都是由于页面设计不合理导致加载时间过长导致的。

我们都知道,页面是用 HTML/CSS/JavaScript 来编写的。

  • HTML 的职责在于告知浏览器如何组织页面,以及搭建页面的基本结构;
  • CSS 用来装饰 HTML,让我们的页面更好看;
  • JavaScript 则可以丰富页面功能,使静态页面动起来。

HTML由一系列的元素组成,通常称为HTML元素。HTML 元素通常被用来定义一个网页结构,基本上所有网页都是这样的 HTML 结构:

<html>
    <head></head>
    <body></body>
</html>

其中:

  • html元素是页面的根元素,它描述完整的网页;
  • head元素包含了我们想包含在 HTML 页面中,但不希望显示在网页里的内容;
  • body元素包含了我们访问页面时所有显示在页面上的内容,是用户最终能看到的内容;


HTML 中的元素特别多,其中还包括可用于 Web Components 的自定义元素。

前面我们提到页面 HTML 结构不合理可能会导致页面响应慢,这个过程很多时候体现在<script><style>元素的设计上,它们会影响页面加载过程中对 Javascript 和 CSS 代码的处理。

因此,如果想要提升页面的加载速度,就需要了解浏览器页面的加载过程是怎样的,从根本上来解决问题。

浏览器在加载页面的时候会用到 GUI 渲染线程和 JavaScript 引擎线程(更详细的浏览器加载和渲染机制将在第 7 讲中介绍)。其中,GUI 渲染线程负责渲染浏览器界面 HTML 元素,JavaScript 引擎线程主要负责处理 JavaScript 脚本程序。

由于 JavaScript 在执行过程中还可能会改动界面结构和样式,因此它们之间被设计为互斥的关系。也就是说,当 JavaScript 引擎执行时,GUI 线程会被挂起。

以网易云课堂官网为例,我们来看看网页加载流程。

(1)当我们打开官网的时候,浏览器会从服务器中获取到 HTML 内容。

(2)浏览器获取到 HTML 内容后,就开始从上到下解析 HTML 的元素。

(3)<head>元素内容会先被解析,此时浏览器还没开始渲染页面。

我们看到<head>元素里有用于描述页面元数据的<meta>元素,还有一些<link>元素涉及外部资源(如图片、CSS 样式等),此时浏览器会去获取这些外部资源。除此之外,我们还能看到<head>元素中还包含着不少的<script>元素,这些<script>元素通过src属性指向外部资源。

(4)当浏览器解析到这里时(步骤 3),会暂停解析并下载 JavaScript 脚本。

(5)当 JavaScript 脚本下载完成后,浏览器的控制权转交给 JavaScript 引擎。当脚本执行完成后,控制权会交回给渲染引擎,渲染引擎继续往下解析 HTML 页面。

(6)此时<body>元素内容开始被解析,浏览器开始渲染页面。

在这个过程中,我们看到<head>中放置的<script>元素会阻塞页面的渲染过程:把 JavaScript 放在<head>里,意味着必须把所有 JavaScript 代码都下载、解析和解释完成后,才能开始渲染页面。

到这里,我们就明白了:如果外部脚本加载时间很长(比如一直无法完成下载),就会造成网页长时间失去响应,浏览器就会呈现“假死”状态,用户体验会变得很糟糕。

因此,对于对性能要求较高、需要快速将内容呈现给用户的网页,常常会将 JavaScript 脚本放在<body>的最后面。这样可以避免资源阻塞,页面得以迅速展示。我们还可以使用defer/async/preload等属性来标记<script>标签,来控制 JavaScript 的加载顺序。

百度首页

三、DOM 解析

对于百度这样的搜索引擎来说,必须要在最短的时间内提供到可用的服务给用户,其中就包括搜索框的显示及可交互,除此之外的内容优先级会相对较低。

浏览器在渲染页面的过程需要解析 HTML、CSS 以得到 DOM 树和 CSS 规则树,它们结合后才生成最终的渲染树并渲染。因此,我们还常常将 CSS 放在<head>里,可用来避免浏览器渲染的重复计算。


二、HTML 与 DOM 有什么不同

我们知道<p>是 HTML 元素,但又常常将<p>这样一个元素称为 DOM 节点,那么 HTML 和 DOM 到底有什么不一样呢?

根据 MDN 官方描述:文档对象模型(DOM)是 HTML 和 XML 文档的编程接口。

也就是说,DOM 是用来操作和描述 HTML 文档的接口。如果说浏览器用 HTML 来描述网页的结构并渲染,那么使用 DOM 则可以获取网页的结构并进行操作。一般来说,我们使用 JavaScript 来操作 DOM 接口,从而实现页面的动态变化,以及用户的交互操作。

在开发过程中,常常用对象的方式来描述某一类事物,用特定的结构集合来描述某些事物的集合。DOM 也一样,它将 HTML 文档解析成一个由 DOM 节点以及包含属性和方法的相关对象组成的结构集合。


三、DOM 解析

我们常见的 HTML 元素,在浏览器中会被解析成节点。比如下面这样的 HTML 内容:

<html>
    <head>
        <title>标题</title>
    </head>
    <body>
        <a href='xx.com'>我的超链接</a>
        <h1>页面第一标题</h1>
    </body>
</html>

打开控制台 Elements 面板,可以看到这样的 HTML 结构,如下图所示:

在浏览器中,上面的 HTML 会被解析成这样的 DOM 树,如下图所示:


我们都知道,对于树状结构来说,常常使用parent/child/sibling等方式来描述各个节点之间的关系,对于 DOM 树也不例外。

举个例子,我们常常会对页面功能进行抽象,并封装成组件。但不管怎么进行整理,页面最终依然是基于 DOM 的树状结构,因此组件也是呈树状结构,组件间的关系也同样可以使用parent/child/sibling这样的方式来描述。同时,现在大多数应用程序同样以root为根节点展开,我们进行状态管理、数据管理也常常会呈现出树状结构。


四、事件委托

我们知道,浏览器中各个元素从页面中接收事件的顺序包括事件捕获阶段、目标阶段、事件冒泡阶段。其中,基于事件冒泡机制,我们可以实现将子元素的事件委托给父级元素来进行处理,这便是事件委托。

如果我们在每个元素上都进行监听的话,则需要绑定三个事件;(假设页面上有a,b,c三个兄弟节点)

function clickEventFunction(e) {
  console.log(e.target === this); // logs `true`
  // 这里可以用 this 获取当前元素
}
// 元素a,b,c绑定
element2.addEventListener("click", clickEventFunction, false);
element5.addEventListener("click", clickEventFunction, false);
element8.addEventListener("click", clickEventFunction, false);

使用事件委托,可以通过将事件添加到它们的父节点,而将事件委托给父节点来触发处理函数:

function clickEventFunction(event) {
  console.log(e.target === this); // logs `false`
  // 获取被点击的元素
  const eventTarget = event.target;
  // 检查源元素`event.target`是否符合预期
  // 此处控制广告面板的展示内容
}
// 元素1绑定
element1.addEventListener("click", clickEventFunction, false);

这样能解决什么问题呢?

  • 绑定子元素会绑定很多次的事件,而绑定父元素只需要一次绑定。
  • 将事件委托给父节点,这样我们对子元素的增加和删除、移动等,都不需要重新进行事件绑定。

常见的使用方式主要是上述这种列表结构,每个选项都可以进行编辑、删除、添加标签等功能,而把事件委托给父元素,不管我们新增、删除、更新选项,都不需要手动去绑定和移除事件。

如果在列表数量内容较大的时候,对成千上万节点进行事件监听,也是不小的性能消耗。使用事件委托的方式,我们可以大量减少浏览器对元素的监听,也是在前端性能优化中比较简单和基础的一个做法。

注意:

  1. 如果我们直接在document.body上进行事件委托,可能会带来额外的问题;
  2. 由于浏览器在进行页面渲染的时候会有合成的步骤,合成的过程会先将页面分成不同的合成层,而用户与浏览器进行交互的时候需要接收事件。此时,浏览器会将页面上具有事件处理程序的区域进行标记,被标记的区域会与主线程进行通信。
  3. 如果我们document.body上被绑定了事件,这时候整个页面都会被标记;
  4. 即使我们的页面不关心某些部分的用户交互,合成器线程也必须与主线程进行通信,并在每次事件发生时进行等待。这种情况,我们可以使用passive: true选项来解决


五、总结

我们了解了 HTML 的作用,以及它是如何影响浏览器中页面的加载过程的,同时还介绍了使用 DOM 接口来控制 HTML 的展示和功能逻辑。我们了解了DOM解析事件委托等相关概念。

TML 是一种标记语言,用于创建网页和应用程序。它的基本结构由以下三个部分组成:

  • 文档类型声明(doctype declaration),用来告诉浏览器文档的版本和规范。它以 <!DOCTYPE html> 开头,表示文档遵循 HTML5 标准。
  • html 标签(html tag),用来包含整个文档的内容。它以 <html> 开始,以 </html> 结束。它还可以包含一个 lang 属性,用来指定文档的主要语言。
  • head 和 body 标签(head and body tags),用来分别包含文档的元数据(metadata)和可见内容(visible content)。head 标签以 <head> 开始,以 </head> 结束。它可以包含一些不显示在网页上的信息,比如标题、字符集、样式表等。body 标签以 <body> 开始,以 </body> 结束。它可以包含一些显示在网页上的内容,比如文本、图片、视频、表单等。

一个 HTML 的基本结构示例如下: