Html5入门教程系列(3)–CSS第一部分

17次阅读

说起 html5,可能是近 1 - 2 年最火的技术词汇之一了,由于市场需求爆增,人才也趋之若鹜。在整个html5 规范中,css3 可谓是最为明显,也是用的最多的。本篇开始连续两篇介绍 css 技术。

历史

css 经历了如下的变迁

Html5 入门教程系列(3)--CSS 第一部分

然而,为什么没有提到 CSS3,因为CSS3 并不是指 CSS 的某个特定版本。怎么理解呢?我来解释一下 CSS 标准制定的过程。

首先,CSS 特性被分成若干组,称为 module,每个module 有自己的独立的演进过程。演进的过程用 level 表示,不少 module 已经演进到 level3 了,所以我们习惯称为 CSS3。在每个level 上,都会经历 4 种表示成熟度的状态:

Html5 入门教程系列(3)--CSS 第一部分

我们经常看见的 WDCRPRREC 就是这四种状态的简写:

  • WD:起草状态,表示该 module 包含的特性正在研究中,进入公测阶段,不保证将来不会变化
  • CR:候选状态,表示通过公测,委员会认为基本稳定,开始征求改进意见
  • PR:提交状态,表示已经提交委员会等待发布
  • REC:发布状态,表示模块已经被推荐可广泛使用

我们来看一些例子,这个截图是从 CSS 工作组的 官方网站 截取的:

Html5 入门教程系列(3)--CSS 第一部分

从图中可以看到,例如 CSS Color Level 3 已经是 REC 状态,CSS Backgrounds and Borders Level 3才是 CR 状态,而我们在很多 H5 动画中广泛使用的动画竟然只是 WD 状态。这里的状态只是给大家一个参考,具体能不能用还要看实际场景和浏览器实现的情况。

CSS 基础部分

CSS 的用处就是修饰 html 文档,使 html 看起来更美观。如果没有 CSS 的话,html 基于从上到下(块元素),从左到右(内联元素)依次渲染标签。不同的浏览器对标签的渲染有所不同,体现在字体,边距这些基本样式上,是有差异的。所以为了能在不同的浏览器上获得相同的视觉体验,前端工程师往往需要对浏览器这种默认的行为利用 CSS 进行覆盖,我们称为reset

在实际的开发过程中,html 和 css 往往是相互配合的,不过应该尽量以 html 标签的语义为主,有些样式实在不方便表达的时候,可以通过添加无用的标签来辅助 css 工作。两者的权衡是一个前端开发人员的经验和个人习惯,没有统一的标准,但有一些可循的规律和最佳实践。随着经验的累积,会越来越轻松和顺手。所以 css 其实并不是有多难,而是需要长时间的积累的经验的功夫,就好比很多后端不是专业的 css 程序员,也能看懂 css,但是实际自己写的时候却无从下手了。

作为入门教程,本系列只是从基础开始带领大家对 css 这门语言有个基本的认识。

基本语法:属性设定

css 主要语法分两部分:属性设定 元素选择 。现在看看属性设定。假设,我希望将一个p 标签中的文字显示成红色(默认是黑色)

<p style="color:red">Hello, Html5!</p>

效果如下:

Hello, Html5!

我们使用 property:value 的形式来指定属性和值,这个例子中 color 属性将设置标签的前景色,而 red 属性是一个常量表示一个纯红色。将这样的属性设置填写在标签 pstyle属性上就可以发生作用。css 规定了大量的属性,随着 css 标准的发展,属性还在不断的增长,在本教程中,我将罗列一下常见的属性,还有很多属性的用法需要大家在日后的工作中逐渐学习掌握。

一些较新的属性可能需要用特定浏览器前缀才能工作,比如:

-moz-box-sizing
-webkit-box-sizing
-o-box-sizing
-ms-box-sizing

moz适用于 firefox,webkit适用于 chrome 和 safari,o适用于 opera,ms适用于 ie。上面的属性其实是表示同一个属性box-sizing,只是由于有些浏览器的较低版本可能无法直接理解box-sizing,而是需要使用特定的前缀。

在一个网站前端页面中,编写 css 的方式有 3 种:

  • 1. 内联样式:上面的例子就是一个内联的样式的例子,即把属性直接写在 style 中,这种写法的优先级最高
  • 2. 在 html 文档中嵌入样式:即写一个 style 标签,将样式统一写在其中
<style type="text/css">

<span class="nt">p</span> <span class="p">{</span>
    <span class="nl">color</span><span class="p">:</span> <span class="no">red</span><span class="p">;</span>
<span class="p">}</span>

</style>

  • 3. 编写一个独立的 .css 文件,将样式写在这个文件中,并在 html 的合适的位置引用这个外部文件(通常在 head 里面引用)。比如本博客的某样式引用:
<link href="/assets/css/style.css?v=1.1" rel="stylesheet">

在遇到样式冲突的时候,一般而言 1 具有最高的优先级,而 2 和 3 的优先级取决于出现的位置,越晚出现的样式会覆盖掉先前出现的样式。关于优先级还有更精细的问题后面会提到。

基本语法:选择器

属性设置 描述了对元素的外观设置,但是却无法表达目标元素到底是什么。css 基本语法的另一个重要部分叫 元素选择 ,也叫 选择器 。即一种指定 html 元素(或者叫标签) 的语法。因此,完整的 css 语法应该是:

selector {

<span class="py">property</span><span class="p">:</span> <span class="n">value</span><span class="p">;</span>

}

selector 选择器和若干属性设置对组成。由于内联样式是直接写在某个元素上的所以无需选择器,这种语法只需写在嵌入型样式和独立的 css 文件中。接下来我们来详细了解一下选择器。

最常用的选择器是 id 选择器class 选择器,例如:

<style type="text/css">

#main {

<span class="nl">width</span><span class="p">:</span> <span class="m">300px</span><span class="p">;</span>
<span class="nl">height</span><span class="p">:</span> <span class="m">20px</span><span class="p">;</span>
<span class="nl">margin</span><span class="p">:</span> <span class="m">20px</span> <span class="nb">auto</span><span class="p">;</span>
<span class="nl">background-color</span><span class="p">:</span> <span class="m">#0ff</span><span class="p">;</span>
<span class="nl">border</span><span class="p">:</span> <span class="m">1px</span> <span class="nb">solid</span> <span class="m">#ff0</span><span class="p">;</span>

}

</style>

<div id="main"></div>

上面的 css 通过嵌入 html 的形式,指定了一个 id 为 main 的元素的样式,效果如下:

此时,无论元素本身是什么元素(此例子为 div),都会在渲染的时候应用指定的样式,只要元素具有 id="main" 这个属性就能应用样式设置,这种选择器称为id 选择器

id 选择器 类似的 class 选择器,有了 id 选择器的知识,不难理解 class 选择器,对上面的例子稍作改动,将id 换成class

<style type="text/css">

.main {

<span class="nl">width</span><span class="p">:</span> <span class="m">300px</span><span class="p">;</span>
<span class="nl">height</span><span class="p">:</span> <span class="m">20px</span><span class="p">;</span>
<span class="nl">margin</span><span class="p">:</span> <span class="m">20px</span> <span class="nb">auto</span><span class="p">;</span>
<span class="nl">background-color</span><span class="p">:</span> <span class="m">#0ff</span><span class="p">;</span>
<span class="nl">border</span><span class="p">:</span> <span class="m">1px</span> <span class="nb">solid</span> <span class="m">#ff0</span><span class="p">;</span>

}

</style>

<div class="main"></div>

效果如下:

作为对比,我们可以发现 id 选择器使用 # 号,而 class 选择器使用 . 号,大家应该牢记这两个符号。

除了这两个,css 的选择器种类还有很多,而且也在不断新增,我们再来看几个例子:

<style type="text/css">

addr {

<span class="nl">display</span><span class="p">:</span> <span class="nb">block</span><span class="p">;</span>
<span class="nl">width</span><span class="p">:</span> <span class="m">300px</span><span class="p">;</span>
<span class="nl">height</span><span class="p">:</span> <span class="m">20px</span><span class="p">;</span>
<span class="nl">line-height</span><span class="p">:</span> <span class="m">20px</span><span class="p">;</span>
<span class="nl">margin</span><span class="p">:</span> <span class="m">20px</span> <span class="nb">auto</span><span class="p">;</span>
<span class="nl">background-color</span><span class="p">:</span> <span class="m">#000</span><span class="p">;</span>
<span class="nl">color</span><span class="p">:</span> <span class="m">#fff</span><span class="p">;</span>
<span class="nl">text-align</span><span class="p">:</span> <span class="nb">center</span><span class="p">;</span>

}

</style>

<addr>Hello html5!</addr>

没有 # 或者 . 开头称为 标签选择器,是直接查找元素名的,元素名可以自定义,也可以使用 html 定义好的元素,效果如下:

Hello html5!

不同的基础选择器语法可以组合:

<style type="text/css">

div#author {

<span class="nl">display</span><span class="p">:</span> <span class="nb">block</span><span class="p">;</span>
<span class="nl">width</span><span class="p">:</span> <span class="m">300px</span><span class="p">;</span>
<span class="nl">height</span><span class="p">:</span> <span class="m">20px</span><span class="p">;</span>
<span class="nl">line-height</span><span class="p">:</span> <span class="m">20px</span><span class="p">;</span>
<span class="nl">margin</span><span class="p">:</span> <span class="m">20px</span> <span class="nb">auto</span><span class="p">;</span>
<span class="nl">background-color</span><span class="p">:</span> <span class="m">#000</span><span class="p">;</span>
<span class="nl">color</span><span class="p">:</span> <span class="m">#fff</span><span class="p">;</span>
<span class="nl">text-align</span><span class="p">:</span> <span class="nb">center</span><span class="p">;</span>

}

</style>

<div id="author">Hello html5!</div>
<div>Hello html5!</div>

在这个例子中,选择的是id 为 author 的 div,所以两个条件必须同时满足才能匹配上,效果如下:

Hello html5!
Hello html5!

还有一种选择方式是基于目标之间的关系的,比如:

<style type="text/css">

div#author div {

<span class="nl">display</span><span class="p">:</span> <span class="nb">block</span><span class="p">;</span>
<span class="nl">width</span><span class="p">:</span> <span class="m">300px</span><span class="p">;</span>
<span class="nl">height</span><span class="p">:</span> <span class="m">20px</span><span class="p">;</span>
<span class="nl">line-height</span><span class="p">:</span> <span class="m">20px</span><span class="p">;</span>
<span class="nl">margin</span><span class="p">:</span> <span class="m">20px</span> <span class="nb">auto</span><span class="p">;</span>
<span class="nl">background-color</span><span class="p">:</span> <span class="m">#000</span><span class="p">;</span>
<span class="nl">color</span><span class="p">:</span> <span class="m">#fff</span><span class="p">;</span>
<span class="nl">text-align</span><span class="p">:</span> <span class="nb">center</span><span class="p">;</span>

}

</style>

<div id="author">

<span class="nt">&lt;div&gt;</span>div#author 下的 div <span class="nt">&lt;/div&gt;</span>

</div>
<div>其他 div</div>

这个例子中的 div#author div 是指 选择 id 为 author 这个 div 内部的 div,所以效果如下:

div#author 下的 div
其他 div

好了例子举到这里,接下来来看下一些常用的选择器汇总:

下面这些是基本选择器:

Html5 入门教程系列(3)--CSS 第一部分

下面这些是属性选择器,即可以对选择的元素属性进行更复杂的定义:

Html5 入门教程系列(3)--CSS 第一部分

下面这些称为伪类和伪元素:

Html5 入门教程系列(3)--CSS 第一部分

伪类可能不太好理解,作为基础教程这里就不详细展开了,举一个使用 :first-child 的例子,也是比较常用的:

  • 第一行顶部不希望有横线
  • 第二行顶部有横线
  • 第三行顶部有横线
  • 第四行顶部有横线

这里例子中,行与行之间有分割线,你可能想到对每一行的元素加一个 border-top 或者 border-bottom,但是,如果用border-top,第一行的上方也会出现横线;border-bottom 解决不了最后一行的问题,这是不希望看到的,所以上面的代码是这么写的:

<style type="text/css">

ul#t5 {

<span class="nl">list-style</span><span class="p">:</span> <span class="nb">none</span><span class="p">;</span>

}

ul#t5 li {

<span class="nl">border-top</span><span class="p">:</span> <span class="m">1px</span> <span class="nb">solid</span> <span class="m">#aaa</span><span class="p">;</span>

}

ul#t5 li:first-child {

<span class="nl">border-top</span><span class="p">:</span> <span class="nb">none</span><span class="p">;</span>

}

</style>

<ul id="t5">

<span class="nt">&lt;li&gt;</span> 第一行顶部不希望有横线 <span class="nt">&lt;/li&gt;</span>
<span class="nt">&lt;li&gt;</span> 第二行顶部有横线 <span class="nt">&lt;/li&gt;</span>
<span class="nt">&lt;li&gt;</span> 第三行顶部有横线 <span class="nt">&lt;/li&gt;</span>
<span class="nt">&lt;li&gt;</span> 第四行顶部有横线 <span class="nt">&lt;/li&gt;</span>

</ul>

我们使用 li:first-child 来选择一个 li,这个li 是其父节点 ul第一个孩子节点 ,这里的重点是li:first-child 选择的仍然是li,而不是li 的子节点。有些新手在遇到这个问题的时候可能会写出下面的代码:

ul:first-child {

<span class="nl">border-top</span><span class="p">:</span> <span class="nb">none</span><span class="p">;</span>

}

这就是理解错了。

优先级

从 css 的书写方式和选择器设计来看,很难保证不会出现样式冲突的问题,那么久必须要规定一种优先级机制来保证行为的一致。在 css 中考察优先级有三个大的方面:

  • 1) 如果属性设置有出现了!important,那么优先级最高,甚至高于内联写法。
color: #999!important
  • 2) 其次内联书写方式优先级比较高。
  • 3) 使用选择器进行样式设定时,如果不同的选择器指向了相同的元素,并且属性属性设置有重复和冲突,那么 选择器越具体的优先级越高。关注这一点下面会详细展开。
  • 4) 如果上述判断都无法决断,那么出现顺序越晚的优先级越高,即后来的覆盖之前的。

根据 3)来看,选择器有个所谓的具体不具体,拿生活中的例子来说,就好比:

  • 去买点水果
  • 去买点苹果
  • 去买点红富士苹果
  • 去买点 5 块钱以上的红富士苹果
  • 去家乐福买点 5 块钱以上的红富士苹果

这几个指令,显然最后一个更详细,更具体。作为浏览器更重视最后一个。言归正传,选择器有很多种,还可以互相组合,为了能够无异议的表达具体与否,每种基础选择器都有相应的分值,组合的选择器就是把基础的选择器相加得到最后的分值。如下表:

Html5 入门教程系列(3)--CSS 第一部分

  • 标签选择器 伪元素选择器 ,具有 c 级的 1 分,多个 标签选择器 组合就是对 c 值进行累加
  • class 选择器 属性选择器 伪类 ,具有 b 级的 1 分,出现多个class 选择器 就是对 b 值进行累加
  • id 选择器 ,具有 a 级的 1 分,出现多个id 选择器 就是对 a 值进行累加

对于 :not() 伪类,括号内的选择器将正常计数,但是 :not() 本身不计数(本来应该 b +1)

上述规则可参见 官方 Calculating a selector’s specificity

可以看到,从 具体 的角度而言,显然 id 选择器 更具体,浏览器认为 id 选择器 是很精确的,而 标签选择器 浏览器不认为是一种精确的选择。通过这样的计算方法,可以算出选择器的 具体值,从而判断优先级,具体指越大,优先级越高。

不过这不代表我们在书写 css 的时候都要用 id 选择器 来避免歧义和优先级判断。相反,前端工程师们,经常利用这一点,实现了很多 css 库,这些库往往都使用较为低优先级的策略,从而使得用户可以自行在需要的时候用高优先级的选择器进行覆盖。

继承性

继承相对比较好理解。如果父元素定义了font(字体),那么子元素默认是会继承这个定义的,除非子元素自己重新定义一下font。比如:

<style type="text/css">

.parent {

<span class="nl">font-size</span><span class="p">:</span> <span class="m">25px</span><span class="p">;</span>
<span class="nl">text-align</span><span class="p">:</span> <span class="nb">center</span><span class="p">;</span>

}

</style>

<div class="parent">

我是父节点里面的文字
<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"child"</span><span class="nt">&gt;</span> 我是子节点里面的文字 <span class="nt">&lt;/div&gt;</span>

</div>

我是父节点里面的文字

我是子节点里面的文字

可以看到子节点的文字也变大了,并且跟父节点的文字大小相同,因为子节点并没有指定字体大小,所以继承了最近的父节点的字体大小。如果此时设置子节点的字体大小,就可以覆盖掉父节点的字体大小:

<style type="text/css">

.parent {

<span class="nl">font-size</span><span class="p">:</span> <span class="m">25px</span><span class="p">;</span>
<span class="nl">text-align</span><span class="p">:</span> <span class="nb">center</span><span class="p">;</span>

}

.child {

<span class="nl">font-size</span><span class="p">:</span> <span class="m">10px</span><span class="p">;</span>

}

</style>

<div class="parent">

我是父节点里面的文字
<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"child"</span><span class="nt">&gt;</span> 我是子节点里面的文字 <span class="nt">&lt;/div&gt;</span>

</div>

我是父节点里面的文字

我是子节点里面的文字

正文完