GDG第一场前端分享

本文参考@李实

前端是什么

相关软件

作者使用的操作系统是 Mac,读者也可以用 Windows,操作使用不会有明显差异,如果有差别会额外注明。
本教程使用的软件主要是 VS Code 用于代码编辑,Chrome 作为浏览器,以及调试工具。另外版本控制软件 (version control software) 例如 Git 是软件开发中必不可少的工具。

VS Code 说明

Visual Studio Code 简称 VS Code 是微软推出的一款代码编辑器,他是开源(源代码公开),免费并且跨平台(Windows/Mac/Linux 都可以安装使用)的。有趣的是他自己也是基于前端技术的,他使用了 Electron 框架,这个框架让你可以使用网页技术和 NodeJS 开发跨平台应用。所以我们会在一个基于前端技术的软件中,写前端代码。

编程语言源代码代码都是纯文本,因为需要从键盘输入。所谓纯文本文件,一般指只有字符原生编码构成的二进制计算机文件。可以理解为除了文字之外,文件不含任何其他数据。一般的 Windows 电脑的 .txt 即是纯文本文件,但是文件的后缀,属于文件名的一部分,和文件的内容没有必然关系,只是暗示操作系统或者使用者文件的内容而已。常见的文档比如 Word 并不是纯文本文件,因为他含有很多额外的信息,比如格式排版等,而这些信息并不是用纯文本表示的,而是文档处理软件比如 Word 生成的,所以如果您用纯文档编辑器,比如 Windows 中的记事本或者 VS Code 打开会 Word 文档会看到乱码。

理解了纯文本文件,那为什么要用 VS Code 而不用记事本呢?你可以选择用记事本,或者其他文本编辑器,比如 Atom, Notepad++, Sublime,但是本教程选择 VS Code。各软件功能都有差异,建议初学者读者使用 VS Code:

Chrome 说明

Chrome 目前是全球最流行的浏览器,并且提供的开发者工具 (developer tools) 非常方便。

如果用其他浏览器可以吗,比如 Firefox, Safari, Edge?当然是可以的,但是本教程选择 Chrome。各浏览器功能都有差异,建议初学者读者使用 Chrome。

网站概述

本章概括性的描述了做网站涉及到的各种概念,运行原理,是整本书的基础。例如:浏览器,网络通信,HTTP,服务器,HTML/CSS/JavaScript。通过本章的介绍,读者可以对 Web 的构成,涉及到的软件和技术有一个概览,知道一个简单的网站是如何工作的。

参考标准W3C

W3C是英文 World Wide Web Consortium 的缩写,中文意思是W3C理事会或万维网联盟。W3C组织是对网络标准制定的一个非赢利组织,像HTML、XHTML、CSS、XML的标准就是由W3C来定制。
到目前为止,W3C已开发了超过50个规范(草案)。这些规范(草案)包括人们早已、耳熟能详的HTML、HTTP、URIs、XML等,也包括针对语义Web的RDF、OWL等。

HTML (超文本标记语言Hypertext Markup Language)

网页的作者,把自己想要展示的内容,以一定的格式表示出来,存放在服务器,由服务器发送给请求访问的用户。这种格式名叫 HTML,最新的版本叫 HTML5。

以下是一段html代码例子:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>文档名</title>
    </head>
    <body>
        <h1>文章标题</h1>
        <p>正文</p>
    </body>
</html>

网页中的效果是这样的:

CSS (层叠样式表 Cascading Style Sheets)

HTML 越来越流行,但有一个需求没有很好的被满足:可以让网页有自定义的样式。开发者和网页设计师需要更自由的控制网页的展示效果,比如布局方式,边框,背景色,背景图片,按钮样式等等。HTML 的布局能力非常有限,如果把非常复杂的样式设计到 HTML 中,那么 HTML 会非常复杂,冗长;另外分离内容与样式,也是一个很好的实践方式。因此,在 1994 年,Håkon Wium Lie 发表了自己的样式表提案,这提案成为了后来的 CSS。下面是一个简单的 CSS 例子。

h1 {
    color: red;
}

上面的 CSS 规定了 h1 元素的文字颜色是红色。如果把上面的 CSS 应用到之前 HTML 的例子,用浏览器打开效果如下:

HTML 语法

在上面的例子中可以看到 HTML 文件是由浏览器处理的,浏览器的工作就是根据 HTML 文件展示效果,这个过程称为渲染。HTML 该怎么写呢?

定义文档类型

在上面的例子中,第一行是:

<!DOCTYPE html>

这一行的作用是定义文档类型,意义是告诉浏览器,以 HTML5 的方式识别内容。历史上有过其他种文档类型,基本已经过时了。因此大家只要记住这个就好。想了解更多请查看链接:https://www.w3.org/QA/2002/04/valid-dtd-list.html

元素 (Element)

HTML 文档由元素组成,在上面的例子中,出现的元素有:html, head, body, meta, title, h1, p。用 p 元素举例子

<p>正文</p>

P 代表 paragraph 即段落,段落是有开始和结束的,可以看到,这个元素由<p>开始,由</p>结束。但并不是所有的元素都有开始和结束之分的,比如例子中的 meta 元素,meta 代表 metadata 是文档的元数据,因此不需要结束标签。再比如 BR 元素用作换行 (break line),写法是 <br>,也不需要结束标签。如何知道一个元素是否需要结束标签呢?推荐的地方是 MDN web docs,这里的文档齐全并且权威,是开发者的好朋友。比如 br 元素的文档:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/br 这里明确说名了不需要结束标签。

另外有的元素还有自己的属性,例子中的 meta:

<meta charset="UTF-8">

charset 是属性名属性的值为 UTF-8,值需要用双引号包含,属性名和属性的值用等号相连。不同的元素有着不同的属性以及值,可以从 MDN 文档中找到答案。

树形结构

上文中我们提到了内容有自己的逻辑结构。在 HTML 中,基本的结构是树形结构,树由元素组成。在上面的例子中 HTML 的树形结构是:

  • 只有1个根元素,元素名为 html
  • 根元素有两个子元素(Child Element)分别是 head 和 body
  • head 和 body 分别有自己的子元素
  • 其中 body 的子节点 h1 包含的是文字,文字就不是元素了,它属于 h1

树形结构也是有限制的:是否能包含子元素,能包含什么样的子元素都各有区别。例如 html 就只能有 2 个子元素,分别是 head 和 body,而 P 元素可以包含很多种元素。读者可以查看 MDN 文档说明 中的 Permitted content (允许的内容,即允许包含的内容)。

总结

本节介绍了 HTML 文档的基本写法,包括标签的写法,以及树形结构,介绍了查文档的地方。但是 HTML 文档很长,需要全看一遍吗?当然不,有经验的程序员通常也不会知道所有元素。下一节我们会介绍一些常用的元素,让大家快速上手。

HTML 常用元素与属性

常用的元素

标题元素 <h1>-<h6>

标题元素用来表示标题,HTML 一共定义了6个级别的标题,即<h1>-<h6>,例如

<h1>Petter Parker</h1>

效果:

<div style="border: 1px dashed;">
    <h1 style="margin: 0;">Petter Parker</h1>
</div>

P 元素

P 元素表示段落(paragraph),P 可以包含文字,或者很多元素,比如A元素,IMG 元素,H1-H6 元素等

<p>我是蜘蛛侠,我做一些很酷的事情,比如拯救世界<p>

效果:

  <div style="border: 1px dashed">
    <p>我是蜘蛛侠,我做一些很酷的事情,比如拯救世界</p>
  </div>

IMG 元素

IMG 元素表示图片(image),img 元素不需要结束标签。需要 src 属性指定图片的 url。alt 属性的作用是给图片一个描述文字,屏幕阅读器会使用到这个描述,另外在图片无法再入的时候,浏览器也会显示这个文字,alt 属性不是必须的。

<img src="http://ku.simon1987.com/spiderman.jpg" alt="spider man" >

效果:

<div style="border: 1px dashed">
    <img src="http://ku.simon1987.com/spiderman.jpg" alt="spider man" >
</div>

A 元素 <a>

A 元素(anchor element)表示超链接(hyperlink)。href 属性指定了超链接的 URL,也可以是 URL 片段或相对路径。关于相对路径,在下一章介绍。URL 片段是以井号开头的文字,例如<a href="#top">顶部</a>,其中 top 是页面中某个元素的 ID,ID 在以后的章节会介绍。另外 A 元素还有 target 属性,表示链接打开的目标。属性值默认是 _self 指定在当前页面打开链接,还可以设置为 _blank 指定浏览器在新窗口打开链接。

<a href="https://www.marvel.com/characters/spider-man-peter-parker">漫威蜘蛛侠</a>

效果:

<div style="border: 1px dashed">
    <a href="https://www.marvel.com/characters/spider-man-peter-parker">漫威蜘蛛侠</a>
</div>

UL, OL 以及 LI 元素

UL 元素表示无序列表 (Unordered List),无序指没有先后顺序。OL 元素表示有序列表(Ordered List)。列表中的内容 (List Item),用 LI 元素表示,例如:

组织:
<ul>
    <li>复仇者联盟</li>
    <li>号角日报</li>
    <li>未来基金会</li>
    <li>新复仇者</li>
    <li>帕克工业</li>
</ul>
敌人:
<ol>
    <li>绿恶魔</li>
    <li>章鱼博士</li>
    <li>灭霸</li>
</ol>

效果:

<div style="border: 1px dashed">
    组织:
    <ul>
        <li>复仇者联盟</li>
        <li>号角日报</li>
        <li>未来基金会</li>
        <li>新复仇者</li>
        <li>帕克工业</li>
    </ul>
    敌人:
    <ol>
        <li>绿恶魔</li>
        <li>章鱼博士</li>
        <li>灭霸</li>
    </ol>
</div>

HEADER, MAIN, SECTION, ARTICLE, FOOTER, DIV元素

HEADER, MAIN, SECTION, ARTICLE, FOOTER 属于内容分区元素(Content sectioning elements),用来把整个文档分为多个逻辑分区,比如 HEADER 元素可以用来表示介绍性内容,MAIN 元素可以用来表示文档的主要内容,SECTION 元素可以用来表示单独的一节内容,ARTICLE 可以用来表示帖子,文章,博客,评论等,FOOTER 表示页脚,经常用来放作者,版权,联系方式等信息。这几个元素都是 HTML5 标准新加入的,可以更准确的表达文档的逻辑结构,也属于语义元素(semantic element) 在 HTML5 之前,通常是用 DIV 元素来分隔。

DIV 元素,即文档分区元素(Content Division element),是一个通用的容器,可以包含各种子元素,比如 UL, H1, P, IMG, DIV 等。在 HTML5 之前,只能用 DIV 来组织文档的逻辑结构,在 HTML5 之后,建议在不同的场景下使用不同的更加准确的语义元素,比如 HEADER, FOOTER, ARTICLE 等,虽然浏览器展示没有分别。

语义元素的好处,请参考 https://developer.mozilla.org/en-US/docs/Glossary/Semantics#Semantics_in_HTML

<footer>
    this website is made by Simon1987
</footer>

效果:

<div style="border: 1px dashed">
<footer>
    this website is made by Simon1987
</footer>
</div>

STRONG, SPAN 元素

STRONG 元素 (<strong>)表示文本十分重要,浏览器通常会用粗体显示。<span>元素是一个文字容器,没有任何特殊语义,经常用来配合 CSS 显示不同的样式。与 DIV 同样是通用的容器,区别是 DIV 是块级元素的容器,可以包含块级元素和行内元素,而 SPAN 只能包含行内元素。

<p>
    <strong>蜘蛛侠</strong>(英语:Spider-Man)是漫威漫画的超级英雄。本名为彼得·班杰明·帕克(Peter Benjamin Parker)他是由作家/编辑史丹·李及作家/画家史蒂夫·迪特科所创造。
</p>

效果:

<div style="border: 1px dashed">
<p style="margin: 0">
    <strong>蜘蛛侠</strong>(英语:Spider-Man)是漫威漫画的超级英雄。本名为彼得·班杰明·帕克(Peter Benjamin Parker)他是由作家/编辑史丹·李及作家/画家史蒂夫·迪特科所创造。
</p>
</div>

FORM, INPUT, BUTTON 等表单交互性元素

块级元素(Block-level elements)和行内元素(Inline elements)

有些元素属于块级元素,有些属于行内元素。上文中的 <h1>-<h6>,<p>,<ul>, <ol>, <header>,<main>,<section>,<footer>,<p>,<div>属于块级元素,<a>, <strong>, <span>, <img> 属于行内元素。

块级元素默认会占满父元素的宽度,前后各新起一行,隔断(Block)其之前与之后的元素。而行内元素默认不会新起一行,大小取决于自己的内容。看下面2个例子:

行内元素,代码如下:

<div>下面的元素是行内元素,<span style="background-color: yellow">行内元素</span>,行内元素不会换行,大小取决于自身的内容。</div>

效果:

<div style="border: 1px dashed">下面的元素是行内元素,<span style="background-color: yellow">行内元素</span>,行内元素不会换行,大小取决于自身的内容。</div>

块级元素,代码如下:

<div>下面的元素是块级元素,<p style="background-color: yellow;">块级元素,</p>块级元素默认会占满父元素的宽度,前后各新起一行,隔断(Block)其之前与之后的元素。</div>

效果:

<div style="border: 1px dashed">下面的元素是块级元素,<p style="background-color: yellow; margin: 0">块级元素,</p>块级元素默认会占满父元素的宽度,前后各新起一行,隔断(Block)其之前与之后的元素。</div>

其中 style 属性在 CSS 章节会详细解释,在这里只要知道它让背景变色就好了。在 CSS 章节中我们会看到可以通过 CSS 改变元素是否块级元素或者行内元素。

一些全局属性(Global attributes)

全局属性是所有 HTML 元素共有的属性; 它们可以用于所有元素,即使属性可能对某些元素不起作用。

id 属性

id 属性给标签定义唯一标识,例如<div id="container">一篇文章</div>,这时候这个 DIV 元素就有了自己的唯一标识 id 为 container。页面中不允许出现另外的 id 为 container 的元素了。如果当前页面有个超链接 <a href="#container">一篇文章</a>,点击这个超链接浏览器便会跳转到上文的 DIV 标签处。另外 id 还可以配合 CSS 选择器,作用于 CSS 和 JavaScript。分别在 CSS 章节和 JavaScript 章节会介绍。

class 属性

一个以空格分隔的元素的类名(classes )列表,例如<div class="container important">,这里我们给 DIV 元素设置了 2 个不同的类,分别是 container 和 important。有了这个类,我们就可以在 CSS 或者 JavaScript 中通过这个类名,找到这个元素。分别在 CSS 章节和 JavaScript 章节会介绍。

style 属性

style 属性可以给元素设置 CSS 样式,例如<span style="color: yellow">行内元素</span>,这里 span 中的内容会显示黄色。在 CSS 章节会详细介绍。

onclick,oncontextmenu,onfocus,onscroll,onblur 等事件相关的属性

这些属性表示在当前元素发生某种事件时应该作出的反应。标签的值是一段 JavaScript 脚本。例如<a onclick="alert('hello')">hello</a>表示这个 A 元素在点击时会执行alert('hello')这个脚本。关于这个脚本的含义在 JavaScript 章节会介绍。

如果 HTML 文档不符合规则了?

规则有很多,例如上文中介绍的:

  1. 很多 HTML 的元素只可以包含一部分 HTML 元素,不是任何内容都可以成为元素的内容。比如<ul> 元素只可以包含 <li> 元素作为子元素,<html> 元素只可以包含 <head><body> 等。
  2. 属性有限制。例如 id 属性必须是唯一的。
  3. 是否可以省略结束标签。例如 <br>, <meta>元素没有结束标签。

这些都是在编码时需要注意的规则。如果不符合规则,会发生未定义的行为,所谓未定义意思是 W3C 标准中没有规定发生这种情况浏览器应该如何处理,于是浏览器会自行处理。很多情况的小错误,浏览器会自动纠正,比如 <br> 写成了 <br /> 浏览器通常不会显示错误,能够正常显示。再比如给多个元素设置同样的 id 属性,浏览器仍然可以正常显示内容,但是这个可能引起相关 CSS 样式和 JavaScript 的错误。

语义类标签是什么,使用它有什么好处?

语义类标签也是大家工作中经常会用到的一类标签,它们的特点是视觉表现上互相都差不多,主要的区别在于它们表示了不同的语义,比如大家会经常见到的 section、nav、p,这些都是语义类的标签。

语义是我们说话表达的意思,多数的语义实际上都是由文字来承载的。语义类标签则是纯文字的补充,比如标题、自然段、章节、列表,这些内容都是纯文字无法表达的,我们需要依靠语义标签代为表达。

在讲语义之前,我们来说说为什么要用语义。

现在我们很多的前端工程师写起代码来,多数都不用复杂的语义标签, 只靠 div 和 span 就能走天下了。

这样做行不行呢?毫无疑问答案是行。那这样做好不好呢?按照正确的套路,我应该说不好,但是在很多情况下,答案其实是好。

这是因为在现代互联网产品里,HTML 用于描述“软件界面”多过于“富文本”,而软件界面里的东西,实际上几乎是没有语义的。比如说,我们做了一个购物车功能,我们一定要给每个购物车里的商品套上 ul 吗?比如说,加入购物车这个按钮,我们一定要用 Button 吗?

实际上我觉得没必要,因为这个场景里面,跟文本中的列表,以及表单中的 Button,其实已经相差很远了,所以,我支持在任何“软件界面”的场景中,直接使用 div 和 span。

不过,在很多工作场景里,语义类标签也有它们自己无可替代的优点。正确地使用语义标签可以带来很多好处

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

不过,不恰当地使用语义标签,反而会造成负面作用。这里我们举一个常见的误区作为例子。我们都知道 ul 是无序列表,ol 是有序列表,所以很多接触过语义这个概念,半懂不懂的前端工程师,特别喜欢给所有并列关系的元素都套上 ul。
实际上, ul 是长成下面的这种样子的 (以下来自 HTML 标准)。

I have lived in the following countries:

Switzerland
Norway
United Kingdom
United States
ul 多数出现正在行文中间,它的上文多数在提示:要列举某些项。但是,如果所有并列关系都用 ul,会造成大量冗余标签。

错误地使用语义标签,会给机器阅读造成混淆、增加嵌套,给 CSS 编写加重负担。

所以,对于语义标签,我的态度是:“用对”比“不用”好,“不用”比“用错”好。当然了,我觉得有理想的前端工程师还是应该去追求“用对”它们。

总结

本章介绍了一些常用的 HTML 元素,有了这些元素,就已经可以做出基本的网页了。到这个时候,HTML 的任务已经完成了:定义内容和定义内容的逻辑结构。但是这个网页视觉效果十分基础,可以说是极简主义设计了,下一步就是进入 CSS 的学习,给网页添加样式。

当然 HTML 元素比本章介绍的这些多很多,大家可以自行查阅文档学习剩下的部分,也可以在实际使用中根据场景再进行针对性学习。

参考文档


CSS (层叠样式表 Cascading Style Sheets) 概述

怎样允许为一个固定的 HTML 设置无限种可能的样式?所谓样式,即视觉效果。肉眼能分辨的事物基本包含3种:大小,距离,色彩,形状:

  • 大小:可以设置元素的长度,宽度,文字的字号,行高等。
  • 距离:元素之间的距离,文字之间的距离
  • 色彩:可以设置元素的背景色,背景图片,边框颜色,文字颜色
  • 形状:可以设置矩形边框,圆角边框,文字的字体

上面的几点可能能够满足平面设计的需求,但是无法满足网页设计的需求,原因是:

  • 浏览器的大小不一。例如分辨率是 1920x1080 和分辨率 1024x768,对于前者,我们让宽度为 20 的元素的左边距为 950 即可达到居中的效果,而同样的设置,显然无法在后者的分辨率下显示居中。例如,在较宽的屏幕我们希望一行显示4列,而在较窄的屏幕,比如手机等移动设备,我们希望一行显示1列。
  • 网页有交互。例如多数网页都可以向下滚动,而我们希望导航栏在滚动时依然保持在最上面的位置。例如当鼠标在某个链接上方时,我们希望改变链接的样式。(复杂的交互可以通过 JavaScript 实现,本章不讨论)
  • 需要动画特效。比如我们希望元素有淡入淡出等效果。

而 CSS 可以满足以上绝大部分的需求。如果能配合 JavaScript (在下一章介绍)更有无限种可能。

CSS 基本语法

CSS 语法的思路是:

  1. 选中元素
  2. 设置属性和值

内联样式 (inline style)

使用 style 属性设置 CSS 的方式叫内联样式 (inline style)

一个例子,代码和效果如下:

<p style="color: yellow; text-align: center">内联样式</p>
<div style="margin: 0, padding: 0; border: 1px dashed">
<p style="color: yellow; margin: 0; text-align: center">内联样式</p>
</div>

在上面的例子中,我们通过给元素添加style属性选中元素,设置了属性(property)colortext-align值(value)分别为yellowcenter。属性和值连起来叫声明(declaration),多个声明用分号;隔开,格式为:

<属性>:<值>;<属性2>:<值2>;...

在需要设置很多元素为相同的样式时,内联样式这样做显然比较冗长,混合了内容与样式的代码,在修改时也不方便,还不支持所有 css 功能,比如不支持伪类(pseudo-class)媒体查询(media query)。所以一般不推荐这种做法。

内部样式

所谓内部样式是指通过<style>标签以及其内容来设置样式,如下可以实现上文例子的同样效果:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>css intro</title>
    </head>
    <style>
    p {
        color: yellow; 
        text-align: center
    }
    </style>
    <body>
        <p>内部样式</p>
    </body>
</html>
<div style="margin: 0, padding: 0; border: 1px dashed">
<p style="color: yellow; margin: 0; text-align: center">内联样式</p>
</div>

通过内部样式,将样式与 HTML 分离开来了,这样 html 就看起来更加清晰,特别是在复杂的网页的情况下。但是这样需要选中元素,选中元素使用CSS 选择器(CSS Selector),上看的例子中<style>标签中的p就是选择器,这里的意思是给当前页面中的所有<p>元素,应用后面{}中定义的样式。除了用选择某一种元素之外,CSS 选择器还有很多种方式,可以按照元素的class属性选,按照 id 属性选,按照某种其他属性选,另外还有很多组合方式,例如选择某个元素的子元素等。将在 CSS 选择器小节详细介绍。

外部样式表

将 CSS 写到独立的文件中,然后通过<link>标签引入到页面,这种方式成为外部样式表。这样也可以将样式与 HTML 分离。是一般情况下推荐使用的方式。例如:

文件:index.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>css intro</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <p>外部样式</p>
    </body>
</html>

文件:style.css

p {
    color: yellow; 
    text-align: center
}

在上面的例子中,我们在<head>标签中添加了子元素<link rel="stylesheet" href="style.css">其中 rel 指定资源的类型,href 指定了资源的 URL(在这里是相对 URL)。可以参考资源定位和 URL 章节了解如何写 URL。

#拓展:为什么link一个css要用href,js用src

CSS 注释

CSS 注释即在 CSS 中的一段用“/*”和“*/”包含起来的文字,这段文字对页面没有任何效果,例如:

p { color: yellow } /* 让段落中的颜色为 yellow */
/*
多行注释
p { color: red }
*/

本章将先后介绍 CSS 选择器,CSS 盒模型 (Box Model),文档流 (Normal Flow),CSS 常见属性,FlexBox 布局。随后会有一些应用作为例子,帮助大家理解。

默认的 CSS

如果不添加任何 CSS 会怎样呢?浏览器有默认的 css,不同的浏览器还会有区别,以至于同样的 HTML 用不同的浏览器打开会不一样,不过通常区别不大。如果希望各个浏览器效果一样,可以事先用 CSS 将所有默认值设置好,这个方式也称为 CSS Reset,万维网上可以搜索出很多例子。

属性的继承 (Inheritance)

有些属性我们不希望所有元素都设置一遍,例如字体(font),颜色(color)。这两个属性有继承的效果,即如果本身没有设置,那么使用父元素的值,如果父元素没有,使用父元素的父元素的值,直到根元素,即 html 元素。

另外一些属性通常希望分别设置,比如大小,边框,背景图片等。查阅 MDN 文档可以知道一个 CSS 属性是否默认会继承。

可以设置某个元素的一个属性为继承,例如 box-sizing 属性默认不继承,我们设置为继承:

p { box-sizing: inherit; }

CSS 选择器 (CSS Selector)

在使用内部样式或者外部样式的时候,需要用到 CSS 选择器,指定一个或者多个元素。CSS 选择器分为以下 4 种:

  • 基本选择器:包括类型选择器(Type Selector),类选择器(Class Selector),ID 选择器(ID Selector),通用选择器(Universal Selector),属性选择器(Attribute Selector)
  • 组合选择器:包括紧邻兄弟选择器(Adjacent Sibling Selector),一般兄弟选择器(General Sibling Selector),子选择器(Child Selector),后代选择器(Descendant Selector)。组合选择器可以认为是通过元素的相互关系来选择。
  • 伪类(pseudo-class)
  • 伪元素(pseudo-element)

这里介绍几例常用的,完整的 CSS 选择器说明可以阅读 MDN 文档

类型选择器(Type Selector)

选择所有匹配给定元素名的元素,下面的例子中给页面中所有的<p>元素设定了样式:

p { color: yellow; }

类选择器

根据元素的class属性选择相应的元素,用“.”加上类名表示。

.yellow { color: yellow; } /* 下面 HTML 中第一个<p>元素和两个<div>元素被选中。*/
div.yellow { font-size: 20px; } /* 选择元素为 div 并且类为 yellow 的元素。下面 HTML 中两个 <div> 元素被选中 */
div.yellow.red { font-weight: bold; } /* 选择同时拥有 yellow 和 red 类的元素。下面 HTML 只有第二个 <div> 元素被选中 */

<p class="yellow">选中的元素</p>
<div class="yellow ">选中的元素</div>
<div class="yellow red">选中的元素</div>
<p>未被选中</p>

ID 选择器

根据元素的 id 属性选择相应的元素,用“#”加上 id 表示。在下面的例子中,第一个<p>元素被选中。

#green { color: green; }
<p id="green">选中的元素</p>
<p class="green">未被选中</p>

通用选择器

通用选择器匹配所有元素,用“*”表示,下面的例子为所有页面元素应用了样式:

* { margin: 0; }

后代选择器

我们介绍过 HTML 文档是个树形结构,所谓后代即某个元素内的所有元素,包括其子元素,子元素的子元素等等。后代选择器属于组合选择器,需要组合两个或多个选择器,例如:

div span { color: blue; } /* 只有作为 <div> 后代的 <span> 元素被选中 */
.center p { text-align: center; } /* 只有作为 center 类元素的后代的 <p> 元素被选中 */
<span>默认文字颜色</span>
<div>
    <p>一段文字<span>显示蓝色</span>另一段文字</p>
</div>
<div class="center"><p>文字剧中</p></div>
<div class="example" style="margin: 0; border: 1px dashed">
    <span>默认文字颜色</span>
    <div style="margin: 0;">
        <p style="margin: 0;">一段文字<span style="color: blue;">显示蓝色</span>另一段文字</p>
    </div>
    <div style="margin: 0"><p style="text-align: center; margin: 0">文字剧中</p></div>
</div>

属性选择器

TODO

伪类选择器

伪类允许基于未包含在文档树中的状态信息来选择元素,例如,我们希望访问过的链接和未访问过的显示不同的样式;希望鼠标悬停在元素上展示特别的效果。具体的写法是在选择器后面加上伪类<选择器>:<伪类>,某些伪类也可以省略冒号前面的部分(例如:not()) 。下面的选择器.shine:hover,表示类为shine的元素,在鼠标悬停时应用样式。

<style>.shine:hover { color: red; background-color: yellow; }</style>
<a class="shine">鼠标悬停效果</a>
<div style="margin: 0; border: 1px dashed">
<a class="shine">鼠标悬停效果</a>
</div>

包括:hover,一共有几十种 css 伪类,常用的有以下:

  • :link,:visited,:hover,:active 这几个伪类主要作用于<a>元素。分别作用于“未访问过的”,“访问过的”,“鼠标悬停中的”,“激活的(鼠标点下去后)”。当几个伪类同时存在一个元素的时候,优先级增。即如果符合的话,优先应用:active,其次:visited,再次:hover,最后:link
  • :first-child,:last-child 当前元素是其父元素的首个/最后一个子元素时生效
  • :not()选择不符合条件的元素,在()中内容是选择器,例如:not(p)选中所有不是<p>的元素;:not(.shine)选择所有没有shine类的元素;例如.icon:last-child:not(:first-child)选择有icon类是其父元素的最后一个子元素,但不是第一个子元素的的元素。

更多的伪类可以查看 MDN 文档:CSS 伪类

伪元素选择器

伪元素的写法与伪类相似,区别是伪元素用“::”分隔(旧的标准也是用“:”)。伪元素可以选择本身不是 HTML 标签定义的元素。

  • ::first-letter代表第一个字母,中文则是第一个汉字
  • ::first-line代表第一行
  • ::before会在当前元素内增加一个内部伪元素,并置于所有子元素之前。定义的样式将作用于增加的元素
  • ::after会在当前元素内增加一个内部伪元素,并置于所有子元素之后。定义的样式将作用于增加的元素
  • ::selection代表鼠标选中的文字的

新的 CSS 标准 css-pseudo-4 定义了更多的伪元素,浏览器实现程度不一,可以自行查阅。

下面是两个例子,说明请看注释:

<style>
    .first-letter-bigger::first-letter { 
        font-size: 2rem; /* 让类为 first-letter-bigger 的元素的第一个字母大小为 2rem */
    }
    .a-after-arrow a::after {
        content: " →"; /* 让类为 a-after-arrow 元素的后代中的 a 元素后面加上右箭头 */
    }
    .selection-black-bg::selection {
        color: white; /* 类为 selection-black-bg 选中文字后文字变为白色 */
        background-color: black; /* 类为 selection-black-bg 选中文字后文字背景变为黑色 */
    }
</style>
<p class="first-letter-bigger">
    这是一个::first-letter的例子,这是一个::first-letter的例子,这是一个::first-letter的例子,这是一个::first-letter的例子,这是一个::first-letter的例子,这是一个::first-letter的例子
</p>
<p class="a-after-arrow"><a href="https://www.w3.org/" target="_blank">https://www.w3.org/</a></p>
<p class="selection-black-bg">选中后样式变化</p>
<div style="margin: 0; border: 1px dashed; width: 20rem;">
<p class="first-letter-bigger" style="">
    这是一个::first-letter的例子,这是一个::first-letter的例子,这是一个::first-letter的例子,这是一个::first-letter的例子,这是一个::first-letter的例子,这是一个::first-letter的例子
</p>
<p class="a-after-arrow"><a href="https://www.w3.org" target="_blank">https://www.w3.org</a></p>
<p class="selection-black-bg" style="margin: 0">选中后样式变化</p>
</div>

参考文档

<style lang="scss">
    .first-letter-bigger::first-letter { 
        font-size: 2rem; 
    }
    .first-letter-bigger {
        width: 20rem;
    }
    .a-after-arrow a::after {
        content: " →"
    }
    .selection-black-bg::selection {
        color: white;
        background-color: black;
    }
    .shine:hover{ color: red; background-color: yellow; }
</style>

CSS 长度单位

CSS 中设置大小是基本操作,本节介绍常用的长度单位。width, height, margin, padding, border-width, font-size, 和 text-shadow 等等 CSS 属性都需要使用长度单位。

像素 px

浏览器的像素与设备像素(device pixel)不一样。我们在 CSS 中设置的像素实际为逻辑像素。为了了解清楚其区别和缘由,必须先解释下设备像素,DPI,DPPX 和逻辑分辨率。

一般的显示器是由一个一个微小的可发光的灯一排一排组成,每个灯叫“像素 (pixel)”。如果一个显示器的分辨率是 1920×1080,代表每一排有 1920 个像素,一共有 1080 排。所以,同样面积分辨率越大,画面就越细腻,因为有更密集的像素点,甚至肉眼无法看到屏幕的像素点,即所谓“视网膜屏幕”。这个属性是生产好显示器就确定了的,称作:设备分辨率设备像素。有时候也称为物理分辨率。

分辨率 1280×720px 经常被称作 720p。分辨率 1920×1080px 经常被称作 1080p,如果水平像素点达到 2000 左右,可以被称为 2k 分辨率,例如 2560×1600px,如果水平像素点达到 4000 左右,可以被称作 4k 分辨率,例如 3840×2160px。

DPI(Dots per inch), PPI(Pixels per inch)

分辨率和像素的密集程度没有关系,因为分辨率不反映面积,而反应像素密集程度的单位是 DPI(Dots per inch) 或者严格说来对于显示器是 PPI(Pixels per inch), 不过很多场合这两者不作区分,这里为了方便直接称作 DPI。

显示器的物理大小通常不会相差很大,特别是笔记本,家用台式机。因此 2k/4k 分辨率的显示器,通常会有更高的 DPI。也能够显示更细致的画面。

逻辑分辨率(Logic Resolution)

试想一下,如果我们有一个 100px 的图,我们的显示器是 1080p 的,现在我们升级显示器到 4k 分辨率的(屏幕尺寸不变,即 4 倍 DPI),这张图就会变成之前的 1/4 大小,文字也是同样的现象。这当然不是我们希望的,因为我们的眼睛没有跟屏幕一起升级,无法轻松辨认原先 1/4 大小的文字或图像。

于是操作系统设计了逻辑分辨率(Logic Resolution),可以让 4k 的显示器的逻辑分辨率为 1920×1080, 让 4 个设备像素显示原来的 1 个设备像素,这样我们的 100px 的图片就不会过分缩小了。

DPPX(Dots per px unit) & Device Pixel Ratio

在上面的例子中,我们将 4K 的显示器设置了 1920×1080 的逻辑分辨率。因此现在的 1 个逻辑像素,其实是有 4 个设备像素显示的,即 4 DPPX(Dots per px unit),设备像素比(Device Pixel Ratio)为 4。其中 DPPX 是的 w3c 标准化的名称,Device Pixel Ratio 会在一些旧的浏览器及文档中使用。

Windows 和 Mac 都可以设置显示的逻辑分辨率,以这台 Mac 为例:

设备分辨率(物理分辨率)为 2560×1600:


image.png

当前设置的逻辑分辨率为 1280×800:


image.png

设置好逻辑分辨率,我们的图片,文字就不会在不同 DPI 显示器显示的大小差异很大了。

但是这里有个问题:上文的例子中,原本 100×100px 的图片在高 DPI 的显示器上,用 400×400 个物理像素显示,那多余的像素怎么来呢?操作系统或者软件会进行缩放计算,得出应该填充的像素颜色。如果 dpi 是原先的两倍,那么 3/4 的像素都是计算得出的,因此图片会变的模糊。这种情况可以在高 DPI 的情况下使用同样图片的高分辨率版本,同时设置逻辑像素不变。例如将 400×400px 的图片,在 4 DPPX 的显示器上设置为 100×100px 的大小显示。通过 CSS 媒体查询(Media query) 技术可以实现。另外如果图片是“矢量图”的话,则可以自动适应不同的 DPPX,例如 SVG 图片。

在 HTML/CSS 中,设置的像素 px 实际是设置的和逻辑分辨率对应的逻辑像素,例如:

p {
  width: 500px;
  font-size: 20px;
}

rem & em

px 是绝对单位(absolute units),CSS 中还有相对单位,例如 rem 和 em。这两者都是相对于字体大小(font-size)的单位,1 rem 就是 1 倍字体大小,2 rem 就是 2倍字体大小。区别是相对于的字体来源,rem 是相对于根元素(即 html 元素)的字体(font-size)大小,而 em 是相对于当前继承的font-size大小。由于 em 受font-size的继承关系影响,因此推荐使用 rem 作单位。

vh && vw

vh(viewport height) 代表 viewport 高度的 1% 大小,vw(viewport width) 代表 viewport 高度的 1% 大小。

viewport 即浏览器的可见区域。不一定和网页一样大,例如:调节浏览器放大网页,这时候网页可能变的比浏览器更大,浏览器就好像一个窗口一样,通过他来看到整个网页的一部分,所以叫做 viewport。如果希望一个元素能正好和浏览器显示区域一样大,那么可以设置:

#fullsize {
  height: 100vh;
  width: 100vw;
}

百分比单位

百分比单位可以设置一个元素的大小为其父元素的一个百分比,父元素放大/缩小,子元素也会随之改变。例如:

<style>
  .parent300 {
    width: 300px;
  }
  .parent500 {
    width: 500px;
    margin-top: 30px;
  }
  .percentage50 {
    height: 30px;
    width: 50%;
    background-color: blue;
  }
</style>
<div class="parent300">
  <div class="percentage50">
  </div>
</div>
<div class="parent500">
  <div class="percentage50">
  </div>
</div>
<style>
  .parent300 {
    width: 300px;
    background-color: #888;
  }
  .parent500 {
    width: 500px;
    background-color: #888;
    margin-top: 10px;
  }
  .percentage50 {
    height: 30px;
    width: 50%;
    background-color: blue;
  }
</style>
<div class="parent300">
  <div class="percentage50">
  </div>
</div>
<div class="parent500">
  <div class="percentage50">
  </div>
</div>

百分比使用在font-size时相对的不是父元素,而是继承到的font-size大小,和 em 效果相同。例如 font-size: 200%font-size: 2em 效果一样。

0

在使用 0 时不需要加单位。例如 margin: 0

其他长度单位

上文介绍了常用的长度单位,可以满足常见需求。
其他长度单位可以查看MDN 文档:values & units

参考


CSS 盒模型 (Box Model)

CSS 能控制大小和距离,有哪些地方的大小和距离可以控制呢?CSS 是通过一个叫做“盒模型 (Box Model)”的模型来描述页面上所有的元素,通过设置这个“盒子”的各种属性,就可以调整任意元素的大小,距离了。

这个盒模型如下

<div class="box-image">
    <div class="margin-box">
      <span class="des margin">外边距 margin</span>
      <div class="border-box">
        <span class="des">边框 border</span>
        <div class="padding-box">
          <span class="des padding">内边距 padding</span>
          <div class="content-box">
            <span>内容 content</span>
          </div>
        </div>
      </div>
    </div>
</div>

可以看到,在盒模型中,每个元素都有 外边距 (margin)边框 (border)内边距 (padding)内容(content) 属性。这几个属性很常用,在 CSS 中是 margin, border, padding 属性,下文将直接使用英文。

设想一下,我们用一个盒子装东西。不同盒子之间有个距离,为 margin,盒子本身有个边框,为 border,盒子与里面的东西之间还有一定的距离,为 padding。最里面才是盒子里面装的东西。

Margin

margin 定义了元素和其他元素之间的距离。即如果希望两个元素靠近,则设置较小 margin,如果希望距离大,设置较大 margin。margin 可以为负,这样两个元素可能会重叠。

margin 有个特殊的属性是他可以重叠(margin collapse):相邻的元素的距离,以他们的 margin 比较大的那个决定,而不是他们的和。例如 a, b 两个元素,margin 分别是 10px, 20px 那么他们的距离是 20px。

margin 有4个方向,上右下左分别为 margin-top, margin-right, margin-bottom 和 margin-bottom。可以分别设置。

margin 的写法如下:

  • 分别设置 4 个方向: margin: 10px 20px 10px 20px。顺序是“上右下左”的顺时针顺序。
  • 缩写 margin: 10px 20px 效果是 maring-top 和 mrgin-bottom 为 10px,margin-right 和 margin-left 为 20px。缩写 margin: 10px 效果是 4 个方向的外边距都为 10px。
  • 可以单独设置 1 个方向:margin-top: 10px 上外边距为 10px。
  • 可以设置margin: auto 这时候浏览器会给一个适当的值,经常用来让块级元素水平居中。

Border

Border 定义了元素的边框,除了可以设置边框的大小粗细,还可以设置边框的样式,颜色以及圆角。大部分元素默认没有边框。

border 写法如下:

  • 设置粗细:border-width: 2px
  • 设置样式:border-style: dashedborder-style 的值还可以为 soliddotted 等。可以查看完整文档
  • 设置颜色:border-color: red
  • 设置圆角:border-radius: 5px
  • border-width, border-style, border-color 可以缩写为:border: 2px dashed red
  • 可以单独设置某一边的 border: border-right: 2px dashed red

Padding

Padding 定义了元素的内边距,即边框与内容间的距离。padding 的值也可以为负。

写法与 margin 类似,只是属性值没有auto

  • 分别设置 4 个方向: padding: 10px 20px 10px 20px。顺序是“上右下左”的顺时针顺序。
  • 缩写 padding: 10px 20px 效果是 padding-top 和 padding-bottom 为 10px,padding-right 和 padding-left 为 20px。缩写 padding: 10px 效果是 4 个方向的内边距都为 10px。
  • 可以单独设置 1 个方向:padding-top: 10px 上内边距为 10px。

内容大小

width, height 来设置内容大小,例如 width: 100px 设置了内容大小为 100px,如果与个元素有 20px 的 padding 以及 5px 的border,不算 margin, 元素的占用宽度为 100px + 20px × 2 + 5px × 2 即 150px。

在这个例子里,计算元素的宽度实在麻烦。例如我们希望设置 200px 宽的元素,需要计算 border 和 padding。而 border 和 padding 在调试外观样式的时候需要频繁修改,这样让布局变的困难。于是在 CSS3 中引入了 box-sizing 属性,让大小设置更为直观简单。

box-sizing 属性

box-sizing 有 2 值可以设置:content-box 和 border-box。

  • content-box: 默认设置,元素占用空间的大小需要 width 加上 border 和 padding。
  • border-box: 元素占用空间的大小为 width 的值。如果设置了 border 和 padding,则会挤占内容的大小,而不会撑大元素的占用空间。

一个建议的做法是设置所有元素的 box-sizing 属性都为 border-box,例如:

html {
  box-sizing: border-box;
}

*, *:before, *:after {
  box-sizing: inherit; /* box-sizing 默认不继承父元素的值 */
}

标准盒子模型与IE盒子模型

标准盒子模型.jpg

IE盒子模型.jpg

参考文档


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容

  • 问答题47 /72 常见浏览器兼容性问题与解决方案? 参考答案 (1)浏览器兼容问题一:不同浏览器的标签默认的外补...
    _Yfling阅读 13,725评论 1 92
  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5? 答:HTML5是最新的HTML标准。 注意:讲述HT...
    kismetajun阅读 27,406评论 1 45
  • HTML 5 HTML5概述 因特网上的信息是以网页的形式展示给用户的,因此网页是网络信息传递的载体。网页文件是用...
    阿啊阿吖丁阅读 3,828评论 0 0
  • 一:在制作一个Web应用或Web站点的过程中,你是如何考虑他的UI、安全性、高性能、SEO、可维护性以及技术因素的...
    Arno_z阅读 1,136评论 0 1
  • •前端面试题汇总 一、HTML和CSS 21 你做的页面在哪些流览器测试过?这些浏览器的内核分别是什么? ...
    Simon_s阅读 2,219评论 0 8