控制页面的滚动:自定义下拉到刷新和溢出效果

本文介绍了如何使用CSS的`overscroll-behavior`属性来控制页面滚动,包括防止滚动逃离固定位置元素、禁用拉到刷新效果、消除过度滚动的发光和橡皮圈回弹,以及创建自定义的下拉刷新动画。通过实例演示和代码示例,展示了如何优化滚动体验,提供更好的用户交互。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

虽互不曾谋面,但希望能和你成为笔尖下的朋友

以读书,技术,生活为主,偶尔撒点鸡汤

不作,不敷衍,意在真诚吐露,用心分享

点击上方,可关注本刊

前言

通过阅读本文,你可以通过css 中overcroll-behavior属性值的设置,处理浏览器溢出滚动,以及禁用移动设备上刷新,下拉滚动时的发光和橡皮圈回弹效果,当然也可以看到css中 Houndini(胡迪宁),也就是css中也可以写变量等知识,如果文有误导的地方,欢迎路过的老师拍砖指正

目录

  • 背景,滚动边界与滚动链接

  • 引入overscroll行为(对应的三个属性值,auto,contain,none)

  • 防止滚动逃离固定位置元素通过overscroll-behavior:contain解决

  • 禁用拉到刷新(overscroll-behavior-y: contain)

  • 禁用超滚色条纹和橡皮筋效果要在滚动边界时禁用反弹效果(橡皮筋效果),使用overscroll-behavior-y: none:

  • 完整Demo

  • 总结

CSS overscroll-behavior属性允许开发人员在达到内容的顶部/底部时覆盖浏览器的默认溢出滚动行为。使用该案例包括禁用移动设备上的“拉动到刷新”功能,消除过度滚动发光和橡皮筋效果,并防止页面内容在模态/叠加层下滚动

背景

滚动边界和滚动链接

滚动是与页面交互的最基本的方式之一,但是由于浏览器的诡异默认行为,某些UX模式可能很难处理。作为一个例子,带一个应用程序抽屉带有大量用户可能需要滚动的项目。当它们到达底部时,溢出容器将停止滚动,因为没有更多内容可供使用。换句话说,用户到达“滚动边界”。但是请注意,如果用户继续滚动会发生什么情况。抽屉后面的内容开始滚动!滚动由父容器占领;例子中的主页面本身

被证实这种行为称为滚动链接;滚动内容时浏览器的默认行为。通常情况下,默认设置非常好,但有时候这并不理想,甚至不可预料。当用户点击滚动边界时,某些应用可能希望提供不同的用户体验

(在Chrome Android上滚动链接)

拉到刷新效果

拉到刷新是一种直观的手势,通过Facebook和Twitter等移动应用推广。拉下页面并释放,为更新近的帖子被加载。事实上,这种特殊用户体验非常流行,以至于Android这样的移动浏览器都采用了相同的效果。向下滑动页面顶部会刷新整个页面

(左边为原生拉到刷新操作,自定义拉到刷新,右边为原生拉到刷新操作刷新整个页面)

对于像Twitter PWA这样的情况,禁用本地“拉动到刷新”操作可能是有意义的。为什么?在这个应用程序中,你可能不希望用户不小心刷新页面。还有可能看到双刷新动画!另外,定制浏览器的动作可能会更好,并将其与网站的品牌更紧密地对齐。不幸的是,这种类型的定制很难实现。开发人员最终编写不必要的JavaScript,添加非被动触摸监听器(阻止滚动),或者将整个页面粘贴到100vw / vh中(以防止页面溢出)。这些变通办法在滚动性能方面具有良好记录的负面影响

引入overscroll行为

overscroll-behavior属性是一个新的CSS功能,用于控制当你过度滚动容器(包括页面本身)时发生的情况。你可以使用它来取消滚动链接,禁用/自定义拉动到刷新操作,禁用iOS上的橡皮圈效果(当Safari实现超滚动行为时)等等。最好的部分是,使用overscroll行为不会对页面性能产生负面影响

该属性有三个可能的值

  1. auto - 默认,源于元素的滚动可能会传播给祖先(父级)元素

  2. contain - 防止滚动链接。滚动不会传播给祖先,但会显示节点内的本地效果。例如,Android上的滚动滚动效果或iOS上的橡皮筋效果,它会在用户点击滚动边界时通知用户。注意:使用overscroll-behavior:包含html元素可防止超滚动导航操作

  3. none - 与包含相同,但它也可以防止节点本身内的超滚动效果(例如,Android超量滚动发光或iOS橡皮圈) 注意:overscroll-behavior还支持overscroll-behavior-x和overscroll-behavior-y的简写,如果您只想定义特定轴的行为

让我们深入一些例子来看看如何使用overscroll-behavior

防止滚动逃离固定位置元素

chatbox聊天场景

考虑位于页面底部的固定定位聊天室。其意图是聊天室是独立的组件,它与它后面的内容分开滚动。但是,由于滚动链接,只要用户点击聊天历史记录中的最后一条消息,文档就开始滚动

对于这个应用程序,让chatbox内的滚动内容始终处于聊天状态更为合适。我们可以通过添加超滚动 `overscroll-behavior:contain行为来实现这一点:包含持有聊天消息的元素


   
   
  1. #chat .msgs {

  2.  overflow: auto;

  3.  overscroll-behavior: contain;

  4.  height: 300px;

  5. }

本质上,我们创建了聊天室的滚动上下文和主页面之间的逻辑分隔。最终的结果是当用户到达聊天记录的顶部/底部时,主页面保持放置状态。在聊天框中开始的滚动不会传播出去

(聊天窗口下的内容也会滚动)

页面重叠场景

下面”方案的另一个变动就是是当你看到内容在固定位置叠加后滚动时。一个死的样品overscroll行为是为了!浏览器试图帮助,但它最终使网站看起来越来越多。

示例 - 带和不带过度滚动行为的模态:包含

(左边之前:页面内容在叠加层下滚动,右边之后:页面内容不会在叠加层下滚动)

禁用拉到刷新

关闭pull-to-refresh操作是一行CSS。只要阻止整个视口定义元素的滚动链接。在大多数情况下,这是


   
   
  1.  body {

  2.  /* 禁用“拉到刷新”功能,但允许发生滚动发光效果 Disables pull-to-refresh but allows overscroll glow effects. */

  3.  overscroll-behavior-y: contain;

  4. }

通过这个简单的添加,我们修复了聊天框演示中的双拉到更新动画,并且可以实现使用整洁加载动画的自定义效果。收件箱刷新时整个收件箱也会变模糊 

(左边为之前,右边为之后)

以下是完整代码的一部分


   
   
  1. <style>

  2.  body.refreshing #inbox {

  3.    filter: blur(1px);

  4.    touch-action: none; /* 防止滚动 prevent scrolling */

  5.  }

  6.  body.refreshing .refresher {

  7.    transform: translate3d(0,150%,0) scale(1);

  8.    z-index: 1;

  9.  }

  10.  .refresher {

  11.    --refresh-width: 55px;

  12.    pointer-events: none;

  13.    width: var(--refresh-width);

  14.    height: var(--refresh-width);

  15.    border-radius: 50%;

  16.    position: absolute;

  17.    transition: all 300ms cubic-bezier(0,0,0.2,1);

  18.    will-change: transform, opacity;

  19.    ...

  20.  }

  21. </style>

  22. <div class="refresher">

  23.  <div class="loading-bar"></div>

  24.  <div class="loading-bar"></div>

  25.  <div class="loading-bar"></div>

  26.  <div class="loading-bar"></div>

  27. </div>

  28. <p id="inbox"><!-- msgs --></p>

  29. <script>

  30.  let _startY;

  31.  const inbox = document.querySelector('#inbox');

  32.  inbox.addEventListener('touchstart', e => {

  33.    _startY = e.touches[0].pageY;

  34.  }, {passive: true});

  35.  inbox.addEventListener('touchmove', e => {

  36.    const y = e.touches[0].pageY;

  37.    // 在容器顶部时激活自定义的拉到刷新效果 Activate custom pull-to-refresh effects when at the top of the container

  38.    // 用户正在滚动 and user is scrolling up.

  39.    if (document.scrollingElement.scrollTop === 0 && y > _startY &&

  40.        !document.body.classList.contains('refreshing')) {

  41.      // refresh inbox.

  42.    }

  43.  }, {passive: true});

  44. </script>

禁用超滚色条纹和橡皮条纹效果

要在滚动边界时禁用反弹效果(橡皮筋效果),请使用 overscroll-behavior-y:none:


   
   
  1. body {

  2.  /* 禁用拉到刷新和过卷滚发光效果。 仍然保持滑动导航Disables pull-to-refresh and overscroll glow effect.

  3.     Still keeps swipe navigations. */

  4.     overscroll-behavior-y: none;

  5. }

(左边之前:下拉滚动边界显示辉光,右边之后:下拉时辉光禁用)

注意:这仍然会保留左/右滑动导航。为了防止导航,你可以使用overscroll-behavior-x:none

完整Demo

把它放在一起,完整的聊天框演示,使用overscroll-behavior行为来创建一个自定义的拉动到刷新动画,并禁用滚动从转义聊天室小部件。这提供了一个最佳的用户体验,如果没有CSS过度滚动行为

这是示例中HTML结构代码:


   
   
  1. <main>

  2.        <!-- header start -->

  3.        <header>

  4.            <div>

  5.                <h2>关注微信itclanCoder公众号...</h2>

  6.            </div>

  7.        </header>

  8.        <!-- header end -->

  9.        <!-- 顶部下拉刷新的小图标start -->

  10.        <div class="refresher">

  11.            <div class="loading-bar"></div>

  12.            <div class="loading-bar"></div>

  13.            <div class="loading-bar"></div>

  14.            <div class="loading-bar"></div>

  15.        </div>

  16.        <!-- 顶部下拉花心的小图标end -->

  17.        <p id="inbox">

  18.            <!-- filled dynamically -->

  19.        </p>

  20.        <!-- 聊天框开始 -->

  21.        <chat-window title="与itclancoder聊天" open>

  22.            <div class="msg">我们聊聊吧</div>

  23.            <div class="msg">我是川川</div>

  24.            <div class="msg">你好啊</div>

  25.            <div class="msg">嗯</div>

  26.            <div class="msg">聊天止于嘻嘻,哈哈,哦哦,嗯</div>

  27.            <div class="msg">全宇宙第一帅</div>

  28.            <div class="msg">没有之一</div>

  29.            <div class="msg">在此窗口中滚动不会滚动页面后面的页面</div>

  30.            <div class="msg">这信息包含有<code>overflow:auto</code> and uses <code>overscroll-behavior-y:contain</code> 去阻止这个默认行为.</div>

  31.        </chat-window>

  32.    </main>

  33.    <template id="chat-window-template">

  34.        <!-- 注意这里的css只能放在里面,放到外面去的话,样式不起作用 -->

  35.        <style type="text/css">

  36.         :host {

  37.            display: block;

  38.            max-width: 250px;

  39.            background: #fff;

  40.            contain: content;

  41.        }

  42.         :host([open]) .msgs {

  43.            display: flex;

  44.        }

  45.        .toolbar {

  46.            padding: 8px;

  47.            background: #404040;

  48.            color: #fff;

  49.            display: flex;

  50.            justify-content: space-between;

  51.            align-items: center;

  52.            border-top-left-radius: 3px;

  53.            border-top-right-radius: 3px;

  54.            cursor: pointer;

  55.            user-select: none;

  56.        }

  57.        .toolbar #title {

  58.            text-overflow: ellipsis;

  59.            white-space: nowrap;

  60.            overflow: hidden;

  61.        }

  62.        .toolbar #close {

  63.            font-size: inherit;

  64.            background: none;

  65.            border: none;

  66.            color: inherit;

  67.        }

  68.        .msgs {

  69.            border-left: 1px solid #ccc;

  70.            border-right: 1px solid #ccc;

  71.            display: flex;

  72.            flex-direction: column;

  73.            align-items: start;

  74.            height: 300px;

  75.            overflow: auto;

  76.            overscroll-behavior-y: contain;

  77.        }

  78.         ::slotted(.msg) {

  79.            padding: 8px 16px;

  80.            margin: 8px;

  81.            border-radius: 5px;

  82.            background-color: #eee;

  83.        }

  84.         ::slotted(.msg:nth-child(even)) {

  85.            align-self: flex-end;

  86.        }

  87.        #input-container {

  88.            border: 1px solid #ccc;

  89.            border-top: 1px solid #aaa;

  90.        }

  91.        #input-container input {

  92.            padding: 8px;

  93.            font-size: inherit;

  94.            width: 100%;

  95.            height: 100%;

  96.            border: none;

  97.            box-sizing: border-box;

  98.        }

  99.        .msgs-container {

  100.            display: none;

  101.        }

  102.         :host([open]) .msgs-container {

  103.            display: block;

  104.        }

  105.        </style>

  106.        <!-- 聊天框顶部开始 -->

  107.        <div class="toolbar">

  108.            <span id="title"></span>

  109.            <button id="close">????</button>

  110.        </div>

  111.        <!-- 聊天框顶部结束 -->

  112.        <div class="msgs-container">

  113.            <div class="msgs">

  114.                <slot></slot>

  115.            </div>

  116.            <!-- 底下输入 -->

  117.            <div id="input-container">

  118.                <input type="text" placeholder="Enter text">

  119.            </div>

  120.        </div>

  121.        <!-- 聊天框结束 -->

  122.    </template>

这是css代码


   
   
  1. @charset "UTF-8";

  2. /**

  3. *

  4. * @authors 随笔川迹 (itclanCode@163.com)

  5. * @date    2018-04-05 01:53:00

  6. * @version $Id$

  7. * @link (https://juejin.im/post/5a005392518825295f5d53c8)

  8. * @weChatPublicId (itclanCoder)

  9. * @QQGroup (643468880)

  10. * @PersonWeChatId (suibichuanji)

  11. * @PersonQQ (1046678249)

  12. * @describe 功能描述 禁用固定位置元素上的滚动链接Demo css样式

  13. *

  14. *

  15. */

  16. * {

  17.    box-sizing: border-box;

  18. }

  19. html {

  20.    /*

  21.      --是css Houndini,是一套正在到来的css APi,css对变量的支持,允许在css中

  22.      声明如--height,--width的自定义属性,而后通过var()函数对变量求值,可以理解为简化版的less/sass,但是它不能通过DOM API存取

  23.     */

  24.    --header-height: 60px;

  25. }

  26. html,

  27. body {

  28.    font-family: "Open Sans", sans-serif;

  29.    font-weight: 300;

  30.    font-size: 16px;

  31.    background: #fafafa;

  32.    margin: 0;

  33.    overscroll-behavior-y: contain;

  34.    /* 禁用下拉刷新,保持发光效果 disable pull to refresh, keeps glow effects */

  35. }

  36. h1,

  37. h2,

  38. h3 {

  39.    margin: 0;

  40.    font-weight: inherit;

  41. }

  42. header {

  43.    padding: 0 8px;

  44.    background: #f44336;

  45.    color: #fff;

  46.    position: fixed;

  47.    top: 0;

  48.    left: 0;

  49.    right: 0;

  50.    z-index: 2;

  51.    height: var(--header-height);

  52.    display: flex;

  53.    align-items: center;

  54.    justify-content: space-between;

  55. }

  56. #inbox {

  57.    padding-top: var(--header-height);

  58.    /* height of header */

  59. }

  60. chat-window {

  61.    position: fixed;

  62.    bottom: 0;

  63.    right: 16px;

  64. }

  65. p {

  66.    /*属性设置某个选择器出现次数的计数器的值。默认为 0,利用这个属性,计数器可以设置或重置为任何值,可以是正值或负值。如果没有提供 number,则默认为 0。*/

  67.    counter-reset: email;

  68. }

  69. p div {

  70.    margin: 0;

  71.    padding: 16px 8px;

  72.    border-top: 1px solid #ccc;

  73.    display: flex;

  74.    justify-content: space-between;

  75. }

  76. p .label::after {

  77.    counter-increment: email;

  78.    content: counter(email);

  79.    margin-left: 8px;

  80. }

  81. body.refreshing #inbox,

  82. body.refreshing header {

  83.    filter: blur(1px);

  84.    /*滤镜,1像素模糊*/

  85.    touch-action: none;

  86.    /* 防止滚动 prevent scrolling */

  87. }

  88. body.refreshing .refresher {  /*下拉刷新小图标*/

  89.    transform: translate3d(0, 150%, 0) scale(1);

  90.    z-index: 1;

  91.    visibility: visible;

  92. }

  93. .refresher {

  94.    /*

  95.      pointer-events即可让这个HTML元素(包括它的所有子孙元素)失去所有的事件响应。鼠标焦点会直接无视它,click、mouseover等所有事件会穿透它到达它的下一级元素

  96.      1. 阻止用户的点击动作产生任何效果

  97.      2. 阻止缺省鼠标指针的显示

  98.      3. 阻止CSS里的hover和active状态的变化触发事件

  99.      4. 阻止JavaScript点击动作触发的事件

  100.      在许多网站上过节的时候页面最上层会用canvas绘制的雨、雪花,避免这些悬浮物遮挡住页面从而影响鼠标点击,可以使用pointer-events=none属性,让这些上方的canvas不会遮挡鼠标事件,让鼠标事件可以穿透上方的canvas来点击页面

  101.    */

  102.    pointer-events: none;

  103.    --refresh-width: 55px;

  104.    background: #fff;

  105.    width: var(--refresh-width);

  106.    height: var(--refresh-width);

  107.    border-radius: 50%;

  108.    position: absolute;

  109.    left: calc(50% - var(--refresh-width) / 2);

  110.    padding: 8px;

  111.    box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14),

  112.    0 1px 5px 0 rgba(0, 0, 0, 0.12),

  113.    0 3px 1px -2px rgba(0, 0, 0, 0.2);

  114.    transition: all 300ms cubic-bezier(0, 0, 0.2, 1);

  115.    will-change: transform, opacity;

  116.    /*使用了CSS3 will-change加速创建新的渲染层*/

  117.    display: inline-flex;

  118.    justify-content: space-evenly;

  119.    align-items: center;

  120.    visibility: hidden;

  121. }

  122. body.refreshing .refresher.shrink {

  123.    transform: translate3d(0, 150%, 0) scale(0);

  124.    opacity: 0;

  125. }

  126. .refresher.done {

  127.    transition: none;

  128. }

  129. .loading-bar {

  130.    width: 4px;

  131.    height: 18px;

  132.    border-radius: 4px;

  133.    animation: loading 1s ease-in-out infinite;

  134. }

  135. .loading-bar:nth-child(1) {

  136.    background-color: #3498db;

  137.    animation-delay: 0;

  138. }

  139. .loading-bar:nth-child(2) {

  140.    background-color: #c0392b;

  141.    animation-delay: 0.09s;

  142. }

  143. .loading-bar:nth-child(3) {

  144.    background-color: #f1c40f;

  145.    animation-delay: .18s;

  146. }

  147. .loading-bar:nth-child(4) {

  148.    background-color: #27ae60;

  149.    animation-delay: .27s;

  150. }

  151. @keyframes loading {

  152.    0% {

  153.        transform: scale(1);

  154.    }

  155.    20% {

  156.        transform: scale(1, 2.2);

  157.    }

  158.    40% {

  159.        transform: scale(1);

  160.    }

  161. }

这是示例的js代码


   
   
  1. /**

  2. *

  3. * @authors 随笔川迹 (itclanCode@163.com)

  4. * @date    2018-04-05 01:56:33

  5. * @version $Id$

  6. * @weChatPublicId ((itclanCoder))

  7. * @QQGroup ((643468880))

  8. * @PersonWeChatId ((suibichuanji))

  9. * @PersonQQ ((1046678249))

  10. * @link ((https://juejin.im/post/5a005392518825295f5d53c8))

  11. * @describe 禁用固定位置元素上的滚动链js

  12. */

  13. (() => {

  14.    if (!CSS.supports('overscroll-behavior-y', 'contain')) {

  15.        alert("Your browser doesn't support overscroll-behavior :(");

  16.    }

  17.    // 定义<chat-window>自定义元素 Define <chat-window> custom element.

  18.    customElements.define('chat-window', class extends HTMLElement {

  19.        constructor() {

  20.            super();

  21.            const shadowRoot = this.attachShadow({ mode: 'open' });

  22.            const tmpl = document.querySelector('#chat-window-template');

  23.            shadowRoot.appendChild(tmpl.content.cloneNode(true));

  24.            shadowRoot.querySelector('#title').textContent = this.title;

  25.            const closeButton = shadowRoot.querySelector('#close');

  26.            closeButton.addEventListener('click', e => {

  27.                this.remove();

  28.            });

  29.            this.msgs = shadowRoot.querySelector('.msgs');

  30.            this.input = shadowRoot.querySelector('input');

  31.            this.input.addEventListener('keypress', e => {

  32.                if (e.code === 'Enter' && this.input.value) {

  33.                    const msg = document.createElement('div');

  34.                    msg.classList.add('msg');

  35.                    msg.textContent = this.input.value;

  36.                    this.appendChild(msg);

  37.                    e.target.value = null;

  38.                    this._scrollToBottom();

  39.                }

  40.            });

  41.            const toolbar = shadowRoot.querySelector('.toolbar');

  42.            toolbar.addEventListener('click', e => {

  43.                this.open = !this.open;

  44.                if (this.open) {

  45.                    this.input.focus();

  46.                } else {

  47.                    this.input.blur();

  48.                    this.blur();

  49.                }

  50.            });

  51.            this.tabIndex = 0;

  52.            this.open = this.hasAttribute('open');

  53.        }

  54.        get open() {

  55.            return this._open;

  56.        }

  57.        set open(val) {

  58.            this._open = val;

  59.            if (this._open) {

  60.                this.setAttribute('open', '');

  61.                this._scrollToBottom();

  62.            } else {

  63.                this.removeAttribute('open');

  64.            }

  65.        }

  66.        _scrollToBottom() {

  67.            this.msgs.scrollTop = this.msgs.scrollHeight;

  68.        }

  69.    });

  70.    async function simulateRefreshAction() {

  71.        const sleep = (timeout) => new Promise(resolve => setTimeout(resolve, timeout));

  72.        const transitionEnd = function(propertyName, node) {

  73.            return new Promise(resolve => {

  74.                function callback(e) {

  75.                    e.stopPropagation();

  76.                    if (e.propertyName === propertyName) {

  77.                        node.removeEventListener('transitionend', callback);

  78.                        resolve(e);

  79.                    }

  80.                }

  81.                node.addEventListener('transitionend', callback);

  82.            });

  83.        }

  84.        const refresher = document.querySelector('.refresher');

  85.        document.body.classList.add('refreshing');

  86.        await sleep(2000);

  87.        refresher.classList.add('shrink');

  88.        await transitionEnd('transform', refresher);

  89.        refresher.classList.add('done');

  90.        refresher.classList.remove('shrink');

  91.        document.body.classList.remove('refreshing');

  92.        await sleep(0); // let new styles settle.

  93.        refresher.classList.remove('done');

  94.    }

  95.    function getRandomIntInclusive(min, max) {

  96.        min = Math.ceil(min);

  97.        max = Math.floor(max);

  98.        return Math.floor(Math.random() * (max - min + 1)) + min;

  99.    }

  100.    function formatDateBasedOnToday(date) {

  101.        const today = new Date();

  102.        const opts = {};

  103.        if (date.getDay() === today.getDay()) {

  104.            opts.minute = 'numeric';

  105.            opts.hour = 'numeric';

  106.        } else {

  107.            opts.month = 'short';

  108.            opts.day = 'numeric';

  109.        }

  110.        return new Intl.DateTimeFormat('en-US', opts).format(date);

  111.    }

  112.    function populatePage(inbox) {

  113.        const frag = new DocumentFragment();

  114.        let date = new Date();

  115.        for (let i = 0; i < NUM_EMAILs; ++i) {

  116.            date.setMinutes(date.getMinutes() - getRandomIntInclusive(1, 10));

  117.            const div = document.createElement('div');

  118.            div.innerHTML = `<span class="label">Email</span></span>${formatDateBasedOnToday(date)}</span>`;

  119.            frag.appendChild(div);

  120.        }

  121.        inbox.appendChild(frag);

  122.    }

  123.    const NUM_EMAILs = 100;

  124.    let _startY = 0;

  125.    const inbox = document.querySelector('#inbox');

  126.    inbox.addEventListener('touchstart', e => {

  127.        _startY = e.touches[0].pageY;

  128.    }, { passive: true });

  129.    inbox.addEventListener('touchmove', e => {

  130.        const y = e.touches[0].pageY;

  131.        // Activate custom pull-to-refresh effects when at the top fo the container

  132.        // and user is scrolling up.

  133.        if (document.scrollingElement.scrollTop === 0 && y > _startY &&

  134.            !document.body.classList.contains('refreshing')) {

  135.            simulateRefreshAction();

  136.        }

  137.    }, { passive: true });

  138.    populatePage(inbox);

  139. })();

  140. (function(i, s, o, g, r, a, m) {

  141.    i['GoogleAnalyticsObject'] = r;

  142.    i[r] = i[r] || function() {

  143.        (i[r].q = i[r].q || []).push(arguments)

  144.    }, i[r].l = 1 * new Date();

  145.    a = s.createElement(o),

  146.        m = s.getElementsByTagName(o)[0];

  147.    a.async = 1;

  148.    a.src = g;

  149.    m.parentNode.insertBefore(a, m)

  150. })(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');

  151. ga('create', 'UA-43475701-1', 'ebidel.github.io');

  152. ga('send', 'pageview');

最终示例效果如下所示

(示例效果)

总结

本文主要是针对页面上的滚动,自定义下拉刷新与溢出效果,通过css中的overscroll-behavior:container阻止滚动链接,也就是在触发子元素的事件操作时,不会传递给父级元素,相当于是阻止事件的冒泡,当然阻止滚动链接在页面上有水平方向的,也有垂直方向的,垂直方向上设置overscroll-behavior-y:none:时可在下拉滚动时禁用反弹效果(橡皮筋效果)

当然文中的刷新动画效果是css3的@keyframes的,当然还有解决这种溢出,系统默认滚动条,橡皮筋回弹,以及禁止长按选中文字,选中图片,系统默认菜单,事件点透问题时可以使用document.addEventListener('touchstart',function(ev){ev.preventDefault();})解决

Demo源码地止:https://ebidel.github.io/demos/chatbox.html

原文出处:httpsdevelopers.google.comwebupdates201711overscroll-behaviorutm_source=mobiledevweekly&utm_medium=email)

[](https://mobiledevweekly.com/issues/185

推荐阅读:

作者川川,一个靠前排的90后帅小伙,具有情怀的代码男,路上正追逐斜杠青年的践行者,愿做你耳朵旁边的枕男,眼睛笔尖下的窗户

随手点赞

手留余香


(个人微信:suibichuanji) 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值