专栏首页王大锤前端入门系列之CSS

前端入门系列之CSS

CSS (Cascading Style Sheets) 是用来样式化和排版你的网页的 —— 例如更改网页内容的字体、颜色、大小和间距,将内容分割成多列或者加入动画以及别的装饰型效果。


CSS是什么

CSS是一种用于向用户指定文档如何呈现的语言 — 它们如何被指定样式、布局等。

文档通常是用标记语言结构化的文本文件 — HTML 是最常用的标记语言, 但你依然可以遇见一些其他的标记语言,比如 SVG 或者 XML


CSS如何影响HTML

Web浏览器将CSS规则应用于文档以影响它们的显示方式。一个CSS规则由以下组成:

  • 一组 属性 ,属性的值更新了 HTML 的内容的显示方式。比如,我想让元素的宽度是其父元素的50%,或者元素背景变为红色。
  • 一个 选择器,它选择元素,这(些)元素是你想应用这些最新的属性值于其上的元素。比如,我想将我的CSS规则应用到我HTML文档中的所有段落上。
外部样式表

外部样式表是指:当你将你的 CSS 保存在一个独立的扩展名为 .css 的文件中,并从HTML的 <link> 元素中引用它。此时 HTML 文件看起来像这样:

    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8">
        <title>My CSS experiment</title>
        <link rel="stylesheet" href="style.css">
      </head>
      <body>
        <h1>Hello World!</h1>
        <p>This is my first CSS example</p>
      </body>
    </html>

以及下面的 CSS 文件

    h1 {
      color: blue;
      background-color: yellow;
      border: 1px solid black;
    }

    p {
      color: red;
    }

这种方法可以说是最好的,因为你可以使用一个样式表来设置多个文档的样式,并且需要更新 CSS 的时候只要在一个地方更新。

内部样式表

内部样式表是指不使用外部 CSS 文件,而是将你的 CSS 放置在<style> 元素中,该元素包含在 HTML head 内。此时HTML看起来像这样:

<!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8">
        <title>My CSS experiment</title>
        <style>
          h1 {
            color: blue;
            background-color: yellow;
            border: 1px solid black;
          }

          p {
            color: red;
          }
        </style>
      </head>
      <body>
        <h1>Hello World!</h1>
        <p>This is my first CSS example</p>
      </body>
    </html>

这在某些情况下很有用(也许你正在使用一个内容管理系统,不能直接修改 CSS 文件),但它不如外部样式表高效 —— 在网站中,CSS 将需要在每个页面重复,并且需要更新时要更改的多个位置。

内联样式

内联样式是仅影响一个元素的CSS声明,被 style 属性包括着:

<!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8">
        <title>My CSS experiment</title>
      </head>
      <body>
        <h1 style="color: blue;background-color: yellow;border: 1px solid black;">Hello World!</h1>
        <p style="color:red;">This is my first CSS example</p>
      </body>
    </html>

除非有必要,否则不要这么做!这很难维护(你可能不得不在每份文档里更新多次同样的信息),并且它还混合了 CSS 表示的样式信息和 HTML 的结构信息,使 CSS 难以阅读和理解。保持不同类型代码的分离和纯净使处理该代码的任何人工作更为容易。

您唯一可能需要使用内联样式是当您的工作环境真的非常受限(也许您的CMS只允许您编辑 HTML 的 body)。


CSS如何工作

当浏览器显示文档时,它必须将文档的内容与其样式信息结合。它分两个阶段处理文档:

  1. 浏览器将 HTMLCSS 转化成 DOM文档对象模型)。DOM在计算机内存中表示文档。它把文档内容和其样式结合在一起。
  2. 浏览器显示 DOM 的内容。

DOM是什么

HTML DOM 是关于如何获取、修改、添加或删除 HTML 元素的标准。它是一个抽象概念。(????)

让我们假定下面这段HTML代码:

    <p>
      Let's use:
      <span>Cascading</span>
      <span>Style</span>
      <span>Sheets</span>
    </p>

在该 DOM 中,我们的 <p> 元素所对应的节点是父节点。它的子节点是一个文本节点和我们的一些 <span> 元素对应的节点。这些 SPAN结点也是父节点,它们各自的文本节点就是它们的子节点:

P
    ├─ "Let's use:"
    ├─ SPAN
    |  └─ "Cascading"
    ├─ SPAN
    |  └─ "Style"
    └─ SPAN
       └─ "Sheets"

这就是浏览器解释先前的HTML片段的过程 —它渲染上述的DOM树,之后在浏览器中像这样输出它。


CSS语法

从最基本的层次来看,CSS是由两块内容组合而成的:

  • 属性(Property): 一些人类可理解的标识符,这些标识符指出你想修改哪一些样式,例如:字体,宽度,背景颜色等。
  • 属性值(Value): 每个指定的属性都需要给定一个值,这个值表示你想把那些样式特征修改成什么样,例如,你想把字体,宽度或背景颜色改成什么。

与值配对的属性被称为CSS声明。CSS声明会被放置在一个CSS声明块中。最后,CSS声明块与选择器相结合形成一个CSS规则集(或CSS规则)

CSS声明

CSS 的属性和属性值都是区分大小写的。属性和属性值之间,用英文半角冒号 (:) 隔离,如下图所示。

css 语法 - 声明

CSS 有超过300 个不同的属性以及几乎无穷无尽的属性值。属性和属性值不能任意组合:每个属性都有一个已经定义好的可用属性值范围。

重要: 如果使用了未知属性,或者给属性赋予了无效值,该声明会被视为无效,浏览器的 CSS 引擎会完全忽略它。

重要: 在 CSS(和其他网络标准)中,使用美式拼写作为单词的标准写法。例如,颜色(见于上述代码所见)应始终拼写为 color。写成 colour会无法正常工作。

CSS声明块

声明按分组,每一组声明都用一对大括号包裹,用 ({) 开始,用 (}) 结束。

声明块里的每一个声明必须用半角分号(;)分隔,否则代码会不生效(至少不会按预期结果生效)。声明块里的最后一个声明结束的地方,不需要加分号,但是最后加分号是个好习惯,因为可以防止在后续增加声明时忘记加分号。

注意: 块有时候是可以嵌套的。这种情况下,每一对括号必须逻辑上嵌套,跟嵌套 HTML 元素的标签嵌套方式相同。最常见的例子是 _@-rules,_这是一种用 @ 标识开头的块,例如 @media, @font-face等(详见下述的 CSS 语句

注意: 声明块的内容允许为空 —— 这完全有效。

CSS选择器和规则

我们需要讨论一下如何告知我们的声明块:哪些元素是它们需要应用的。通过在每个声明块前加上选择器(selector) 来完成这一动作,选择器是一种模式,它能在页面上匹配一些元素。这将使相关的声明仅被应用到被选择的元素上。选择器加上声明块被称为 规则集(ruleset),通常简称规则rule)。

CSS语句

CSS 规则只是被称为 CSS 语句中的一种。

  • @-规则(At-rules) 在CSS中被用来传递元数据、条件信息或其它描述性信息。它由(@)符号开始,紧跟着一个表明它是哪种规则的描述符,之后是这种规则的语法块,并最终由一个半角分号(;)结束。每种由描述符定义的@-规则,都有其特有的内部语法和语义。一些例子如下:

    @import 'custom.css'; 该@-规则向当前 CSS 导入其它 CSS 文件

  • 嵌套语句 是@-规则中的一种,它的语法是 CSS 规则的嵌套块,只有在特定条件匹配时才会应用到文档上。特定条件如下:
    • @media 只有在运行浏览器的设备匹配其表达条件时才会应用该@-规则的内容;
    • @supports 只有浏览器确实支持被测功能时才会应用该@-规则的内容;
    • @document 只有当前页面匹配一些条件时才会应用该@-规则的内容。具体语法示例

    @media (min-width: 801px) { body { margin: 0 auto; width: 800px; } } 上述的嵌套语句只有在页面宽度超过801像素时才会应用。


CSS选择器

选择器可以被分为以下类别:

  • 简单选择器(Simple selectors): 通过元素类型、classid 匹配一个或多个元素。
  • 属性选择器(Attribute selectors): 通过 属性 / 属性值 匹配一个或多个元素。
  • 伪类(Pseudo-classes): 匹配处于确定状态的一个或多个元素,比如被鼠标指针悬停的元素,或当前被选中或未选中的复选框,或元素是DOM树中一父节点的第一个子节点。
  • 伪元素(Pseudo-elements): 匹配处于相关的确定位置的一个或多个元素,例如每个段落的第一个字,或者某个元素之前生成的内容。
  • 组合器(Combinators): 这里不仅仅是选择器本身,还有以有效的方式组合两个或更多的选择器用于非常特定的选择的方法。例如,你可以只选择divs的直系子节点的段落,或者直接跟在headings后面的段落。
  • 多重选择器(Multiple selectors): 这些也不是单独的选择器;这个思路是将以逗号分隔开的多个选择器放在一个CSS规则下面, 以将一组声明应用于由这些选择器选择的所有元素。

简单选择器

1) 类选择器 类选择器由一个点“.”以及类后面的类名组成。类名是在HTML class文档元素属性中没有空格的任何值。由你自己选择一个名字。同样值得一提的是,文档中的多个元素可以具有相同的类名,而单个元素可以有多个类名(以空格分开多个类名的形式书写)。

我们来看一个例子: 这是一些HTML:

      <ul>
        <li class="first done">Create an HTML document</li>
        <li class="second done">Create a CSS style sheet</li>
        <li class="third">Link them all together</li>
      </ul>

这是一些CSS样式:

    /* The element with the class "first" is bolded */
    .first {
      font-weight: bold;
    }

    /* All the elements with the class "done" are strike through */
    .done {
      text-decoration: line-through;
    }

效果:

  • Create an HTML document
  • Create a CSS style sheet
  • Link them all together

2) 类型选择器 此选择器只是一个选择器名和指定的HTML元素名的不区分大小写的匹配。这是选择所有指定类型的最简单方式。让我们一起看看下面这个例子:

这是HTML:

    <p>What color do you like?</p>
    <div>I like blue.</div>
    <p>I prefer red!</p>

这是样式表:

    /* All p elements are red */
    p {
      color: red;
    }

    /* All div elements are blue */
    div {
      color: blue;
    }

效果:

What color do you like?

I like blue.

I prefer red!

3) ID选择器 ID选择器是由一个哈希/磅符号 (#),后面跟着给定元素的ID名称组成的。 任何元素都可以使用id属性设置唯一的ID名称。 由你自己决定选择一个ID名称是什么。 这是选择单个元素的最有效的方式。 重要提示:一个ID名称必须在文档中是唯一的。关于重复ID的行为是不可预测的,比如一些浏览器只是计入第一个实例,其余的将被忽略。

我们来看一个简单的例子 - 这是HTML:

    <p id="polite"> — "Good morning."</p>
    <p id="rude"> — "Go away!"</p>

这是样式表:

      #polite {
        font-family: cursive;
      }

      #rude {
        font-family: monospace;
        text-transform: uppercase;
      }

效果:

— "Good morning."

— "GO AWAY!"

4) 通用选择器 通用选择(*)是最终的王牌。它允许选择在一个页面中的所有元素。由于给每个元素应用同样的规则几乎没有什么实际价值,更常见的做法是与其他选择器结合使用(参考下面 组合 .)

重要提示:使用通用选择时小心。因为它适用于所有的元素,在大型网页利用它可能对性能有明显的影响:网页可能显示比预期要慢。大多数情况下,你都不会使用这个选择器。

例如,这是HTML:

    <div>
      <p>I think the containing box just needed
      a <strong>border</strong> or <em>something</em>,
      but this is getting <strong>out of hand</strong>!</p>
    </div>

这是样式表:

* {
      padding: 5px;
      border: 1px solid black;
      background: rgba(255,0,0,0.25)
    }

属性选择器

属性选择器是一种特殊类型的选择器,它根据元素的属性和属性值来匹配元素。它们的通用语法由方括号 ([]) 组成,其中包含属性名称,后跟可选条件以匹配属性的值。 属性选择器可以根据其匹配属性值的方式分为两类: 存在和值属性选择器和子串值属性选择器。

1) 存在和值(Presence and value)属性选择器

这些属性选择器尝试匹配精确的属性值:

  • [attr]:该选择器选择包含 attr 属性的所有元素,不论 attr 的值为何。
  • [attr=val]:该选择器仅选择 attr 属性被赋值为 val 的所有元素。
  • [attr~=val]:该选择器仅选择具有 attr 属性的元素,而且要求 val 值是 attr 值包含的被空格分隔的取值列表里中的一个。

让我们看一个特别的例子,下面是它的的HTML代码:

我的食谱配料: <i lang="fr-FR">Poulet basquaise</i>
    <ul>
      <li data-quantity="1kg" data-vegetable>Tomatoes</li>
      <li data-quantity="3" data-vegetable>Onions</li>
      <li data-quantity="3" data-vegetable>Garlic</li>
      <li data-quantity="700g" data-vegetable="not spicy like chili">Red pepper</li>
      <li data-quantity="2kg" data-meat>Chicken</li>
      <li data-quantity="optional 150g" data-meat>Bacon bits</li>
      <li data-quantity="optional 10ml" data-vegetable="liquid">Olive oil</li>
      <li data-quantity="25cl" data-vegetable="liquid">White wine</li>
    </ul>

和一个简单的样式表:

/* 所有具有"data-vegetable"属性的元素将被应用绿色的文本颜色 */
    [data-vegetable] {
      color: green
    }

    /* 所有具有"data-vegetable"属性且属性值刚好为"liquid"的元素将被应用金色的背景颜色 */
    [data-vegetable="liquid"] {
      background-color: goldenrod;
    }

    /* 所有具有"data-vegetable"属性且属性值包含"spicy"的元素,
    即使元素的属性中还包含其他属性值,都会被应用红色的文本颜色 */
    [data-vegetable~="spicy"] {
      color: red;
    }

效果: TODO:

2) 子串值(Substring value)属性选择器 这种情况的属性选择器也被称为“伪正则选择器”,因为它们提供类似 regular expression 的灵活匹配方式(但请注意,这些选择器并不是真正的正则表达式):

  • [attr|=val] : 选择attr属性的值是 val 或值以 val- 开头的元素(注意,这里的 “-” 不是一个错误,这是用来处理语言编码的)。
  • [attr^=val] : 选择attr属性的值以 val 开头(包括 val)的元素。
  • [attr$=val] : 选择attr属性的值以 val 结尾(包括 val)的元素。
  • [attr*=val] : 选择attr属性的值中包含子字符串 val 的元素(一个子字符串就是一个字符串的一部分而已,例如,”cat“ 是 字符串 ”caterpillar“ 的子字符串)。

让我们继续我们前面的例子,并添加以下CSS规则:

/* 语言选择的经典用法 */
    [lang|="fr"] {
      font-weight: bold;
    }

    /* 
        具有"data-vegetable"属性含有值"not spicy"的所有元素,都变回绿色
    */
    [data-vegetable*="not spicy"] {
      color: green;
    }

    /* 
       具有"data-quantity"属性其值以"kg"结尾的所有元素*/
    [data-quantity$="kg"] {
      font-weight: bold;
    }

    /* 
       具有属性"data-quantity"其值以"optional"开头的所有元素 
    */
    [data-quantity^="optional"] {
      opacity: 0.5;
    }

效果: TODO:

伪类和伪元素

该选择器不是选择元素,而是元素的某些部分,或仅在某些特定上下文中存在的元素。它们有两种主要类型 : 伪类和伪元素。 1)伪类 一个 CSS 伪类(pseudo-class) 是一个以冒号(:)作为前缀,被添加到一个选择器末尾的关键字,当你希望样式在特定状态下才被呈现到指定的元素时,你可以往元素的选择器后面加上对应的伪类(pseudo-class)。你可能希望某个元素在处于某种状态下呈现另一种样式,例如当鼠标悬停在元素上面时,或者当一个复选框被禁用或被勾选时,又或者当一个元素是它在 DOM 树中父元素的第一个子元素时。

现在,让我们来看一个简单的使用例子。首先是一个 HTML 片段:

<a href="https://developer.mozilla.org/" target="_blank">Mozilla Developer Network</a>

然后,一些 CSS 样式:

/* 这些样式将在任何情况下应用于我们
    的链接 */

    a {
      color: blue;
      font-weight: bold;
    }

    /* 我们想让被访问过的链接和未被访问
    的链接看起来一样 */

    a:visited {
      color: blue;
    }

    /* 当光标悬停于链接,键盘激活或锁定
    链接时,我们让链接呈现高亮 */

    a:hover,
    a:active,
    a:focus {
      color: darkred;
      text-decoration: none;
    }

效果: TODO:

2)伪元素 伪元素(Pseudo-element)跟伪类很像,但它们又有不同的地方。它们都是关键字,但这次伪元素前缀是两个冒号 (::) , 同样是添加到选择器后面去选择某个元素的某个部分。

我们在这里仅展示一个简单的 CSS 例子,就是如何在所有超链接元素后面的增加一个箭头:

<ul>
      <li><a href="https://developer.mozilla.org/en-US/docs/Glossary/CSS">CSS</a> defined in the MDN glossary.</li>
      <li><a href="https://developer.mozilla.org/en-US/docs/Glossary/HTML">HTML</a> defined in the MDN glossary.</li>
    </ul>

让我们加上 CSS 规则:

/* 所有含有"href"属性并且值以"http"开始的元素,
    将会在其内容后增加一个箭头(去表明它是外部链接)
    */

    [href^=http]::after {
      content: '⤴';
    }

组合器和选择器组

将多个选择器组合在一起以进一步利用其选择能力。

名称

-------组合器

选择

选择器组

A,B

匹配满足A(和/或)B的任意元素(参见下方 同一规则集上的多个选择器).

后代选择器

A B

匹配B元素,满足条件:B是A的后代结点(B是A的子节点,或者A的子节点的子节点)

子选择器

A > B

匹配B元素,满足条件:B是A的直接子节点

相邻兄弟选择器

A + B

匹配B元素,满足条件:B是A的下一个兄弟节点(AB有相同的父结点,并且B紧跟在A的后面)

通用兄弟选择器

A ~ B

匹配B元素,满足条件:B是A之后的任意一个兄弟节点(AB有相同的父节点,B在A之后,但不一定是紧挨着A)

接下来看一个使用了组合器的例子:

<table lang="en-US" class="with-currency">
  <thead>
    <tr>
      <th scope="col">Product</th>
      <th scope="col">Qty.</th>
      <th scope="col">Price</th>
    </tr>
  </thead>
  <tfoot>
    <tr>
      <th colspan="2" scope="row">Total:</th>
      <td>148.55</td>
    </tr>
  </tfoot>
  <tbody>
    <tr>
      <td>Lawnchair</td>
      <td>1</td>
      <td>137.00</td>
    </tr>
    <tr>
      <td>Marshmallow rice bar</td>
      <td>2</td>
      <td>1.10</td>
    </tr>
    <tr>
      <td>Book</td>
      <td>1</td>
      <td>10.45</td>
    </tr>
  </tbody>
</table>

然后对该HTML文档应用下面的样式表:

/* 基本的table样式(类型选择器/元素选择器/element selector) */
table {
  font: 1em sans-serif;
  border-collapse: collapse;
  border-spacing: 0;
}

/* 所有在table里的td以及th,这里的逗号不是一个组合器,
它只是允许你把几个选择器对应到相同的CSS规则上.*/
table td, table th {
  border : 1px solid black;
  padding: 0.5em 0.5em 0.4em;
}

/* 所有table里的thead里的所有th */
table thead th {
  color: white;
  background: black;
}

/* 所有table里的tbody里的所有td(第一个除外),每个td都是由它上边的td选择 */
table tbody td + td {
  text-align: center;
}

/*table里所有的tbody里的td当中的最后一个 */
table tbody td:last-child {
  text-align: right
}

/* 所有table里的tfoot里的th */
table tfoot th {
  text-align: right;
  border-top-width: 5px;
  border-left: none;
  border-bottom: none;
}

/* 在table当中,所有的th之后的td */
table th + td {
  text-align: right;
  border-top-width: 5px;
  color: white;
  background: black;
}

/* 定位在“with-currency”类中拥有属性lang并且这个属性值为en-US的元素中的,最后td(:last-child)节点的前面(::before)*/
.with-currency[lang="en-US"] td:last-child::before {
  content: '$';
}

/* 定位在“with-currency”类中拥有属性lang并且这个属性值为fr的元素中的,最后td(:last-child)节点的后面(::after) */
.with-currency[lang="fr"] td:last-child::after {
  content: ' €';
}

表格如下:

Product

Qty.

Price

Total:

148.55

Lawnchair

1

$137.00

Marshmallow rice bar

2

$1.10

Book

1

$10.45

Total:

$148.55


CSS数值和单位

数值:

p {
  margin: 5px;
  padding: 10px;
  border: 2px solid black;
  background-color: cyan;
}

p:nth-child(1) {
  width: 150px;
  font-size: 18px;
}

p:nth-child(2) {
  width: 250px;
  font-size: 24px;
}

p:nth-child(3) {
  width: 350px;
  font-size: 30px;
}

绝对单位

像素 (px) 是一种绝对单位(absolute units 因为无论其他相关的设置怎么变化,像素指定的值是不会变化的。其他的绝对单位如下:

  • mm, cm, in: 毫米(Millimeters),厘米(centimeters),英寸(inches)
  • pt, pc: 点(Points (1/72 of an inch)), 十二点活字( picas (12 points.))

除了px之外,你很可能都不怎么使用其他的单位。 绝对单位之间的关系如下: 1in = 2.54cm = 25.4mm = 72pt = 6pc

相对单位

  • em:1em与当前元素的字体大小相同(更具体地说,一个大写字母M的宽度)。CSS样式被应用之前,浏览器给网页设置的默认基础字体大小是16像素,这意味着对一个元素来说1em的计算值默认为16像素。但是要小心—em单位是会继承父元素的字体大小,所以如果在父元素上设置了不同的字体大小,em的像素值就会变得复杂。现在不要过于担心这个问题,我们将在后面的文章和模块中更详细地介绍继承和字体大小设置。em是Web开发中最常用的相对单位
  • ex, ch: 分别是小写x的高度和数字0的宽度。这些并不像em那样被普遍使用或很好地被支持。
  • rem: REM(root em)和em以同样的方式工作,但它总是等于默认基础字体大小的尺寸;继承的字体大小将不起作用,所以这听起来像一个比em更好的选择,虽然在旧版本的IE上不被支持(查看关于跨浏览器支持 Debugging CSS.)
  • vw, vh: 分别是视口宽度的1/100和视口高度的1/100,其次,它不像rem那样被广泛支持。

无单位的值

在CSS中,你有时会遇到一些无单位的数值——这并不总是意味着错误,在某些情况下,使用无单位的数值是完全允许的。例如,如果你想让一个元素完全去除边距或者边框,你可以使用无单位的0——因为不管单位是什么,0就是0!

1 边距

margin: 0;

2 行高

另一个例子是 line-height,设置元素中每行文本的高度。你可以使用单位设置特定的行的高度,但使用一个无单位的值往往更容易,它就像一个简单的乘法因子。例如

下面的CSS:

p {
  line-height: 1.5;
}

这里font-size的值为16px; 行高为font-size值的1.5倍,也就是24px。

3 动画的值

p:hover {
  animation-name: rotate;
  animation-duration: 0.6s;
  animation-timing-function: linear;
  animation-iteration-count: 5;
}

animation-iteration-count: 5; ——此行控制着动画启动(这里是指光标浮动至段落上时)后会执行多少次,而且这是一个简单的,无单位,纯数字(计算机中称之为整型)。

百分比

首先,使用HTML标记创建两个相似的盒子:

<div>
  <div class="boxes">Fixed width layout with pixels</div>
  <div class="boxes">Liquid layout with percentages</div>
</div>

然后是一些CSS来装饰这些盒子:

div .boxes {
  margin: 10px;
  font-size: 200%;
  color: white;
  height: 150px;
  border: 2px solid black;
}

.boxes:nth-child(1) {
  background-color: red;
  width: 650px;
}

.boxes:nth-child(2) {
  background-color: blue;
  width: 75%;
}

这两种不同的框布局类型通常被称为动态(流体)布局(跟随浏览器视口大小的变化)和固定宽度布局(不管怎样都保持不变),两种布局方式有着不同的应用场景:

颜色

和iOS一样,有一下几种表示方式:

  1. 十六进制值
p:nth-child(1) {
  background-color: #ff0000;
}
  1. RGB:
p:nth-child(1) {
  background-color: rgb(255,0,0);
}
  1. HSL
p:nth-child(1) {
  background-color: hsl(0,100%,50%);
}

hsl()函数接受三个表示色调饱和度以及亮度的参数

  1. RGBA, HSLA,增加一个alpha通道

层叠和继承

有多个选择器匹配到同一个元素上时,哪个选择器的 CSS 规则最终会应用到元素上?其实这是通过层叠机制来控制的,这也和样式继承(元素从其父元素那里获得属性值)有关。

层叠

CSS 是 Cascading Style Sheets 的缩写,这暗示层叠(cascade)的概念是很重要的。在最基本的层面上,它表明CSS规则的顺序很重要,但它比那更复杂。什么选择器在层叠中胜出取决于三个因素(这些都是按重量级顺序排列的——前面的的一种会否决后一种):

  1. 重要性(Importance)
  2. 专用性(Specificity)
  3. 源代码次序(Source order)

1 重要性 在CSS中,有一个特别的语法可以让一条规则总是优先于其他规则:!important。把它加在属性值的后面可以使这条声明有无比强大的力量。 显示声明重要性!

让我们看一下这个例子:

<p class="better">This is a paragraph.</p>
<p class="better" id="winning">One selector to rule them all!</p>
#winning {
  background-color: red;
  border: 1px solid black;
}

.better {
  background-color: gray;
  border: none !important;
}

p {
  background-color: blue;
  color: white;
  padding: 5px;
}

让我们一起来看看发生了什么。

  1. 你可以看到第三条规则 colorpadding 被运用了, 但 background-color没有,为什么?实际上,这三种情况都应该应用,因为在源顺序后面的规则通常会覆盖较早的规则。
  2. 然而, 在前面的规则被运用了,因为 IDs/class 选择器优先于element选择器。 (对此,你将在下一章中学到更多)
  3. 这两个元素都有 class并带有 better属性, 但是第二个元素有 id 值为winning 。 因为比起class而言id专用性更高(在一个页面上id是唯一的, 但很多元素可以拥有相同的class — ID 选择器在它们的目标中是非常优先的),红色背景色和1pixel的黑色边框都应应用于第二元素,第一个元素获得灰色背景色,没有边框,如类所指定。
  4. 第二个元素获得红色背景色,但没有边框。为什么?因为 !important 在第二条规则中的声明——在 border: none之后写入它意味着尽管id具有更高的优先性,该声明也将优先于前面规则中的边界值声明。

不要使用 !important 我们建议你千万不要使用它,除非你绝对必须使用它。由于 !important 改变了层叠正常工作的方式,因此调试CSS问题,尤其是在大型样式表中,会变得非常困难。

冲突处理 要注意一个CSS声明的重要性取决于它被指定在什么样式表内——用户可以设置自定义样式表覆盖开发者的样式,例如用户可能有视力障碍,想设置字体大小对所有网页的访问是双倍的正常大小,以便更容易阅读。

相互冲突的声明将按以下顺序适用,后一种将覆盖先前的声明:

  1. 在用户代理样式表的声明 (浏览器默认样式).
  2. 用户样式表中的普通声明(由用户设置的自定义样式)。
  3. 作者样式表中的普通声明(这是我们设置的样式,Web开发人员)。
  4. 作者样式表中的重要声明(Web开发人员!important)
  5. 用户样式表中的重要声明(用户!important)

2 专用性 专用性基本上是衡量选择器的具体程度的一种方法——它能匹配多少元素。如上面所示的示例所示,元素选择器具有很低的专用性。类选择器具有更高的专用性,所以将战胜元素选择器。ID选择器有甚至更高的专用性, 所以将战胜类选择器. 战胜ID选择器的唯一方法是使用 !important。 选择越唯一越专用!

一个选择器具有的专用性的量是用四种不同的值(或组件)来衡量的,它们可以被认为是千位,百位,十位和个位——在四个列中的四个简单数字:

  1. 千位:如果声明是在style 属性中该列加1分(这样的声明没有选择器,所以它们的专用性总是1000。)否则为0。
  2. 百位:在整个选择器中每包含一个ID选择器就在该列中加1分。
  3. 十位:在整个选择器中每包含一个类选择器、属性选择器、或者伪类就在该列中加1分。
  4. 个位:在整个选择器中每包含一个元素选择器或伪元素就在该列中加1分。

下表显示了几个示例。试着通过这些,并确保你理解他们为什么具有我们给予他们的专用性。

选择器

千位

百位

十位

个位

合计值

h1

0

0

0

1

0001

#indentifier

0

1

0

0

0100

h1 + p::first-letter

0

0

0

3

0003

li > a[href*="zh-CN"] > .inline-warning

0

0

2

2

0022

没有选择器, 规则在一个元素的 <style> 属性里

1

0

0

0

1000

在我们继续之前,让我们看看一个行动中的例子。这是我们将要使用的HTML:

<div id="outer" class="container">
  <div id="inner" class="container">
    <ul>
      <li class="nav"><a href="#">One</a></li>
      <li class="nav"><a href="#">Two</a></li>
    </ul>
  </div>
</div>

下面是CSS的示例:

/* specificity: 0101 */
#outer a {
  background-color: red;
}

/* specificity: 0201 */
#outer #inner a {
  background-color: blue;
}

/* specificity: 0104 */
#outer div ul li a {
  color: yellow;
}

/* specificity: 0113 */
#outer div ul .nav a {
  color: white;
}

/* specificity: 0024 */
div div li:nth-child(2) a:hover {
  border: 10px solid black;
}

/* specificity: 0023 */
div li:nth-child(2) a:hover {
  border: 10px dashed black;
}

/* specificity: 0033 */
div div .nav:nth-child(2) a:hover {
  border: 10px double black;
}

a {
  display: inline-block;
  line-height: 40px;
  font-size: 20px;
  text-decoration: none;
  text-align: center;
  width: 200px;
  margin-bottom: 10px;
}

ul {
  padding: 0;
}

li {
  list-style-type: none;
}

这里发生了什么?首先,我们只对本例的前七个规则感兴趣,正如您将注意到的,我们已经在每个注释中包含了它们的专用性值。

  • 前两个选择器正在竞争链接的背景颜色的样式——第二个赢得并使背景色为蓝色,因为它有一个额外的ID选择器在链中:其专用性值为201比101。
  • 第三个和第四个选择器在链接文本颜色的样式上进行竞争——第二个选择器获胜,使文本变白,因为缺少一个元素选择器,缺少的选择器被换成类选择器,它的值是十,而不是个位。所以专用性值为113和104。
  • 选择器5 - 7在徘徊在链接附近时的样式进行竞争。选择器六明显地输给了了五,其专用性值为23和24——它在链中少了一个元素选择器。然而选择器七同时击败了五和六——它有与五相同数量的子选择器在链中,但一个元素已被换为了一个类选择器。所以获胜的专用性值是33比23和24。

3 源代码次序 如上所述,如果多个相互竞争的选择器具有相同的重要性和专用性,那么第三个因素将帮助决定哪一个规则获胜——后面的规则将战胜先前的规则

注意:(属性覆盖其他属性而不是规则凌驾于规则之上) 在考虑所有这些层叠理论和什么样式优先于其他样式被应用时,你应该记住的一件事是,所有这些都发生在属性级别上——属性覆盖其他属性,但你不会让整个规则凌驾于其他规则之上。

当多个CSS规则匹配相同的元素时,它们都被应用到该元素中。只有在这之后,任何相互冲突的属性才会被评估,以确定哪种风格会战胜其他类型。

层叠结束


继承

应用于某个元素的一些属性值将由该元素的子元素继承,而有些则不会。

  • 例如,对 font-familycolor 进行继承是有意义的,因为这使得您可以很容易地设置一个站点范围的基本字体,方法是应用一个字体到 <html> 元素;然后,您可以在需要的地方覆盖单个元素的字体。如果要在每个元素上分别设置基本字体,那就太麻烦了。
  • 再如,让 marginpaddingborderbackground-image 不被继承是有意义的。想象一下,如果在容器元素上设置这些属性并让它们由每个子元素继承,那么样式/布局会发生混乱,然后必须在每个单独的元素上_取消_它们!

哪些属性默认被继承哪些不被继承大部分符合常识。如果你想确定,你可以参考CSS参考资料—— 每个单独的属性页都会从一个汇总表开始,其中包含有关该元素的各种详细信息,包括是否被继承。

控制继承

CSS为处理继承提供了四种特殊的通用属性值:

  • inherit: 该值将应用到选定元素的属性值设置为与其父元素一样。
  • initial :该值将应用到选定元素的属性值设置为与浏览器默认样式表中该元素设置的值一样。如果浏览器默认样式表中没有设置值,并且该属性是自然继承的,那么该属性值就被设置为 inherit
  • unset :该值将属性重置为其自然值,即如果属性是自然继承的,那么它就表现得像 inherit,否则就是表现得像 initial
  • revert:如果当前的节点没有应用任何样式,则将该属性恢复到它所拥有的值。换句话说,属性值被设置成自定义样式所定义的属性(如果被设置), 否则属性值被设置成用户代理的默认样式。(没有应用任何样式时,先使用自定义属性,否则使用默认样式)

inherit 值是最有趣的——它允许我们显式地让一个元素从其父类继承一个属性值。

让我们看一个例子。首先有以下一段HTML:

<ul>
  <li>Default <a href="#">link</a> color</li>
  <li class="inherit">Inherit the <a href="#">link</a> color</li>
  <li class="initial">Reset the <a href="#">link</a> color</li>
  <li class="unset">Unset the <a href="#">link</a> color</li>
</ul>

现在用CSS给它添加样式:

body {
  color: green;
}

.inherit a {
  color: inherit;
}

.initial a {
  color: initial
}

.unset a {
  color: unset;
}
屏幕快照 2019-08-16 13.37.26

让我们解释这里发生了什么:

  • 我们首先设置<body>color为绿色。
  • 由于color属性是自然继承的,所有的body子元素都会有相同的绿色。需要注意的是默认情况下浏览器设置链接的颜色为蓝色,而不是自然继承color属性,因此在我们列表中的第一个链接是蓝色的。
  • 第二个规则设置一个类 inherit 的元素内的链接,并从父类继承它的颜色。在这种情况下, 意思是说链接继承了父元素<li>的颜色,默认情况下<li>的颜色来自于它的父元素 <ul> , 最后<ul> 继承自 <body>元素,而<body>color 根据第一条规则设置成了绿色。
  • 第三个规则选择了在元素上使用类 initial 的任意链接然后设置他们的颜色为 initial 。通常, initial 的值被浏览器设置成了黑色,因此该链接被设置成了黑色。
  • 最后一个规则选择了在元素上使用类 unset 的所有链接然后设置它们的颜色为 unset ——即我们不设置值。因为color属性是一个自然继承的属性,它实际上就像把值设置成 inherit 一样。结果是,该链接被设置成了与body一样的颜色——绿色。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 前端入门系列之HTML

    超文本标记语言 (英语:Hypertext Markup Language,简称:HTML ) 是一种用来结构化 Web 网页及其内容的标记语言。网页内容可以是...

    王大锤
  • ios TextField限制输入两位小数

    王大锤
  • iOS AFNetworking “Request failed: unacceptable content-type: text/html”问题

    王大锤
  • JQuery快速入门

    Write less, do more, I like jQuery. ? ? jQuery是最常用的js库,整体来说非常轻量并易于扩展,对于移动应用可以使用...

    用户1216676
  • CSS 属性选择器的深入挖掘

    属性选择器是在 CSS2 中引入的并且在 CSS3 中得到了很好拓展。本文将会比较全面的介绍属性选择器,尽可能的去挖掘这个选择器在不同场景下的不同用法。

    Sb_Coco
  • 苗哥的深度思考and如何象苗哥一样深度思考

    刚加入了苗三原大哥的币圈西点军校,还没有开班,苗哥就给我上了生动的一课:如何做好社群管理?感觉一扇门被打开了。

    凌帅出口
  • NEC css规范

    CSS规范 - 分类方法 SS文件的分类和引用顺序 通常,一个项目我们只引用一个CSS,但是对于较大的项目,我们需要把CSS文件进行分类。 我们按照CSS的性质...

    用户1197315
  • ceph v12版本直升v14

    一个RGW环境的更新,ceph 12.2.12升级到14.2.4流程,跳过中间的13版本。 注意:升级很危险,操作需谨慎。升级没有后悔药,本人不承担任何因升级及...

    用户1260683
  • 金融风控领域的工业级大数据应用: 如何跨越AI与业务经验结合前的鸿沟?

    大数据文摘
  • 快手直播平台演进之路

    大家好我是郭亮,目前负责快手的直播架构和算法团队。很高兴今天有机会给大家分享“快手直播平台架构的演进历程”。首先,我会简单说明一下快手直播平台的现状;接着,我会...

    LiveVideoStack

扫码关注云+社区

领取腾讯云代金券