scenario

When there is a floating layer on the page, slide the content of the floating layer, normally expect that the content below the floating layer will not scroll; However, this is not the case.

To solve

First go to Github search, found that there is an open source package to solve this problem, simple to select the star of the highest (body-scroll Lock) operation! Some problems were found after use:

  • All Android ends are mounted
  • The ios side occasionally fails to lock

On the iOS side, the package is handled separately by disabling TouchMove, but on the other side, it is simply handled by adding overflow: hidden to the body. I decided to write a multiterminal generic package to deal with similar problems.

Explore # 1: Overflow: Hidden

< span style = “box-sizing: border-box; color: RGB (74, 74, 74); line-height: 22px; font-size: 14px! Important; word-break: inherit! Important;”

body { overflow: hidden; }
Copy the code

This solution perfectly solves our problem on the PC side, but things are not that simple;

Try mobile again:

Exploration two: Body positioning

Setting overflow: hidden for the body doesn’t solve our problem on mobile. Is the height of the body not set

  • Set the height of both HTML and body to100%;
  • Set the body to fixed;

Using these two operations together seems to satisfy our needs perfectly;

Top value

Tips: Body setting relative position will pull up the page itself, leaving white space at the bottom

Several experiments have found that this scheme perfectly achieves the results we want in Android, but is not ideal in ios. There will be a flashing problem every time the positioning; Let’s explore the ios solution.

Exploration 3: No Touchmove

Is it possible to disable touchMove that kills pages? No more talking is doing! Disables the touchmove of a page element when a floating layer pops up

document.addEventListener('touchmove'.function (event) {
    event.preventDefault()
})
Copy the code

The test found that the result did not reach the imagined effect. I feel that this result is unacceptable. Can scroll be banned even if touchmove of document is banned?

Further exploration revealed that the reason was this attribute

  • Passive addEventListener is passed in the third parameter

Passive Event Listeners are a new feature in Chrome: The Web developer uses the new passive property to tell the browser whether the preventDefault function should be called within the event listeners registered on the current page to prevent the default event behavior, so that the browser can better use this information to optimize the performance of the page. If the value of passive is true, the preventDefault function will not be called within the listener to preventDefault sliding. Chrome calls this type of listener passive.

You know what the problem is, pass a third argument to addEventListener

document.addEventListener('touchmove'.function (event) {
    event.preventDefault()
}, { passive: false })
Copy the code

And we’re done! Suddenly thought, if the floating layer also need to roll that not GG! So, is it possible to selectively disable scrolling (disables scrolling after an element has been rolled to the top or bottom of the floating layer)? Separately handle elements that need to be rolled in the floating layer;

targetElement.ontouchmove = function (event) {
    const clientY = event.targetTouches[0].clientY - initialClientY

    if (targetElement && targetElement.scrollTop === 0 && clientY > 0) {
        return preventDefault(event)
    }

    if (targetElement && (targetElement.scrollHeight - 1 - targetElement.scrollTop <= targetElement.clientHeight) && clientY < 0) {
        return preventDefault(event)
    }

    event.stopPropagation()
    return true
}
Copy the code

This solution works perfectly on ios, but on Android it’s a bit of a problem; Floating content at the top or bottom still moves the content of the page to a certain extent.

tua-body-scroll-lock

Here comes the ultimate solution!

Tua-body-scroll-lock is handled separately on ios, Android and PC, ensuring perfect results on each end!

demo

The installation

$ npm i -S tua-body-scroll-lock
# OR
$ yarn add tua-body-scroll-lock
Copy the code

use

The mobile terminal
import { lock, unlock } from 'tua-body-scroll-lock'

// Disables swiping and requires internal elements that can be scrolled (for mobile ios processing)
const targetElement = document.querySelector("#someElementId");

lock(targetElement)
unlock(targetElement)
Copy the code
PC

Tips: PC does not need targetElement. If you do not want to send targetElement and do not want console prompts, you can pass null

import { lock, unlock } from 'tua-body-scroll-lock'

lock()
unlock()
Copy the code