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
计算。