1、什么是CSS
CSS (Cascading Style Sheets,层叠样式表)是用来控制网页在浏览器中的显示外观的声明式语言。
CSS 的样式定义包括属性和属性值,它们共同决定网页的外观。
以下示例将页面中的所有 HTML 段落显示为黑色背景和黄色文本:
/* p 选择器表示页面中的所有段落都会被该规则所影响 */
p {
/* color 属性用来定义文本颜色,这里为黄色 */
color: yellow;
/* background-color 属性用来定义元素的背景色,这里为黑色 */
background-color: black;
}
CSS 中的第一个**“C”(Cascading)表示“层叠”**,意为多个选择器之间具有特定的优先级。这一点非常重要,因为复杂网站可能会有非常多的 CSS 规则,因此必须规定好这些规则的优先级,以免乱套。
1.1、CSS的作用
通过 CSS,你可以精确控制 HTML 元素在浏览器中的外观,以你喜欢的设计和布局呈现文档。
CSS 可用于网页外观相关的多种用途,例如:
- 文本样式,包括更改标题和链接的颜色和大小
- 创建布局,如网格布局或多列布局
- 特效,如动画
1.2、CSS语法基础
CSS 是一种基于规则的语言——通过定义一组样式规则来指定网页上哪些元素应该应用哪些样式。
例如,你可能希望将页面主标题设置为红色的大号文字。以下代码展示了一个非常简单的 CSS 规则:
h1 {
color: red;
font-size: 2.5em;
}
- 在上面的示例中,CSS 规则以一个选择器开头,用于选择我们要设置样式的 HTML 元素。在这个例子中,我们为一级标题(
<h1>)添加样式。 - 接着我们使用一对大括号
{ }。 - 大括号中包含一个或多个声明,每个声明由属性和值组成。我们在冒号前指定属性(例如上述示例中的
color),并在冒号后指定该属性的值(我们为color属性设置取值red)。 - 此示例包含两个声明,一个是
color,另一个是font-size。
1.2.1、逗号隔开选择器
用逗号将不同选择器隔开,即可一次使用多个选择器。譬如,若要将所有段落与列表变成绿色,只需:
p,
li {
color: green;
}
1.2.2、使用class类名
可以给 HTML 元素加个类名(class),再选中那个类名,这样就可以样式化一组元素。
举个例子,把 class 属性加到表里面第二个对象。你的列表看起来应该是这样的:
<ul>
<li>项目一</li>
<li class="special">项目二</li>
<li>项目 <em>三</em></li>
</ul>
在 CSS 中,要选中这个 special 类,只需在选择器的开头加个西文句点(.)。在你的 CSS 文档里加上如下代码:
.special {
color: orange;
font-weight: bold;
}
有时你会发现选择器中,HTML 元素选择器跟类一起出现,这个意思是说,“选中每个 special 类的 li 元素”。
li.special {
color: orange;
font-weight: bold;
}
1.2.3、根据元素在HTML文档中的位置确定样式
仅选择嵌套在<li> 元素内的<em>我们可以使用一个称为包含选择符的选择器,它只是单纯地在两个选择器之间加上一个空格。
将以下规则添加到样式表。该选择器将选择<li>内部的任何<em>元素(<li>的后代)。
li em {
color: rebe***apurple;
}
在 HTML 文档中设置直接出现在标题后面并且与标题具有相同层级的段落样式,为此需在两个选择器之间添加一个 + 号 (成为 相邻选择符)。
h1 + p {
font-size: 200%;
}
1.2.4、根据状态确定样式
当我们修改一个链接的样式时我们需要定位(针对) <a> (锚)标签。取决于是否是未访问的、访问过的、被鼠标悬停的、被键盘定位的,亦或是正在被点击当中的状态,这个标签有着不同的状态。
a:link {
color: pink;
}
a:visited {
color: green;
}
你可以改变链接被鼠标悬停的时候的样式,例如移除下划线,下面的代码就实现了这个功能。
a:hover {
text-decoration: none;
}
1.2.5、同时使用选择器和选择符
你可以将多种类型组合在一起。试试将下面的代码添加到你的代码里:
body h1 + p .special {
color: yellow;
background-color: black;
padding: 5px;
}
上面的代码为以下元素建立样式:在 <body> 之内,紧接在 <h1> 后面的 <p> 元素的内部,类名为 special。
1.3、为HTML文档添加CSS
让 HTML 文档能够遵守我们给它的 CSS 规则。其实有三种方式可以实现,而目前我们更倾向于利用最普遍且有用的方式——在文档的开头链接 CSS。
为了把 styles.css 和 index.html 连接起来,可以在 HTML 文档中,<head> 语句模块里面加上下面的代码:
<link rel="stylesheet" href="styles.css" />
2、CSS选择器
CSS 选择器是 CSS 规则的第一部分。它是元素和其他部分组合起来告诉浏览器哪个 HTML 元素应当是被选为应用规则中的 CSS 属性值的方式。选择器所选择的元素,叫做选择器的对象。
2.1、选择器列表
如果你有多个使用相同样式的 CSS 选择器,那么这些单独的选择器可以被混编为一个“选择器列表”。
例如,如果我的h1和.special类有相同的 CSS,那么我可以把它们写成两个分开的规则。
h1 {
color: blue;
}
.special {
color: blue;
}
我也可以将它们组合起来,在它们之间加上一个逗号,变为选择器列表。
h1, .special {
color: blue;
}
空格可以在逗号前或后,你可能还会发现如果每个选择器都另起一行,会更好读些。
h1,
.special {
color: blue;
}
失效的选择器列表
当你使用选择器列表时,如果任何一个选择器无效 (存在语法错误),那么整条规则都会被忽略。
在下面的示例中,无效的 class 选择器会被忽略,而h1选择器仍会被样式化。
h1 {
color: blue;
}
/*..special为语法错误的语句*/
..special {
color: blue;
}
但是在被组合起来以后,整个规则都会失效,无论是h1还是这个 class 都不会被样式化。
h1,
..special {
color: blue;
}
2.2、选择器的种类
2.2.1、类型、类和ID选择器
这个选择器组,第一个是指向了所有 HTML 元素 <h1>。
h1 {
}
它也包含了一个 class 的选择器:
.box {
}
亦或,一个 id 选择器:
#unique {
}
2.2.2、标签属性选择器
这组选择器根据一个元素上的某个标签的属性的存在以选择元素的不同方式:
a[title] {
}
或者根据一个有特定值的标签属性是否存在来选择:
a[href="https://example.***"]
{
}
2.2.3、伪类与伪元素
伪类就是开头为冒号的关键字。例如,:hover 就是一个伪类。
这组选择器包含了伪类,用来样式化一个元素的特定状态。例如:hover伪类会在鼠标指针悬浮到一个元素上的时候选择这个元素:
a:hover {
}
它还可以包含了伪元素,选择一个元素的某个部分而不是元素自己。例如,::first-line是会选择一个元素(下面的情况中是<p>)中的第一行,类似<span>包在了第一个被格式化的行外面,然后选择这个<span>。
p::first-line {
color: red;
}
<!-- 只有第一行会变红色字体 -->
<body>
<p>
<span>第一行</span>
<br>
<span>第二行</span>
<br>
<span>第三行</span>
</p>
</body>
2.2.3.1、组合伪类和伪元素
如果你想让第一段的第一行加粗,你需要把:first-child和::first-line选择器放到一起。
article p:first-child::first-line {
font-size: 120%;
font-weight: bold;
}
2.2.3.2、生成带有::before和::after的内容
有一组特别的伪元素,它们和content属性一同使用,使用 CSS 将内容插入到你的文档中。
<p class="box">我的 HTML 页面的盒子中的内容。</p>
.box::before {
content: "这应该显示在其他内容之前。";
}
这样这应该显示在其他内容之前。就会被插入到我的 HTML 页面的盒子中的内容。之前了。
2.2.4、初探关系选择器
最后一组选择器可以将其他选择器组合起来,更复杂的选择元素。下面的示例用运算符(>)选择了<article>元素的初代子元素。
article > p {
color: blue;
}
<body>
<article>
<p>第一行</p>
<section>
<p>第二行</p>
</section>
</article>
</body>
2.3、属性选择器
2.3.1、存否和值选择器
这些选择器允许基于一个元素自身是否存在(例如href)或者基于各式不同的按属性值的匹配,来选取元素。
| 选择器 | 示例 | 描述 |
|---|---|---|
[attr] |
a[title] |
匹配带有一个名为attr的属性的元素——方括号里的值。 |
[attr=value] |
a[href="https://example.***"] |
匹配带有一个名为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类的值,它选中了第二和第三项。 -
li[class|="ab"]会匹配一个类名开始为ab类或正为ab的类,后面紧随连字符(-)的类。
<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-a">Item 4</li>
</ul>
body {
font-family: sans-serif;
}
li[class] {
font-size: 120%;
}
li[class="a"] {
background-color: yellow;
}
li[class~="a"] {
color: red;
}
li[class|="ab"] {
color: blue;
}
2.3.2、子字符串匹配选择器
这些选择器让更高级的属性的值的子字符串的匹配变得可行。例如,如果你有box-warning和box-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^="list-"]匹配了任何值开头为list-的属性,于是匹配了前两项。 -
li[class$="-list"]匹配了任何值结尾为-list的属性,于是匹配了第一和第三项。 -
li[class*="list"]匹配了任何值的字符串中出现了list的属性,于是匹配了所有项。
<h1>Attribute substring matching selectors</h1>
<ul>
<li class="list-list">Item 1</li>
<li class="list-a">Item 2</li>
<li class="bca-list">Item 3</li>
<li class="bc-list-abc">Item 4</li>
</ul>
body {
font-family: sans-serif;
}
li[class^="list-"] {
font-size: 120%;
}
li[class$="-list"] {
background-color: yellow;
}
li[class*="list"] {
color: red;
}
2.4、关系选择器
关系选择器(***binator),它们在其他选择器之间和其他选择器与文档内容的位置之间建立了一种有用的关系。
2.4.1、后代选择器
后代选择器通常用单个空格( )字符来组合两个选择器。当第二个选择器匹配的元素存在一个祖先元素(父元素、祖父元素等)与第一个选择器匹配时,该元素就会被选中。通过这种方式组合出的选择器被称作后代选择器。
下面的示例中,我们只会匹配处于带有.box类的元素里面的<p>元素。
<div class="box"><p>Text in .box</p></div>
<p>Text not in .box</p>
.box p {
color: red;
}
2.4.2、子代关系选择器
子代关系选择器是个大于号(>),只会在选择器选中直接子元素的时候匹配。继承关系上更远的后代则不会匹配。例如,只选中作为<article>的直接子元素的<p>元素:
article > p {
color:red;
}
下个示例中,我们弄了个有序列表,内嵌于另一个无序列表里面。我用子代关系选择器,只选中为<ul>的直接子元素的<li>元素,给了它们一个顶端边框。
如果你移去指定子代选择器的>的话,你最后得到的是后代选择器,所有的<li>会有个红色的边框。
<ul>
<li>Unordered item</li>
<li>
Unordered item
<ol>
<li>Item 1</li>
<li>Item 2</li>
</ol>
</li>
</ul>
ul > li {
border-top: 5px solid red;
}
2.4.3、邻接兄弟
邻接兄弟选择器(+)用来选中恰好处于另一个在继承关系上同级的元素旁边的物件。例如,选中所有紧随<p>元素之后的<img>元素:
p + img
常见的使用场景是,改变紧跟着一个标题的段的某些表现方面,就像是我下面的示例那样。这里我们寻找一个紧挨<h1>的段,然后样式化它。
<article>
<h1>A heading</h1>
<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 zu***hini.
</p>
</article>
body {
font-family: sans-serif;
}
h1 + p {
font-weight: bold;
background-color: #333;
color: #fff;
padding: 0.5em;
}
2.4.4、通用兄弟
如果你想选中一个元素的兄弟元素,即使它们不直接相邻,你还是可以使用通用兄弟关系选择器(~)。要选中所有的<p>元素后任何地方的<img>元素,我们会这样做:
p ~ img
在下面的示例中,我们选中了所有的 <h1>之后的<p>元素,虽然文档中还有个 <div>,其后的<p>还是被选中了。
<article>
<h1>A heading</h1>
<p>I am a paragraph.</p>
<div>I am a div</div>
<p>I am another paragraph.</p>
</article>
body {
font-family: sans-serif;
}
h1 ~ p {
font-weight: bold;
background-color: #333;
color: #fff;
padding: 0.5em;
}
2.4.5、使用关系选择器
你能用关系选择器,将任何在我们前面的学习过程中学到的选择器组合起来,选出你的文档中的一部分。例如如果我们想选中为<ul>的直接子元素的带有“a”类的列表项的话,我可以用下面的代码。
ul > li[class="a"] {
}
3、盒模型
在 CSS 中,我们有几种类型的盒子,一般分为区块盒子(block boxes)和行内盒子(inline boxes)。类型指的是盒子在页面流中的行为方式以及与页面上其他盒子的关系。盒子有内部显示(inner display type)和外部显示(outer display type)两种类型。
3.1、外部显示类型
一个拥有 block 外部显示类型的盒子会表现出以下行为:
- 盒子会产生换行。
-
width和height属性可以发挥作用。 - 内边距、外边距和边框会将其他元素从当前盒子周围“推开”。
- 如果未指定
width,方框将沿行向扩展,以填充其容器中的可用空间。在大多数情况下,盒子会变得与其容器一样宽,占据可用空间的 100%。
某些 HTML 元素,如 <h1> 和 <p>,默认使用 block 作为外部显示类型。
一个拥有 inline 外部显示类型的盒子会表现出以下行为:
- 盒子不会产生换行。
-
width和height属性将不起作用。 - 垂直方向的内边距、外边距以及边框会被应用但是不会把其他处于
inline状态的盒子推开。 - 水平方向的内边距、外边距以及边框会被应用且会把其他处于
inline状态的盒子推开。
某些 HTML 元素,如 <a>、 <span>、 <em> 以及 <strong>,默认使用 inline 作为外部显示类型。
3.2、内部显示类型
盒子还有内部显示类型,它决定了盒子内元素的布局方式。
区块和行内布局是网络上的默认行为方式。默认情况下,在没有任何其他指令的情况下,方框内的元素也会以标准流的方式布局,并表现为区块或行内盒子。
例如,可以通过设置 display: flex; 来更改内部显示类型。该元素仍将使用外部显示类型 block 但内部显示类型将变为 flex。该方框的任何直接子代都将成为弹性(flex)项,并按照弹性盒子规范执行。
当你继续详细学习 CSS 布局时,将会遇到 flex 以及盒子可以具有的其他各种内部值,例如 grid。
3.3、不同显示类型的例子
下面的示例中有三个不同的 HTML 元素,它们的外部显示类型都是 block。
- 在 CSS 中添加了边框的段落。浏览器会将其渲染为一个盒子框。段落从新行开始,并扩展整个可用宽度。
- 使用
display: flex布局的列表。这就为容器的子项(即弹性项)建立了弹性布局。列表本身是一个区块盒子,与段落一样,会扩展到整个容器的宽度,然后换行。 - 一个块级段落,内含两个
<span>元素。这些元素通常是inline,但是其中一个元素的类是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>
body {
font-family: sans-serif;
}
p,
ul {
border: 2px solid rebe***apurple;
padding: 0.2em;
}
.block,
li {
border: 2px solid blue;
padding: 0.2em;
}
ul {
display: flex;
list-style: none;
}
.block {
display: block;
}
在下一个示例中,我们可以看到 inline 元素是如何表现的。
- 第一段中的
<span>元素默认为行级,因此不会强制换行。 - 设置为
display: inline-flex的<ul>元素会创建一个行向盒子,其中包含一些弹性项目。 - 这两个段落都设置为
display: inline。行向弹性容器和段落都在一行中流动,而不是分成两行(如果它们显示为块级元素,就会这样)。
要在显示模式之间切换,可以将 display: inline 更改为 display: block,或将 display: inline-flex 更改为 display: flex。
<p>
I am a paragraph. Some of the
<span>words</span> have been wrapped in a <span>span element</span>.
</p>
<ul>
<li>Item One</li>
<li>Item Two</li>
<li>Item Three</li>
</ul>
<p class="inline">I am a paragraph. A short one.</p>
<p class="inline">I am another paragraph. Also a short one.</p>
body {
font-family: sans-serif;
}
p,
ul {
border: 2px solid rebe***apurple;
}
span,
li {
border: 2px solid blue;
}
ul {
display: inline-flex;
list-style: none;
padding: 0;
}
.inline {
display: inline;
}
3.4、什么是CSS盒模型?
CSS 盒模型整体上适用于区块盒子,它定义了盒子的不同部分(外边距、边框、内边距和内容)如何协同工作,以创建一个在页面上可以看到的盒子。
3.4.1、盒模型的各个部分
CSS 中组成一个区块盒子需要:
-
内容盒子:显示内容的区域;使用
inline-size和block-size或width和height等属性确定其大小。 -
内边距盒子:填充位于内容周围的空白处;使用
padding和相关属性确定其大小。 -
边框盒子:边框盒子包住内容和任何填充;使用
border和相关属性确定其大小。 -
外边距盒子:外边距是最外层,其包裹内容、内边距和边框,作为该盒子与其他元素之间的空白;使用
margin和相关属性确定其大小。
下图显示了这些层次:
3.4.2、CSS标准盒模型(box-sizing: content-box;)
在标准盒模型中,如果在盒子上设置了 inline-size 和 block-size(或 width 和 height)属性值,这些值就定义了内容盒子的 inline-size 和 block-size(水平语言中为 width 和 height)。然后将任何内边距和边框添加到这些尺寸中,以获得盒子所占的总大小(见下图)。
假设一个盒子的 CSS 如下:
.box {
width: 350px;
height: 150px;
margin: 10px;
padding: 25px;
border: 5px solid black;
}
方框实际占用的空间宽为 410px(350 + 25 + 25 + 5 + 5),高为 210px(150 + 25 + 25 + 5 + 5)。
外边距不计入盒子的实际大小——当然,它影响盒子在页面上所占的总空间,但只影响盒子外的空间。盒子的面积止于边框,不会延伸到外边距中。
3.4.3、CSS替代盒模型(box-sizing: border-box;)
在替代盒模型中,任何宽度都是页面上可见方框的宽度。内容区域的宽度是该宽度减去填充和边框的宽度(见下图)。无需将边框和内边距相加,即可获得盒子的实际大小。
要为某个元素使用替代模型,可对其设置 box-sizing: border-box:
.box {
box-sizing: border-box;
}
假设一个盒子的 CSS 与上例相同:
.box {
width: 350px;
inline-size: 350px;
height: 150px;
block-size: 150px;
margin: 10px;
padding: 25px;
border: 5px solid black;
}
现在,盒子实际占用的空间在行向为 350px,在块向为 150px。
要在所有元素中使用替代方框模型(这是开发人员的常见选择),请在 <html> 元素上设置 box-sizing 属性,并将所有其他元素设置为继承该值:
html {
box-sizing: border-box;
}
*,
*::before,
*::after {
box-sizing: inherit;
}
3.4.5、外边距、内边距和边框
在上面的示例中,你已经看到了 margin、padding 和 border 属性的作用。该示例中使用了简写属性,允许我们一次性设置盒子的所有边。这些简写属性也有等效的普通属性,可以单独控制盒子的不同边。
外边距(margin)
外边距是盒子周围一圈看不到的空间。它会把其他元素退推离盒子。外边距属性值可以为正也可以为负。在盒子一侧设置负值会导致盒子和页面上的其他内容重叠。无论使用标准模型还是替代模型,外边距总是在计算可见部分后额外添加。
我们可以使用 margin 属性一次性控制一个元素的所有外边距,或者每边单独使用等价的普通属性控制:
margin-topmargin-rightmargin-bottommargin-left
在下面的示例中,尝试更改外边距的值,来查看当前元素和其包含元素,在外边距设置为正时如何推开周边元素,以及设置为负时,是如何收缩空间的。
<div class="container">
<div class="box">Change my margin.</div>
</div>
.container {
border: 5px solid blue;
margin: 40px;
}
.box {
border: 5px solid rebe***apurple;
background-color: lightgray;
padding: 10px;
height: 100px;
/* try changing the margin properties: */
margin-top: -40px;
margin-right: 30px;
margin-bottom: 40px;
margin-left: 4em;
}
外边距折叠
根据外边距相接触的两个元素是正边距还是负边距,结果会有所不同:
- 两个正外边距将合并为一个外边距。其大小等于最大的单个外边距。
- 两个负外边距会折叠,并使用最小(离零最远)的值。
- 如果其中一个外边距为负值,其值将从总值中减去。
在下面的示例中,我们有两个段落。最上面一段的 margin-bottom 为 50 像素,另一段的 margin-top 为 30 像素。页边距折叠在一起,因此方框之间的实际页边距是 50 像素,而不是两个页边距的总和。
你可以通过将第 2 段的 margin-top 设置为 0 来测试它。两个段落之间的可见边距不会改变——它保留了第一个段落 margin-bottom 设置的 50 像素。如果将其设置为 -10px,你会发现总边距变成了 40px(从 50px 中减去该负值)。
<div class="container">
<p class="one">I am paragraph one.</p>
<p class="two">I am paragraph two.</p>
</div>
.container {
border: 5px solid blue;
margin: 40px;
}
p {
border: 5px solid rebe***apurple;
background-color: lightgray;
padding: 10px;
}
.one {
margin-bottom: 50px;
}
.two {
margin-top: 30px;
}
边框(border)
边框是在边距和填充盒子之间绘制的。如果你正在使用标准的盒模型,边框的大小将添加到框的宽度和高度。如果你使用的是替代盒模型,边框越大会使内容框越小,因为它会占用一些可用的宽度和高度。
为边框设置样式时,有大量的属性可以使用——有四个边框,每个边框都有样式、宽度和颜色,我们可能需要对它们进行操作。
可以使用 border 属性一次性设置所有四个边框的宽度、颜色和样式。
欲分别设置每边的属性,可以使用:
border-topborder-rightborder-bottomborder-left
欲设置所有边的宽度、样式或颜色,可以使用:
border-widthborder-styleborder-color
欲设置单条边的宽度、样式或颜色,可以使用最细粒度的普通属性之一:
border-top-widthborder-top-styleborder-top-colorborder-right-widthborder-right-styleborder-right-colorborder-bottom-widthborder-bottom-styleborder-bottom-colorborder-left-widthborder-left-styleborder-left-color
在下面的示例中,我们使用了各种简写属性和普通属性来创建边框。请尝试使用不同的属性,以了解它们的工作原理。有关边框属性的 MDN 页面提供了有关不同可用边框样式的信息。
<div class="container">
<div class="box">Change my borders.</div>
</div>
body {
font-family: sans-serif;
}
.container {
margin: 40px;
padding: 20px;
border-top: 5px dotted green;
border-right: 1px solid black;
border-bottom: 20px double rgb(23 45 145);
}
.box {
padding: 20px;
background-color: lightgray;
border: 1px solid #333333;
border-top-style: dotted;
border-right-width: 20px;
border-bottom-color: hotpink;
}
内边距(padding)
内边距位于边框和内容区域之间,用于将内容推离边框。与外边距不同,内边距不能为负数。任何应用于元素的背景都会显示在内边距后面。
我们可以使用 padding 简写属性一次性控制元素所有边,或者每边单独使用等价的普通属性:
padding-toppadding-rightpadding-bottompadding-left
在下面的示例中,你可以更改类 .box 上的内边距值,从而看到文本开始的位置与盒子的关系发生了变化。你还可以更改类 .container 的内边距,在容器和盒子之间创建空间。你可以更改任何元素的内边距,在其边框和元素内部的任何内容之间创建空间。
<div class="container">
<div class="box">Change my padding.</div>
</div>
body {
font-family: sans-serif;
}
.box {
border: 5px solid rebe***apurple;
background-color: lightgray;
padding-top: 0;
padding-right: 30px;
padding-bottom: 40px;
padding-left: 4em;
}
.container {
border: 5px solid blue;
margin: 40px;
padding: 20px;
}
把百分比作为内外边距
如果你把 margins 和 padding 设置为百分比的话,你会注意到一些奇怪的表现。在下面的例子里,我们有一个盒子,我们给了里面的盒子 10% 的 margin 以及 10% 的 padding。盒子底部和顶部的内外边距,和左右外边距有同样的大小。
<div class="box">I have margin and padding set to 10% on all sides.</div>
body {
font: 1.2em sans-serif;
}
.box {
border: 5px solid darkblue;
width: 200px;
margin: 10%;
padding: 10%;
}
或许,你期望元素的上下外边距是其高度的百分比,元素的左右外边距是其宽度的百分比。但情况并非如此!
使用百分比作为元素外边距(margin)或填充(padding)的单位时,值是以包含块的内联尺寸进行计算的,也就是元素的水平宽度。在我们的示例中,所有的外边距或填充都是宽度的 10%。请记住一个事实,当你使用百分比作为元素外边距或填充的单位时,你将得到一个相同尺寸的外边距或填充。
3.5、盒子模型和行内盒子
以上所有的方法都完全适用于块级盒子。某些属性也适用于行内盒子,例如由 <span> 元素创建的盒子。
在下面的示例中,我们在一个段落中使用了 <span>,并对其应用了 width、height、margin、border 和 padding。可以看到,宽度和高度都被忽略了。上下外边距、内边距边框都得到了应用,但不会改变其他内容与行内盒子之间的关系。内边距和边框与段落中的其他文字重叠。左右内边距、外边距和边框会将其他内容从方框中推开。
<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>
body {
font-family: sans-serif;
}
p {
border: 2px solid rebe***apurple;
width: 200px;
}
span {
margin: 20px;
padding: 20px;
width: 80px;
height: 150px;
background-color: lightblue;
border: 2px solid blue;
}
3.6、使用display:inline-block
display: inline-block 是 display 的一个特殊值,它提供了介于 inline 和 block 之间的中间位置。如果不希望项目换行,但又希望它使用 width 和 height 值并避免出现上述重叠现象,请使用它。
一个元素使用 display: inline-block,实现我们需要的块级的部分效果:
- 设置
width和height属性会生效。 -
padding、margin和border会推开其他元素。
不过,它不会换行,只有在明确添加 width 和 height 属性后,才会变得比其内容大。
在下一个示例中,我们将 display: inline-block 添加到 <span> 元素中。尝试将此更改为 display: 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>
body {
font-family: sans-serif;
}
p {
border: 2px solid rebe***apurple;
width: 300px;
}
span {
margin: 20px;
padding: 20px;
width: 80px;
height: 50px;
background-color: lightblue;
border: 2px solid blue;
display: inline-block;
}
当你想通过添加 padding 来扩大链接的点击范围时,这个功能就派上用场了。<a> 和 <span> 一样是一个行内元素;可以使用 display: inline-block 在其上设置内边距,使用户更容易点击链接。
这种情况在导航栏中很常见。下面的导航使用弹性盒显示在同一行中,我们为 <a> 元素添加了内边距,因为我们希望能够在 <a> 在鼠标移动到上面时改变背景色。内边距似乎覆盖了 <ul> 元素上的边框。这是因为 <a> 是一个内联元素。
在带有 .links-list a 选择器的规则中添加 display: inline-block,你就会看到它是如何通过使其他元素考虑内边距来解决这个问题的。
<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>
ul {
font-family: sans-serif;
display: flex;
list-style: none;
border: 1px solid #000;
}
li {
margin: 5px;
}
.links-list a {
background-color: rgb(179 57 81);
color: #fff;
text-decoration: none;
padding: 1em 2em;
}
.links-list a:hover {
background-color: rgb(66 28 40);
color: #fff;
}
4、层叠、优先级与继承
4.1、冲突规则
CSS 代表层叠样式表(Cascading Style Sheets),理解第一个词层叠(cascade)很重要——层叠的表现方式是理解 CSS 的关键。
在某些时候,在做一个项目过程中你会发现一些应该产生效果的样式没有生效。通常的原因是你创建了两个应用于同一个元素的规则。与层叠密切相关的概念是优先级(specificity),决定在发生冲突的时候应该使用哪条规则。设计元素样式的规则可能不是期望的规则,因此需要了解这些机制是如何工作的。
这里也有继承的概念,也就是在默认情况下,一些 css 属性继承当前元素的父元素上设置的值,有些则不继承。这也可能导致一些和期望不同的结果。
4.1.1、层叠
样式表层叠——简单的说,就是 CSS 规则的顺序很重要;当应用两条同级别的规则到一个元素的时候,写在后面的就是实际使用的规则。
下面的示例中,我们有两个关于 <h1> 的规则。<h1> 最后显示蓝色——这两个规则来自同一个源,且具有相同的元素选择器,有相同的优先级,所以顺序在最后的生效。
<h1>这是我的标题。</h1>
h1 {
color: red;
}
h1 {
color: blue;
}
4.1.2、优先级
浏览器是根据优先级来决定当多个规则有不同选择器对应相同的元素的时候需要使用哪个规则。它基本上是一个衡量选择器具体选择哪些区域的尺度:
- 一个元素选择器不是很具体,则会选择页面上该类型的所有元素,所以它的优先级就会低一些。
- 一个类选择器稍微具体点,则会选择该页面中有特定
class属性值的元素,所以它的优先级就要高一点。
下面我们再来介绍两个适用于 <h1> 的规则。下面的 <h1> 最后会显示红色——类选择器 main-heading 有更高的优先级,因此就会被应用——即使元素选择器顺序在它后面。
<h1 class="main-heading">这是我的标题。</h1>
.main-heading {
color: red;
}
h1 {
color: blue;
}
4.1.3、继承
继承也需要在上下文中去理解——一些设置在父元素上的 CSS 属性是可以被子元素继承的,有些则不能。
举一个例子,如果你设置一个元素的 color 和 font-family,每个在里面的元素也都会有相同的属性,除非你直接在元素上设置属性。
<p>由于主题颜色被设置为蓝色,因此该颜色会被子元素继承。</p>
<p>我们可以通过选择器定位元素来改变颜色,比如这个<span>内容跨越</span>元素。</p>
body {
color: blue;
}
span {
color: black;
}
4.2、理解继承
我们从继承开始。下面的例子中我们有一个 <ul> 元素,里面有两个无序列表。我们已经给 <ul> 设置了边框(border)、内边距(padding)和字体颜色。
color 属性是一个继承属性。因此,color 属性应用在直接子元素和其后代——直接子元素 <li> 和第一个嵌套列表中的子项。然后添加了一个 special 类到第二个嵌套列表,其中使用了不同的颜色。然后通过它的子元素继承。
<ul class="main">
<li>项目 1</li>
<li>
项目 2
<ul>
<li>2.1</li>
<li>2.2</li>
</ul>
</li>
<li>
项目 3
<ul class="special">
<li>
3.1
<ul>
<li>3.1.1</li>
<li>3.1.2</li>
</ul>
</li>
<li>3.2</li>
</ul>
</li>
</ul>
.main {
color: rebe***apurple;
border: 2px solid #***c;
padding: 1em;
}
.special {
color: black;
font-weight: bold;
}
像 width(上面提到的)、margin、padding 和 border 不会被继承。如果 border 可以被继承,每个列表和列表项都会获得一个边框——可能就不是我们想要的结果!
尽管每个 CSS 属性页都列出了属性是否被继承,但我们通常可以通过常识来判断哪些属性属于默认继承。
4.2.1、控制继承
CSS 为控制继承提供了五个特殊的通用属性值。每个 CSS 属性都接收这些值。
-
inherit设置该属性会使子元素属性和父元素相同。实际上,就是“开启继承”。
-
initial将应用于选定元素的属性值设置为该属性的初始值。
-
revert将应用于选定元素的属性值重置为浏览器的默认样式,而不是应用于该属性的默认值。在许多情况下,此值的作用类似于
unset。 -
revert-layer将应用于选定元素的属性值重置为在上一个层叠层中建立的值。
-
unset将属性重置为自然值,也就是如果属性是自然继承那么就是
inherit,否则和initial一样。
我们可以查看一个链接列表来探索这些值是如何运作的。在下面的实例中,你可以通过修改 CSS 来查看它们的功能,写代码是掌握 HTML 和 CSS 最好的办法。
示例:
- 第二个列表项应用了类
my-class-1。它设置了内部元素来继承属性。如果你删除这个类,它会如何改变链接的颜色? - 你知道为什么第三个和第四个链接会是这样的颜色?第三个链接设置了
initial,这意味着它使用了属性的初始值(在本例中为黑色),而不是链接的浏览器默认样式的蓝色。第四个设置了unset,这意味着链接文本会使用其父元素的颜色——绿色。 - 如果你为
<a>元素定义新的颜色(例如:a { color: red; }),哪些链接会改变颜色? - 阅读下一节有关重置所有属性的内容后,回到这里,并将
color属性改为all属性。注意第二个链接是怎么出现在新的一行中,还带有一个无序列表的符号的。你认为继承了哪些属性。
<ul>
<li>默认<a href="#">链接</a>颜色</li>
<li class="my-class-1">继承<a href="#">链接</a>颜色</li>
<li class="my-class-2">重置<a href="#">链接</a>颜色</li>
<li class="my-class-3">取消<a href="#">链接</a>颜色的设置</li>
</ul>
body {
color: green;
}
.my-class-1 a {
color: inherit;
}
.my-class-2 a {
color: initial;
}
.my-class-3 a {
color: unset;
}
4.2.2、重设所有属性值
CSS 的简写属性 all 可以用于同时将这些继承值中的一个应用于(几乎)所有属性。它的值可以是其中任意一个(inherit、initial、unset 或 revert)。这是一种撤销对样式所做更改的简便方法,以便回到之前已知的起点。
下面的示例中有两个块级引用元素。第一个用元素本身的样式,第二个设置 all 为 unset
<blockquote>
<p>当前块引用设置了样式</p>
</blockquote>
<blockquote class="fix-this">
<p>当前块引用未设置样式</p>
</blockquote>
blockquote {
background-color: orange;
border: 2px solid blue;
}
.fix-this {
all: unset;
}
4.3、理解层叠
我们现在明白了为什么嵌套在 HTML 结构中的段落和应用于正文中的 CSS 颜色相同,从入门课程中,我们了解了如何将文档中的任何修改应用于某个对象的 CSS,无论是把 CSS 指定某个元素还是创建一个类。现在,我们将要了解层叠如何定义在不止一个元素的时候怎么应用 CSS 规则。
有三个因素需要考虑,根据重要性排序如下,后面的更重要:
- 资源顺序
- 优先级
- 重要程度
我们从上往下看,看看浏览器是如何决定该应用哪个 CSS 规则的。
4.3.1、资源顺序
我们已经看到了顺序对于层叠的重要性。如果你有超过一条规则,而且都是相同的权重,那么最后面的规则会应用。可以理解为后面的规则覆盖前面的规则,直到最后一个开始设置样式。
资源顺序仅在规则的优先级相同时才体现出来,下面让我们看一下优先级:
4.3.2、优先级
你会发现在一些情况下,有些规则在最后出现,但是却应用了前面的具有冲突的规则。这是因为前面的有更高的优先级——它范围更小,因此浏览器就把它选择为元素的样式。
就像前面看到的,类选择器的权重大于元素选择器,因此类上定义的属性将覆盖应用于元素上的属性。
这里需要注意虽然我们考虑的是选择器,以及应用在选中对象上的规则,但不会覆盖所有规则,只覆盖相同的属性。
这样可以避免重复的 CSS。一种常见的做法是给基本元素定义通用样式,然后给不同的元素创建对应的类。举个例子,在下面的样式中我给 2 级标题定义了通用样式,然后创建了一些类只修改部分属性的值。最初定义的值应用于所有标题,然后更具体的值通过对应类来实现。
<h2>未设置类的标题</h2>
<h2 class="small">设置了 small 类的标题</h2>
<h2 class="bright">设置了 bright 类的标题</h2>
h2 {
font-size: 2em;
color: #000;
font-family: Georgia, "Times New Roman", Times, serif;
}
.small {
font-size: 1em;
}
.bright {
color: rebe***apurple;
}
优先级分数计算
现在让我们来看看浏览器如何计算优先级。我们已经知道一个元素选择器比类选择器的优先级更低,会被其覆盖。本质上,不同类型的选择器有不同的分数值,把这些分数相加就得到特定选择器的权重,然后就可以进行匹配。
一个选择器的优先级可以说是由三个不同的值(或分量)相加,可以认为是百(ID)十(类)个(元素)——三位数的三个位数:
- ID:选择器中包含 ID 选择器则百位得一分。
- 类:选择器中包含类选择器、属性选择器或者伪类则十位得一分。
- 元素:选择器中包含元素、伪元素选择器则个位得一分。
/* 1. 优先级:1-0-1 */
#outer a {
background-color: red;
}
/* 2. 优先级:2-0-1 */
#outer #inner a {
background-color: blue;
}
/* 3. 优先级:1-0-4 */
#outer div ul li a {
color: yellow;
}
/* 4. 优先级:1-1-3 */
#outer div ul .nav a {
color: white;
}
/* 5. 优先级:0-2-4 */
div div li:nth-child(2) a:hover {
border: 10px solid black;
}
/* 6. 优先级:0-2-3 */
div li:nth-child(2) a:hover {
border: 10px dashed black;
}
/* 7. 优先级:0-3-3 */
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;
}
4.3.3、内联样式
内联样式,即 style 属性内的样式声明,优先于所有普通的样式,无论其优先级如何。这样的声明没有选择器,但它们的优先级可以理解为 1-0-0-0;即无论选择器中有多少个 ID,它总是比其他任何优先级的权重都要高。
4.3.4、!important
有一个特殊的 CSS 可以用来覆盖所有上面所有优先级计算,不过需要很小心的使用——!important。用于修改特定属性的值,能够覆盖普通规则的层叠。
<p class="better">这是个段落。</p>
<p class="better" id="winning">一个选择器掌管一切!</p>
#winning {
background-color: red;
border: 1px solid black;
}
.better {
background-color: gray;
border: none !important;
}
p {
background-color: blue;
color: white;
padding: 5px;
}