CSS on MDN

Learning CSS on MDN

Posted by Pele on February 27, 2022

CSS on MDN

CSS 语法

语法由一个 选择器(selector)起头。 它 选择(selects) 了我们将要用来添加样式的 HTML 元素。 在这个例子中我们为一级标题(主标题<h1>)添加样式。

接着输入一对大括号{ }。 在大括号内部定义一个或多个形式为 属性(property):值(value);声明(declarations)。每个声明都指定了我们所选择元素的一个属性,之后跟一个我们想赋给这个属性的值。

向HTML中添加CSS

<link rel="stylesheet" href="style.css">

<link>语句块里面,我们用属性 rel,让浏览器知道有 CSS 文档存在(所以需要遵守 CSS 样式的规定),并利用属性 href 指定,寻找 CSS 文件的位置。 你可以做测试来验证CSS是否有效:在 styles.css 里面加上CSS样式并观察显示的结果。

用逗号将不同选择器隔开,即可一次使用多个选择器。譬如,若要将所有段落与列表变成绿色,只需:

p, li {
    color: green;
}

改变元素的默认行为

只要一个 HTML 文档标记正确,即使像我们的例子那么简单,浏览器都会尽全力将其渲染至可读状态。标题默认使用大号粗体;列表旁总有项目符号。这是因为浏览器自带一个包含默认样式的样式表,默认对任何页面有效。没有了它们,所有文本会夹杂在一起变得一团糟,我们只得从头开始规定,好糟糕。话说回来,所有现代浏览器的默认样式都没什么差距。

不过你可能对浏览器的默认样式不太满意。没关系,只需选定那个元素,加一条 CSS 规则即可。就拿我们的无序列表 <ul>举个例子吧,它自带项目符号,不过要是你跟它有仇,你就可以这样移除它们:

li {
  list-style-type: none;
}

使用类名

<ul>
  <li>项目一</li>
  <li class="special">项目二</li>
  <li>项目 <em></em></li>
</ul>

在 CSS 中,要选中这个 special 类,只需在选择器的开头加个西文句点(.)。在你的 CSS 文档里加上如下代码:

.special {
  color: orange;
  font-weight: bold;
}

有时你会发现选择器中,HTML 元素选择器跟类一起出现:

li.special {
  color: orange;
  font-weight: bold;
}

这个意思是说,“选中每个 special 类的 li 元素”。 你真要这样,好了,它对 <span> 还有其它元素不起作用了。你可以把这个元素再添上去就是了:

li.special,
span.special {
  color: orange;
  font-weight: bold;
}

根据元素在文档中的位置确定样式

包含选择符

在我们的文档中有两个 <em>元素 ——一个在段落内,另一个在列表项内。仅选择嵌套在<li> 元素内的<em>我们可以使用一个称为包含选择符的选择器,它只是单纯地在两个选择器之间加上一个空格。

将以下规则添加到样式表。

li em {
  color: rebeccapurple;
}
相邻选择符

另一些可能想尝试的事情是在 HTML 文档中设置直接出现在标题后面并且与标题具有相同层级的段落样式,为此需在两个选择器之间添加一个 + 号 (成为 相邻选择符)

也将这个规则添加到样式表中:

h1 + p {
  font-size: 200%;
}

根据状态确定样式

一个直观的例子就是当我们修改链接的样式时。 当我们修改一个链接的样式时我们需要定位(针对) <a> (锚)标签。取决于是否是未访问的、访问过的、被鼠标悬停的、被键盘定位的,亦或是正在被点击当中的状态,这个标签有着不同的状态。你可以使用CSS去定位或者说针对这些不同的状态进行修饰——下面的CSS代码使得没有被访问的链接颜色变为粉色、访问过的链接变为绿色。

a:link {
  color: pink;
}

a:visited {
  color: green;
}

Copy to Clipboard

你可以改变链接被鼠标悬停的时候的样式,例如移除下划线,下面的代码就实现了这个功能。

a:hover {
  text-decoration: none;
}

同时使用选择器和选择符

你可以同时使用选择器和选择符。来看一些例子:

body h1 + p .special {
  color: yellow;
  background-color: black;
  padding: 5px;
}

内部样式表

<!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>

内联样式

<!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>

除非你有充足的理由,否则不要这样做!它难以维护(在需要更新时,你必须在修改同一个文档的多处地方),并且这种写法将文档结构和文档表现混合起来了,这使得代码变得难以阅读和理解。将不同类型的代码分开存放在不同的文档中,会让我们的工作更加清晰。

在某些地方,内联样式更常见,甚至更可取。 如果您的工作环境确实很严格(也许网站管理系统(CMS)仅允许您编辑HTML正文),则可能不得不使用它们。 您也会发现它们很长时间被应用在HTML电子邮件中,以便与尽可能多的电子邮件客户端兼容。

选择器

讲到CSS就不得不说到选择器, 并且在之前的辅导教程中我们已经列举了一些不同的选择器。为了样式化某些元素,我们会通过选择器来选中HTML文档中的这些元素。如果你的样式没有生效,那很可能是你的选择器没有像你想象的那样选中你想要的元素。

每个CSS规则都以一个选择器或一组选择器为开始,去告诉浏览器这些规则应该应用到哪些元素上。以下都是有效的选择器或组合选择器的示例。

h1
a:link
.manythings
#onething
*
.box p
.box p:first-child
h1, h2, .intro

专一性

通常情况下,两个选择器可以选择相同的HTML元素。考虑下面的样式表,其中我有一个规则,其中有一个将段落设置为蓝色的p选择器,还有一个将选定元素设置为红色的类。

.special {
  color: red;
}

p {
  color: blue;
}

比方说,在我们的HTML文档中,我们有一个带有特殊类的段落。这两条规则都适用,那么谁赢了?你认为我们的段落会变成什么颜色?

<p class="special">What color am I?</p>

CSS语言有规则来控制在发生碰撞时哪条规则将获胜–这些规则称为级联规则和专用规则。在下面的代码块中,我们为p选择器定义了两个规则,但是段落最后是蓝色的。这是因为将其设置为蓝色的声明将出现在样式表的后面,而稍后的样式将覆盖以前的样式。这就是起作用的级联

p {
  color: red;
}

p {
  color: blue;
}

但是,在我们同时使用了类选择器和元素选择器的前一个例子中,将获胜,使得段落变红–即使它出现在样式表的前面。一个类被描述为比元素选择器更具体,或者具有更多的特异性,所以它获胜了。

  • 同级:稍后的样式覆盖前面的样式

  • 类选择器 > 元素选择器

属性和值

属性:color
值:blue
属性+值🢣CSS声明:color: blue
声明+选择器🢣CSS规则集:

h1 {
  color: blue;
  background-color: yellow;
}

函数

虽然大多数值是相对简单的关键字或数值,但也有一些可能的值以函数的形式出现。一个例子是calc()函数。这个函数允许您在CSS中进行简单的计算,例如:

<div class="outer"><div class="box">The inner box is 90% - 30px.</div></div>

clac

.outer {
  border: 5px solid black;
}

.box {
  padding: 10px;
  width: calc(90% - 30px);
  background-color: rebeccapurple;
  color: white;
}

image-20220225152643179

transform

另一个例子是<transform>, 例如 rotate().

<div class="box"></div>
.box {
  margin: 30px;
  width: 100px;
  height: 100px;
  background-color: rebeccapurple;
  transform: rotate(0.8turn)
}

image-20220225153354364

@规则

到目前为止,我们还没有遇到 @rules (pronounced “at-rules”). 这是一些特殊的规则,为 CSS提供了一些关于如何表现的指导。 有些@rules 规则很简单,有规则名和值。例如,要将额外的样式表导入主CSS样式表,可以使用@import:

@import 'styles2.css';

您将遇到的最常见的 @rules 之一是@media,它允许您使用 媒体查询 来应用CSS,仅当某些条件成立(例如,当屏幕分辨率高于某一数量,或屏幕宽度大于某一宽度时)。

在下面的 CSS中,我们将给 <body> 元素一个粉红色的背景色。但是,我们随后使用@media创建样式表的一个部分,该部分仅适用于视口大于30em的浏览器。如果浏览器的宽度大于30em,则背景色将为蓝色。

body {
  background-color: pink;
}

@media (min-width: 30em) {
  body {
    background-color: blue;
  }
}

在这些教程中,你将遇到一些其他的规则 @rules

查看是否可以将媒体查询添加到CSS中,该查询将根据视口宽度更改样式。更改浏览器窗口的宽度以查看结果。

速记属性

一些属性,如 font, background, padding, border, and margin 等属性称为速记属性–这是因为它们允许您在一行中设置多个属性值,从而节省时间并使代码更整洁。

例如,这一行代码:

/* In 4-value shorthands like padding and margin, the values are applied
   in the order top, right, bottom, left (clockwise from the top). There are also other
   shorthand types, for example 2-value shorthands, which set padding/margin
   for top/bottom, then left/right */
padding: 10px 15px 15px 5px;

与这四行代码是等价的:

padding-top: 10px;
padding-right: 15px;
padding-bottom: 15px;
padding-left: 5px;

这一行:

background: red url(bg-graphic.png) 10px 10px repeat-x fixed;

与这五行代码是等价的:

background-color: red;
background-image: url(bg-graphic.png);
background-position: 10px 10px;
background-repeat: repeat-x;
background-attachment: fixed;

空格

在CSS中,属性和它们的值之间的空格需要小心。

例如,以下声明是有效的CSS:

margin: 0 auto;
padding-left: 10px;

以下内容无效:

margin: 0auto;
padding- left: 10px;

“0auto”不被识别为边距属性的有效值(“0”和“AUTO”是两个独立的值),而浏览器会将“padding- ”识别为有效属性。因此,您应该始终确保通过至少一个空格将不同的值分隔开来,但将属性名称和属性值作为单个未中断的字符串放在一起。

CSS属性选择器

存否和值选择器

选择器 示例 描述
[*attr*] a[title] 匹配带有一个名为attr的属性的元素——方括号里的值。
[*attr*=*value*] a[href="https://example.com"] 匹配带有一个名为attr的属性的元素,其值正为value——引号中的字符串。
[*attr*~=*value*] p[class~="special"] 匹配带有一个名为attr的属性的元素 ,其值正为value,或者匹配带有一个attr属性的元素,其值有一个或者更多,至少有一个和value匹配。注意,在一列中的好几个值,是用空格隔开的。
[*attr*|=*value*] div[lang|="zh"] 匹配带有一个名为attr的属性的元素,其值可正为value,或者开始为value,后面紧随着一个连字符。

下面的示例中,你可以看到这些选择器是怎样使用的。

  • 使用li[class],我们就能匹配任何有class属性的选择器。这匹配了除了第一项以外的所有项。
  • li[class="a"]匹配带有一个a类的选择器,不过不会选中一部分值为a而另一部分是另一个用空格隔开的值的类,它选中了第二项。
  • li[class~="a"]会匹配一个a类,不过也可以匹配一列用空格分开、包含a类的值,它选中了第二和第三项。

image-20220311090519619

Interactive editor

li[class] {
    font-size: 200%;
}

li[class="a"] {
    background-color: yellow;
}

li[class~="a"] {
    color: red;
}
<h1>Attribute presence and value selectors</h1>
<ul>
    <li>Item 1</li>
    <li class="a">Item 2</li>
    <li class="a b">Item 3</li>
    <li class="ab">Item 4</li>
</ul>

子字符串匹配选择器

这些选择器让更高级的属性的值的子字符串的匹配变得可行。例如,如果你有box-warningbox-error类,想把开头为“box-”字符串的每个物件都匹配上的话,你可以用[class^="box-"]来把它们两个都选中。

选择器 示例 描述
[*attr*^=*value*] li[class^="box-"] 匹配带有一个名为attr的属性的元素,其值开头为value子字符串。
[*attr*$=*value*] li[class$="-box"] 匹配带有一个名为attr的属性的元素,其值结尾为value子字符串
[*attr**=*value*] li[class*="box"] 匹配带有一个名为attr的属性的元素,其值的字符串中的任何地方,至少出现了一次value子字符串。

下个示例展示了这些选择器的用法:

  • li[class^="a"]匹配了任何值开头为a的属性,于是匹配了前两项。
  • li[class$="a"]匹配了任何值结尾为a的属性,于是匹配了第一和第三项。
  • li[class*="a"]匹配了任何值的字符串中出现了a的属性,于是匹配了所有项。

image-20220311090721559

Interactive editor

li[class^="a"] {
    font-size: 200%;
}

li[class$="a"] {
    background-color: yellow;
}

li[class*="a"] {
    color: red;
}
<h1>Attribute substring matching selectors</h1>
<ul>
    <li class="a">Item 1</li>
    <li class="ab">Item 2</li>
    <li class="bca">Item 3</li>
    <li class="bcabc">Item 4</li>
</ul>

大小写敏感

如果你想在大小写不敏感的情况下,匹配属性值的话,你可以在闭合括号之前,使用i值。这个标记告诉浏览器,要以大小写不敏感的方式匹配ASCII字符。没有了这个标记的话,值会按照文档语言对大小写的处理方式,进行匹配——HTML中是大小写敏感的。

下面的示例中,第一个选择器将会匹配一个开头为a的值,这样它只匹配了第一项,因为另外两项开头是大写的A。第二个选择器使用了大小写不敏感的标记,于是匹配了所有项。

image-20220311090846609

Interactive editor

li[class^="a"] {
    background-color: yellow;
}

li[class^="a" i] {
    color: red;
}
<h1>Case-insensitivity</h1>
<ul>
    <li class="a">Item 1</li>
    <li class="A">Item 2</li>
    <li class="Ab">Item 3</li>
</ul>
伪 类

伪类是选择器的一种,它用于选择处于特定状态的元素,比如当它们是这一类型的第一个元素时,或者是当鼠标指针悬浮在元素上面的时候。它们表现得会像是你向你的文档的某个部分应用了一个类一样,帮你在你的标记文本中减少多余的类,让你的代码更灵活、更易于维护。

伪类就是开头为冒号的关键字:

:pseudo-class-name

简单伪类示例

让我们看下一个简单的示例。如果我们想要让一篇文章中的第一段变大加粗,可为此段加上一个类,然后为那个类添加CSS,正如下面的示例展示的这样:

不过,这在维护的时候可能会很恼人——要是文档的头部又加上一段的话呢?我们会需要把这个类挪到新加的这段上。假如我们不加类,我们可以使用:first-child伪类选择器——这将一直选中文章中的第一个子元素,我们将不再需要编辑HTML(编辑HTML并不总是可行,也许是因为它是由一个CMS生成的)。

image-20220311091545429

article p:first-child {
    font-size: 120%;
    font-weight: bold;
}   
<article>
    <p>Veggies es bonus vobis, proinde vos postulo essum magis kohlrabi welsh onion daikon amaranth tatsoi tomatillo
            melon azuki bean garlic.</p>

    <p>Gumbo beet greens corn soko endive gumbo gourd. Parsley shallot courgette tatsoi pea sprouts fava bean collard
            greens dandelion okra wakame tomato. Dandelion cucumber earthnut pea peanut soko zucchini.</p>
</article>

所有的伪类以同样的方式实现。它们选中你的文档中处于某种状态的那部分,表现得就像是你已经向你的HTML加入类一样。看下MDN上的另外几个示例:

  • :last-child
  • :only-child
  • :invalid

用户行为伪类

一些伪类只会在用户以某种方式和文档交互的时候应用。这些用户行为伪类,有时叫做动态伪类,表现得就像是一个类在用户和元素交互的时候加到了元素上一样。案例包括:

  • :hover——上面提到过,只会在用户将指针挪到元素上的时候才会激活,一般就是链接元素。
  • :focus——只会在用户使用键盘控制,选定元素的时候激活。

伪元素

伪元素以类似方式表现,不过表现得是像你往标记文本中加入全新的HTML元素一样,而不是向现有的元素上应用类。伪元素开头为双冒号::

::pseudo-element-name

例如,如果你想选中一段的第一行,你可以把它用一个<span>元素包起来,然后使用元素选择器;不过,如果包起来的单词/字符数目长于或者短于父元素的宽度,这样做会失败。由于我们一般不会知道一行能放下多少单词/字符——因为屏幕宽度或者字体大小改变的时候这也会变——通过改变HTML的方式来可预测地这么做是不可能的。

::first-line伪元素选择器会值得信赖地做到这件事——即使单词/字符的数目改变,它也只会选中第一行。

image-20220311091848763

article p::first-line {
    font-size: 120%;
    font-weight: bold;
}   
<article>
    <p>Veggies es bonus vobis, proinde vos postulo essum magis kohlrabi welsh onion daikon amaranth tatsoi tomatillo
            melon azuki bean garlic.</p>

    <p>Gumbo beet greens corn soko endive gumbo gourd. Parsley shallot courgette tatsoi pea sprouts fava bean collard
            greens dandelion okra wakame tomato. Dandelion cucumber earthnut pea peanut soko zucchini.</p>
</article>

这表现得就像是<span>神奇地包在第一个被格式化的行一样,每当行长改变的时候还会更新。

你可以看到它把两段的第一行都选中了

伪类和伪元素结合

如果你想让第一段的第一行加粗,你需要把:first-child::first-line选择器放到一起。试着编辑前面的实时示例,让它使用下面的CSS。这里的意思是,我们想选择一个<article>元素里面的第一个<p>元素的第一行。

article p:first-child::first-line {
  font-size: 120%;
  font-weight: bold;
}

生成带有::before和::after的内容

有一组特别的伪元素,它们和content属性一同使用,使用CSS将内容插入到你的文档中中。

你能用这些插入一个文本字符串,和在下面的实时示例里那样。试着改变content属性的文本值,看看输出是怎么改变的。你也能改变::before伪元素为::after,看到这段文本插入到了元素的末尾而不是开头。

image-20220311092543032

.box::before {
    content: "This should show before the other content."
}   
<p class="box">Content in the box in my HTML page.</p>

从CSS插入文本字符串,我们并不会在Web浏览器上经常这么做,因为对于一些屏幕阅读器来说,文本是不可见的,而且对于未来别人的查找和编辑也不是很方便。

这些伪元素的更推荐的用法是插入一个图标,例如下面的示例加入的一个小箭头,作为一个视觉性的提示,而且我们并不希望屏幕阅读器读出它。

image-20220311092642646

.box::after {
	content:" ➥";
}
<p class="box">
  Content in the box in my HTML page.
</p>

伪类

选择器 描述
:active 在用户激活(例如点击)元素的时候匹配。
:any-link 匹配一个链接的:link:visited状态。
:blank 匹配空输入值的``元素
:checked 匹配处于选中状态的单选或者复选框。
:current (en-US) 匹配正在展示的元素,或者其上级元素。
:default 匹配一组相似的元素中默认的一个或者更多的UI元素。
:dir 基于其方向性(HTMLdir属性或者CSSdirection属性的值)匹配一个元素。
:disabled 匹配处于关闭状态的用户界面元素
:empty 匹配除了可能存在的空格外,没有子元素的元素。
:enabled 匹配处于开启状态的用户界面元素。
:first 匹配分页媒体的第一页。
:first-child 匹配兄弟元素中的第一个元素。
:first-of-type 匹配兄弟元素中第一个某种类型的元素。
:focus 当一个元素有焦点的时候匹配。
:focus-visible 当元素有焦点,且焦点对用户可见的时候匹配。
:focus-within 匹配有焦点的元素,以及子代元素有焦点的元素。
:future (en-US) 匹配当前元素之后的元素。
:hover 当用户悬浮到一个元素之上的时候匹配。
:indeterminate 匹配未定态值的UI元素,通常为复选框
:in-range 用一个区间匹配元素,当值处于区间之内时匹配。
:invalid 匹配诸如<input>的位于不可用状态的元素。
:lang 基于语言(HTMLlang属性的值)匹配元素。
:last-child 匹配兄弟元素中最末的那个元素。
:last-of-type 匹配兄弟元素中最后一个某种类型的元素。
:left 分页媒体 (en-US)中,匹配左手边的页。
:link 匹配未曾访问的链接。
:local-link (en-US) 匹配指向和当前文档同一网站页面的链接。
:is() 匹配传入的选择器列表中的任何选择器。
:not 匹配作为值传入自身的选择器未匹配的物件。
:nth-child 匹配一列兄弟元素中的元素——兄弟元素按照an+b形式的式子进行匹配(比如2n+1匹配元素1、3、5、7等。即所有的奇数个)。
:nth-of-type 匹配某种类型的一列兄弟元素(比如,<p>元素)——兄弟元素按照an+b形式的式子进行匹配(比如2n+1匹配元素1、3、5、7等。即所有的奇数个)。
:nth-last-child 匹配一列兄弟元素,从后往前倒数。兄弟元素按照an+b形式的式子进行匹配(比如2n+1匹配按照顺序来的最后一个元素,然后往前两个,再往前两个,诸如此类。从后往前数的所有奇数个)。
:nth-last-of-type 匹配某种类型的一列兄弟元素(比如,<p>元素),从后往前倒数。兄弟元素按照an+b形式的式子进行匹配(比如2n+1匹配按照顺序来的最后一个元素,然后往前两个,再往前两个,诸如此类。从后往前数的所有奇数个)。
:only-child 匹配没有兄弟元素的元素。
:only-of-type 匹配兄弟元素中某类型仅有的元素。
:optional 匹配不是必填的form元素。
:out-of-range 按区间匹配元素,当值不在区间内的的时候匹配。
:past (en-US) 匹配当前元素之前的元素。
:placeholder-shown 匹配显示占位文字的input元素。
:playing (en-US) 匹配代表音频、视频或者相似的能“播放”或者“暂停”的资源的,且正在“播放”的元素。
:paused (en-US) 匹配代表音频、视频或者相似的能“播放”或者“暂停”的资源的,且正在“暂停”的元素。
:read-only 匹配用户不可更改的元素。
:read-write 匹配用户可更改的元素。
:required 匹配必填的form元素。
:right 分页媒体 (en-US)中,匹配右手边的页。
:root 匹配文档的根元素。
:scope 匹配任何为参考点元素的的元素。
:valid 匹配诸如<input>元素的处于可用状态的元素。
:target 匹配当前URL目标的元素(例如如果它有一个匹配当前URL分段的元素)。
:visited 匹配已访问链接。

伪元素

选择器 描述
::after 匹配出现在原有元素的实际内容之后的一个可样式化元素。
::before 匹配出现在原有元素的实际内容之前的一个可样式化元素。
::first-letter 匹配元素的第一个字母。
::first-line 匹配包含此伪元素的元素的第一行。
::grammar-error 匹配文档中包含了浏览器标记的语法错误的那部分。
::selection 匹配文档中被选择的那部分。
::spelling-error 匹配文档中包含了浏览器标记的拼写错误的那部分。

关系选择器

后代选择器

后代选择器——典型用单个空格( )字符——组合两个选择器,比如,第二个选择器匹配的元素被选择,如果他们有一个祖先(父亲,父亲的父亲,父亲的父亲的父亲,等等)元素匹配第一个选择器。选择器利用后代组合符被称作后代选择器。

body article p

下面的示例中,我们只会匹配处于带有.box类的元素里面的<p>元素。

image-20220311093205840

.box p {
  color : red;
}
<div class="box">
  <p>
    Text in  .box
  </p>
</div>
<p>
    Text not in .box
</p>
子代关系选择器

子代关系选择器是个大于号(>),只会在选择器选中直接子元素的时候匹配。继承关系上更远的后代则不会匹配。例如,只选中作为<article>的直接子元素的<p>元素:

article > p

下个示例中,我们弄了个有序列表,内嵌于另一个无序列表里面。我用子代关系选择器,只选中为<ul>的直接子元素的<li>元素,给了它们一个顶端边框。

如果你移去指定子代选择器的>的话,你最后得到的是后代选择器,所有的<li>会有个红色的边框。

image-20220311093351825

ul > li {
  border-top: 5px solid red;
}
<ul>
  <li> Unordered item</li>
  <li> Unordered item
    <ol>
      <li>Item 1</li>
      <li>Item 2</li>
    </ol>
  </li>
</ul>
邻接兄弟

邻接兄弟选择器(+)用来选中恰好处于另一个在继承关系上同级的元素旁边的物件。例如,选中所有紧随<p>元素之后的<img>元素:

p + img

常见的使用场景是, 改变紧跟着一个标题的段的某些表现方面,就像是我下面的示例那样。这里我们寻找一个紧挨<h1>的段,然后样式化它。

如果你往<h1><p>之间插入其他的某个元素,例如<h2>,你将会发现,段落不再与选择器匹配,因而不会应用元素邻接时的前景和背景色。

通用兄弟

如果你想选中一个元素的兄弟元素,即使它们不直接相邻,你还是可以使用通用兄弟关系选择器(~)。要选中所有的<p>元素后任何地方<img>元素,我们会这样做:

p ~ img

在下面的示例中,我们选中了所有的 <h1>之后的<p>元素,虽然文档中还有个 <div>,其后的<p>还是被选中了。

image-20220311133704150

h1 ~ p {
    font-weight: bold;
    background-color: #333;
    color: #fff;
    padding: .5em;
}
<article>
    <h1>A heading</h1>
    <p>I am a paragraph.</p>
    <div>I am a div</div>
    <p>I am another paragraph.</p>
</article>
使用选择器

你能用关系选择器,将任何在我们前面的学习过程中学到的选择器组合起来,选出你的文档中的一部分。例如如果我们想选中为<ul>的直接子元素的带有“a”类的列表项的话,我可以用下面的代码。

ul > li[class="a"]  {  }

不过,建立一长列选中你的文档中很明确的部分的选择器的时候,小心一些。这些CSS规则难以复用,因为你让选择器在表示标记文本中的元素的相对位置上过于明确。

建立简单的一个类,然后把它应用到有需求的元素上,经常会是更好的做法。不过话说回来,如果你需要让你的文档变换一下样式,但是没法编辑HTML(也许是因为它由CMS生成)的话,你的关系选择器的知识会派上用场。

CSS小试牛刀

image-20220311135640433

<div class="container">
    <h1>This is a heading</h1>
    <p>Veggies es <span class="alert">bonus vobis</span>, proinde vos postulo <span class="alert stop">essum magis</span> kohlrabi welsh onion daikon amaranth tatsoi tomatillo melon azuki bean garlic.</p>
    <h2 id="special">A level 2 heading</h2>
    <p>Gumbo beet greens corn soko endive gumbo gourd.</p>
    <h2>Another level 2 heading</h2>
    <p><span class="alert go">Parsley shallot</span> courgette tatsoi pea sprouts fava bean collard greens dandelion okra wakame tomato. Dandelion cucumber earthnut pea peanut soko zucchini.</p>

  </div>
h1 { 
color:blue;
}
.alert{
  border:solid 1px;
}
.alert.stop{
background-color:red;
}

#special{
  background-color:yellow;
}
.alert.go{
  background-color:green;
}

盒模型

块级盒子(Block box)和 内联盒子(Inline box)

在 CSS 中我们广泛地使用两种“盒子” —— 块级盒子 (block box) 和 内联盒子 (inline box)这两种盒子会在页面流(page flow)和元素之间的关系方面表现出不同的行为:

一个被定义成块级的(block)盒子会表现出以下行为:

  • 盒子会在内联的方向上扩展并占据父容器在该方向上的所有可用空间,在绝大数情况下意味着盒子会和父容器一样宽
  • 每个盒子都会换行
  • widthheight 属性可以发挥作用
  • 内边距(padding), 外边距(margin) 和 边框(border) 会将其他元素从当前盒子周围“推开”

除非特殊指定,诸如标题(<h1>等)和段落(<p>)默认情况下都是块级的盒子。

如果一个盒子对外显示为 inline,那么他的行为如下:

  • 盒子不会产生换行。
  • widthheight 属性将不起作用。
  • 垂直方向的内边距、外边距以及边框会被应用但是不会把其他处于 inline 状态的盒子推开。
  • 水平方向的内边距、外边距以及边框会被应用且会把其他处于 inline 状态的盒子推开。

用做链接的 <a> 元素、 <span><em> 以及 <strong> 都是默认处于 inline 状态的。

我们通过对盒子display 属性的设置,比如 inline 或者 block ,来控制盒子的外部显示类型。

不同现实类型的例子

让我们继续看看别的例子。下面三个html元素,都有一个外部显示类型 block。第一个是一个段落,在 CSS 中加了边框。浏览器把它渲染成一个块级盒子,所以段落从新的一行开始,而且宽度占满一行。

第二个是一个列表,布局属性是 display: flex。 将在容器中建立一个flex布局,但是每个列表是一个块级元素 —— 像段落一样 —— 会充满整个容器的宽度并且换行。

下面有个块级段落,里面有两个 <span> 元素。正常情况下是 inline,但是其中一个加了block类,设置属性 display: block

image-20220311140402404

p, 
ul {
  border: 2px solid rebeccapurple;
  padding: .5em;
}

.block,
li {
  border: 2px solid blue;
  padding: .5em;
}

ul {
  display: flex;
  list-style: none;
}

.block {
  display: block;
}      
<p>I am a paragraph. A short one.</p>
<ul>
  <li>Item One</li>
  <li>Item Two</li>
  <li>Item Three</li>
</ul>
<p>I am another paragraph. Some of the <span class="block">words</span> have been wrapped in a <span>span element</span>.</p>

CSS盒子模型

完整的 CSS 盒模型应用于块级盒子,内联盒子只使用盒模型中定义的部分内容。模型定义了盒的每个部分 —— margin, border, padding, and content —— 合在一起就可以创建我们在页面上看到的内容。为了增加一些额外的复杂性,有一个标准的和替代(IE)的盒模型。

盒模型的各个部分

CSS中组成一个块级盒子需要:

  • Content box: 这个区域是用来显示内容,大小可以通过设置 widthheight.
  • Padding box: 包围在内容区域外部的空白区域; 大小通过 padding 相关属性设置。
  • Border box: 边框盒包裹内容和内边距。大小通过 border 相关属性设置。
  • Margin box: 这是最外面的区域,是盒子和其他元素之间的空白区域。大小通过 margin 相关属性设置。

image-20220311142032819

标准盒模型

在标准模型中,如果你给盒设置 widthheight,实际设置的是 content box。 padding 和 border 再加上设置的宽高一起决定整个盒子的大小。 见下图。

假设定义了 width, height, margin, border, and padding:

.box {
  width: 350px;
  height: 150px;
  margin: 25px;
  padding: 25px;
  border: 5px solid black;
}

替换IE盒模型

你可能会认为盒子的大小还要加上边框和内边距,这样很麻烦,而且你的想法是对的! 因为这个原因,css还有一个替代盒模型。使用这个模型,所有宽度都是可见宽度,所以内容宽度是该宽度减去边框和填充部分。使用上面相同的样式得到 (width = 350px, height = 150px).

Showing the size of the box when the alternate box model is being used.

默认浏览器会使用标准模型。如果需要使用替代模型,您可以通过为其设置 box-sizing: border-box 来实现。 这样就可以告诉浏览器使用 border-box 来定义区域,从而设定您想要的大小。

.box {
  box-sizing: border-box;
} 

外边距,内边距,边框

  • 外边距 margin
    • margin-top
    • margin-right
    • margin-bottom
    • margin-left

外边距折叠

理解外边距的一个关键是外边距折叠的概念。如果你有两个外边距相接的元素,这些外边距将合并为一个外边距,即最大的单个外边距的大小。

在下面的例子中,我们有两个段落。顶部段落的页 margin-bottom为50px。第二段的margin-top 为30px。因为外边距折叠的概念,所以框之间的实际外边距是50px,而不是两个外边距的总和。

image-20220316140958898

.one {
  margin-bottom: 50px;
}

.two {
  margin-top: 30px; // 实际上该属性无效
}

有许多规则规定了什么时候外边距会折叠,什么时候不会折叠。相关更多信息,请参阅 mastering margin collapsing。现在首先要记住的事情是,外边距会折叠这个事情。如果你用外边距创建空间而没有得到你想要的效果,那这可能就是这个原因。

边框

边框是在边距和填充框之间绘制的。如果您正在使用标准的盒模型,边框的大小将添加到框的宽度和高度。如果您使用的是替代盒模型,那么边框的大小会使内容框更小,因为它会占用一些可用的宽度和高度。

为边框设置样式时,有大量的属性可以使用——有四个边框,每个边框都有样式、宽度和颜色,我们可能需要对它们进行操作。

可以使用border属性一次设置所有四个边框的宽度、颜色和样式。

分别设置每边的宽度、颜色和样式,可以使用:

设置所有边的颜色、样式或宽度,请使用以下属性:

设置单边的颜色、样式或宽度,可以使用最细粒度的普通属性之一:

内边距

内边距位于边框和内容区域之间。与外边距不同,您不能有负数量的内边距,所以值必须是0或正的值。应用于元素的任何背景都将显示在内边距后面,内边距通常用于将内容推离边框。

我们可以使用padding简写属性控制元素所有边,或者每边单独使用等价的普通属性:

盒子模型和内联盒子

以上所有的方法都完全适用于块级盒子。有些属性也可以应用于内联盒子,例如由<span>元素创建的那些内联盒子。

在下面的示例中,我们在一个段落中使用了<span>,并对其应用了宽度、高度、边距、边框和内边距。可以看到,宽度和高度被忽略了。外边距、内边距和边框是生效的,但它们不会改变其他内容与内联盒子的关系,因此内边距和边框会与段落中的其他单词重叠。

使用display: inline-block

display有一个特殊的值,它在内联和块之间提供了一个中间状态。这对于以下情况非常有用:您不希望一个项切换到新行,但希望它可以设定宽度和高度,并避免上面看到的重叠。

一个元素使用 display: inline-block,实现我们需要的块级的部分效果:

  • 设置widthheight 属性会生效。
  • padding, margin, 以及border 会推开其他元素。

但是,它不会跳转到新行,如果显式添加widthheight 属性,它只会变得比其内容更大。

image-20220316142155370

span {
  margin: 10px;
  padding: 20px;
  width: 60px;
  height: 40px;
  background-color: lightblue;
  border: 10px double red;
  display: inline-block;
}
<p>
    I am a paragraph and this is a <span>span</span> inside that paragraph. A span is an inline element and so does not respect width and height.
</p>     

当您想要通过添加内边距使链接具有更大的命中区域时,这是很有用的。<a>是像<span>一样的内联元素;你可以使用display: inline-block来设置内边距,让用户更容易点击链接。

这种情况在导航栏中很常见。下面的导航使用flexbox显示在一行中,我们为<a>元素添加了内边距,因为我们希望能够在<a>在鼠标移动到上面时改变背景色。内边距似乎覆盖了<ul>元素上的边框。这是因为<a>是一个内联元素。

image-20220316144715611

image-20220316144804171

.links-list a {
  background-color: rgb(179,57,81);
  color: #fff;
  text-decoration: none;
  padding: 1em 2em;
  display:inline-block
}

.links-list a:hover {
  background-color: rgb(66, 28, 40);
  color: #fff;
}
<nav>
  <ul class="links-list">
    <li><a href="">Link one</a></li>
    <li><a href="">Link two</a></li>
    <li><a href="">Link three</a></li>
  </ul>
</nav>    

背景与边框

###

背景颜色

background-color属性定义了CSS中任何元素的背景颜色。属性接受任何有效的<color>值。背景色扩展到元素的内容和内边距的下面。

背景图片

background-image属性允许在元素的背景中显示图像。在下面的例子中,我们有两个方框——一个是比方框大的背景图像,另一个是星星的小图像。

这个例子演示了关于背景图像的两种情形。默认情况下,大图不会缩小以适应方框,因此我们只能看到它的一个小角,而小图则是平铺以填充方框。在这种情况下,实际的图像只是单独的一颗星星。

image-20220318132516758

控制背景平铺

background-repeat属性用于控制图像的平铺行为。可用的值是:

  • no-repeat — 不重复。
  • repeat-x —水平重复。
  • repeat-y —垂直重复。
  • repeat — 在两个方向重复。

调整背景图像的大小

在上面的例子中,我们有一个很大的图像,由于它比作为背景的元素大,所以最后被裁剪掉了。在这种情况下,我们可以使用 background-size属性,它可以设置长度或百分比值,来调整图像的大小以适应背景。

你也可以使用关键字:

  • cover —浏览器将使图像足够大,使它完全覆盖了盒子区,同时仍然保持其高宽比。在这种情况下,有些图像可能会跳出盒子
  • contain — 浏览器将使图像的大小适合盒子内。在这种情况下,如果图像的长宽比与盒子的长宽比不同,则可能在图像的任何一边或顶部和底部出现间隙

背景图像定位

background-position属性允许您选择背景图像显示在其应用到的盒子中的位置。它使用的坐标系中,框的左上角是(0,0),框沿着水平(x)和垂直(y)轴定位。

注意:默认的背景位置值是(0,0)。

最常见的背景位置值有两个单独的值——一个水平值后面跟着一个垂直值。

你可以使用像topright这样的关键字(在background-image页面上查找其他的关键字):

.box {
  background-image: url(star.png);
  background-repeat: no-repeat;
  background-position: top center;
} 

或者使用 长度值, and 百分比

.box {
  background-image: url(star.png);
  background-repeat: no-repeat;
  background-position: 20px 10%;
} 

你也可以混合使用关键字,长度值以及百分比,例如:

.box {
  background-image: url(star.png);
  background-repeat: no-repeat;
  background-position: top 20px;
}

最后,您还可以使用4-value语法来指示到盒子的某些边的距离——在本例中,长度单位是与其前面的值的偏移量。所以在下面的CSS中,我们将背景从顶部调整20px,从右侧调整10px:

.box {
  background-image: url(star.png);
  background-repeat: no-repeat;
  background-position: top 20px right 10px;
} 

渐变背景

当渐变用于背景时,也可以使用像图像一样的background-image属性设置。

您可以在MDN的<gradient>数据类型页面上,了解更多关于渐变的不同类型,以及使用它们可以做的事情。使用渐变的一个有趣方法是,使用web上可用的许多CSS渐变生成器之一,比如这个 。您可以创建一个渐变,然后复制并粘贴生成它的源代码。

在下面的示例中尝试一些不同的渐变。在这两个盒子里,我们分别有一个线性梯度,它延伸到整个盒子上,还有一个径向梯度,它有一个固定的大小,因此会重复。

background: linear-gradient(90deg, rgba(2,0,36,1) 0%, rgba(9,121,81,1) 34%, rgba(0,212,255,1) 100%);

多个背景图像

也可以有多个背景图像——在单个属性值中指定多个background-image值,用逗号分隔每个值。

当你这样做时,你可能会以背景图像互相重叠而告终。背景将与最后列出的背景图像层在堆栈的底部,背景图像在代码列表中最先出现的在顶端。

注意:渐变可以与常规的背景图像很好地混合在一起。

其它 background-*属性,该属性值用逗号分隔的方式设置。例如下列background-image

background-image: url(image1.png), url(image2.png), url(image3.png), url(image1.png);
background-repeat: no-repeat, repeat-x, repeat;
background-position: 10px 20px,  top right;

不同属性的每个值,将与其他属性中相同位置的值匹配。例如,上面的image1的background-repeat值将是no-repeat。但是,当不同的属性具有不同数量的值时,会发生什么情况呢?答案是较小数量的值会循环—在上面的例子中有四个背景图像,但是只有两个背景位置值。前两个位置值将应用于前两个图像,然后它们将再次循环—image3将被赋予第一个位置值,image4将被赋予第二个位置值。

背景附加

另一个可供选择的背景是指定他们如何滚动时,内容滚动。这是由background-attachment属性控制的,它可以接受以下值:

  • scroll: 使元素的背景在页面滚动时滚动。如果滚动了元素内容,则背景不会移动。实际上,背景被固定在页面的相同位置,所以它会随着页面的滚动而滚动。
  • fixed: 使元素的背景固定在视图端口上,这样当页面或元素内容滚动时,它就不会滚动。它将始终保持在屏幕上相同的位置。
  • local: 这个值是后来添加的(它只在Internet Explorer 9+中受支持,而其他的在IE4+中受支持),因为滚动值相当混乱,在很多情况下并不能真正实现您想要的功能。局部值将背景固定在设置的元素上,因此当您滚动元素时,背景也随之滚动。

background-attachment属性只有在有内容要滚动时才会有效果,所以我们做了一个示例来演示这三个值之间的区别——看看 background-attachment.html (或者看看这儿的 源代码))。

使用background 的简写

正如我在本课开始时提到的,您将经常看到使用background属性指定的背景。这种简写允许您一次设置所有不同的属性。

如果使用多个背景,则需要为第一个背景指定所有普通属性,然后在逗号后面添加下一个背景。在下面的例子中,我们有一个渐变,它指定大小和位置,然后是一个无重复的图像背景,它指定位置,然后是一个颜色。

这里有一些规则,需要在简写背景属性时遵循,例如:

  • background-color 只能在逗号之后指定。
  • background-size 值只能包含在背景位置之后,用’/’字符分隔,例如:center/80%
.box {
  background:   
    linear-gradient(105deg, rgba(2,0,36,1) 39%, rgba(0,212,255,1) 96%) center center / 40px 20px no-repeat,
url(big-star.png) center no-repeat, 
    green;
}

边框

在学习盒子模型时,我们发现了边框如何影响盒子的大小。在这节课中,我们将看看如何创造性地使用边界。通常,当我们使用CSS向元素添加边框时,我们使用一个简写属性在一行CSS中设置边框的颜色、宽度和样式。我们可以使用border为一个框的所有四个边设置边框。

.box {
  border: 1px solid black;
} 

或者我们可以只设置盒子的一个边,例如:

.box {
  border-top: 1px solid black;
} 

这些简写的等价于:

.box {
  border-width: 1px;
  border-style: solid;
  border-color: black;
} 

也可以使用更加细粒度的属性:

.box {
  border-top-width: 1px;
  border-top-style: solid;
  border-top-color: black;
} 

圆角

通过使用border-radius属性和与方框的每个角相关的长边来实现方框的圆角。可以使用两个长度或百分比作为值,第一个值定义水平半径,第二个值定义垂直半径。在很多情况下,您将只传递一个值,这两个值都将使用。

例如,要使一个盒子的四个角都有10px的圆角半径:

.box {
  border-radius: 10px;
} 

或使右上角的水平半径为1em,垂直半径为10%:

.box {
  border-top-right-radius: 1em 10%;
} 

我们在下面的示例中设置了所有四个角,然后更改右上角的值使之不同。您可以使用这些值来更改圆角样式。查看border-radius的属性页,查看可用的语法选项。

处理不同方向的文本

什么是书写模式

CSS中的书写模式是指文本的排列方向是横向还是纵向的。writing-mode 属性使我们从一种模式切换到另一种模式。为此,你不必使用一种竖向的语言——你还可以更改部分文字的方向以实现创新性的布局。

下面的例子中,我们使用writing-mode : vertical-rl对一个标题的显示进行设置。现在,标题文本是竖向的了。竖向文本在平面设计中很常见,也可以为你的网页设计增添更加有趣的外观。

writing-mode的三个值分别是:

  • horizontal-tb: 块流向从上至下。对应的文本方向是横向的。
  • vertical-rl: 块流向从右向左。对应的文本方向是纵向的。
  • vertical-lr: 块流向从左向右。对应的文本方向是纵向的。

书写模式、块级布局和内联布局

我们已经讨论了块级布局和内联布局(block and inline layout),也知道外部显示类型元素分为块级元素和内联元素。如上所述,块级显示和内联显示与文本的书写模式(而非屏幕的物理显示)密切相关。如果你使用书写模式的显示是横向的,如英文,那么块在页面上的显示就是从上到下的。

用一个例子可以更清楚地说明这一点。下一个例子中有两个盒子,分别包含一个标题和一个段落。第一个盒子应用的是writing-mode: horizontal-tb,这是一个从上到下的横向的书写模式。第二个盒子应用的是writing-mode: vertical-rl,这是一个从右到左的纵向的书写模式。

image-20220318140326164