CSS scroll-snap scroll event stop and element position detection

One, Scroll Snap is a necessary front-end skill

CSS Scroll Snap is a very useful feature. When the scrolling of the web page container stops, without the participation of any JS code, the browser can automatically and smoothly locate the specified position of the specified element. The effect of similar slideshow ads can be realized by pure CSS.

And the compatibility of CSS Scroll Snap is very good, and the mobile terminal can almost be used with confidence.

scroll-snap compatibility

For more information about CSS Scroll Snap, please refer to my previous article: " Heroes, don't you want to learn about CSS Scroll Snap? ", there is a detailed introduction to related CSS properties.

2. Scroll-snap scene from actual project

When implementing a functional requirement this afternoon, I happened to encounter a scene that is very suitable for using Scroll Snap to achieve, sliding to display the characters in turn. So I used it boldly, wow, great, without any js to make boundary judgments, sliding stops and automatically locates to the desired position.

The key CSS code is as follows:

ul {
    width: 375px; height: 667px;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    white-space: nowrap;
    overflow-y: hidden;    
}
at the {
    display: inline-block;
    width: 100%; height: 100%;
    scroll-snap-align: center;
}

Scrolling the parent container element settings scroll-snap-type:x mandatory, horizontal scrolling, forced positioning, and the child list element setting scroll-snap-align:centerallows the list to be displayed in the middle of the scrolling container, so the effect is achieved.

However, after the scroll positioning is over, you still need to highlight the currently positioned character material. I found it difficult! Previously, this kind of sliding effect was realized with JS. Whether it is the end of JS animation or the end of CSS animation, there are callback functions that can be used. But here it is scrolling, and after scrolling, it will reposition itself for a while. The positioning time is long or short, who knows when to stop? Sometimes I slide multiple elements in one breath, and I am not sure which element I stop on.

In fact, standard makers and browser manufacturers are actively promoting the implementation of Scroll Snap related callback events, so that you can know exactly when to stop and which element the scroll is positioned on. However, the standard is still tossing, and the browser has not yet stand by. The project is going to be used now, what should I do?

Correct! JS assistance must be dispatched.

In fact, even if it is not the use scene of Scroll Snap, even if it is ordinary scrolling, due to the inertia of scrolling, detecting whether scrolling has stopped is also a frequently encountered requirement. Therefore, it is necessary to use a method to detect when scrolling stops.

Three, my rolling suspension detection method

Detect whether the scrolling of the element stops. My idea is to run a timer in the scroll event to record whether the scrolling distance of the current time is equal to the last scrolling distance. If they are equal, the scrolling has stopped, if not equal , It is considered that scrolling is still in progress.

Use JavaScript to indicate that ( this implementation has been obsolete ):

// Timer, used to detect whether the horizontal scrolling is over
var timer = zero;
// last scroll distance
var scrollLeft = 0, scrollTop = 0;
// start of scroll event
container.addEventListener('scroll', function () {
    clearInterval(timer);
    // Renew the timer
    timer = setInterval(function () {
        if (container.scrollLeft == scrollLeft && container.scrollTop == scrollTop) {
            // The scrolling distance is equal, and it is considered to stop scrolling
            clearInterval(timer);
            // ... do what you want, such as callback processing
        } else {
            // Otherwise, still remember the last scroll position
            scrollLeft = container.scrollLeft;
            scrollTop = container.scrollTop;
        }
    }, 100);
});

If you are interested, you can further encapsulate the above code.

Update on the next day

The scroll termination detection can eliminate the need to determine whether the forward and backward scroll distances are equal, because the scroll event is continuously triggered regardless of inertia or Snap positioning. Therefore, it can be directly like this:

// Timer, used to detect whether the horizontal scrolling is over
var timer = zero;
// start of scroll event
container.addEventListener('scroll', function () {
    clearTimeout(timer);
    // Renew the timer
    timer = setTimeout(function () {
        // No scroll event is triggered, think it stopped scrolling
        // ... do what you want, such as callback processing
    }, 100);
});

Of course, the method provided above is not very accurate to stop the detection, because the last relocation of Scroll Snap has a detection in the browser itself. According to my repeated research and testing, this detection event should be 350ms (the actual operation may be slightly larger. A few milliseconds), which is much larger than the above setting 100ms. Therefore, there will be a false redundant judgment that occurs before the start of Snap positioning.

I thought about it, this problem cannot be avoided, but it is not a big problem. It is always impossible to set up 400msdetection, the delay is too high, and the experience is not necessarily good.

Fourth, the current scroll target element detection method

The principle is as follows, traverse all list elements, and detect the position of the left edge of the list element relative to the left edge (if it is left-aligned- scroll-snap-align:left) or the center (center-aligned) or the right edge (right-aligned) of the scroll container . Of course, if the size of the list element is the same as the size of the scroll container, the left, middle, and right edges can be detected.

JS indicates:

[].slice.call(container.children).forEach(function (ele, index) {
    if (Math.abs(ele.getBoundingClientRect().left - container.getBoundingClientRect().left) < 10) {
        // The ele element at the moment is the currently positioned element
        // ... you can do what you want to ele
    } else {
        // The ele element at the moment is not the currently positioned element
    }
});

Strictly speaking, it should be calculated whether it is equal to 0, not less than 10. Here, let's add some tolerance interval.

After getting the above two demand points that require JS assistance, the final effect will come out.

Five, the final effect display

You can click here: CSS scroll-snap scroll event end judgment demo

This demo is more suitable for mobile phone access, so attach the QR code:

Scroll stop detection QR code

The final result is shown in the video below (please click if you don't move):

 

By detecting the end of scrolling, the currently displayed element is accurately highlighted (the grayscale grayscale of the element is controlled through the CSS filter). As for the sliding and positioning effects, they are completely implemented by CSS. It is much simpler than the traditional use of similar Swipe.js to achieve the switching effect, the performance is also better, and the resource usage is less.

Six, conclusion

After all, it is a new property of CSS, and some old Android phones do have some problems in compatibility. For this reason, many people are discouraged from using these excellent features.

No need to sacrifice 99% of the essence for 1% of the dross.

For obsolete equipment, we don’t have to have a perfect and consistent experience, as long as we ensure that the functions are completely normal, users don’t actually care. At this point, you can communicate with the test students in the factory. It is not necessary that all browsers are the same.

In addition, there scroll-snap-typeis a polyfill for equal attributes, just introduce a JS.

If the polyfill is useless, it's a big deal to do a feature detection. If the browser does not support scroll-snap-typesuch attributes, use the transformdisplacement to locate it, or specifically load a third-party JS for processing.

The more you toss, the more you grow. If you make your own projects more difficult and pursue more, the technology will grow faster than others.

Guess you like

Origin blog.csdn.net/lu92649264/article/details/112857961
Recommended