我们通常认为背景图片是纹理或提供易于阅读内容对比的东西 - 换句话说,不是真正的内容。 如果是内容,您可能会使用 <img>
,无障碍和其他东西。
但有时,背景图片的 位置 或 比例 可能介于内容和装饰之间。 上下文为王,对吧? 如果我们更改背景图片的位置,它可能会传达更多上下文或体验。
怎么会这样? 让我们看看我看到的几个例子。
在开始之前,我要提醒大家,这些演示中,用于装饰的图片和用作内容的图片之间有一条细线。 区别在于无障碍方面,背景不会向屏幕阅读器宣布。 如果您的图片真的是图片,那么也许可以考虑使用 <img>
标签以及适当的 alt
文本。 同时,当我们谈论无障碍时,最好 考虑用户的运动偏好。
显示更多!
Chris Coyier 几年前就展示了这个简洁的小演示。
该演示非常实用,因为它是一种在内容中显示广告的巧妙方法。 您有销售宣传和引人入胜的图片来补充它。
我认为大多数广告的最大限制是有限的空间。 我不知道您是否曾经需要在页面上放置广告,但我曾经这样做过,并且通常要求广告商提供符合确切像素尺寸的图片,以便资产适合空间。
但 Chris 的演示消除了空间问题。 将鼠标悬停在图片上,观察它移动和缩放。 用户实际上比图片处于原始位置时获得 更多 产品上下文。 这不是双赢吗? 广告商可以创建醒目的图片,而不会影响上下文。 同时,用户从新显示的图片部分获得了一些额外的价值。
如果您查看演示的标记,您会注意到它几乎与您预期的一样。 以下是简略版本
<div class="ad-container">
<a href="#" target="_blank" rel="noopener">
<!-- Background image container -->
<div class="ad-image"></div>
</a>
<div class="ad-content">
<!-- Content -->
</div>
</div>
我们可能会对语义略微挑剔,但这并不是重点。 我们有一个容器,其中包含一个链接到背景图片的 <div>
和另一个包含内容的 <div>
。
至于样式,重要的部分在这里
.container {
background-image: url("/path/to/some/image.png");
background-repeat: no-repeat;
background-position: 0 0;
height: 400px;
width: 350px;
}
不错吧? 我们为容器提供一些尺寸,并为其设置一个不重复且由其左下角边缘定位的背景图片。
真正的技巧在于 JavaScript。 我们将用它来获取鼠标位置和容器的偏移量,然后将该值转换为适当的比例以设置 background-position
。 首先,让我们监听 .container
元素上的鼠标移动。
let container = document.querySelector(".container");
container.addEventListener("mousemove", function(e) {
// Our function
}
);
从这里,我们可以使用容器的 offsetX
和 offsetY
属性。 但我们不会直接使用这些值,因为 X 坐标的值小于我们需要的值,而 Y 坐标的值更大。 我们需要进行一些操作,才能找到可以作为乘数使用的常数。
这有点摸索,但我发现 1.32
和 0.455
分别适用于 X 和 Y 坐标。 我们将偏移量乘以这些值,在结果中追加一个 px
单位,然后将其应用于 background-position
值。
let container = document.querySelector(".container");
container.addEventListener("mousemove", function(e) {
container.style.backgroundPositionX = -e.offsetX * 1.32 + "px";
container.style.backgroundPositionY = -e.offsetY * 0.455 + "px";
}
);
最后,如果用户离开图片容器,我们还可以将背景位置重置回原始位置。
container.addEventListener("mouseleave", function() {
container.style.backgroundPosition = "0px 0px";
}
);
由于我们是在 CSS-Tricks 上,我要提议,我们本可以使用纯 CSS 中的少量悬停过渡来完成更便宜的版本。
绘制更宏伟的画面
毫无疑问,您去过一些在线服装店或其他地方,遇到了老式的悬停缩放功能。
这种模式已经存在了很长时间(Dylan Winn-Brown 在 2016 年 分享了他的方法),但这仅仅证明了(我希望)它的实用性。 用户在放大时获得更多上下文,并能更好地了解毛衣的缝合或其他东西。
这分为两部分:容器 和 放大镜。 容器是我们唯一需要在标记中包含的东西,因为我们将在用户交互期间注入放大镜元素。 所以,请看我们的 HTML 代码!
<div class="container"></div>
在 CSS 中,我们将创建 width
和 height
变量来存储放大镜本身的尺寸。 然后,我们将为 .container
提供一些形状和 background-image
:root {
--magnifer-width: 85;
--magnifer-height: 85;
}
.container {
width: 500px;
height: 400px;
background-size: cover;
background-image: url("/path/to/image.png");
background-repeat: no-repeat;
position: relative;
}
在我们看到放大镜之前,我们已经知道它的某些信息,并且可以预先定义这些样式,特别是之前为 .maginifier
的 width
和 height
定义的变量
.magnifier {
position: absolute;
width: calc(var(--magnifer-width) * 1px);
height: calc(var(--magnifer-height) * 1px);
border: 3px solid #000;
cursor: none;
background-image: url("/path/to/image.png");
background-repeat: no-repeat;
}
这是一个绝对定位的小方块,它使用与 .container
相同的背景图片文件。 请注意,calc 函数仅用于将变量中的无单位值转换为像素。 您可以根据需要随意安排它,以便消除代码中的重复。
现在,让我们转向将所有这些内容整合在一起的 JavaScript。 首先,我们需要访问之前定义的 CSS 变量。 我们稍后将在多个地方使用它。 然后,我们需要获取容器内的鼠标位置,因为这是我们将用于放大镜背景位置的值。
// Get the css variables
let root = window.getComputedStyle(document.documentElement);
let magnifier_width = root.getPropertyValue("--magnifer-width");
let magnifier_height = root.getPropertyValue("--magnifer-height");
let container = document.querySelector(".container");
let rect = container.getBoundingClientRect();
let x = (e.pageX - rect.left);
let y = (e.pageY - rect.top);
// Take page scrolling into account
x = x - window.pageXOffset;
y = y - window.pageYOffset;
我们基本上需要在 .container
上添加一个 mousemove
事件监听器。 然后,我们将使用 event.pageX
或 event.pageY
属性来获取鼠标的 X 或 Y 坐标。 但是要获得鼠标在元素上的 精确 相对位置,我们需要从上面 JavaScript 获得的鼠标位置中减去父元素的位置。 一个“简单”的方法是使用 getBoundingClientRect()
,它返回元素的大小及其相对于视窗的位置。
请注意,我将滚动考虑在内。 如果有溢出,减去窗口 pageX
和 pageY
偏移量将确保效果按预期运行。
我们将首先创建放大镜 div。 接下来,我们将创建一个 mousemove
函数并将其添加到图片容器中。 在此函数中,我们将为放大镜提供一个 class 属性。 我们还将计算鼠标位置,并为放大镜提供我们之前计算的 left 和 top 值。
让我们在 .container
上听到 mousemove
事件时构建 magnifier
// create the magnifier
let magnifier = document.createElement("div");
container.append(magnifier);
现在,我们需要确保它有一个类名,我们可以将其限定到 CSS
// run the function on `mousemove`
container.addEventListener("mousemove", (e) => {
magnifier.setAttribute("class", "magnifier");
}
我之前展示的示例视频将放大镜定位在容器外部。 我们将保持简单,将其叠加在容器之上,而不是随着鼠标移动而移动。 我们将使用 if
语句仅在 X 和 Y 值 大于 或 等于 零,并且 小于 容器的宽度或高度时设置放大镜的位置。 这应该可以将其保持在范围内。 请务必从 X 和 Y 值中减去放大镜的宽度和高度。
// Run the function on mouse move.
container.addEventListener("mousemove", (e) => {
magnifier.setAttribute("class", "magnifier");
// Get mouse position
let rect = container.getBoundingClientRect();
let x = (e.pageX - rect.left);
let y = (e.pageY - rect.top);
// Take page scrolling into account
x = x - window.pageXOffset;
y = y - window.pageYOffset;
// Prevent magnifier from exiting the container
// Then set top and left values of magnifier
if (x >= 0 && x <= container.clientWidth - magnifier_width) {
magnifier.style.left = x + "px";
}
if (y >= 0 && y <= container.clientHeight - magnifier_height) {
magnifier.style.top = y + "px";
}
});
最后但并非最不重要的一点是……我们需要稍微调整一下放大镜的背景图片。 关键是,用户可以根据鼠标悬停的位置获得背景图片的 更大 视图。 因此,让我们定义一个放大镜,我们可以用它来放大图像。 然后,我们将为背景图片的宽度和高度定义变量,以便我们有一些参考来进行缩放,并为 .magnifier
样式设置所有这些值
// Magnifier image configurations
let magnify = 2;
let imgWidth = 500;
let imgHeight = 400;
magnifier.style.backgroundSize = imgWidth * magnify + "px " + imgHeight * magnify + "px";
让我们获取放大镜图片的 X 和 Y 坐标,并将其应用于 .magnifier
元素的 background-position
。 与之前放大镜位置一样,我们需要使用 CSS 变量从 X 和 Y 值中减去放大镜的宽度和高度。
// the x and y positions of the magnifier image
let magnify_x = x * magnify + 15;
let magnify_y = y * magnify + 15;
// set backgroundPosition for magnifier if it is within image
if (
x <= container.clientWidth - magnifier_width &&
y <= container.clientHeight - magnifier_height
) {
magnifier.style.backgroundPosition = -magnify_x + "px " + -magnify_y + "px";
}
瞧!
让它更具电影感
您是否见过 肯·伯恩斯效果? 它是一种经典且永恒的东西,其中图片大于它所在的容器,然后缓慢地像蜗牛一样滑动和缩放。 几乎世界上每一部纪录片似乎都将其用于图片静止画面。 如果您有 Apple TV,那么您一定在屏幕保护程序上看到过它。
如果您想更好地了解它,有很多 CodePen 上的示例。
您会看到,有多种方法可以实现这一点。 有些使用 JavaScript。 其他是 100% CSS。 我相信 JavaScript 方法对于某些用例来说是不错的,但如果目标只是微妙地缩放图片,CSS 完全适用。
我们可以使用多个背景而不是一个背景来稍微增加趣味性。 或者,更好的方法是,如果我们将规则扩展到使用元素而不是背景图片,我们可以将相同的动画应用于所有背景,并使用一些 animation-delay
来交错效果。
当然,有很多方法可以实现这一点! 它当然可以使用 Sass 和/或 CSS 变量进行优化。 heck,也许您可以使用单个 <div>
来实现。 如果是这样,请在评论中分享!
奖励:让它更身临其境
我不知道还有什么比 Sarah Drasner 的 “万圣节快乐” 代码笔 更酷了…… 而且那是 2016 年的!这是一个很好的例子,它分层背景并在不同的速度下移动它们,从而创造出一种近乎电影般的体验。天哪,太酷了!
GSAP 是那里的主要驱动因素,但我认为我们可以做一个简化的版本,它只是以不同的速度将每个背景层从左到右平移。当然,不那么酷,但肯定是最基本体验。必须确保每个背景图像的开始和结束一致,以便在动画重复时无缝重复。
目前就这些了!很酷的是,我们可以将背景用于比纹理和对比度更多的东西。我绝对相信,我们可以将大量的其他巧妙交互应用于背景。Temani Afif 就做了类似的事情,为链接创建了一堆很酷的悬停效果。您有什么想法吗?在评论中与我分享!
好文章。
我记得几年前自己创建了一个图像放大镜组件。
为了让它在移动设备上也友好,需要不少 JS 代码。