CSS中百分比单位计算方式
CSS中的单位有很多类型,不同类型单位计算方式也有所不同,特别是**百分比(%)**单位,它的计算和使用的属性有着直接关系。其中最为重要的是:百分比是一定要有其对应的参照值,也就是说,百分比值是一种相对值,任何时候要分析它的计算值,都需要正确的找到它的参照值。言外之意,CSS中的百分比单位值最终计算出来的值是可变的。在这篇文章中,我们主要来看看百分比单位在不同使用场景中计算方式。
在CSS中能运用%值的属性很多,为了能让大家更好的理解使用%的规则,我们从最熟悉和最简单地属性开始。
font-size中的%
在font-size属性中,有的时候会取%为单位,比如:
:root {
--font-size: 100%
}
h1 {
font-size: var(--font-size)
}
当font-size的值为%值时,它的计算是相对于父元素的font-size来计算,如果父元素(以及它的祖先元素)未显式设置font-size值的话,将会以浏览器的默认值16px为基准。比如下面这个示例:
<body>
<div class="container">
<h1>font-size</h1>
</div>
</body>
:root {
--font-size: 100%;
}
h1 {
font-size: var(--font-size);
}
设置了%的元素将会根据它的DOM层级从底层向上层寻找,将会相对于离元素最近的父元素的font-size值计算。比如上面示例:

如果div.container显式设置了font-size的值,那么h1的font-size: 100%会相对于div.container的font-size值计算;反之往上寻找div.container的父元素(本例中对应的是body)的font-size。依此类推,直到寻找到显式设置了font-size值的祖先元素。这个过程有点类似于JavaScript中的事件冒泡的过程:

比如下面这个示例,你拖动下面的滑块,可以看到<h1>元素font-size的变化:
示例中body显示设置了font-size: 100%,计算出来的px值是16px,而且该示例<h1>的font-size是相对于<body>来计算。我们可以用下面的表格来整个计算的变化过程:
font-size |
font-size: 100% (<body>) |
<h1>计算后的font-size值 |
|---|---|---|
50% |
100% x 16 = 16px |
50% ❯ 50% x 16 = 8px |
100% |
100% x 16 = 16px |
100% ❯ 100% x 16 = 16px |
150% |
100% x 16 = 16px |
150% ❯ 150% x 16 = 24px |
200% |
100% x 16 = 16px |
200% ❯ 200% x 16 = 32px |
在上面的示例上稍作调整,把div.container的font-size也设置为%值:
.container {
font-size: var(--font-size)
}
这个时候<h1>的font-size会相对于它的父元素div.container的font-size计算,而div.container会相对于它的父元素body的font-size计算。整体的效果如下:
同样用表格来描述它们的计算过程:
font-size |
font-size: 100% (<body>) |
<div.container>计算后的值 |
<h1>计算后的font-size值 |
|---|---|---|---|
50% |
100% x 16 = 16px |
50% ❯ 50% x 16 = 8px |
50% ❯ 50% x 8 = 4px |
100% |
100% x 16 = 16px |
100% ❯ 100% x 16 = 16px |
100% ❯ 100% x 16 = 16px |
150% |
100% x 16 = 16px |
150% ❯ 150% x 16 = 24px |
150% ❯ 150% x 24 = 36px |
200% |
100% x 16 = 16px |
200% ❯ 200% x 16 = 32px |
200% ❯ 200% x 32 = 64px |
如果在每个DOM元素的
font-size都采用%值,那么越在DOM底层的元素,其font-size计算越复杂。
line-height中的%
CSS中的line-height取值为%时,它的计算方式是基于元素自身的font-size的值来计算。如果元素自身未显式设置font-size,则会基于元素继承过来的font-size的值计算。
比如下面这个示例:
<!-- HTML -->
<body>
<h1></h1>
<p></p>
<footer></footer>
</body>
/* CSS */
body {
font-size: 16px;
line-height: 120%;
}
h1 {
font-size: 32px;
}
p {
font-size: 16px;
}
footer {
font-size: 12px;
}
注意,line-height和font-size类似,也是一个继承属性,就上面这个示例,每个元素的line-height计算出来的值如下表所示:
| 元素 | font-size |
line-height |
计算出来的line-height |
|---|---|---|---|
body |
16px |
120% |
120% ❯ 16px x 120% = 19.2px |
h1 |
32px |
继承body的line-height |
19.2px |
p |
16px |
继承body的line-height |
19.2px |
footer |
12px |
继承body的line-height |
19.2px |
上面的示例中稍作调整,如果显式的在每个元素中设置font-size的值都是120%,这个时候每个元素的line-height的就会像下表这样:
| 元素 | font-size |
line-height |
计算出来的line-height |
|---|---|---|---|
body |
16px |
120% |
120% ❯ 16px x 120% = 19.2px |
h1 |
32px |
120% |
120% ❯ 32px x 120% = 38.4px |
p |
16px |
120% |
120% ❯ 16px x 120% = 19.2px |
footer |
12px |
120% |
120% ❯ 12px x 120% = 14.4px |
你可能看出它们之间的差异了。
上面的示例还算是简单的,因为每个元素的font-size都是固定单位px的值。如果元素的font-size是个%值,而且元素还有相应的嵌套关系,那么每个元素的line-height计算会更复杂一些。它的计算要分两个步骤:
- 根据
font-size的计算原理,先计算出每个元素自身的font-size值 - 元素的
line-height根据元素自身的font-size再计算出line-height的值
来看一个简单的示例:
<!-- HTML -->
<body>
<div class="container">
<h1></h1>
</div>
</body>
/* CSS */
:root {
--font-size: 100%;
}
body {
font-size: 100%;
line-height: 150%;
}
.container {
font-size: var(--font-size)
}
h1 {
font-size: var(--font-size)
line-height: 120%
}
你可以尝试着拖动下面Demo中的滑块,查看body、div.container和h1三个元素的line-height的值变化:
- 先来看
<html>元素,该元素显式的设置了line-height值为1.15,计算出来的line-height的值为18.4px; <body>元素显式设置了font-size为100%和line-height的值为150%,计算出来的line-height为24px(即100% x 16px x 150% = 24px);div.container元素会继承<body>的line-height,即计算出来的值是24px,即使font-size的值有所改变,但该元素并没有显式设置line-height的值,因此该元素的line-height不受元素自身的font-size值影响
最为复杂的是h1元素,该元素显式设置了font-size的值和line-height的值,而且它们的值都是百分比。虽然line-height的计算是基于font-size,并不复杂;但元素的font-size百分值计算相对而言较为复杂,特别是在层级复杂的情况之下。就该示例而言,它的计算过程如下表所示:
font-size |
font-size: 100% (<body>) |
<div.container>计算后的font-size值 |
<h1>计算后的font-size值 |
h1的line-height |
计算出来的h1的line-height值 |
|---|---|---|---|---|---|
50% |
100% x 16 = 16px |
50% ❯ 50% x 16 = 8px |
50% ❯ 50% x 8 = 4px |
120% |
120% x 4px = 4.8px |
100% |
100% x 16 = 16px |
100% ❯ 100% x 16 = 16px |
100% ❯ 100% x 16 = 16px |
120% |
120% x 16px = 19.2 |
150% |
100% x 16 = 16px |
150% ❯ 150% x 16 = 24px |
150% ❯ 150% x 24 = 36px |
120% |
120% x 36px = 43.199px |
200% |
100% x 16 = 16px |
200% ❯ 200% x 16 = 32px |
200% ❯ 200% x 32 = 64px |
120% |
120% x 64px = 76.8px |
CSS中使用line-height的时候,使用不带单位的因子数场景更多,比如line-height: 1.5。它的计算也是基于元素的font-size值来计算的,只不过继承过来的line-height如果是因子数,那么计算的结果和%是有所差异的。比如:
<!-- HTML -->
<body>
<h1></h1>
<p></p>
<footer></footer>
</body>
/* CSS */
body {
font-size: 16px;
line-height: 1.2;
}
h1 {
font-size: 32px;
}
p {
font-size: 16px;
}
footer {
font-size: 12px;
}
这个时候每个元素的line-height计算出来的值如下表所示:
| 元素 | font-size |
line-height |
计算出来的line-height |
|---|---|---|---|
body |
16px |
1.2 |
1.2 ❯ 16px x 1.2 = 19.2px |
h1 |
32px |
继承body的line-height值1.2 |
1.2 ❯ 32px x 1.2 = 38.4px |
p |
16px |
继承body的line-height值1.2 |
1.2 ❯ 16px x 1.2 = 19.2px |
footer |
12px |
继承body的line-height值1.2 |
1.2 ❯ 12px x 1.2 = 14.4px |
CSS中的
line-height是一个特复杂的属性,它的大小除了受元素font-size的值影响之外,同时也受font-family的影响。有关于line-height更详细的介绍可以阅读《深入了解CSS字体度量,行高和vertical-align》一文。
vertical-align中的%
CSS的vertical-align取值为%时,它的计算方式是基于元素自身的line-height值计算。如果元素自身未显式设置line-height的值,那么元素会继承其父元素(或祖先元素)的line-height值。
而line-height会受font-size的影响,这样一来,font-size也会影响取值为%的vertical-align。
body {
font-size: 100%;
line-height: 150%;
}
.container {
font-size: 2rem; // -> 2 x 16 = 32px
}
h1 {
line-height: 120%;
font-size: 2em; // -> 2 x 32 = 64px
// line-height 计算出来的值 64 x 1.2 = 76.8px
}
#per {
vertical-align: 100%;
// i 继承 h1的 line-height, 即 76.8px
// -> 100% x 76.8 = 76.8px
}
text-indent中的%
CSS的text-indent属性可以让一个块元素首行文本内容的缩进量。有的时候也会使用该方法实现图像替换文本(也属于Web隐藏术中的一种)。
同样的,text-indent取值也可以是个%值,它的计算是相对于元素块width(或height)计算,如果是逻辑属性的话,相对于inline-size(或block-size)计算。具体相对于width(inline-size)还是height(block-size)取决于CSS的书写模式(即受writing-mode和direction)。
这里以大家最为熟悉的书写模式为例,即水平方向书写模式。那么text-indent的%值是相对于width(或inline-size)的值计算:
上面聊的都是有关于Web排版中用到的CSS属性,接下来我们来看看CSS中盒模型中属性(比如width、height、margin和padding)取%值的计算方式(这些属性也是元素尺寸设置常见的属性)。
width和height中的%
先来看元素尺寸设置中的width和height属性:
- 元素的
width属性取%值时,它的计算是相对于元素父容器的width计算 - 元素的
height属性取%值时,它的计算是相对于元素父容器的height计算
我们来一个示例。
<!-- HTML -->
<div class="container">
<div class="element"></div>
</div>
其中.element元素是.container的子元素。.element元素的width和height取值为%值,为了更好的通过示例向大家演示,这里将该元素的父元素.container的width和height显式设置一个固定值,比如:
.container {
width: 500px;
height: 200px;
border: 1px dashed #f36;
}
:root {
--width: 50%;
--height: 50%;
}
.element {
width: var(--width);
height: var(--height);
background-color: #09f;
}
你可以尝试着拖动示例中的滑块,查看具体的效果:
margin中的%
margin是margin-top、margin-right、margin-bottom和margin-left的简写属性。这几个属性也可以取%的值。如果margin取%的值,它的计算是相对于像容器(父元素)的width来计算。
我们在上面的示例基础上,稍作调整后的效果如下:
你操作上面的Demo,你可能发现了,显式给.element元素设置margin-left和margin-right值,而且都同时为正值时,元素自身的空间会被margin-left和margin-right挤压,当margin-left和margin-right两个属性的值之和等元素元素width时,该元素将在视图中不可见:
另外,元素margin-left的值为负值时,元素会往左拉:

元素margin-right的值为正值时且大到一定的值(一般容器剩余空间),那么将会挤压元素自身的width:

CSS的margin属性在CSS领域既是一个基础属性,但也是一个复杂的体系,如果你想彻底了解该属性,建议您花时间阅读下面几篇文章:
- Everything You Need To Know About CSS Margins
- The Definitive Guide to Using Negative Margins
- CSS探索之旅:
margin系列
padding中的%
padding是CSS盒模型中的另一个属性,用来设置元素内容与元素边框之间的间距(常被称为内距),该属性也会影响影响盒模型的大小,只不过受box-sizing的值的影响。
注意,接下来的示例中,
box-sizing取值为border-box。如果你对box-sizing属性不太了解的话,建议你花点时间阅读《CSS3 Box-sizing》一文。
同样来看一个示例:
.container {
width: 500px;
height: 300px;
}
:root {
--padding-top: 0;
--padding-right: 0;
--padding-bottom: 0;
--padding-left: 0;
}
.element {
padding: var(--padding-top) var(--padding-right) var(--padding-bottom)
var(--padding-left);
}
可以尝试着拖动下面Demo中的滑块,调整每个方向的padding值,你会发现元素.element大小会改变(其中#09f)就是内距区域:
注意,负值对
padding属性无效。
margin、padding、width和height是CSS盒模型中可以用%定义值的属性,不过这几个属性都是CSS的物理属性,随着CSS逻辑属性的到来,对盒模型的定义带来了新的变化,在CSS的逻辑属性都有和物理属性相匹配的属性。也就是说,上面的百分比计算方式同样适用于CSS逻辑属性(指的是与margin、padding、width和height相匹配的属性)。不同的是,CSS逻辑属性会受CSS的书写模式的影响。
除此之外,CSS中的min-width、max-width也可以取%值,它的计算方式和width相同;min-height和max-height取%值计算方式和height相同。
偏移中的%
CSS中定位框(显式设置了值为非static的position元素)的精确位置是由**嵌入(Inset Properties)**属性来控制。其中物理嵌入属性有top、right、bottom和left;而逻辑嵌入属性有inset-block-start、inset-block-end、inset-inline-start、inset-inline-end以及它们的简写属性inset-block、inset-inline和inset。
CSS偏移属性是隶属于CSS Positioned Layout Module Level 3模块,有关于这方面更详细的介绍可以阅读Web布局系列中的《CSS定位和层叠控制》一文。
这些偏移属性都可以取%值,不过他的计算方式相对而言要复杂一些,因为它的计算取决于元素自身position所设置的值。
当元素position的取值为relative或absolute时,那么元素的偏移属性的%值计算相对于离元素最近的设置了position为非static的元素的width和height。其中top和bottom相对于height计算;left和right相对于width计算。
我们来看一个最简单的示例:
<!-- HTML -->
<div class="container">
<div class="element"></div>
</div>
/* CSS */
.container {
width: 500px;
height: 300px;
position: relative;
}
:root {
--top: 0;
--right: 0;
--bottom: 0;
--left: 0;
}
.element {
top: var(--top);
right: var(--right);
bottom: var(--bottom);
left: var(--left);
position: absolute;
}
你可以尝试着拖动下面示例中的滑块,查看效果:
但如果你将结构稍作调整:
<!-- HTML -->
<div class="wrapper">
<div class="container">
<div class="element"></div>
</div>
</div>
/* CSS */
.wrapper {
width: 40vw;
height: 40vh;
position: relative;
}
.container {
width: 30vw;
height: 30vh;
}
:root {
--top: 20%;
--left: 20%;
}
.element {
top: var(--top);
left: var(--left);
position: absolute;
}
这个时候,.element的top和left是相对于div.wrapper的height和width计算:
我们来看计算出来的结果:

对于position取值为absolute的元素,如果找不到最近的祖先元素有显式设置position(非static)值,那么元素的偏移属性会相对于视窗(Viewport)的width和height来计算。
如果元素的position取值为fixed时,一般情况之下,元素的偏移属性取%值的计算是相对于视窗的width和height。不过CSS的transform对于position值为fixed的元素有所影响,如果固定定位元素的祖先元素显式设置了transform属性,那么该固定元素会相对于设置了transform的祖先元素定位,这个时候取值为%的偏移属性的计算也会相对于该元素的width和height,将不会再相对于视窗计算。
特别声明,如果固定定位元素的祖先元素显式设置了
contain:paint的话,其计算方式和祖先元素显式设置transform等同。
如果元素的position显式设置值为sticky,那么偏移属性取%值的计算是相对于相关的滚动端口(Scrollport)的大小计算
滚动端口(Scrollport)是指文档(Document)中滚动容器(Scroll Container)的可视窗口。显式给元素设置
overflow: scroll或overflow: auto(在内容足够导出溢出时产生)可以创建滚动容器。
border-radius中的%
border-radius属性相对于前面几个属性要复杂一点。不过@supremebeing09的《CSS Border-Radius Can Do That?》对border-radius做过详细的阐述。如果你不愿意花时间阅读文章的话,可以用几张简单的图来阐述border-radius属性。
border-radius是一个简写属性,是border-top-left-radius、border-top-right-radius、border-bottom-right-radius和border-bottom-left-radius四个属性的简写属性。这几个属性可以接受一个值,也可以接受两个值<length-percentage>{1,2},简写语法:
border-radius: <length-percentage>{1,4} [ / <length-percentage>{1,4} ]?
其中/前面的值表示x轴的半径,/后面的值表示y轴的半径,如果没有显式使用/表示x和y的值相同,比如像下图这样:

同样的,border-radius也可以接受%的值,如果像border-radius: 30%表示每个角的圆角半径(x轴和y轴)都是30%:

在border-radius使用%值时,它计算的相对值是需要分开来算的,其中 x轴的%值相对于元素的width值计算;y轴的%值相对于元素的height值计算,比如:
.element {
width: 300px;
height: 300px;
border-radius: 30% 70% 20% 40%;
}
上面示例中border-radius: 30% 70% 20% 40%;对应的计算结果是:
左上角(top-left)⇒ border-top-left-radius: 30% ⇒ x = y = 300px x 30% = 90px
右上角(top-right) ⇒ border-top-right-radius: 70% ⇒ x = y = 300px x 70% = 210px
右下角(bottom-right)⇒ border-bottom-right-radius: 20% ⇒ x = y = 300px x 20% = 60px
左下角(bottom-left)⇒ border-bottom-left-radius: 40% ⇒ x = y = 300px x 40% = 120px
效果看上去像下图这样:

上面示例是元素width和height相等,如果元素width和height不相等时:
.element {
width: 600px;
height: 300px;
border-radius: 30% 70% 20% 40%;
}
这个时候,border-radius: 30% 70% 20% 40%;对应的计算结果是:
左上角(top-left)⇒ border-top-left-radius: 30% ⇒ x = 600px x 30% = 180px; y = 300px x 30% = 90px
右上角(top-right)⇒ border-top-right-radius: 70% ⇒ x = 600px x 70% = 420px; y = 300px x 70% = 210px
右下角(bottom-right)⇒ border-bottom-right: 20% ⇒ x = 600px x 20% = 120px; y = 300px x 20% = 60px
左下角(bottom-left)⇒ border-bottom-left: 40% ⇒ x = 600px x 40% = 240px; y = 300px x 40% = 120px
效果看上去像下图这样:

如果元素的width和height相等,但border-radius属性的值是一个带/符号的八个值:
.element { width: 300px; height: 300px; border-radius: 70% 30% 30% 70% / 60% 40% 60% 40%; }
对应的计算如下:
左上角(top-left)⇒ border-top-left-radius: 70% 60% ⇒ x = 300px x 70% = 210px; y = 300px x 60% = 180px
右上角(top-right)⇒ border-top-right-radius: 30% 40% ⇒ x = 300px x 30% = 90px; y = 300px x 40% = 120px
右下角(bottom-right)⇒ border-bottom-right-radius: 30% 60% ⇒ x = 300px x 30% = 90px; y = 300px x 60% = 180px
左下角(bottom-left) ⇒ border-bottom-left-radius: 70% 40% ⇒ x = 300px x 70% = 210px; y = 300px x 40% = 120px
对应的效果如下:

同样的,如果元素的width和height值不同时,计算方式相似:
.element {
width: 600px;
height: 300px;
border-radius: 70% 30% 30% 70% / 60% 40% 60% 40%;
}
对应的计算如下:
左上角(top-left)⇒ border-top-left-radius: 70% 60% ⇒ x = 600px x 70% = 420px; y = 300px x 60% = 180px
右上角(top-right)⇒ border-top-right-radius: 30% 40% ⇒ x = 600px x 30% = 180px; y = 300px x 40% = 120px
右下角(bottom-right)⇒ border-bottom-right-radius: 30% 60% ⇒ x = 600px x 30% = 180px; y = 300px x 60% = 180px
左下角(bottom-left) ⇒ border-bottom-left-radius: 70% 40% ⇒ x = 600px x 70% = 420px; y = 300px x 40% = 120px
对应的效果如下图所示:

如果你感兴趣的话,可以尝试着拖动下面示例中每个点的滑块,查看元素圆角的变化:
特别声明,上面的Demo由@supremebeing09提供,源于《CSS Border-Radius Can Do That?》一文。
border-image中的%
border-image也是一个简写属性,它的子属性有 border-image-source、 border-image-slice、 border-image-width、 border-image-outset 和 border-image-repeat。其中border-image-slice和border-image-width取值也可以是%:
border-image-slice: [<number> | <percentage>]{1,4} && fill?
border-image-width: [ <length-percentage> | <number> | auto ]{1,4}
其中,border-image-slice取值为%时,其计算是相对于border-image-source引入的图像源尺寸进行计算,其中x方向相对于图像的width计算,y方向相对于图像的height计算。比如引入的图像尺寸是240px x 240px:
border-image-slice: 20% 30% 40% 50%;
其中20%是距离图像顶部边缘的距离(y轴),30%是距离图像右侧边缘的距离(x轴),40%是距离图像底部边缘的距离(y轴),50%是距离图像左侧边缘的距离(x轴),其计算出来的值:
距离顶部边缘 ⇒ 20% ⇒ 240px x 20% = 48px
距离右侧边缘 ⇒ 30% ⇒ 240px x 30% = 72px
距离底部边缘 ⇒ 40% ⇒ 240px x 40% = 96px
距离左侧边缘 ⇒ 50% ⇒ 240px x 50% = 120px
如下图所示:

而border-image-width和border-image-slice类似,也是相对于图像的width和height来计算。border-image-width的四个值指定用于将边框图像区域划分为九个部分的偏移量。它们分别表示从该区域的顶部、右侧、底部和左侧向内的距离。
具体的效果可以查看MDN提供的Border-image generator。
background-position中的%
CSS中的background-position除了使用关键字来给图片指定位置之外,还可以使用具体的长度值,即,可以是%值。不过它的计算相对而言要更为复杂一些。
background-position可以分为background-position-x和background-position-y,换句话说,background-position接受多个值,但我们习惯于两个值的用法,即background-position: 50% 20%,如果background-position只显式的设置了一个值,那么表示backgrounnd-position-x和background-position-y的值相同。
刚才提到过了,background-position取%值计算要比前面介绍过的属性更为复杂。那是因为它是相对于元素尺寸与背景图片尺寸差计算,也就是说:
- 水平方向(
x轴),即background-position-x的%值是相对于元素的width与背景图片的width差 计算 - 垂直方向(
y轴),即background-position-y的%值是相对于元素的height与背景图片的height差计算
特别声明,背景图片的大小将会受
background-size值的影响,上面提到的图片的尺寸是指backgroud-size的值为auto的情景下的尺寸,即背景图片的初始尺寸(原始尺寸)。
比如下面这个示例:
<!-- HTML -->
<div class="element">
</div>
.element {
width: 500px;
height: 300px;
background-position: 70% 30%
}
比如我们在.element中使用像下面这样的一张背景图(图片原始尺寸:280px x 180px):

按照上面所说的:
background-position-x: 70% ⇒ (500px - 280px) x 70% = 154px
background-position-y: 30% ⇒ (300px - 180px) x 30% = 36px
效果如下图所示:

你也可以尝试着在下面的示例中拖动滑块,但看具体的效果:
background-size中的%
background-size属性可以用来指定背景图像的尺寸大小,同样background-size属性可以取%的值。当background-size取%的值时,它的计算是相对于元素自身的尺寸进行计算:background-size的第一个值是x轴方向,其计算相对于元素的width计算;background-size的第二个值是y轴方向,其计算相对于元素的height计算。比如下面这个示例:
<!-- HTML -->
<div class="container">
</div>
.container {
width: 500px;
height: 300px;
background-size: 50% 50%; // ⇒ 250px 150px
}
有的时候background-size只会显式的设置一个值,比如background-size: 50%,这个时候它相当于background-size: 50% auto。这个时候,background-size值的计算相对同时显式设置两个%值的计算要复杂的多。我们来看一个示例,有一背景图像,其尺寸是280px x 180px:

但元素的尺寸是150px x 150px,并且该元素显式设置了background-size: 100%(即100% auto):
.container {
width: 150px;
height: 150px;
background-size: 100%
}
这个时候你看到的效果如下:
这个时候background-size在x轴是100%,即是元素的width,也就是150px。简单地说,背景图像从280px缩小到150px,它们的缩放的比例是150 / 280 = 0.5357(即53.57%)。因此,为了保持宽高比,背景图像的高度也被缩小到53.57%,即180px x 53.57% = 96.428px(约97px)。
针对上面的示例,还可以像下面这样计算。背景图像的尺寸是280px x 180px,它的宽高比180 / 280 = 0.642857,当我们显式设置background-size: 100%时,此时图像的宽度就是150px,对应的高度150px x 0.642857 = 96.428px。
相比而言,第二种方式更易于理解,因为background-size的第二个值取值为auto时,就是为了满足背景图像宽高比,背景图像的高度会根据第一个值做相应的处理。同样拿上面的示例作为演示:
background-size: 100% ⇒ background-size: 100% auto;
⇒ x = 100% x 150px = 150px
⇒ r = 180 / 280 = 0.642857 ⇒ 背景图片宽高比
⇒ y = 0.642857 x 150px = 96.42857px
background-size: 50% ⇒ background-size: 50% auto
⇒ x = 50% x 150px = 75px
⇒ r = 180 / 280 = 0.642857 ⇒ 背景图片宽高比
⇒ y = 0.642857 x 75px = 48.21429px
background-size: 150% ⇒ background-size: 150% auto
⇒ x = 150% x 150px = 225px
⇒ r = 180 / 280 = 0.642857 ⇒ 背景图片宽高比
⇒ y = 0.642857 x 225px = 144.64286px
具体效果如下:
渐变中的%
CSS图像模块 Level 3和CSS图像值和替换内容模块Level 4包含了CSS渐变相关的属性,比如linear-gradient()、radial-gradient()、conic-gradient()、repeating-linear-gradient()、repeating-radial-gradient()和repeating-conic-gradient()。在这些属性的运用中也能看到%的身影,其中设置颜色位置可以用%,而且在径向渐变和锥形渐变的圆心位置也可以使用%。
其中颜色位置的%值是相对于渐变线做计算,如下图所示:

而径向渐变和锥形渐变的圆心位置的%分为x轴和y,其中x轴是相对于元素的width计算,y轴是相对于元素的height计算,如下图所示:

@Patrick Brosset在CodePen写了一个线性渐变的Demo,查看相应的效果:
object-position中的%
CSS有两个运用于可替换元素(比如<img>、<iframe>、<object>和<video>等)的属性object-fit,object-position,其中object-fit的表现行为和background-size非常相似,而object-position和background-position非常相似。前面和大家一起聊了聊background-position在background-size: 100% 100%情况之下background-position取%的计算方式。这里我们简单地聊一下object-position取%值的计算方式。
就取%值而言,其中object-position要考虑的场景较多,换句话说,object-fit取不同的值其计算方式不同,而且可替换元素的宽高比对其计算也有直接的影响。这里我们看一个简单的场景,即 **object-fit取值为none**情景。在这种情景之下,%值的计算:
x ⇒ (容器宽度 - 图片宽度) x 百分比值
y ⇒ (容器高度 - 图片高度) x 百分比值
刚才也提到过了,如果object-fit的值不同时,object-position的%值计算是有所不同,比如下面这个Demo:
特别声明,在后续将会和大家深入探讨
object-position和background-position在不同场景下取%值计算方式!
clip-path中的%
clip-path: inset( <shape-arg>{1,4} [round <border-radius>]? )
clip-path: circle( [<shape-radius>]? [at <position>]? )
clip-path: ellipse( [<shape-radius>{2}]? [at <position>]? )
clip-path: polygon( [<fill-rule>,]? [<shape-arg> <shape-arg>]# )
其中<shape-arg>、<border-radius>、<position>和<shape-radius>取值都可以是%值。为了更易于向大家阐述相应属性值取%值计算方式,将会借助@Bennett Feely的 **CSS clip-path maker**在线工具为例。
先来看inset()中的<shape-arg>和<border-radius>:
.element {
width: 800px;
height: 400px;
clip-path: inset(12% 12% 12% 12% round 5% 6% 7% 8% / 8% 7% 6% 5%);
}
其中<shape-arg>的使用和margin属性类似,<border-radius>的使用border-radius类似。在<shape-arg>中的top和bottom相对于元素的height计算;right和left相对于元素的width计算。<border-radius>中的%值计算方式和前面介绍的border-radius相同。

我们再来看circle()中的<shape-radius>和<position>:
.element {
width: 800px;
height: 400px;
clip-path: circle(22.5% at 50% 36%);
}
其中<shape-radius>的%计算是相对于半径r值计算,circle()的r的计算是相对于参考框(Reference Box)的width和height来计算,具体的计算公式如下:

就上例的话,计算出来的结果即是:
r = Math.sqrt(Math.pow(800, 2) + Math.pow(400, 2)) / Math.sqrt(2) = 632.4555320336758px
那么r x 22.5%计算出来的值大约为142.3024947px。
对于circle()中的<position>的%值是相对于元素的width和height值计算,其中第一个值是x轴,其相对于width计算,第二个值是y轴的值,相对于元素的height计算:

ellipse()中的<shape-radius>相比于circle()中的要简单地多,ellipse()中的半径分rx和ry,其中rx取%是相对于元素的width计算;ry取%是相对于元素的height计算。对于<position>而言,和circle()中的<position>相同。

polygon()用来绘制多边形(至少需要三个顶点才能构建一个多边形),在polygon()会有多个<shape-arg>,而每个<shape-arg>都是一个顶点在参考框中的x轴和y轴的坐标点。如果取%值时,x轴相对于元素的width计算,y相对于元素的height计算:

Masking中的%
CSS Masking的mask-position和mask-size属性取值的时候也可以是%的值。如果你理解了前面介绍的background-position和background-size属性中的%值计算方式的话,那也能理解mask-position和mask-size属性中的%值计算方式。其中mask-position和background-position相似,mask-size和background-size相似。
路径动画中的%
CSS路径动画offset属性中的子属性offset-position、offset-distance和offset-anchor在取值也可以使用%值。
offset-distance取值为%值时,它的计算是相对于偏移路径的长度(也就是偏移路径的初始位置和结束位置之间的距离)。
offset-position的计算方式可以参考background-position的方式。
offset-anchor取%值时,它的计算是根据运动物体(元素)的width和height来计算,其中x相对于width计算,y相对于height计算。比如我们所说的(50%, 50%)指的就是我们常说的center(或者center center)。
Transform中的%
transform中的translateX()和translateY()取%值时,它的计算是相对于元素自身的width和height。其中translateX()相对于元素自身的width计算,translateY()相对于元素自身的height计算。