假设您有一个带有 `background-image` 的元素,其中图像的一部分可见,因为图像比元素本身更大。 其余部分被裁剪掉,位于元素之外。
现在您想要移动该 `background-image`,以便将元素的中心聚焦在图像的特定点上。 您还想用百分比值而不是像素值来完成。 我们需要动动脑筋。
这将涉及一些数学。
让我们使用此作为我们的图像,其中包含用于大小调整的标记

这是我们的元素,已应用了该 `background-image`。 注意我们只能看到图像的(顶部)左侧
查看 Pen 背景焦点:无位置 by Jay (@jsit) on CodePen.
现在假设我们要将图像上的特定点与该元素的中心对齐。 例如,距离左侧 300 像素的点。

由于我们要求的是以像素为单位的位置,因此非常简单。 在没有定义位置的情况下,`background-image` 以中心点位于 100 像素的位置“开始”,因此您需要将其向左移动 200 像素
查看 Pen 背景焦点:像素位置 by Jay (@jsit) on CodePen.
让我们将其规范化。
您用于 `background-position-x` 的 `x` 值是按如下方式计算的
(0.5 × [bounding box width]) - [x-coordinate]
0.5 × 200px - 300px
100px - 300px = -200px
花点时间就能弄明白,但这并不难。 您可能可以直观地想明白这一点,而无需使用公式。
但是,如果要(或必须)将 `background-position-x` 表达为百分比怎么办? 应该不难吧? 让我们尝试使用百分比再次将自己居中在 300 像素处。 我们的 `background-position-x` 为 `-200px`,因此让我们将其转换为百分比:-200 / 800 = -25%,因此
查看 Pen 背景焦点:百分比(第一次尝试) by Jay (@jsit) on CodePen.
嗯,根本没有用。 也许我们需要使用正值?
查看 Pen 背景焦点:百分比(第二次尝试) by Jay (@jsit) on CodePen.
这好多了,但它居中在…… 250 像素? 如何将其作为边界框宽度的百分比:300 / 200 = 150%。 这不可能正确…
查看 Pen 背景焦点:百分比(第三次尝试) by Jay (@jsit) on CodePen.
是的,这不对。
让我们退一步。 如果我们这样做会怎么样?
查看 Pen 背景焦点:百分比(第四次尝试) by Jay (@jsit) on CodePen.
感觉有点道理;`background-position-x: 100%;` 使 `background-image` 靠右对齐,并在 700 像素处居中,即图像宽度 7/8。 但是,如果我们要将其居中在 100% 处? 我想我们必须做… 9/8?
查看 Pen 背景焦点:百分比(第五次尝试) by Jay (@jsit) on CodePen.
此时,我不惊讶它没有用。
这感觉不是正确的方向。 让我们退一步。
规范怎么说?
例如,对于 ‘0% 0%’ 的值对,图像的左上角与(通常)框的填充边的左上角对齐。 ‘100% 100%’ 的值对将图像的右下角放置在区域的右下角。 对于 ‘75% 50%’ 的值对,图像上横跨 75% 纵向 50% 的点将放置在区域上横跨 75% 纵向 50% 的点。
也许我们可以反向工程它。
在最后一个 112.5% 中,它将 `background-image` 上横跨 112.5% 的点与边界框上横跨 112.5% 的点对齐。 感觉有点道理。 规范似乎写得容易,只有三个值:0%、50% 和 100%。 任何其他值都不那么直观。
使用 `background-position-x: 0;`,我们关注的是 100 像素,即 12.5%。 使用 `background-position-x: 100%;`,我们关注的是 700 像素,即 87.5%。 那么 `background-position-x: 50%;` 究竟是什么样呢?
查看 Pen 背景焦点:百分比(第六次尝试) by Jay (@jsit) on CodePen.
50% 有点像我们的“锚点”; 这是我们想要聚焦的点以及相应的 `background-position-x` 值相等的地方。
假设我们要关注 700 像素或 87.5%。 我们从中心向右走 100%:50% + 50%。
查看 Pen 背景焦点:百分比(第四次尝试) by Jay (@jsit) on CodePen.
将 `background-position-x` 设置为 `100%`,我们绑定框的中心已从图像的中心“平移”,朝最右边边缘平移了 3/4(从 400 像素到 700 像素)。 如果我们要“平移”到最右边边缘,我们需要向右平移那额外的 1/4,即 200 像素。 1/4 是 3/4 的 1/3,因此我们需要比刚才多走三分之一,或者从中心走 66.667%
查看 Pen 背景焦点:百分比(第七次尝试) by Jay (@jsit) on CodePen.
哇! 因此,要将 `background-image` 的最右边边缘聚焦,该 `background-image` 的大小是我们绑定框的 4 倍,我们需要设置 `background-position-x: 116.667%;`。
我们到底该怎么弄明白呢?
它与我们可能期望的 100% 的“差”是 16.667%。 因此,如果我们要关注最初的目标 300 像素(或 37.5%),我们会…… 添加 16.667% 吗? 这不可能有效
查看 Pen 背景焦点:百分比(第八次尝试) by Jay (@jsit) on CodePen.
不行。
如果我们要关注最左边边缘,我们可能会从 0% 中减去 16.667%,对吧? 这听起来可能是对的。
查看 Pen 背景焦点:百分比(第九次尝试) by Jay (@jsit) on CodePen.
太棒了!
要将焦点定位在 100% 或 0% 处,您必须“超出”这些值,从中心测量时。
因此,如果我们要关注 0%,即“从背景图像最左边边缘向左走 100%”,我们必须从 50% 中减去 66.667%。 如果我们要关注 100%,即“从背景图像最左边边缘向右走 100%”,我们必须将 66.667% 添加到 50% 中。
我可能期望从 50% 中添加或减去 50%,以达到这些边缘: “从中心走多远”到“我的 `background-position-x` 值应该是什么”的 1:1 比例。 但相反,我们必须使用 4:3 的比例。 换句话说,我们必须使用一个“远离中心”的值,这个值是其四分之三倍。
事情变得有点复杂了,因此让我们引入一些术语
- c:从背景图像最左边边缘测量的所需焦点(以百分比计)
- z:缩放因子(背景宽度 ÷ 边界框宽度)
- p:`background-position-x`,用于在给定 z 的情况下将焦点定位在 c 上
因此,我们将焦点的距离从中心(c − 50)乘以 4/3,然后将结果添加到“中心”,即 50。
如果要关注 600 像素(或 75%)处的点,我的 `background-position-x` 值应该是
(75% − 50%) × 4/3 + 50% = 83.333%
是的,这听起来可能有效! 拜托拜托拜托
查看 Pen 背景焦点:百分比(第十次尝试) by Jay (@jsit) on CodePen.
太棒了!
如果要关注 200 像素(或 25%)处的点,您将执行以下操作
(25% − 50%) × 4/3 + 50% = 16.667%
查看 Pen 背景焦点:百分比(第十一次尝试) by Jay (@jsit) on CodePen.
哇。
让我们将其概括
(c − 50%) × 4/3 + 50% = p
那么为什么是 4/3 呢?4 是我们 background-image
宽度与边界框宽度的比例;而 3 是…… 比 4 小 1。就这么简单吗?让我们试试一个更大的 background-image
,这次宽度为 1000px,是边界框宽度的 5 倍。我们再次尝试将焦点放在 200px 的点上。这里我们的公式将是
(20% − 50%) × 5/4 + 50% = 12.5%
查看 CodePen:背景焦点:百分比(第 12 次尝试) by Jay (@jsit) on CodePen.
我的天啊,它真的起作用了!
回到我们的公式,使用可变的背景与边界框比例
(c − 50%) × z/(z − 1) + 50% = p
让我们把它翻译成英文
给定
background-image
上位置为 c 的点…
- 其中 c 表示为图像宽度的百分比
- 其中 c 预计位于背景图像边界框的水平中心
- 并且
background-image
的宽度是其边界框的 z 倍正确的
background-position-x
p(以百分比表示)由以下公式给出
(c − 50%) × z/(z − 1) + 50% = p
我们能更进一步推广这个公式吗?
如果我们想将 background-image
上 25% 的点与边界框上 75% 的点对齐,会怎么样?天啊!
让我们重新看一下原始公式
(c − 50%) × z/(z − 1) + 50% = p
现在让我们引入一些新术语
- b:从边界框最左侧边缘开始的所需焦点位置(以百分比表示)。之前我们假设这个位置始终为 50%,这样边界框的中心就会与
background-image
中的目标对齐。 - d:
background-image
的焦点位置(以百分比表示),与边界框的中点对齐,以使background-image
上的 c 与边界框上的 b 对齐;如果background-image
上的 d 与边界框的 50% 对齐,那么background-image
上的 c 将与边界框上的 b 对齐。
让我们这样想
想要将 background-image
上的 c 位置与边界框上的 b 位置对齐,就等同于想要将 background-image
上的另一个位置 d 与边界框的中心对齐 - 我们已经知道如何做到这一点。那么我们能找到一种方法从 c、b 和 z 推导出 d(我们需要在 50% 位置的点)吗?当然可以!
对于我们的 800px 宽的 background-image
,在一个 200px 宽的边界框中(z = 4),如果我们想将边界框的最右侧边缘(b = 100%)与图像中 600px(c = 75%)的位置对齐,我们希望边界框的中心与 500px(d = 62.5%)的点对齐。
我们如何从 c(75%)得到 d(62.5%)?-12.5% 的差异从哪里来?
嗯,我们的 b 是 100%,比我们之前“默认”的 b(50%)高 50%。而 12.5% 是这个值的 1/4;1/4 是我们 z(4)的倒数。我们的 d 是从这里来的吗?这将是
d = c + (50% - b)/z
看起来很有希望。现在我们可以将 d 代入原始公式中的 c
(d − 50%) × z/(z − 1) + 50% = p
或者
(c + (50% − b)/z - 50%) × z/(z − 1) + 50% = p
哇!让我们测试一下。让我们尝试将 background-image
中 25% 的位置(200px)与边界框中 75% 的位置对齐。这将是
p = (25% + (50% - 75%)/4 - 50%) × 4/(4 - 1) + 50%
p = -31.25% × 1.333 + 50%
p = 8.333%
查看 CodePen:背景焦点:百分比(第 13 次尝试) by Jay (@jsit) on CodePen.
难以置信!让我们再确认一下。background-image
中 87.5% 的点(700px)与边界框中 33.333% 的位置对齐会怎么样?
p = (87.5% + (50% - 33.333%)/4 - 50%) × 4/(4 - 1) + 50%
p = 41.6667% × 1.333 + 50%
p = 105.555%
查看 CodePen:背景焦点:百分比(第 14 次尝试) by Jay (@jsit) on CodePen.
对我来说看起来已经足够好了!
我确信对于某些类型的人来说,这里面有一些直观的道理,但我不是其中之一。
让我们创建一个 Sass 函数,它将为我们完成所有这些荒谬的数学运算。
查看 CodePen:背景焦点:百分比(最终 Sass 函数) by Jay (@jsit) on CodePen.
我的头都晕了。
当我开始着手解决这个问题时,我并没有预料到它会如此困难,但这是一段奇妙的旅程。我希望引导你了解我的思维过程能够让你有所启发,并且你可能会在某些时候发现我们的 Sass 函数很有用。
本文中嵌入的所有 CodePen 都可以在这个集合中找到。
这非常棒。我想知道四值语法(对任何边缘的偏移的支持)是否可以帮助解决这个问题?https://mdn.org.cn/en-US/docs/Web/CSS/background-position
background-position: right 3em bottom 10px;
嗯,想法很好,但在我看来这似乎并没有帮助。我还没有使用过四值语法,但据我所知,它只允许你将底部或右侧指定为替代起点,但对于使用百分比表示位置没有任何帮助。
谢谢!
好吧,我上次尝试这个的时候,我“试错” 了很长时间(很长时间)。你的公式非常有效,而且对我来说很有意义。太棒了。
感谢你的想法和分享。
是的,太棒了,感谢你为我们做了 SASSify 的工作。
几个月前我不得不自己解决类似的问题。基本上,我需要弄清楚应该将哪些百分比应用于背景图像,以确保用户之前选择的图像部分确实正在显示。
http://stackoverflow.com/a/35493320/937377
你可能需要阅读问题和答案才能完全理解,但这是我最终用来根据背景图像及其容器的所需 y 坐标计算背景图像的垂直百分比的公式。
嘿,很高兴看到这个方法得到了一些关注 - 我已经使用这个方法来处理精灵图很长时间了 - 它在旧的浏览器上也起作用。你会发现关于这个主题的文章可以追溯到大约 10 年前,但难点在于如何在更大的工作流程中有效地包含它。