css背景视差
Recently a number of sites, including Bioware’s promotional page for Mass Effect Andromeda and Active Theory’s work for Under Armour have featured a parallax effect that ties mouse movement to the motion of a page element in the opposite direction. I was interested in recreating the effect using vanilla JavaScript and modern CSS, an example of which you can see above.
最近,包括Bioware的Mass Effect Andromeda促销页面和Active Theory的Under Armour作品在内的许多站点都具有视差效果,该效果将鼠标移动与页面元素在相反方向上的运动联系起来。 我对使用香草JavaScript和现代CSS重新创建效果很感兴趣,您可以在上面看到一个示例。
入环 (Get In The Ring)
The markup consists of a <div>
container, an image, a heading, and body text (extracted from the short story “A Piece of Steak” by Jack London) surrounded by another <div>
:
标记由<div>
容器 , 图像 , 标题和正文(由Jack London的短篇小说“ A Piece of Steak”摘录)和另一个<div>
包围组成:
<div id="boxercontainer">
<img src="boxer.png" alt>
<div>
<h1>The Boxer</h1>
<p>Well, a man had only so many fights in him, to begin with…
</div>
</div>
The boxer was extracted from his background and turned into an alpha-masked PNG, reduced in file size by converting it to a 16-bit image.
该拳击手是从他的背景中提取出来的,并变成了带有alpha蒙版的PNG ,通过将其转换为16位图像来减小文件大小。
The outer #boxercontainer
element is styled: note that the background-image
is made slightly larger than its container and positioned from its center, facts that will be important later:
外部的#boxercontainer
元素具有样式:请注意,将background-image
制作成比其容器稍大一点 ,并从其中心开始放置,这些事实稍后将很重要:
#boxercontainer {
width: 80%;
max-width: 900px;
margin: 0 auto;
background-image: url(concrete-background.jpg);
position: relative;
padding-bottom: 45%;
background-size: 120% 120%;
background-position: 50% 50%;
overflow: hidden;
min-height: 650px;
}
The inner div
is given a transparent, slightly dark background color to increase the contrast of the text inside it:
内部div
具有透明的,略暗的背景色,以增加内部文本的对比度:
#boxercontainer div {
position: absolute;
width: 60%;
left: 20px;
top: 20px;
border: 1px solid #fff;
padding: 2rem;
background: rgba(0,0,0,0.2);
}
The image is also positioned absolutely (taking advantage of the absolute-position-inside-relative trick), dropped down so that the lower portion of the boxer’s legs are hidden by the overflow: hidden
on the parent element. It’s also provided with a drop-shadow
filter, making a far smaller image file size than baking the drop-shadow into the PNG; as we’ll see in a moment, this also createsfar more dynamic options for the image.
图像也绝对定位(利用绝对位置相对内幕技巧),向下放置,以使拳击手腿的下部被overflow: hidden
物隐藏overflow: hidden
在父元素上。 它还提供了一个drop-shadow
过滤器 ,与将drop-shadow
烘焙到PNG中相比,图像文件的大小要小得多。 稍后我们将看到,这还会为图像创建更多的动态选项。
#boxercontainer img {
position: absolute;
bottom: -35px;
right: 50px;
width: 40%;
filter: drop-shadow(-200px 200px 50px #000);
padding: 1rem;
z-index: 2;
}
The z-index
value of 2
places the boxer visually above the div
containing the text, but it also means that the shadow falls over the words. To correct that, I modified the appearance of the paragraph text:
z-index
值为2
使拳击手在视觉上位于包含文本的div
上方 ,但这也意味着阴影落在单词上。 为了解决这个问题,我修改了段落文本的外观:
#boxercontainer p {
position: relative;
z-index: 3;
}
With a higher z-index
, the shadow now falls under the text, but over the border
on the div.
使用更高的z-index
,阴影现在落在文本下方 ,但位于div的border
上方 。
居中 (Getting Centered)
The core idea of the parallax effect is finding the center of the affected element. The cursor’s distance from this center will displace the element by the same distance in the opposite direction:
视差效果的核心思想是找到受影响元素的中心。 光标到该中心的距离将使元素在相反的方向上移动相同的距离:
To make this happen, the script starts by identifying the elements (using the fact that an id
automatically turns into a reference in JavaScript, and using a querySelector
for the boxer:
为此,脚本首先要标识元素(使用id
自动变成JavaScript中的引用这一事实,然后对拳击手使用querySelector
:
const boxer = boxercontainer.querySelector("img"),
maxMove = boxercontainer.offsetWidth / 30,
boxerCenterX = boxer.offsetLeft + (boxer.offsetWidth / 2),
boxerCenterY = boxer.offsetTop + (boxer.offsetHeight / 2);
maxMove
is the maximum distance we want the boxer to move, since we don’t usually want the image to move with complete freedom in response to the mouse being anywhere on the page.
maxMove
是我们希望拳击手移动的最大距离,因为我们通常不希望图像完全自由地移动以响应鼠标在页面上的任何位置 。
We’ll also need to determine the position of the mouse inside boxercontainer
, for which I’ll use a function:
我们还需要确定boxercontainer
内鼠标的位置,为此我将使用一个函数 :
function getMousePos(xRef, yRef) {
let panelRect = boxercontainer.getBoundingClientRect();
return {
x: Math.floor(xRef - panelRect.left) /
(panelRect.right - panelRect.left)*boxercontainer.offsetWidth,
y: Math.floor(yRef - panelRect.top) /
(panelRect.bottom - panelRect.top) * boxercontainer.offsetHeight
};
}
像蝴蝶一样漂浮 (Float Like a Butterfly)
Effects like this usually respond to mouse movement in the page:
这样的效果通常会响应页面中的鼠标移动:
document.body.addEventListener("mousemove", function(e) {
let mousePos = getMousePos(e.clientX, e.clientY),
distX = mousePos.x - boxerCenterX,
distY = mousePos.y - boxerCenterY;
if (Math.abs(distX) < 500 && distY < 200) {
boxer.style.transform =
"translate("+(-1 * distX) / 12 + "px," + (-1 * distY) / 12 + "px)";
}
})
distX
is the horizontal distance between the current mouse position and the initial center of the boxer image; distY
is the vertical distance. If the vertical difference (positive or negative) is less than 500px, and the horizontal distance less than 200px, then we move the boxer image using a CSS transform:
distX
是当前鼠标位置和拳击手图像的初始中心之间的水平距离; distY
是垂直距离。 如果垂直差异(正值或负值)小于500px,水平距离小于200px,则我们使用CSS变换移动拳击手图像:
both distances are multiplied by
-1
(turning a positive distance into a negative, and a negative into a positive)两个距离都乘以
-1
(将正距离变成负值,将负距离变成正值)the result is then divided by 12, to reduce the ratio of movement between the mouse and the image (a 1:1 relationship between mouse position and image position would make movement far too confusing).
然后将结果除以12,以减少鼠标与图像之间的移动比例 (鼠标位置与图像位置之间的1:1关系会使移动过于混乱)。
It should be noted at this point that I would never suggest using this technique for UI elements: trying to click a “moving target” can be very difficult to users with motion or visual issues. A potential solution to this is discussed below.
在这一点上应该指出的是,我永远不会建议对UI元素使用这种技术:对于有运动或视觉问题的用户,尝试单击“移动目标”可能非常困难。 一个潜在的解决方案将在下面讨论。
When we move our head position, it’s not only elements in the foreground that change position; objects in the background also shift, in the opposite direction. Think of an object placed a few feet in front of a wall: moving to the right will change your perspective on both.
当我们移动头部位置时,不仅是前景中的元素会改变位置,而且还会改变位置。 背景中的对象也会向相反的方向移动。 想像一下放在墙前几英尺的物体: 向右移动将改变您对两者的看法。
To recreate this effect, I also move the background-image
of the concrete wall. The addEventListener
callback has the following added at the end of the script:
为了重现这种效果,我还移动了混凝土墙的background-image
。 addEventListener
回调在脚本末尾添加了以下内容:
boxercontainer.style.backgroundPosition =
`calc(50% + ${distX / 50}px) calc(50% + ${distY / 50}px)`;
To make the background move, I’m using calc
to produce an offset from the background image’s default center position. (I’m also using template literals to make concatenation easier).
为了使背景移动,我使用calc
来生成与背景图像默认中心位置的偏移量 。 (我也使用模板文字使连接更容易)。
I’m initiating movement based on mouse position, rather than touch, since adults tend not to have their fingertips constantly sliding across the screen.
我要根据鼠标位置而不是触摸来开始运动,因为成年人的指尖通常不会在屏幕上不断滑动。
数了 (Counted Out)
As a general rule, parallax effects work well on larger desktop and laptop screens, but not at all on smaller viewports. Because the effect is created with JavaScript, we must also detect the viewport width with JS, via matchMedia
:
通常,视差效果在较大的台式机和笔记本电脑屏幕上效果很好,但在较小的视口上根本不起作用。 由于效果是使用JavaScript创建的,因此我们还必须通过matchMedia
使用JS检测视口宽度:
let fluidboxer = window.matchMedia("(min-width: 726px)");
The if
condition for moving the image and background changes to:
用于移动图像和背景的if
条件变为:
if (Math.abs(distX) < 500 && distY < 200 && fluidboxer.matches) { … }
There are more changes in CSS @media
queries to change the design at smaller viewport sizes; see the CodePen demo for more details.
CSS @media
查询中有更多更改,可以在较小的视口尺寸下更改设计; 有关更多详细信息, 请参见CodePen演示 。
拳头醉 (Punch-Drunk)
Parallax effects can adversely affect users with vestibular disorders (sensitivity to visual motion and change) to the point of nausea and seizure; at the minimum, displaying a warning or some other indication that the page contains motion effects is a good idea. Browser vendors are currently working on a “reduce motion” user setting that will be detectable using an @media
query in the near future; in response, features like parallax effects could be automatically turned off on the page for affected users.
视差效应可能会对前庭不适(对视觉运动和变化敏感)的使用者产生恶心和癫痫发作的不利影响; 最好至少显示警告或其他指示页面包含运动效果的指示。 浏览器供应商目前正在研究“减少运动”用户设置 ,不久以后可以使用@media
查询检测到该设置 。 作为响应,视差效果之类的功能可能会在受影响的用户页面上自动关闭。
结论 (Conclusion)
Using CSS transforms with JavaScript mouse events can be a cheap and relatively easy way to achieve parallax effects, with a little math. In future articles, I’ll explore these kinds of effects further.
将CSS转换与JavaScript鼠标事件一起使用,是一种廉价且相对简单的方法,只需一点数学就可以实现视差效果。 在以后的文章中,我将进一步探讨这些影响。
翻译自: https://thenewcode.com/1162/Cheap-Parallax-with-JavaScript-and-CSS-Transforms
css背景视差