浮层滚动问题

引子

使用 position transform 实现从右边滑出的 h5 浮层效果,但在手机浏览器上左右滑动时,页面产生了左右滚动条,浮层也出来了。这是问题页面,移动端访问如下:

浮层滚动问题

这个现象不应该出现,问题好解决,但为什么会这样?想了一下,好像知道相关点,但又讲不清,所以在此梳理一下。

原因

产生了滚动,很自然的就会想到 overflow 属性,那么就先来了解一下。

overflow 属性指定了块容器元素的内容溢出时是否被剪裁,是 overflow-xoverflow-y 的简写。

Name overflow
可取值 visible
默认值 visible
适用于 块级容器和建立了格式化上下文的盒子
继承性
  • visible:这个值表示内容不会被剪切,可能会在盒子之外渲染。
  • hidden:这个值表示内容被剪切,并且不应提供滚动用户界面来查看剪裁区域之外的内容。
  • scroll:这个值表示内容被剪切,并且如果用户代理使用在屏幕上可见的滚动机制(例如滚动条或窗格),则无论盒子中的任何内容是否被剪裁,都应为盒子显示该机制。这是为了避免滚动条在一个动态环境中,出现和消失造成的任何问题。当指定这个值且目标媒介是打印时,溢出的内容可能会被打印,也可能不会打印。当用在 table boxes 时,这个值跟 visible 作用一致。
  • auto:这个值表示依赖用户代理,但应为溢出的盒子提供滚动机制。当用在 table boxes 时,这个值跟 visible 作用一致。

通过上面的了解,想先纠正一下取值为 auto 的一种认识:浏览器会自动根据内容决定是否产生滚动。从现象上看似乎是这样,但标准上不是这样的,只是建议。如果用户代理不提供滚动,那就没有,而且也不一定是滚动,这都依赖于用户代理。

再来分析一下上面有问题的情况,主要的结构和样式如下:

<!doctype html>
<html>
  <body>
    <div class="pop"></div>
  </body>
</html>
html {overflow-x: hidden;}
html,body { height: 100%; }
body { position: relative; }
.pop {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, .5);
  transform: translateX(100%);
}

body 没有显式设置 overflow 的值,所以默认是 visible ,由于浮层使用 transform 超出了可视区,那么先来确定一下 bodyoverflow 是否有效。

设置 body 宽度的效果页面,移动端访问如下:

浮层滚动问题

发现符合 overflow: visible 的效果,没有产生左右滚动条。

接着有了下面的猜想:只要超出了可视区就会产生滚动。在前面的基础上,设置浮层 transform 超出可视区,这是效果页面,移动端访问如下:

浮层滚动问题

结果跟猜想的一样,这也说明从一开始并不是 body 产生了滚动,而是 viewport 产生了滚动。继续查找资料,发现了下面的标准说明:

用户代理必须将根元素上设置的 overflow 属性应用于 viewport 。当根元素是一个 HTML 的 html 元素且它的 overflow 值是 visible ,并且它拥有 body 元素作为后代,用户代理必须将这样的第一个后代元素的 overflow 的属性值应用于 viewport 。如果 visible 应用于 viewport ,则必须将其解释为 auto 。从中传播值的元素必须有一个 overflow 已使用的值为 visible

从上面的说明以及实际测试,推测上述情况中 body 的 overflow 属性应用到了 viewport 上,导致产生了滚动。把 body 设置 overflow-x: hidden ,就发现不会产生左右滚动了,移动端访问如下:

浮层滚动问题

后记

在 IOS 和 安卓上测试了 4、5 个浏览器都会出现左右滚动,但一些安卓手机上的 Chrome 浏览器没有出现滚动,例如在红米6手机。还有一点就是:PC 端浏览器都不会产生左右滚动。

此外,标准上其实说的并不是很清楚,再加上标准是一回事,各家实现并不一定都是符合标准。

以上见解都是个人结合资料和实际测试得出,是否真是这样,真不好说,不过可以当作一个思考的方向。

参考资料

上一篇:通过接口返回信息判断模态框显示与隐藏


下一篇:javascript-原型:将此可见性检查脚本隐瞒为原型语法?