返回顶部
首页 > 资讯 > 精选 >css怎么实现滚动吸顶
  • 603
分享到

css怎么实现滚动吸顶

2023-06-08 06:06:29 603人浏览 独家记忆
摘要

小编给大家分享一下CSS怎么实现滚动吸顶,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!修改版预览这篇文章是三天前写就的,有大佬给我提了一些修改意见,我觉得这个意见

小编给大家分享一下CSS怎么实现滚动吸顶,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

修改版预览

这篇文章是三天前写就的,有大佬给我提了一些修改意见,我觉得这个意见确实中肯。所以就有了这个升级的修改版本。代码同步更新到 GitHub 了。

修改内容如下:

  1. 添加了图文说明,直观的说明 getBoundinGClientRect()集合含义

  2. 频繁 reflow 风险该如何规避(优化滚动监听)

  3. 监听滚动带来的性能问题(使用 IntersectionObserver, 新方案)

修改更新的内容在第 4 点和第 5 点,如果你看过本文,可以直接看修改更新的内容。或者你可以再看一遍。

前言

我入职第二家公司接到的第一个需求就是修复之前外包做的滚动吸顶效果。我当时很纳闷为何一个滚动吸顶会有 bug,后来我查看代码才发现直接用的是 offsetTop 这个属性,而且并没有做兼容性处理。

offsetTop

用于获得当前元素到定位父级( element.offsetParent )顶部的距离(偏移值)。

定位父级 offsetParent 的定义是:与当前元素最近的 position != static 的父级元素。

或许写这个代码的人没有注意到“定位父级”这个这个附属条件。

后来在项目中总会遇到滚动吸顶的效果需要实现,现在我将我知道的 4 种滚动吸顶实现方式做详细介绍。

以上这四种方式你都了解吗?相关代码已上传到 gitHub ,感兴趣的可以 clone 代码到本地运行。望给个 star 支持一下。

四种实现方式

我们先看一下效果图:

css怎么实现滚动吸顶

一、使用 position:sticky 实现

1、粘性定位是什么?

粘性定位 sticky 相当于相对定位 relative 和固定定位 fixed 的结合;在页面元素滚动过程中,某个元素距离其父元素的距离达到 sticky 粘性定位的要求时;元素的相对定位 relative 效果变成固定定位 fixed 的效果。

MDN 传送门

2、如何使用?

使用条件:

  1. 父元素不能 overflow:hidden 或者 overflow:auto 属性

  2. 必须指定 top、bottom、left、right 4 个值之一,否则只会处于相对定位

  3. 父元素的高度不能低于 sticky 元素的高度

  4. sticky 元素仅在其父元素内生效

在需要滚动吸顶的元素加上以下样式便可以实现这个效果:

.sticky {    position: -WEBkit-sticky;    position: sticky;    top: 0;}

3、这个属性好用吗?

我们先看下在 Can I use 中看看这个属性的兼容性:

css怎么实现滚动吸顶

可以看出这个属性的兼容性并不是很好,因为这个 api 还只是实验性的属性。不过这个 API 在 iOS 系统的兼容性还是比较好的。

所以我们在生产环境如果使用这个 API 的时候一般会和下面的几种方式结合使用。

二、使用 JQuery 的 offset().top 实现

我们知道 Jquery 中封装了操作 DOM 和读取 DOM 计算属性的 API,基于 offset().top 这个 API 和 scrollTop() 的结合,我们也可以实现滚动吸顶效果。

...window.addEventListener('scroll', self.handleScrollOne);...handleScrollOne: function() {    let self = this;    let scrollTop = $('html').scrollTop();    let offsetTop = $('.title_box').offset().top;    self.titleFixed = scrollTop > offsetTop;}...

这样实现固然可以,不过由于 JQuery 慢慢的退出历史的舞台,我们在代码中尽量不使用 JQuery 的 API。我们可以基于 offset().top 的源码自己处理原生 offsetTop。于是乎就有了第三种方式。

scrolloTop() 有兼容性问题,在微信浏览器、IE、某些 firefox 版本中 $('html').scrollTop() 的值会为 0,于是乎也就有了第三种方案的兼容性写法。

三、使用原生的 offsetTop 实现

我们知道 offsetTop 是相对定位父级的偏移量,倘若需要滚动吸顶的元素出现定位父级元素,那么 offsetTop 获取的就不是元素距离页面顶部的距离。

我们可以自己对 offsetTop 做以下处理:

getOffset: function(obj,direction){    let offsetL = 0;    let offsetT = 0;    while( obj!== window.document.body && obj !== null ){        offsetL += obj.offsetLeft;        offsetT += obj.offsetTop;        obj = obj.offsetParent;    }    if(direction === 'left'){        return offsetL;    }else {        return offsetT;    }}

使用:

...window.addEventListener('scroll', self.handleScrollTwo);...handleScrollTwo: function() {    let self = this;    let scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;    let offsetTop = self.getOffset(self.$refs.pride_tab_fixed);    self.titleFixed = scrollTop > offsetTop;}...

你是不是看出了以上两种方式的一些问题?

我们一定需要使用 scrollTop - offsetTop 的值来实现滚动吸顶的效果吗?答案是否定的。

我们一同看看第四种方案。

四、使用 obj.getBoundingClientRect().top 实现

定义:这个 API 可以告诉你页面中某个元素相对浏览器视窗上下左右的距离。

使用:tab 吸顶可以使用 obj.getBoundingClientRect().top 代替 scrollTop - offsetTop,代码如下:

// html<div class="pride_tab_fixed" ref="pride_tab_fixed">    <div class="pride_tab" :class="titleFixed == true ? 'isFixed' :''">        // some code    </div></div> // Vueexport default {    data(){      return{        titleFixed: false      }    },    activated(){      this.titleFixed = false;      window.addEventListener('scroll', this.handleScroll);    },    methods: {      //滚动监听,头部固定      handleScroll: function () {        let offsetTop = this.$refs.pride_tab_fixed.getBoundingClientRect().top;        this.titleFixed = offsetTop < 0;        // some code      }    }  }

offsetTop 和 getBoundingClientRect() 区别

getBoundingClientRect():

用于获得页面中某个元素的左,上,右和下分别相对浏览器视窗的位置。不包含文档卷起来的部分。

css怎么实现滚动吸顶

该函数返回一个 object 对象,有8个属性:top, right, buttom, left, width, height, x, y

css怎么实现滚动吸顶

offsetTop:

用于获得当前元素到定位父级( element.offsetParent )顶部的距离(偏移值)。

定位父级 offsetParent 的定义是:与当前元素最近的 position != static 的父级元素。

offsetTop 和 offsetParent 方法相结合可以获得该元素到 body 上边距的距离。代码如下:

getOffset: function(obj,direction){    let offsetL = 0;    let offsetT = 0;    while( obj!== window.document.body && obj !== null ){        offsetL += obj.offsetLeft;        offsetT += obj.offsetTop;        obj = obj.offsetParent;    }    if(direction === 'left'){        return offsetL;    }else {        return offsetT;    }}

延伸知识点

offsetWidth:

元素在水平方向上占用的空间大小:

offsetWidth =  border-left + padding-left + width + padding-right + border-right

offsetHeight:

元素在垂直方向上占用的空间大小:

offsetHeight =  border-top + padding-top + height + padding-bottom + border-bottom

注:如果存在垂直滚动条,offsetWidth 也包括垂直滚动条的宽度;如果存在水平滚动条,offsetHeight 也包括水平滚动条的高度;

offsetTop:

元素的上外边框至 offsetParent 元素的上内边框之间的像素距离;

offsetLeft:

元素的左外边框至 offsetParent 元素的左内边框之间的像素距离;

注意事项

  1. 所有偏移量属性都是只读的;

  2. 如果给元素设置了 display:none,则它的偏移量属性都为 0;

  3. 每次访问偏移量属性都需要重新计算(保存变量);

  4. 在使用的时候可能出现 DOM 没有初始化,就读取了该属性,这个时候会返回 0;对于这个问题我们需要等到 DOM 元素初始化完成后再执行。

遇到的两个问题

一、吸顶的那一刻伴随抖动

出现抖动的原因是因为:在吸顶元素 position 变为 fixed 的时候,该元素就脱离了文档流,下一个元素就进行了补位。就是这个补位操作造成了抖动。

解决方案

为这个吸顶元素添加一个等高的父元素,我们监听这个父元素的 getBoundingClientRect().top 值来实现吸顶效果,即:

<div class="title_box" ref="pride_tab_fixed">    <div class="title" :class="titleFixed == true ? 'isFixed' :''">    使用 `obj.getBoundingClientRect().top` 实现    </div></div>

这个方案就可以解决抖动的 Bug 了。

二、吸顶效果不能及时响应

这个问题是我比较头痛,之前我没有在意过这个问题。直到有一天我用美团点外卖的时候,我才开始注意这个问题。

描述:

  1. 当页面往下滚动时,吸顶元素需要等页面滚动停止之后才会出现吸顶效果

  2. 当页面往上滚动时,滚动到吸顶元素恢复文档流位置时吸顶元素不恢复原样,而等页面停止滚动之后才会恢复原样

原因:

在 ios 系统上不能实时监听 scroll 滚动监听事件,在滚动停止时才触发其相关的事件。

解决方案:

还记得第一种方案中的 position:sticky 吗?这个属性在 IOS6 以上的系统中有良好的兼容性,所以我们可以区分 IOS 和 Android 设备做两种处理。

IOS 使用 position:sticky,Android 使用滚动监听 getBoundingClientRect().top 的值。

如果 IOS 版本过低呢?这里提供一种思路:window.requestAnimationFrame()。

性能优化篇(新增)

到此 4 中滚动吸顶的方式介绍完了,可是这样就真的结束了吗?其实还是有优化的空间的。
我们从两个方向做性能优化(其实是一个方向):

  1. 避免过度的 reflow

  2. 优化滚动监听事件

问题定位过程

我们知道过度的 reflow 会使页面的性能下降。所以我们需要尽可能的降低 reflow 的次数,给用户更加流畅的感觉。

有的朋友或许会说这个我知道,可是这和滚动吸顶有什么关系呢?

不急,你是否还记得滚动吸顶使用了 offsetTop 或者 getBoundingClientRect().top 来获取响应的偏移量呢?

既然有读取元素的属性就自然会导致页面 reflow。

因此我们优化的方向就是从减少读取元素属性次数下手,查看代码发现一触发屏幕滚动事件就会调用相关方法读取元素的偏移量。

优化方案

解决这个问题有以下两个方案:

  1. 牺牲平滑度满足性能,使用节流控制相关方法的调用

  2. 使用 IntersectionObserver 和节流结合,也牺牲了平滑度。

第一种方案

这个方案很常见,不过其带来的副作用也很明显,就是在吸顶效果会有些延迟,如果产品可以接受那就不失为一种好方法。

这样可以控制在一定时间内只读取

这里节流函数就直接是用 lodash.js 封装好的 throttle 方法。

代码如下:

window.addEventListener('scroll', _.throttle(self.handleScrollThree, 50));

第二种方案

第二种方案相对来说容易接受一点,就是支持 IntersectionObserver 就用 IntersectionObserver,否则就用 throttle。

我们先讲讲 IntersectionObserver

IntersectionObserver 可以用来监听元素是否进入了设备的可视区域之内,而不需要频繁的计算来做这个判断。

通过这个属性我们就可以在元素不在可视范围内,不去读取元素的相对位置,已达到性能优化;当浏览器不支持这个属性的时候就使用 throttle 来处理。

我们看看这个属性的兼容性怎么样:

css怎么实现滚动吸顶

大概支持了 60% 以上,在项目中还是可以使用的(你需要做好兼容性处理)。

关于 IntersectionObserver 如何使用,请看MDN 或者阮一峰教程

使用 IntersectionObserver 和 throttle 优化的代码如下:

IntersectionObserverFun: function() {    let self = this;    let ele = self.$refs.pride_tab_fixed;    if( !IntersectionObserver ){        let observer = new IntersectionObserver(function(){            let offsetTop = ele.getBoundingClientRect().top;            self.titleFixed = offsetTop < 0;        }, {            threshold: [1]        });        observer.observe(document.getElementsByClassName('title_box')[0]);    } else {        window.addEventListener('scroll', _.throttle(function(){            let offsetTop = ele.getBoundingClientRect().top;            self.titleFixed = offsetTop < 0;        }, 50));    }},

注意

IntersectionObserver API 是异步的,不随着目标元素的滚动同步触发。

规格写明,IntersectionObserver的实现,应该采用 requestIdleCallback()。它不会立即执行回调,它会调用 window.requestIdleCallback() 来异步的执行我们指定的回调函数,而且还规定了最大的延迟时间是 100 毫秒。

以上是“css怎么实现滚动吸顶”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注编程网精选频道!

--结束END--

本文标题: css怎么实现滚动吸顶

本文链接: https://lsjlt.com/news/252152.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • css怎么实现滚动吸顶
    小编给大家分享一下css怎么实现滚动吸顶,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!修改版预览这篇文章是三天前写就的,有大佬给我提了一些修改意见,我觉得这个意见...
    99+
    2023-06-08
  • react.js中怎么实现tab吸顶效果
    这篇文章给大家分享的是有关react.js中怎么实现tab吸顶效果的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。在react项目开发中有一个需求是,页面滚动到tab所在位置时,t...
    99+
    2024-04-02
  • css怎么实现元素不随滚动条滚动
    今天小编给大家分享的是css怎么实现元素不随滚动条滚动,相信很多人都不太了解,为了让大家更加了解,所以给大家总结了以下内容,一起往下看吧。一定会有所收获的哦。什么是csscss是一种用来表现HTML或XML等文件样式的计算机语言,主要是用来...
    99+
    2023-06-14
  • 如何用CSS实现平滑滚动到顶部按钮
    如何用CSS实现平滑滚动到顶部按钮在网页设计中,为了提高用户体验,让用户可以快速回到页面顶部是非常重要的。而通过实现一个平滑滚动到顶部的按钮,可以使用户回到顶部的过程更加流畅和美观。本文将介绍如何使用CSS来实现这个功能,并提供具体的代码示...
    99+
    2023-11-21
    CSS 平滑滚动 顶部按钮
  • 怎么在Html5中实现title吸顶功能
    怎么在Html5中实现title吸顶功能?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。吸顶功能吸顶是一种比较常见的交互效果,当页面滑出屏幕边界,标题会自动吸附在屏幕边缘,用于提...
    99+
    2023-06-09
  • AndroidRecyclerView实现吸顶动态效果流程分析
    目录一、ItemDecoration二、实现RecyclerView吸顶效果1、实现一个简单的RecyclerView2、通过ItemDecoration画分割线3、画出每个分组的组...
    99+
    2022-12-22
    Android RecyclerView吸顶效果 Android RecyclerView
  • 怎么用css实现滚动文字
    这篇文章主要介绍了怎么用css实现滚动文字,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。     代码  ...
    99+
    2024-04-02
  • 怎么用css实现滚动效果
    使用css实现滚动效果的方法:1.通过“overflow”属性设置滚动条使网页元素的内容实现滚动效果,在css中添加样式代码,比如语法样式为:“overflow: scroll;”设置滚动条即可。css通过overflow属性设置滚动条示例...
    99+
    2024-04-02
  • Android实现上拉吸顶效果
    本文实例为大家分享了Android实现上拉吸顶效果的具体代码,供大家参考,具体内容如下 效果图 1.home_layout.xml 此布局即可实现上拉标题固定在顶部 <xml...
    99+
    2024-04-02
  • AndroidJetpackCompose实现列表吸顶效果
    目录stickyHeader实体类加载假数据吸顶标题二级条目完整代码效果图安卓传统的 Recyclerview 打造悬浮头部StickyHeader的吸顶效果,十分麻烦,而在Comp...
    99+
    2024-04-02
  • RecyclerVIew实现悬浮吸顶效果
    RecyclerVIew实现悬浮吸顶效果图 这里写图片描述主页面布局<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="htt...
    99+
    2023-05-30
    recyclerview 悬浮吸顶 recycle
  • Android CoordinatorLayout+AppBarLayout顶部栏吸顶效果的实现
    1.控件简介。 CoordinatorLayout遵循Material 风格,包含在 support Library中,结合AppbarLayout, CollapsingToolbarLayout等 可 产生各种炫酷的折叠悬浮效果。   ...
    99+
    2023-10-06
    android
  • CSS怎么实现吸附效果
    这篇文章主要讲解了“CSS怎么实现吸附效果”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“CSS怎么实现吸附效果”吧!原理在 jQuery 时代就有很多吸附效果插件了,现在常用的三大前端框架也...
    99+
    2023-06-27
  • React 实现具备吸顶和吸底功能组件实例
    目录背景实现结语背景 现在手机应用经常有这样一个场景: 页面上有一个导航,导航位置在页面中间位置,当页面顶部滚动到导航位置时,导航自动吸顶,页面继续往下滚动时,它就一直在页面视窗顶...
    99+
    2023-02-23
    React吸顶吸底功能 React 功能组件
  • CSS怎么实现视差滚动效果
    这篇文章主要介绍“CSS怎么实现视差滚动效果”,在日常操作中,相信很多人在CSS怎么实现视差滚动效果问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”CSS怎么实现视差滚动效果”...
    99+
    2024-04-02
  • CSS怎么实现滚动的图片栏
    这篇文章给大家分享的是有关CSS怎么实现滚动的图片栏的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。在一些网站上可以经常看到有一些图片进行持续不断的滚动,这个效果可以通过css的动画效果来实现。具体效果如下主要原理...
    99+
    2023-06-08
  • CSS怎么实现滚动阴影效果
    这篇文章主要为大家展示了CSS怎么实现滚动阴影效果,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带大家一起来研究并学习一下“CSS怎么实现滚动阴影效果”这篇文章吧。css是什么意思css是一种用来表现HTML或XML等文件样...
    99+
    2023-06-06
  • 微信小程序怎么实现吸顶盒效果
    本文小编为大家详细介绍“微信小程序怎么实现吸顶盒效果”,内容详细,步骤清晰,细节处理妥当,希望这篇“微信小程序怎么实现吸顶盒效果”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。html部分 <!--...
    99+
    2023-07-02
  • 怎么实现CSS隐藏滚动条并可以滚动内容
    本篇内容主要讲解“怎么实现CSS隐藏滚动条并可以滚动内容”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么实现CSS隐藏滚动条并可以滚动内容”吧!方法1:计算滚...
    99+
    2024-04-02
  • vue中el-table实现自动吸顶效果(支持fixed)
    目录前言实现思路效果:使用:主要源码:前言 看了很多案例,从简单的角度,position:sticky,似乎是比较理想的选择,可是当el-table设置了fixed后,这里的fix...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作