原生纵向滚动与横向滚动,完美解决滚动问题

纵向滚动与横向滚动

1 原理

先来看一下浏览器的滚动原理:当页面内容的高度超过视口高度的时候,会出现纵向滚动条;当页面内容的宽度超过视口宽度的时候,会出现横向滚动条。也就是当我们的视口展示不下内容的时候,会通过滚动条的方式让用户滚动屏幕看到剩余的内容。

同理当子元素内容高度或宽度超过父元素后,父元素也会产生滚动条。

所以我们需要准备以下 DOM 结构:

DOM 结构分为三层,wrapper => content => item

  • wrapper: 可视区 or 滚动区,一般是有固定高度的容器
  • content: 内容区域,他的高度是由子元素 item 撑开的
  • item: 子元素,一般有多个

在这里插入图片描述

tips: 横向滚动 DOM 结构也是如此

在这里插入图片描述

2 非 flex 布局

2.1 纵向滚动

除了需要准备三层 DOM 结构外,还需要注意以下 2 点:

  1. 父层的 wrapper 固定高度
  2. 父层的 wrapper 设置overflow: auto;
<div class="vertical_wrapper">
  <div class="content">
    <div class="item">1</div>
    <div class="item">2</div>
    <div class="item">3</div>
    <div class="item">4</div>
    <div class="item">5</div>
    <div class="item">6</div>
    <div class="item">7</div>
    <div class="item">8</div>
    <div class="item">9</div>
    <div class="item">10</div>
  </div>
</div>
.vertical_wrapper {
  width: 300px;
  height: 300px; /* wrapper中高固定 */
  border: 1px solid #ccc;
  box-sizing: border-box;
  overflow: auto; /* 超出部分显示滚动条 */
}
.vertical_wrapper .item {
  height: 50px;
}

2.2 横向滚动

除了需要准备三层 DOM 结构外,还需要注意以下 4 点:

  1. 父层的 wrapper 固定宽度
  2. 父层的 wrapper 设置overflow: auto;
  3. 父层的 wrapper 设置white-space: nowrap;,否则会换行
  4. content 与 item 设置display: inline-block;
<div class="horizontal_wrapper">
  <div class="content">
    <div class="item">1</div>
    <div class="item">2</div>
    <div class="item">3</div>
    <div class="item">4</div>
    <div class="item">5</div>
    <div class="item">6</div>
    <div class="item">7</div>
    <div class="item">8</div>
    <div class="item">9</div>
    <div class="item">10</div>
  </div>
</div>
.horizontal_wrapper {
  width: 300px;
  border: 1px solid #ccc;
  box-sizing: border-box;
  overflow: auto; /* 超出部分显示滚动条 */
  white-space: nowrap; /* 不换行 */
}
.horizontal_wrapper .content,
.horizontal_wrapper .content .item {
  display: inline-block; /* content与item需要设置为行内块元素 */
}
.horizontal_wrapper .content .item {
  width: 50px;
  height: 50px;
  background-color: red;
}

2.3 横向滚动中的问题

以上布局由于 item 设置了display: inline-block;,而且 item 元素之间是用回车进行换行,所以在浏览器渲染的时候回车符会解析成一个空格,如下图所示

在这里插入图片描述

可以使用以下 3 种解决方案之一解决:

  • item 元素之间不使用回车进行换行

    <div class="horizontal_wrapper">
      <div class="content">
        <div class="item">1</div><div class="item">2</div><div class="item">3</div><div class="item">4</div><div class="item">5</div><div class="item">6</div><div class="item">7</div><div class="item">8</div><div class="item">9</div><div class="item">10</div>
      </div>
    </div>
    
  • content 元素的font-size设置为 0

    .horizontal_wrapper {
      width: 300px;
      border: 1px solid #ccc;
      box-sizing: border-box;
      overflow: auto; /* 超出部分显示滚动条 */
      white-space: nowrap; /* 不换行 */
    }
    .horizontal_wrapper .content {
      font-size: 0; /* 为了消除空格 */
    }
    .horizontal_wrapper .content,
    .horizontal_wrapper .content .item {
      display: inline-block; /* content与item需要设置为行内块元素 */
    }
    .horizontal_wrapper .content .item {
      width: 50px;
      height: 50px;
      background-color: red;
      font-size: 14px; /* 为了不让item继承父元素的font-size,需要单独设置字号 */
    }
    
  • 使用 flex 布局,下文会讲到

3 flex 布局

3.1 纵向滚动

不需要使用 flex 布局

3.2 横向滚动

除了需要准备三层 DOM 结构外,还需要注意以下 2 点:

  1. 父层的 wrapper 固定宽度
  2. 父层的 wrapper 设置overflow: auto;
  3. content 设置 display: flex;
  4. item 设置 flex-shrink: 0;,不压缩子元素
<div class="horizontal_wrapper">
  <div class="content">
    <div class="item">1</div>
    <div class="item">2</div>
    <div class="item">3</div>
    <div class="item">4</div>
    <div class="item">5</div>
    <div class="item">6</div>
    <div class="item">7</div>
    <div class="item">8</div>
    <div class="item">9</div>
    <div class="item">10</div>
  </div>
</div>
.horizontal_wrapper {
  width: 300px;
  border: 1px solid #ccc;
  box-sizing: border-box;
  overflow: auto; /* 超出部分显示滚动条 */
}
.horizontal_wrapper .content {
  display: flex;
}
.horizontal_wrapper .content .item {
  width: 50px;
  height: 50px;
  background-color: red;
  flex-shrink: 0; /* 不压缩子元素 */
}

3.3 横向滚动中的问题

使用 flex 布局后,content 元素的宽度变为了 wrapper 的宽度,目前笔者暂未想到解决方案

4 完美解决方案

上述在不使用 flex 和使用 flex 布局后都会有小问题,解决方案是使用betterScroll 插件。该插件基于原生 JS 实现的,不依赖任何框架。完美运用于 Vue、React 等 MVVM 框架。

该插件的滚动原理与 1 描述一致,DOM 结构和 CSS 样式与 2.1、2.2 描述一致。

具体使用请参照betterScroll 文档
.io/docs/zh-CN/)。该插件基于原生 JS 实现的,不依赖任何框架。完美运用于 Vue、React 等 MVVM 框架。

该插件的滚动原理与 1 描述一致,DOM 结构和 CSS 样式与 2.1、2.2 描述一致。

具体使用请参照betterScroll 文档

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值