我试图禁用父母的html/身体滚动条,而我正在使用一个灯箱。这里的主要词是disable。我不想用溢出来隐藏它。

这样做的原因是overflow: hidden会使站点跳转并占用原来滚动的区域。

我想知道是否有可能禁用滚动条,同时仍然显示它。


当前回答

我注意到YouTube网站就是这么做的。所以通过检查它一点,我已经能够确定他们正在使用@聚合物/铁覆盖-行为,幸运的是,它可以在web组件/聚合物之外使用:

import {
    pushScrollLock,
    removeScrollLock,
} from '@polymer/iron-overlay-behavior/iron-scroll-manager';

// lock scroll everywhere except scrollElement
pushScrollLock(scrollElement);

// restore scrolling
removeScrollLock(scrollElement);

允许滚动选定的元素 不会以任何方式干扰样式 是否在YouTube网站上进行了实战测试

这似乎是一个成熟的解决方案,当然也是我能找到的最好的解决方案。包装有点重,但我猜大部分都是分开的,当只进口铁卷轴管理器。

干杯

其他回答

这里是一个工作演示。这是你如何用纯JavaScript做到这一点:

const { body, documentElement } = document;
let { scrollTop } = document.documentElement;

function disableScroll() {
  scrollTop = documentElement.scrollTop;
  body.style.top = `-${scrollTop}px`;
  body.classList.add("scroll-disabled");
}

function enableScroll() {
  body.classList.remove("scroll-disabled");
  documentElement.scrollTop = scrollTop;
  body.style.removeProperty("top");
}

这是CSS:

.scroll-disabled {
  position: fixed;
  width: 100%;
  overflow-y: scroll;
}

我们使用position: fixed on body来防止它可滚动,我们使用overflow-y来显示滚动条。我们还需要设置宽度,因为position: fixed是如何工作的。

我们跟踪滚动位置,并在禁用滚动时更新它,以便在禁用滚动时使用top适当地定位主体,并在启用滚动时恢复滚动位置。否则,当禁用或启用滚动时,身体将继续跳到顶部。

当启用滚动时,我们从主体中删除顶部样式。这可以防止它打破你的布局,如果你有一个不同的位置,而不是静态的主体。

如果你在html上使用scroll-behavior: smooth,你还需要像这样修改enableScroll函数:

function enableScroll() {
  body.classList.remove("scroll-disabled");
  // Set "scroll-behavior" to "auto"
  documentElement.style.scrollBehavior = "auto";
  documentElement.scrollTop = scrollTop;
  // Remove "scroll-behavior: auto" after restoring scroll position
  documentElement.style.removeProperty("scroll-behavior");
  body.style.removeProperty("top");
}

我们需要临时将滚动行为设置为自动,这样就不会出现跳转。

位置:固定;解决方案有一个缺点-当应用此样式时,页面跳转到顶部。Angular的材质对话框有一个很好的解决方案,他们通过将定位应用到html元素来伪造滚动位置。

下面是我修改后的算法仅垂直滚动。左滚动块以完全相同的方式完成。

// This class applies the following styles:
// position: fixed;
// overflow-y: scroll;
// width: 100%;
const NO_SCROLL_CLASS = "bp-no-scroll";

const coerceCssPixelValue = value => {
  if (value == null) {
    return "";
  }

  return typeof value === "string" ? value : `${value}px`;
};

export const blockScroll = () => {
  const html = document.documentElement;
  const documentRect = html.getBoundingClientRect();
  const { body } = document;

  // Cache the current scroll position to be restored later.
  const cachedScrollPosition =
    -documentRect.top || body.scrollTop || window.scrollY || document.scrollTop || 0;

  // Cache the current inline `top` value in case the user has set it.
  const cachedHTMLTop = html.style.top || "";

  // Using `html` instead of `body`, because `body` may have a user agent margin,
  // whereas `html` is guaranteed not to have one.
  html.style.top = coerceCssPixelValue(-cachedScrollPosition);

  // Set the magic class.
  html.classList.add(NO_SCROLL_CLASS);

  // Return a function to remove the scroll block.
  return () => {
    const htmlStyle = html.style;
    const bodyStyle = body.style;

    // We will need to seamlessly restore the original scroll position using
    // `window.scroll`. To do that we will change the scroll behavior to `auto`.
    // Here we cache the current scroll behavior to restore it later.
    const previousHtmlScrollBehavior = htmlStyle.scrollBehavior || "";
    const previousBodyScrollBehavior = bodyStyle.scrollBehavior || "";

    // Restore the original inline `top` value.
    htmlStyle.top = cachedHTMLTop;

    // Remove the magic class.
    html.classList.remove(NO_SCROLL_CLASS);

    // Disable user-defined smooth scrolling temporarily while we restore the scroll position.
    htmlStyle.scrollBehavior = bodyStyle.scrollBehavior = "auto";

    // Restore the original scroll position.
    window.scroll({
      top: cachedScrollPosition.top
    });

    // Restore the original scroll behavior.
    htmlStyle.scrollBehavior = previousHtmlScrollBehavior;
    bodyStyle.scrollBehavior = previousBodyScrollBehavior;
  };
};

逻辑非常简单,如果不考虑某些边界情况,还可以进一步简化。例如,这是我使用的:

export const blockScroll = () => {
  const html = document.documentElement;
  const documentRect = html.getBoundingClientRect();
  const { body } = document;
  const screenHeight = window.innerHeight;

  // Only do the magic if document is scrollable
  if (documentRect.height > screenHeight) {
    const cachedScrollPosition =
      -documentRect.top || body.scrollTop || window.scrollY || document.scrollTop || 0;

    html.style.top = coerceCssPixelValue(-cachedScrollPosition);

    html.classList.add(NO_SCROLL_CLASS);

    return () => {
      html.classList.remove(NO_SCROLL_CLASS);

      window.scroll({
        top: cachedScrollPosition,
        behavior: "auto"
      });
    };
  }
};

所有基于javascript的modal/lightbox系统在html标签或body标签上显示modal/lightbox时都会使用溢出。

当lightbox显示时,js会推送一个隐藏在html或body标签上的溢出。 当lightbox被隐藏时,有些人会删除隐藏的,有些人会在html或body标签上推一个溢出自动。

在Mac上工作的开发人员没有看到滚动条的问题。

只需替换隐藏的unset不看到内容滑动下的模式删除滚动条。

Lightbox开放/显示:

<html style="overflow: unset;"></html>

Lightbox隐藏/关闭:

<html style="overflow: auto;"></html>

你可以用Javascript来做:

// Classic JS
window.onscroll = function(ev) {
  ev.preventDefault();
}

// jQuery
$(window).scroll(function(ev) {
  ev.preventDefault();
}

然后当你的灯箱关闭时禁用它。

但如果你的灯箱包含滚动条,你将无法在它打开时滚动。这是因为window包含了body和#lightbox。 所以你必须使用像下面这样的架构:

<body>
  <div id="global"></div>
  <div id="lightbox"></div>
</body>

然后只在#global上应用onscroll事件。

我已经做了这个函数,用JS解决了这个问题。 这个原则可以很容易地扩展和定制,这对我来说是一个很大的优势。

使用这个js DOM API函数:

const handleWheelScroll = (element) => (event) => {
  if (!element) {
    throw Error("Element for scroll was not found");
  }
  const { deltaY } = event;
  const { clientHeight, scrollTop, scrollHeight } = element;
  if (deltaY < 0) {
    if (-deltaY > scrollTop) {
      element.scrollBy({
        top: -scrollTop,
        behavior: "smooth",
      });
      event.stopPropagation();
      event.preventDefault();
    }
    return;
  }

  if (deltaY > scrollHeight - clientHeight - scrollTop) {
    element.scrollBy({
      top: scrollHeight - clientHeight - scrollTop,
      behavior: "smooth",
    });
    event.stopPropagation();
    event.preventDefault();
    return;
  }
};

简而言之,如果滚动要滚动给定元素(您想要滚动的元素)之后的其他内容,则此函数将停止事件传播和默认行为。

然后你可以像这样把它勾起来和解开:

const wheelEventHandler = handleWheelScroll(elementToScrollIn);

window.addEventListener("wheel", wheelEventHandler, {
    passive: false,
});

window.removeEventListener("wheel", wheelEventHandler);

注意,它是一个高阶函数,所以必须保持对给定实例的引用。

我在鼠标进入中挂钩addEventListener部分,在鼠标离开事件中取消挂钩removeEventListener,但你可以随心所欲地使用它。