High-performance Parallax http://www.php.cn/code/9595.html "target=" _blank "> Animation
Love or hate, parallax effect has spread over the web. When you use it skillfully, it can add depth and metaphor to your application. But the problem is that achieving a high-performance parallax effect is a challenging task. In this article, we will discuss how to construct a high-performance parallax effect, and of course it is also important to cross-browser.
Parallax effect
Summary
Do not use scrolling events (scroll events) or background positioning (background-position) to create parallax animations.
Use the CSS 3D transform to create a more accurate parallax effect.
For iOS mobile devices, the Safari browser is used position: sticky
to ensure that parallax can take effect.
If you want an out-of-the-box solution, please visit Parallax Helper JS, which also has a demo demo.
Analysis of Parallax problem
Before we begin, let's take a look at two common ways to implement parallax and explore why they are not suitable for the goal we are pursuing.
Bad scenario: using a scrolling event
The key requirement for Parallax is that it should be a rolling coupling: the location of parallax elements should be updated for each position of page scrolling. This looks easy, and one of the important mechanisms of modern browsers is that they can work asynchronously. However, in most browsers, scrolling events are handled as "best effort", which means that the browser does not ensure that scrolling animations are delivered for every frame!
This important message tells us why we should avoid using JavaScript to move elements based on scrolling events:JavaScript does not ensure that Parallax is kept at the same pace as page scrolling. . On some older versions of mobile Safari, scrolling events are triggered even after scrolling is complete, which makes JavaScript-based scrolling ineffective. In newer mobile safari versions, scrolling events can be triggered during animation, but like Chrome, it is based on the "best possible" principle. So when the main thread is busy with other work, the scrolling event does not trigger immediately, which means that the parallax effect is lost.
Bad scenario: Update the background location
Another scenario that we want to avoid is drawing at every frame. Many scenarios attempt to use changes background-position
to provide parallax, but this will allow the browser to redraw the affected parts while scrolling, which can be quite resource-intensive, and this effect will cause the animation to stutter.
If we want to provide a high-quality parallax animation, we want a property that can be used as an acceleration (here we mean transform
and opacity
), and this is not dependent on scrolling events.
CSS 3D
Both Scott Kellum and Keith Clark have done important work in the area of using CSS 3D to achieve parallax effects. The very effective technologies they employ are:
Creates a container element that is set overflow-y: scroll
so that it can be scrolled (and possibly required overflow-x: hidden
).
For the above element, we will apply a perspective
value and set it perspective-origin
to top left
, or 0 0
.
Apply a transform on the Z-axis to the child elements of the above element, and then restore them back to achieve the parallax effect without affecting their size on the screen.
The CSS for this scenario looks like the following:
. container { width:100%; height:100%; Overflow-x: Hidden; OVERFLOW-Y: scroll; perspective:1px; perspective-origin:0 0;}. Parallax-child { transform-origin:0 0; Transform:translatez ( -2px) scale (3);}
Of course, let's assume that your HTML looks like this:
<p class= "Container" > <p class= "Parallax-child" ></p></p>
Adjust the ratio of perspective
Squeezing the elements back will require it to set a smaller relative perspective
ratio. You can calculate the desired zoom ratio by using the following equation: (perspective-distance)/perspective. Since we want the parallax element to look as large as the one we set at the beginning, it should be indented rather than unchanged based on this equation.
With the above example, perspective
Yes, and in the direction of the 1px
Z- parallax-child
axis -2px
, this means that the element needs to be magnified 3 times times, and you can see that we have scale
written 3
this value in.
For any content that is not applied, translateZ
you can replace it with 0, which is the scaling ratio (perspective - 0) / perspective
and the result is 1, which means neither zooming in nor shrinking. really is very convenient.
Why is this scheme useful?
It is important to find out why this scheme works well, because we will soon be using this knowledge. Scrolling is essentially a transformation, which is why it can be accelerated. Scrolling largely uses the GPU to participate in the transformation of the layer. A common scroll (without applying any perspective
) is this: scrolling in this case is done in a 1:1
way that treats the scrolling element and its child elements. In other words, if you scroll down an element 300px
, then its child elements are shifted upward by the same number: 300px
.
However, applying a value to the scrolling element perspective
will "confuse" the process: This value changes the ideal path for the scrolling transformation. Now if one 300px
of the scrolls may be moving the handle element 150px
, of course it depends on perspective
what value you give and translateZ
set. If a translateZ
child element is set to 0, it scrolls all the same as usual ( 1:1
), but a child element pushed to the Z-axis ( translateZ
not 0) will scroll at a different scale! Therefore, the parallax effect occurs. It is also important to note that the process itself is part of the scrolling mechanism inside the browser, so there is no need to listen for scrolling events or change the background position.
In the ointment: Mobile Safari
Each effect has some constraints, and for Transformations ( transform
), the 3D effect of the child element is maintained. If perspective
there are other elements in the structure of the applied element and its "parallax" sub-element, then the effect of 3D will be "flattened", that is, the effect will no longer exist.
<p class= "Container" > <p class= "Parallax-container" > <p class= "Parallax-child" ></p > </p></p>
In the above HTML .parallax-container
is a newly added element, and it will "erase", resulting in perspective
loss of effect. Typically, the solution is more intuitive: Add this element transform-style: preserve-3d
so that it can apply 3D effects to deeper nodes.
. parallax-container { transform-style:preserve-3d;}
For Mobile Safari, things have become a bit of a hassle. Apply to container elements overflow-y
: Technically this is fine, but this will make the scrolling elements move too fiercely. The solution is to add one -webkit-overflow-scrolling: touch
, but this setting will result in the perspective
flattening, so we will not get any parallax effect.
From a development point of view, this may not be a problem (because only in the older version of Mobile Safari), even if we can not show the parallax in every browser, but the functionality of an application is good, but we'd better find a solution.
position:sticky
To save
In fact, we can position: sticky
get some help from the, this setting allows the element to be fixed at viewport
the top or fixed in a scrolling element of the parent element. The document for this property, like any other document, stinks and grows, but can still find some useful information:
A fixed "box" is very much like a relatively positioned box, but the displacement is calculated by referencing the nearest scrollable ancestor, or by viewport
calculation, if no such ancestor is found-CSS positioned Layout Module level 3
The first glance seems to help little, but a key point in the sentence is how to calculate the part of the element's fixed position: "The displacement is calculated by referencing the nearest scrollable ancestor ." In other words, moving the distance of a fixed element (in order for it to appear to be fixed on an element or viewport
on) is calculated before any other transformations are applied, not later. This means that, as we just said, the scrolling example is quite similar, if the result of the displacement calculation is 300px
, then we have a new opportunity to use perspective
(or any other transformation) to 300px
change it before applying it to a fixed element.
By setting the Parallax element position: -webkit-sticky
, we can effectively "flip" the -webkit-overflow-scrolling: touch
resulting "erase" effect. This ensures that the Parallax element refers to the nearest scrollable ancestor element, which is .container
. Then, like above, .parallax-container
set a perspective
value, which changes the calculated scrolling displacement and creates a parallax effect.
<p class= "Container" > <p class= "Parallax-container" > <p class= "Parallax-child" ></p > </p></p>.container { overflow-y: scroll; -webkit-overflow-scrolling:touch;}. Parallax-container { perspective:1px;}. Parallax-child { position:-webkit-sticky; top:0px; Transform:translate ( -2px) scale (3);}
This restores the parallax effect to Mobile Safari, which is a good result.
Fixed positioning problems
And the previous scheme does have a clear difference, position: sticky
changing the mechanism of parallax. Fixed positioning attempts to fix an element at the top of the scroll container, rather than a fixed element. This means that the parallax generated by the fixed positioning and the non-stationary chromatic aberration are reversed:
use position: sticky
: The closer z=0
the element is, the less it moves
not used position: sticky
: The closer the element is z=0
, the more it moves
If you still feel some abstraction, take a look at Robert Flack's demo, which shows how elements behave differently under fixed and non-fixed positioning conditions. To see this effect, you need Chrome Canary (writing this article is, version 56) or Safari.
position: sticky
The effect of visual aberration
Fancy Bugs and coping
As with anything, there are plenty of pits to fill.
Fixed positioning support is inconsistent: currently in Chrome for this feature is still in development, Edge is completely missing, Firefox has drawn bugs. In this case, we should add a bit of code that will be added when needed (this is Mobile Safari)position: sticky
The effect is completely ineffective in the Edge. Edge tries to handle scrolling at the OS level, which is usually a good thing. But in this case, this mechanism will make it impossible for us to apply when scrolling perspective
. To fix this problem, we can set ' Translatez (0px) ' for the parent element.
The page content is too large: many browsers are responsible for shrinking when deciding how big the page content is, but unfortunately Chrome and Safari are not responsible. So if you have a 3 times-fold transformation applied to an element, you may see the scrollbar appear, and once it appears, the 1:1
scrollbar will not disappear even after you restore the proportions. There is one way to avoid this: to indent () from the lower-right corner transform-origin: bottom right
. The rationale behind this scenario is that it causes the "negative" (usually upper left) of an oversized element to enter the scrolling area, and the scrolling area never lets you see the "negative" area.
Conclusion
Parallax animations can be a very interesting effect if they are considered in a thoughtful design. And now you should be able to see that we can implement a high-performance, rolling-coupled, cross-browser scenario. Since this requires a little bit of math and some templating, we encapsulate a tool class and an example.
Welcome to the trial, and put forward your valuable comments.