第1章 层叠、优先级和继承
1.1 层叠
层叠规则
1.1.1 样式表的来源
用户代理样式表:浏览器默认样式。
作者样式表:自己设置的样式。
作者样式覆盖用户代理样式,因为作者样式的优先级更高
!important声明
在声明的后面、分号的前面加上!important
,该声明就会被标记为重要的声明
color: red !important;
总体的优先级
- 作者的
!important
- 作者
- 用户代理
1.1.2 理解优先级
浏览器将优先级分为两部分:HTML的行内样式和选择器的样式
行内样式
如果用HTML的style属性写样式,这个声明智慧作用于当前元素。实际上行内元素属于“带作用域的”声明,它会覆盖任何来自样式表或者<style>标签的样式
选择器优先级
不同类型的选择器有不同的优先级。优先级的准确规则如下:
- 如果选择器的ID数量更多,则它会胜出(即它更明确)。
- 如果ID数量一致,那么拥有最多类的选择器胜出。
- 如果以上两次比较都一致,那么拥有最多标签名的选择器胜出。
Attention! 伪类选择器和属性选择器与一个类选择器的优先级相同
通用选择器(*)和组合器(>、<、~)对优先级没有影响
优先级标记
常用的表示优先级的方式
用数值形式来标记,通常用逗号隔开每个数。比如,“1,2,2”表示选择器由1个ID、2个类、2个标签组成。优先级最高的ID列为第一位,紧接着是类,最后是标签。
有时,还会用4个数的标记,其中将最重要的位置用0或1来表示,代表一个声明是否是用行内样式添加的。此时,行内样式的优先级为“1,0,0,0”。它会覆盖通过选择器添加的样式,比如优先级为“0,1,2,0”(1个ID和2个类)的选择器。
1.1.3 源码顺序
如果两个声明的来源和优先级相同,其中一个声明在样式表中出现较晚,或者位于页面较晚引入的样式表中,则该声明胜出。
链接样式和源码顺序
//顺序不可改变
a:link {
color: blue;
text-decoration: none;
}
a:visited {
color: purple;
}
a:hover {
text-decoration: underline;
}
a:active {
color: red;
}
书写顺序之所以很重要,就是因为层叠。像上述的代码如果顺序发生变化,这个效果就会遭到破坏。
层叠值
如果一个声明在层叠中“胜出”,它就被称作一个层叠值。元素的每个属性最多只有一个层叠值。
1.1.4 两条经验法则
(1)在选择器中不要使用ID。
就算只用一个ID,也会大幅提升优先级。当需要覆盖这个选择器时,通常找不到另一个有意义的ID,于是就会复制原来的选择器,然后加上另一个类,让它区别于想要覆盖的选择器。
(2)不要使用!important
。
它比ID更难覆盖,一旦用了它,想要覆盖原先的声明,就需要再加上一个!important
,而且依然要处理优先级的问题。
1.2 继承
如果一个元素的某个属性没有层叠值,则可能会继承某个祖先元素的值。但不是所有的属性都能被继承。
能继承的属性通常是我们希望被继承的那些。它们主要是跟文本相关的属性:
color
、font
、font-family
、font-size
、font-weight
、font-variant
、font-style
、line-height
、letter-spacing
、text-align
、text-indent
、text-transform
、white-space
以及word-spacing
。还有一些属性也可以被继承,比如列表属性:
list-style
、list-style-type
、list-style-position
以及list-style-image
。表格的边框属性border-collapse
和border-spacing
也能被继承。
1.3 特殊值
有两个特殊值可以赋给任意属性,用于控制层叠:inherit
和initial
。
1.3.1 使用inherit关键字
我们想用继承代替一个层叠值。这时候可以用inherit
关键字。可以用它来覆盖另一个值,这样该元素就会继承其父元素的值。还可以使用inherit
关键字强制继承一个通常不会被继承的属性。
1.3.2 使用initial关键字
撤销作用于某个元素的样式可以用initial
关键字来实现。如果将initial
值赋给某个属性,那么就会有效地将其重置为默认值,这种操作相当于硬复位了该值。
1.4 简写属性
简写属性是用于同时给多个属性赋值的属性。例如font
//用font简写属性来指定font-style、font-weight、font-size、font-height以及font-family。
font: italic bold 18px/1.2 "Helvetica", "Arial", sans-serif;
1.4.1 简写属性会默默覆盖其他样式
大多数简写属性可以省略一些值,只指定我们关注的值。但是要知道,这样做仍然会设置省略的值,即它们会被隐式地设置为初始值。
1.4.2 理解简写值的顺序
简写属性会尽量包容指定的属性值的顺序。
上、右、下、左
当遇到像**margin
、padding
这样的属性,还有为元素的四条边分别指定值的边框属性时**,开发者容易弄错这些简写属性的顺序。这些属性的值是按顺时针方向,从上边开始的。
第2章 相对单位
绝对单位:像素单位(px)
相对单位:em rem
2.1 相对值的好处
相对单位就是CSS用来解决抽象的一种工具。我们可以基于窗口大小来等比例地缩放字号,而不是固定为14px,或者将网页上的任何元素的大小都相对于基础字号来设置,然后只用改一行代码就能缩放整个网页。
2.1 em和rem
em
em是最常见的相对长度单位,适合基于特定的字号进行排版。在CSS中,1em等于当前元素的字号,其准确值取决于作用的元素。
.padded {
font-size: 16px;
padding: 1em; ←---- 设置四个内边距为font-size
}
//内边距为1em,浏览器将其乘以字号,最终渲染为16px
浏览器会根据相对单位的值计算出绝对值,称作计算值
2.2.1 使用em定义字号
font-size: 1.2em //这个font-size是根据继承的字号来计算的
例:
body {
font-size: 16px;
}
.slogan { (以下3行)计算结果为元素继承的字号的1.2倍
font-size: 1.2em;
}
<body>
We love coffee
<p class="slogan">We love coffee</p> ←---- slogan继承了<body>的字号
</body>
em同时用于字号和其他属性
同时用它指定一个元素的字号和其他属性时,浏览器必须先计算字号,然后使用这个计算值去算出其余的属性值。
body {
font-size: 16px;
}
.slogan {
font-size: 1.2em; ←---- 计算值为19.2px
padding: 1.2em; ←---- 计算值为23.04px
background-color: #ccc;
}
//padding值为1.2em乘以19.2px,得到23.04px
字体缩小的问题
当用em来指定多层嵌套元素的字号时,为了算出每个元素的准确值,需要知道继承的字号,如果这个值是在父元素上用em定义的,就要知道父元素的继承值。
body {
font-size: 16px;
}
ul {
font-size: .8em;
}
<ul>
<li>Top level
<ul> (以下2行)这个列表嵌套在第一个列表中,继承它的字号
<li>Second level
<ul> (以下2行)这个嵌套在上一个列表中,继承第二个列表的字号
<li>Third level
<ul> (以下2行)以此类推
<li>Fourth level
<ul>
<li>Fifth level</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
纠正文字缩小的问题
ul {
font-size: .8em;
}
ul ul { (以下3行)嵌套的列表应当跟其父级的字号一致
font-size: 1em;
}
2.2.2 使用rem设置字号
根节点是所有其他元素的祖先节点,根节点有一个伪类选择器(:root),可以用它来选中自己。
rem是root em的缩写,rem是相对于根元素的单位。不管在文档的什么位置使用rem,1.2rem都会有相同的计算值:1.2乘以根元素的字号。
推荐使用rem设置字号,用px设置边框,用em设置其他大部分属性(尤其内边距、外边距和圆角)
2.3.1 设置一个合理的默认字号
将默认字号设置为14px:
:root { ←---- 使用HTML选择器
font-size: 0.875em; ←---- 14/16(理想的px/继承的px)=0.875
}
2.3.2 构造响应式面板
我们可以根据屏幕尺寸,用媒体查询改变根元素的字号。这样就能够基于不同用户的屏幕尺寸,渲染出不同大小的面板。
:root { (以下3行)作用到所有的屏幕,但是在大屏上会被覆盖
font-size: 0.75em;
}
@media (min-width: 800px) { (以下5行)仅作用到宽度800px及其以上的屏幕,覆盖之前的值
:root {
font-size: 0.875em;
}
}
@media (min-width: 1200px) { (以下5行)仅作用到宽度1200px及其以上的屏幕,覆盖前面两个值
:root {
font-size: 1em;
}
}
2.3.3 缩放单个组件
需要让同一个组件在页面的某些部分显示不同的大小,可以通em来单独缩放一个组件
2.4 视窗的相对窗口
em和rem都是相对font-size定义的,CSS里还有相对于浏览器视口定义长度的视口的相对单位的。
- vh:视口高度的1/100。
- vw:视口宽度的1/100。
- vmin:视口宽、高中较小的一方的1/100(IE9中叫vm,而不是vmin)。
- vmax:视口宽、高中较大的一方的1/100(本书写作时IE和Edge均不支持vmax)2。
2.4.1 使用vw定义字号
使用vh和vw设置字号非常实用,但优势在大屏上字还是太大了
2.4.2 使用calc()定义字号
calc()
函数内可以对两个及其以上的值进行基本运算。注意加号和减号两边必须有空白。
:root {
font-size: calc(0.5em + 1vw);
}
0.5保证了最小字号,1vw则确保了字体会随视口缩放。
2.5 无单位的数值和行高
有些属性允许无单位的值:line-height
、z-index
、font-weight
(700等于bold,400等于normal,等等)
任何长度单位(如px、em、rem)都可以用无单位的值0,因为这些情况下单位不影响计算值,即0px、0%、0em均相等。
2.6 自定义属性(即CSS变量)
层叠变量的自定义属性
给CSS引进了变量的概念,开启了一种全新的基于上下文的动态样式。可以声明一个变量,为它赋值,然后再样式表的其他的地方引用这个值。
:root {
--main-font: Helvetica, Arial, sans-serif; //
}
变量名前面必须有两个连字符(--
),用于跟CSS属性区分,剩下的部分可以随便命名。
变量必须在一个声明块内声明。这里是用了:root选择器,所以变量可以在整个网页使用。
使用:
:root {
--main-font: Helvetica, Arial, sans-serif;
}
p { (以下3行)将段落的字体设置为Helvetica、Arial、sans-serif
font-family: var(--main-font);
}
:root {
--main-font: Helvetica, Arial, sans-serif;
--brand-color: #369; ←---- 定义一个蓝色的brand-color变量
}
p {
font-family: var(--main-font);
color: var(--brand-color);
}
:root {
--main-font: Helvetica, Arial, sans-serif;
--brand-color: #369;
}
p {
font-family: var(--main-font, sans-serif); ←---- 指定备用值为sans-serif
color: var(--secondary-color, blue); ←---- secondary-color变量没有定义,因此会使用备用值blue
}
var()函数接受第二个参数,它指定了备用值。如果第一个参数指定的变量未定义,就会使用第二个值)
2.6.1 动态改变自定义属性
自定义属性真正的意义在于,自定义属性的声明能够层叠和继承:可以在多个选择器中定义相同的变量,这个变量在网页的不同地方有不同的值。
例:
<body>
<div class="panel"> ←-- 网页中的一个普通面板
<h2>Single-origin</h2>
<div class="body">
We have built partnerships with small farms
around the world to hand-select beans at the
peak of season. We then careful roast in
small batches to maximize their potential.
</div>
</div>
<aside class="dark"> (以下2行)深色容器内的另一个面板
<div class="panel">
<h2>Single-origin</h2>
<div class="body">
We have built partnerships with small farms
around the world to hand-select beans at the
peak of season. We then careful roast in
small batches to maximize their potential.
</div>
</div>
</aside>
</body>
//在:root选择器的规则中定义变量,这样的话这些值就可以提供给根元素(整个网页)下的任何元素。
:root {
--main-bg: #fff; (以下2行)分别将背景色和文字颜色变量定义为白色和黑色
--main-color: #000;
}
.panel {
font-size: 1rem;
padding: 1em;
border: 1px solid #999;
border-radius: 0.5em;
background-color: var(--main-bg); (以下2行)在面板样式中使用变量
color: var(--main-color);
}
.panel > h2 {
margin-top: 0;
font-size: 0.8em;
font-weight: bold;
text-transform: uppercase;
}
.dark {
margin-top: 2em; //给深色容器和前面的面板之间加上外边距
padding: 1em;
background-color: #999; //给深色容器加上深灰色背景
--main-bg: #333; //在容器内重定义--main-bg和--main-color变量
--main-color: #fff;
}
2.6.2 使用JavaScript改变自定义属性
<script type="text/javascript">
var rootElement = document.documentElement;
var styles = getComputedStyle(rootElement); ←-- 获取一个元素的styles对象
var mainColor = styles.getPropertyValue('--main-bg'); ←-- 获取styles对象的--main-bg值
console.log(String(mainColor).trim()); ←---- 确保mainColor是一个字符串,并去掉前后空格;打印结果为“#fff”
</script>
在不支持自定义属性的浏览器上,任何使用var()
的声明都会被忽略。请尽量为这些浏览器提供回退方案
第3章 盒模型
3.1 元素宽度的问题
案例
<body>
<header>
<h1>Franklin Running Club</h1>
</header>
<div class="container">
<main class="main">
<h2>Come join us!</h2>
<p>
The Franklin Running club meets at 6:00pm every Thursday
at the town square. Runs are three to five miles, at your
own pace.
</p>
</main>
<aside class="sidebar">
<div class="widget"></div>
<div class="widget"></div>
</aside>
</div>
</body>
body {
background-color: #eee;
font-family: Helvetica, Arial, sans-serif;
}
header {
color: #fff;
background-color: #0072b0;
border-radius: .5em;
}
main {
display: block; ←-- 修复IE的bug
}
.main {
background-color: #fff;
border-radius: .5em;
}
.sidebar {
padding: 1.5em; ←-- 给侧边栏加上内边距
background-color: #fff;
border-radius: .5em;
}
此时效果
想要做出主栏和侧栏的效果,我们首先使用浮动布局,将main
和sidebar
向左浮动,分别设置70%和30%的宽度
.main {
float: left;
width: 70%; ←---- 将main列向左浮动,设置宽度为70%
background-color: #fff;
border-radius: .5em;
}
.sidebar {
float: left;
width: 30%; ←---- 将sidebar向左浮动,设置宽度为30%
padding: 1.5em;
background-color: #fff;
border-radius: .5em;
}
但是效果却是这样
因为虽然将两列宽度设置为70%和30%,但是这是指定的内容的宽和高,注意,当给一个元素设置宽或高的时候,指定的是内容的宽和高。
在本例中,侧边栏的宽度等于30%宽度再加上各边1.5em左右的内边距
3.1.1 避免魔术数值
最笨的方法就是减少其中一列的宽度。替代魔术数值的一个方法就是让浏览器帮忙计算。
在本例中,因为加了内边距,两列的宽度总和超出了3em。所以我们可以使用calc()函数减去这个值,得到刚好100%的总和。比如设置侧边栏宽度为calc(30%-3em)。但是还有更好的解决办法
3.1.2 调整盒模型
使用box-sizing属性调整盒模型的行为,我们让指定的宽度包含内边距和边框
box-sizing的默认值为content-box,这意味着任何指定的宽或高都只会设置内容盒子的大小。把box-sizing设置为border-box后,height和width属性会设置内容、内边距以及边框的大小总和。
所以我们相对应的修改代码,给两个盒子加上box-sizing:border-box;属性
.main {
box-sizing: border-box; (以下9行)将盒模型改为border-box
float: left;
width: 70%;
background-color: #fff;
border-radius: .5em;
}
.sidebar {
box-sizing: border-box;
float: left;
width: 30%;
padding: 1.5em;
background-color: #fff;
border-radius: .5em;
}
3.1.3 全局设置border-box
可以利用通用选择器,一劳永逸,再也不用想着调整盒模型
*,
::before,
::after{
box-sizing:border-box;//给页面上所有的元素和伪元素设置border-box
}
但是用第三方组件的时候要小心,因为三方组件在开发CSS的过程中没有考虑到使用者会修改盒模型时。因为全局设置border-box
时使用的通用选择器会选中第三方组件内的每个元素,修改盒模型可能会有问题,所以最终需要写另外的样式将组件内的元素恢复为content-box
。
也可以利用继承改一下修改盒模型的方式
:root{
box-sizing:border-box;
}
*,
::before,
::after {
box-sizing: inherit; ←---- 告诉其他所有元素和伪元素继承其盒模型
}
用inherit强制继承border-box。在必要时选中第三方组件的顶级容器,将其恢复为content-box
.third-party-component {
box-sizing: content-box;
}
3.1.4 给列之间加上间隔
从宽度中减掉1.5em分给外边距
.main {
float: left;
width: 70%;
background-color: #fff;
border-radius: .5em;
}
.sidebar {
float: left;
width: calc(30% - 1.5em); ←---- 从宽度中减去1.5em
margin-left: 1.5em; ←---- ……将其添加到外边距
padding: 1.5em;
background-color: #fff;
border-radius: .5em;
}
这种方式不仅能够使用em指定间距,而且能让代码意图更明显。之后再看代码,从代码清单3-7中可能看不出为什么使用29%,但是代码清单3-8中的30% - 1.5em
则能提供线索,知道它是基于30%算出来的。
3.2 元素高度的问题
对border-box的修改适用于高度,但是通常最好避免给元素指定明确的高度。容器的高度应该由内容决定,而不是由容器自己决定。
3.2.1 控制溢出行为
当明确设置一个元素的高度时,内容可能会溢出容器。
overflow属性
用overflow属性可以控制溢出内容的行为,该属性支持下面四个值
- visible(默认值) 所有内容可见,即使溢出
- hidden 溢出容器内边距边缘的内容被裁剪,无法看见
- scroll 容器会一直出现滚动条,用户可以通过滚动查看剩余内容
- auto 只有内容溢出时容器才会出现滚动条
3.2.2 百分比高度的备选方案
要想让百分比高度生效,必须给父元素明确定义一个高度。(因为容器的高度一般由子元素决定,不设定的话会造成死循环,浏览器无法处理,会忽略)
等高列
现代浏览器支持了CSS表格,可以轻松实现等高列。比如IE8+支持display: table
,IE10+支持弹性盒子或者Flexbox,都默认支持等高列。
我现在想要将上面的例子主列和侧边栏高度对齐,看起来更好看。想要任意一列的内容增加,两列的高度都会增加的效果,同时要保持底部对齐
下面演示通过CSS表格和Flexbox两种方式实现这种效果。
CSS表格布局
用CSS表格布局替代浮动布局。给容器设置display: table
,给每一列设置display: table-cell
.container {
display: table; ←---- 让容器布局像表格一样
width: 100%; ←---- ❶让表格填充容器的宽度
}
.main {
display: table-cell;
width: 70%; (以下7行)让列布局像表格的单元格一样
background-color: #fff;
border-radius: .5em;
}
.sidebar {
display: table-cell;
width: 30%;
margin-left: 1.5em; ←---- ❷外边距不再生效
padding: 1.5em;
background-color: #fff;
border-radius: .5em;
}
默认情况下,display:table的元素不会扩展到100%,所以需要明确指定宽度,下图是没有指定宽度的情况
border-spacing 定义单元格的间距。该属性接受两个长度值:水平间距和垂直间距
但是会产生副作用,这个值也会作用于表格的外边缘。这样两列就无法跟头部左右对齐了
负外边距
需要给整个表格包裹一层新的容器
在表格容器外面包一个元素<div class="wrapper">
,将其左右外边距设置为-1.5em,从而抵消表格容器外侧1.5em的border-spacing
。
正的外边距会将容器的边缘往里推,而负的外边距则会将边缘往外拉。结合border-spacing
,两列靠近外侧的边缘跟<body>
(包裹元素所在的容器盒子)的边缘对齐了。现在的布局满足了需求:两列等高,1.5em的间距,外边缘跟头部对齐
Flexbox
可以利用Flexbox实现两列等高布局。Flexbox不需要一个额外的div
包裹元素,它默认会产生等高的元素。此外也不需要使用负外边距。
.container {
display: flex; ←---- 将容器的display属性设置为flex
}
.main { (以下7行)弹性容器内的元素不需要指定display或者float属性
width: 70%;
background-color: #fff;
border-radius: 0.5em;
}
.sidebar {
width: 30%;
padding: 1.5em;
margin-left: 1.5em; ←---- 跟浮动布局一样,外边距可以生效
background-color: #fff;
border-radius: .5em;
}
给容器设置display: flex
,它就变成了一个弹性容器,子元素默认等高。
3.2.3 使用min-height和max-height
可以用这俩属性指定最小或最大值,而不是明确定义高度,这样元素就可以在这些界限内自动决定高度
有三个元素。左边的元素没有min-height
,因此它的高度由自身决定,另外两个元素都设置了min-height
为3em。中间的元素如果自己决定高度的话应该比现在矮,但是min-height
值让它的高度为3em。右边的元素内容多到已经超过3em,容器自然地扩展高度,以容纳内容。
用人话讲就是,只要我设定了min-heigth,就算内容没有这么高也要设这么高,如果内容高于这个就自然扩容
同理,max-height
允许元素自然地增高到一个特定界限。如果到达这个界限,元素就不再增高,内容会溢出。还有类似的属性是min-width
和max-width
,用于限制元素的宽度。
3.2.4 垂直居中的内容
最简单的垂直居中方法:给容器相等的上下内边距
3.3 负外边距
负外边距有一些特殊用途,比如让元素重叠或者拉伸到比容器还宽。
负外边距的具体行为取决于设置在元素的哪边
如果设置左边或顶部的负外边距,元素就会相应地向左或向上移动,导致元素与它前面的元素重叠,如果设置右边或者底部的负外边距,并不会移动元素,而是将它后面的元素拉过来
在margin属性中一共有两类参考线,top和left的参考线属于一类,right和bottom的参考线属于另一类。top和left是以外元素为参考,right和bottom是以元素本身为参考
如果不给一个块级元素指定宽度,它会自然地填充容器的宽度。但如果在右边加上负外边距,则会把它拉出容器。如果在左边再加上相等的负外边距,元素的两边都会扩展到容器外面。这就是为什么可以拉宽图3-12里的表格容器布局,让它填满<body>
的宽度,忽略border-spacing的影响。
3.4 外边距折叠
3.4.1 文字折叠
段落(<p>
)默认有1em的上外边距和1em的下外边距。这是用户代理的样式表添加的,但当前后叠放两个段落时,它们的外边距不会相加产生一个2em的间距,而会折叠,只产生1em的间隔。
折叠外边距大小等于相邻外边距中的最大值
3.4.2 多个外边距折叠
即使两个元素不是相邻的兄弟节点也会产生外边距折叠。在没有其他CSS的影响下,所有相邻的顶部和底部外边距都会折叠。
也就是说可以给任何元素加上外边距,而不必担心它们前后的元素是什么。
3.4.3 容器外部折叠
网页标题是
,用户代理样式给他底部设置的外边距0.67em
它的父元素是
但是"Come join us"上方的外边距没有在容器外面折叠。这是因为弹性子元素的外边距不会折叠。利用Flexbox布局。
给头部添加上下内边距,外边距就不会在容器外部折叠。
现在更新CSS:
header {
padding: 1em 1.5em;
color: #fff;
background-color: #0072b0;
border-radius: .5em;
}
看看变化!
防止外边距折叠的方法
- 对容器使用overflow:auto(或者非visible的值),防止内部元素的外边距跟容器外部的外边距折叠,此方法副作用小
- 在两个外边距之间加上边框或者内边距,防止它们折叠(两个都要加!!)
- 如果容器为浮动元素、内敛块、绝对定位或固定定位时,外边距不会在它外面折叠
- 当使用flexbox布局时,弹性布局内的元素之间不会发生外边距折叠
- 当元素显示为table-cell时不具备外边距属性,因此不会折叠
3.5 容器内的元素边距
想要的效果:加上两个按钮和一个链接
<aside class="sidebar">
<a href="/twitter" class="button-link">
follow us on Twitter
</a>
<a href="/facebook" class="button-link">
like us on Facebook
</a>
</aside>
.button-link {
display: block; ←---- 块级元素填满了可用宽度,同时让每个链接单独一行
padding: 0.5em;
color: #fff;
background-color: #0090C9;
text-align: center;
text-decoration: none;
text-transform: uppercase;
}
此时的效果
需要给两个按钮之间加间距
如果直接加上margin-top:1.5rem,效果如图
侧边栏的内部边距padding和按钮的外边距接触了,按钮的上外边距使得容器的内边距看起来更大了
解决办法:使用相邻的兄弟组合器(+)选中同一个父元素下紧跟在其他button-link后面的button-link元素。
.button-link {
display: block;
padding: .5em;
color: #fff;
background-color: #0090C9;
text-align: center;
text-decoration: none;
text-transform: uppercase;
}
.button-link + .button-link {
//只给紧跟在其他button-link后面的button-link加上顶部外边距
margin-top: 1.5em;
}
只有第二个按钮有margin-top,这样显示就正常了
但是,当我们再往侧边栏加点内容
<a href="/sponsors" class="sponsor-link"> (以下3行)给侧边栏加上另一种链接
become a sponsor
</a>
加上样式
.sponsor-link {
display: block;
color: #0072b0;
font-weight: bold;
text-decoration: none;
}
可以给这个链接增加顶部外边距以实现效果,但是每次增加内容、修改HTML都要改动,每次都要考虑这些外边距问题。
3.5.2 更通用的解决方案:猫头鹰选择器
Web设计师Heydon Pickering曾表示外边距“就像是给一个物体的一侧涂了胶水,而你还没有决定是否要将它贴到某处,或者还没想好要贴到什么东西上”。不要给网页当前的内容固定外边距,而是应该采取更通用的方式,不管网页结构如何变化都能够生效。这就是Heydon Pickering所说的迟钝的猫头鹰选择器(以下简称猫头鹰选择器),因为它长这样:* + *
。
该选择器开头是一个通用选择器(*),可以选中所有元素,后面是一个相邻兄弟组合器(+),最后是另一个通用选择器 。它会选中页面上有着相同父级的非第一个子元素
body * + * {
margin-top: 1.5em;
}
我们将body放选择器的前面,这样该选择器就只能选中body内的元素。
效果如图。此时sidebar上面也会有顶部外边距,header和container是兄弟,所以container被选中,然后container中main和siderbar是兄弟,所以siderbar被选中,所以siderbar上面有外间距
要修正此错误,可以给主列补上内边距
.main {
width: 70%;
padding: 1em 1.5em; ←----给主列加上内边距
background-color: #fff;
border-radius: .5em;
}
.sidebar {
width: 30%;
padding: 1.5em;
margin-top: 0; ←---- 移除猫头鹰选择器设置的顶部外边距
margin-left: 1.5em;
background-color: #fff;
border-radius: .5em;
}
margin-top=0;修正顶部外边距
给main栏补上内边距
考虑这些外边距问题。
3.5.2 更通用的解决方案:猫头鹰选择器
Web设计师Heydon Pickering曾表示外边距“就像是给一个物体的一侧涂了胶水,而你还没有决定是否要将它贴到某处,或者还没想好要贴到什么东西上”。不要给网页当前的内容固定外边距,而是应该采取更通用的方式,不管网页结构如何变化都能够生效。这就是Heydon Pickering所说的迟钝的猫头鹰选择器(以下简称猫头鹰选择器),因为它长这样:* + *
。
该选择器开头是一个通用选择器(*),可以选中所有元素,后面是一个相邻兄弟组合器(+),最后是另一个通用选择器 。它会选中页面上有着相同父级的非第一个子元素
body * + * {
margin-top: 1.5em;
}
我们将body放选择器的前面,这样该选择器就只能选中body内的元素。
效果如图。此时sidebar上面也会有顶部外边距,header和container是兄弟,所以container被选中,然后container中main和siderbar是兄弟,所以siderbar被选中,所以siderbar上面有外间距
要修正此错误,可以给主列补上内边距
.main {
width: 70%;
padding: 1em 1.5em; ←----给主列加上内边距
background-color: #fff;
border-radius: .5em;
}
.sidebar {
width: 30%;
padding: 1.5em;
margin-top: 0; ←---- 移除猫头鹰选择器设置的顶部外边距
margin-left: 1.5em;
background-color: #fff;
border-radius: .5em;
}
margin-top=0;修正顶部外边距
给main栏补上内边距