关于 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% 0bottom=bottom center=center bottom=50% 100%center=center center=50% 50%top left=left top=0% 0%top right=right top=100% 0bottom 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% 0150px 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=2background-size200%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 Yright X top Y=calc(100% - X) Yleft 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对你来说已经没有任何秘密了。👌
后端开发教程 - Java、Spring Boot 实战 - msg200.com







