关于 background-position 你需要知道的一切
将我的 Stack Overflow 答案之一转换为帖子
目录
我们在处理时background-position
有两种常见的情况:
- 我们使用像素值(简单的值)
- 我们使用百分比值(比较棘手)
让我们开始彻底解释并消除周围的所有歧义background-position
!
像素值
使用像素值时,无论图像大小如何,参考点都是图像的左上角。这就像在定位元素中使用左上角一样:
请注意,其他单位(例如em
、ch
等)的行为与 相同px
。它们被称为长度。我们的比较可以推广到长度与百分比。您只需知道如何将每个长度转换为像素即可。
百分比值
使用百分比值时,参考与使用像素值时不同;它不再是上角/左角:
在这种情况下,我们需要考虑两个参数:容器的大小和图像的大小。以下是其工作原理的说明(我取了background-position
等于30% 30%
):
首先,我们考虑图像,找到用于放置图像的参考点。它是图像内部的点,根据图像的大小,30% 30%
从左上角算起(如绿线所示)。然后,我们将该点放置在容器内部,根据容器的大小,从左上角算起。30% 30%
从这个逻辑中,我们可以识别出一些简单的情况,例如
50% 50%
(中间) 100% 100%
(右下) 100% 0%
(右上)
以下是常见价值观及其等价性的完整列表:
left
=left center
=center left
=0 50%
right
=right center
=center right
=100% 50%
top
=top center
=center top
=50% 0
bottom
=bottom center
=center bottom
=50% 100%
center
=center center
=50% 50%
top left
=left top
=0% 0%
top right
=right top
=100% 0
bottom left
=left bottom
=0 100%
bottom right
=right bottom
=100% 100%
现在很明显,如果图像的大小等于容器的大小,那么使用百分比值不会有任何变化,因为所有位置都是相等的。图像的左上角已经位于0% 0%
容器的左上角( ),中心也已经位于中心( 50% 50%
),等等。
🏆 使用百分比值时的第一条黄金法则是:图像的大小需要与容器的大小不同
那么渐变呢?
上述逻辑应用于渐变时也是一样的,因为渐变被视为图像。默认情况下,如果你不指定background-size
,渐变的大小将等于其容器 的大小,这与使用图像时不同。这是每个开发人员在处理渐变时面临的主要问题。
如果我们参考的规范background-size
,我们可以看到问题是如何产生的:
如果两个值都是 auto ,则应使用图像的固有宽度和/或高度(如有),缺失的尺寸(如有)如上所述以 auto 的方式处理。如果图像既没有固有宽度也没有固有高度,则其大小将按照contain的方式确定。
和
包含
将图像缩放到最大尺寸,同时保留其固有纵横比(如果有),以便其宽度和高度都可以适合背景定位区域。
还有:
位图图像(例如 JPG)始终具有固有的尺寸和比例。
CSS没有固有尺寸或固有
<gradient>
比例ref
图像始终具有固有值,因此在大多数情况下,它的尺寸与其容器不同,因此background-position
使用百分比单位会产生效果。渐变没有固有值,因此渐变的尺寸等于其容器的尺寸,除非我们指定与容器尺寸不同的值,background-position
否则使用百分比单位永远不会起作用。background-size
🏆 使用随机值时的第二条黄金法则是:使用渐变时始终定义背景大小
更深入
我们在上面的例子中看到了使用介于和background-size
之间的值时如何工作,但是使用负值或大于 的值时又如何呢?逻辑是一样的,但找到参考点会更加棘手。0%
100%
100%
负值(< 0%)
假设我们想在 处放置一个背景-50% 0
。在这种情况下,参考点将位于图像之外。以下是示例:https://jsfiddle.net/no87qv2r/4/
如图所示,我们首先考虑-50%
图像的 ,即-50px
,来定义我们的参考点(即-50px
从图像的左边缘开始)。然后,我们-50%
根据容器的大小将该点放置在 (-100px
从容器的左边缘开始)。然后我们绘制图像,就得到了上述结果。只有100px
的图像可见。
我们可能还会注意到,当图像尺寸小于容器尺寸时,负百分比值的行为与负固定值相同(两者都会使图像向左移动)。在本例中,与( https://jsfiddle.net/no87qv2r/5/-50% 0
)相同。-50px 0
例如,如果我们将图像尺寸增加到150px 150px
,-50% 0
将与相同-25px 0
。
当我们使尺寸大于容器时,负值将开始将图像向右移动(就像正像素值一样),这是合乎逻辑的,因为50%
图像的尺寸会增加,而50%
容器的尺寸将保持不变。
如果我们考虑上图的情况,这就像增加顶部绿线,直到它比底部绿线更大。所以,仅凭符号不足以了解图像将如何移动;我们还需要考虑尺寸。
从逻辑上讲,这同样适用于渐变:
在上面,请注意以下语法的用法
background:linear-gradient(to right,red,blue) -50% 0/50px 150px no-repeat
这意味着
background:[image or gradient] [background-position]/[background-size] no-repeat
大值(> 100%)
与之前的逻辑相同:如果我们在 处定义背景,那么我们从左边缘(或从右边缘)150% 0
考虑我们的参考点,然后我们将它放置在容器的左边缘:https://jsfiddle.net/no87qv2r/9/(在此示例中,相当于)150%
50%
150%
150% 0
150px 0
如果我们开始增加,background-size
我们将会有与之前演示相同的行为:
特殊情况
使用范围之外的值[0% 100%]
可以让我们隐藏背景图像,但我们如何找到精确的值来完全隐藏图像呢?
让我们考虑下面的例子:
我们的图像有一个宽度Ws
,容器也有一个宽度Wp
,我们需要找到的值p
。从图中我们可以得到以下公式:
p * Wp = p * Ws + Ws <=> p = Ws/(Wp - Ws) with p in [0,1]
如果容器大小为200px
且图像为100px
则 p 也是1
如此100%
(我们当然添加负号并且它是-100%
)。
如果我们考虑百分比值而background-size
不是固定值,我们可以使这个公式更通用。假设background-size
是S%
。那么我们将得到
Ws = Wp * s (s in [0,1] and S=s*100)
第一个公式是:
p = Ws/(Wp - Ws) <=> p = s / (1 - s)
我们加上负号,得到p = s / (s - 1)
现在,如果我们想隐藏右侧的图像,我们会在右侧执行相同的逻辑(我们考虑上一个插图的镜像),但由于我们总是会考虑左边缘来找到我们需要添加的百分比100%
。
我们定义p'%
为等于100% + p%
,公式为
p' = 1 + p <=> p' = 1 + s / (1 - s) = 1 / (1 - s)
以下动画演示了上述计算:
让我们计算一些值:
当 时s=0.5
, 等于,百分比值将从到。在这种情况下,我们从负值开始,以正值结束,因为图像的大小background-size
小于容器的大小。如果我们考虑最后一种情况(),等于,百分比值将从到。我们从正值开始,以负值结束,因为图像的大小大于容器的大小。50%
-100%
200%
s=2
background-size
200%
200%
-100%
🏆 我们有第三条黄金法则:要将图像向左移动,如果尺寸小于容器尺寸,则需要负值,但如果尺寸大于容器尺寸,则需要正值(右侧也一样)。
像素和百分比值之间的关系
让我们定义一种根据像素值计算百分比值的方法,反之亦然(即两者之间的转换公式)。为此,我们只需要考虑参考点。
当使用像素值时,我们将考虑蓝线,并且我们将得到background-position:X Y
。
当使用百分比值时,我们将考虑绿线,并且我们将得到background-position:Px Py
。
公式如下:X + Px * Ws = Px * Wp
其中Ws
是图像的宽度,Wp
是容器的宽度(考虑到高度,Y 轴的公式相同)。
我们将得到X = Px * (Wp - Ws)
。通过这个公式,我们可以验证之前解释的黄金法则:
- 当 时
Wp = Ws
,公式不再有效,这证实了当图像的大小与容器相同时百分比值不起作用;因此像素和百分比值之间没有关系。 X
当 时,和的Px
符号相同;Wp > Ws
当 时,和 的符号相反Wp < Ws
。这证实了百分比值会根据图像大小而有所不同。如果我们考虑 的百分比值,我们也可以以不同的方式表达公式background-size
。我们将得到X = Px * Wp * (1 - s)
。
以下动画演示了上述计算:
更改参考
在上面的计算中,我们始终考虑图像和容器的左上角,以便将逻辑应用于像素值或百分比值。可以通过向 中添加更多值来更改此参考值background-position
。
默认情况下,background-position: X Y
相当于background-position: left X top Y
(左侧 X 轴和顶部 Y 轴的位置)。通过调整top
和/或,left
我们可以更改参考点和图像的放置方式。
以下是一些示例:
显然,对于 的X
值,我们只能使用left
和right
(水平位置),而对于 的Y
值,我们只能使用bottom
和top
(垂直位置)。通过所有不同的组合,我们逻辑上可以得到 4 个不同的角。
此功能还有助于优化某些计算。在特殊情况部分的示例中,我们进行了第一次计算以隐藏左侧图像,然后又进行了另一次计算以隐藏右侧图像。如果我们考虑更改参考,则只需进行一次计算。我们采用左侧使用的公式,并在右侧使用相同的公式。
这是新版本:
因为s=0.5
我们不再会从-100%
到 制作动画200%
,而是从left -100%
到right -100%
。
下面是另一个使用像素值的示例,我们可以看到在改变参考时处理计算是多么容易:
通过保持相同的参考来实现相同的动画会很棘手。
🏆 另一条黄金法则:如果您想要一个对称的动画,请在一侧执行逻辑,并通过更改参考在另一侧使用相同的逻辑。
结合像素和百分比值
我们可以用它calc()
进行一些涉及不同单位的复杂计算。例如,我们可以这样写width:calc(100px + 20% + 12em)
,浏览器会根据每个单位的工作原理来计算计算值,最终得到一个像素值(在本例中)。
那怎么办background-position
?如果我们写calc(50% + 50px)
,它会被计算为百分比值还是像素值?像素值会转换为百分比吗?还是反过来?
结果不会转换为像素值或百分比值,而是两者一起使用。background-position
在混合百分比和像素值时有特殊行为calc()
,逻辑如下:
- 我们首先通过应用与百分比值相关的所有逻辑,使用百分比值来定位图像。
- 我们将 (1) 的位置作为参考,并通过应用与像素值相关的所有逻辑,使用像素值再次定位图像。
做法是:将图像置于中心,然后向左calc(50% + 50px)
移动。50px
这个特性可以简化很多计算。以下是一个例子:
找到正确的百分比或像素值来放置如上所示的 4 个红色方块会很繁琐,但通过混合使用则calc()
非常容易。
现在,假设我们有这样的内容:calc(10% + 20px + 30% + -10px + 10% + 20px)
。浏览器将如何处理这个问题?
在这种情况下,浏览器将首先评估每个单元以获得简化形式calc(X% + Ypx)
,然后应用上述逻辑来定位图像。
calc(10% + 20px + 30% + -10px + 10% + 20px)
calc((10% + 30% + 10%) + (20px + -10px + 20px))
calc(50% + 30px)
例如:https://jsfiddle.net/no87qv2r/17/
无论公式的复杂程度如何,浏览器总是会分别评估百分比和像素值。
如果我们考虑的话,这里有更多等效值calc()
:
left X top Y
=X Y
right X top Y
=calc(100% - X) Y
left X bottom Y
=X calc(100% - Y)
right X bottom Y
=calc(100% - X) calc(100% - Y)
X
是像素值Y
而不是百分比!
使用 background-origin
这是另一个可用于更改背景图像位置的重要属性。此属性依赖于盒子模型,因此让我们快速回顾一下它的工作原理:
每个元素内部都有 3 个不同的框:边框框、填充框和内容框。background-origin
指定我们需要考虑哪个框来完成所有先前的计算。
这是一个不言自明的例子:
很明显,当我们没有padding时content-box
等同于padding-box
,当我们没有border时border-box
等同于padding-box
,而当没有padding和border时,这三者都是等价的。
值得注意的是,background-size
当与百分比值一起使用时,会受到此属性的影响。
我们也有这个background-clip
属性,但它不会影响计算。它只会通过裁剪部分背景来影响视觉效果。
使百分比表现得像像素
如果我们需要使图像(或渐变)的大小等于容器大小并使用像素等百分比移动它,我们可以考虑以下想法。
使用伪元素作为背景层
需要注意的是,translate 会考虑伪元素的大小,但由于它与容器本身相同,因此不会出现任何问题。我们也可以使用left
/ top
,但transform
性能会更好。使用这种方法不会出现重复。
使用 background-origin
诀窍是使用一些填充,限制原点content-box
并使其尺寸大于100%
覆盖填充,然后让图像再次填充容器。
在上面的例子中,我将填充设置为大小的一半,因此从逻辑上讲,我需要使用200%
来background-size
进行校正。对于background-position
,现在根据前面的解释,很容易找到所需的值。
另一个例子:
使用这种方法,我们可以实现重复,但由于我们添加了填充,所以我们无法添加内容。为了解决这个问题,我们可以结合这两种方法,得到以下效果:
就是这样!
现在background-position
对你来说已经没有任何秘密了。👌