一.场景

“吸顶”是一种比较老的交互方式,在PC页面已经用了很多年了,如图:

sticky

吸顶元素的初始位置一般靠近页面顶部,但与顶部有一定距离,这块区域放的是最醒目的元素,比如Banner图。页面向下滚动超过吸顶元素初始位置时,把吸顶元素固定在顶部

要求吸顶的元素一般是二级导航栏、搜索框、文章标题栏(h1)、表头(thead)、tab条等等,共同特点是在内容或功能上比较重要,但又不是最重要的元素(最重要的元素通常固定在页面顶部,navbar-fixed-top)

二.PC解决方案

页面滚动到一定位置时,做一些事情

“回到顶部”按钮也是这样的,页面向下滚动超过150px时,显示该按钮,否则隐藏

所以实现思路是监听scroll事件:

var stickyEl = document.querySelector('.sticky');

var stickyT = stickyEl.offsetTop;

window.onscroll = function(e) {

var scrollT = document.body.scrollTop;

// console.log(scrollT, stickyT);

if (scrollT > stickyT) {

stickyEl.classList.add('fixed-top');

}

else {

stickyEl.classList.remove('fixed-top');

}

};

和“回到顶部”的实现方式一模一样,效果好像还不错,但很快会发现滚动到临界位置stickyT的时候,页面抖了一下,向上缩了一截。因为stickyEl此时fixed出去了,下面的元素上来,抢占sticky元素老家,所以页面抖了一下

我们希望平滑,不要抖动,所以还需要一个占位符,守住stickyEl老家:

var stickyEl = document.querySelector('.sticky');

// 守家占位符

var stickyHolder = document.createElement('div');

var rect = stickyEl.getBoundingClientRect();

// console.log(rect);

stickyEl.parentNode.replaceChild(stickyHolder, stickyEl);

stickyHolder.appendChild(stickyEl);

stickyHolder.style.height = rect.height + 'px';

var stickyT = stickyEl.offsetTop;

window.onscroll = function(e) {

var scrollT = document.body.scrollTop;

// console.log(scrollT, stickyT);

if (scrollT > stickyT) {

stickyEl.classList.add('fixed-top');

}

else {

stickyEl.classList.remove('fixed-top');

}

};

把吸顶元素用相同高度的占位符包起来,临界位置stickyEl被fixed出去,空间由stickyHolder撑起来,下面元素挤不上来,页面不抖了

这样做还有一些问题,吸顶元素上方的各个元素加载很慢的话,拿到的stickyT比实际的小,甚至为0(如果上方是一张很大的Banner图的话)。所以需要配合默认图片占位符(base64)使用,或者偷懒先用min-height顶着,上方图片onload时再修正stickyT

三.移动端解决方案

从原理上看,直接搬过来是可以的。在Android 4.0+确实可以,但IOS几乎全家都行不通

Android scroll

Android 4.0的scroll事件不那么实时(自带节流的感觉),但Android 4.1之后scroll事件和PC几乎没什么区别

The Android browser in Ice Cream Sandwich fires the event but doesn’t feel very responsive and only sporadically re-paints the DOM to move the blue box. Luckily, Jelly Bean’s Android browser handles this example perfectly; everything is updated and rendered smoothly as the user scrolls.

(引自参考资料1)

只要页面还在滚动,scroll事件就疯狂触发,需要手动节流,这正是我们需要的效果。如果scroll本身自带节流,就很容易错过临界点判断,导致吸顶元素“跳一下”,体验不平滑

IOS scroll

IOS 8-的Safari,包括UIWebView,对scroll事件做了很大限制:

手指划动屏幕 -> 滚动 -> 手指抬起 -> 惯性滚动 -> 停止滚动

整个过程,直到停止滚动时才会触发1次scroll事件,也就是说,IOS8以下的scroll变成了scrollend。监听滚动判断位置的方法完全失效,平滑吸顶效果变成了滚过临界位置直到停止滚动时,吸顶元素跳到目标位置,体验非常差,不可忍受

scroll不能用,但还可以有一些奇怪的思路,比如定时器读scrollTop,touchmove,iscroll等等

有前辈做了详细测试,见参考资料1

定时器在手指没有离开屏幕时不会执行,touchmove触发频率足够,也能拿到scrollTop,但touchend后,惯性滚动期间,没有任何事件可用,拿不到这段的scrollTop,很难预测这段惯性滚动距离(减速运动),甚至不确定各IOS版本这段距离的计算方式是否相同

iscroll这种假滚动,自然可以实时获取滚动位置,iscroll有一个专用版本来做这个事情:

iscroll-probe.js, probing the current scroll position is a demanding task, that’s why I decided to build a dedicated version for it. If you need to know the scrolling position at any given time, this is the iScroll for you. (I’m making some more tests, this might end up in the regular iscroll.js script, so keep an eye on it).

IOS 8+的Safari和WKWebView能够疯狂触发scroll,无论手指在不在屏幕上,无论是不是惯性滚动期间。但IOS 8+的UIWebView,scroll限制还在

如果要支持IOS 8-设备以及任意IOS版本的UIWebView,此路不通,忘掉scroll

sticky

虽然scroll方案行不通,但IOS提供了另一种方式:position: sticky,自IOS 6.1就支持了,最近Chrome56才支持

这个CSS规则专门负责吸顶,一般用法:

.sticky {

// 滚过初始位置时自动吸顶

position: -webkit-sticky;

position: sticky;

// 吸顶时的定位

top: 0;

left: 0;

// z比下方所有z高

z-index: 9999;

}

没有滚过初始位置时,和position: relative表现类似(占据空间,!static能为后代元素提供定位参照),但top和left无效

滚过初始位置时,和position: fixed表现类似,top和left生效,固定在屏幕可见区域,但页面不会抖动,原本占据的空间还在(自带守家占位符的感觉)

吸顶效果非常平滑,比Android scroll方案体验更平滑,但限制很明显,无法实时获知吸顶状态,于此相关的各种效果都受限制,比如吸顶tab列表:

sticky-tab

非吸顶状态时可以划动列表部分,让页面滚动,转到吸顶状态,多个tab列表无缝切换,浏览状态互不影响

吸顶状态时划动当前tab列表,到头,让页面滚动,转到非吸顶状态

也就是说,非吸顶状态时,让tab列表不能滚动(overflow-y: hidden);吸顶状态时,让tab列表可以滚动(overflow-y: auto)

但是IOS sticky不由我们控制,且无法实时获知吸顶状态,想要获知吸顶状态的话,又回到了最初的问题,页面滚动过程中,怎样实时获知滚动条位置?CSS sticky并不能解决这个问题

笔者还没有找到合适的解决方案,目前方案是牺牲tab浏览状态独立性,多tab共用body的滚动条,切换tab时滚回之前的位置。这样做避免了判断吸顶状态,但牺牲了tab列表无缝切换的完美体验

如果有新思路、好点子,或者成熟方案,麻烦告知,感激不尽

四.在线Demo

五.总结

一般元素吸顶:Android用scroll方案,在效果可接受范围内手动节流,提升性能;IOS用CSS sticky,如果不需要兼容IOS 8-以及任意版本UIWebView的话,也可以采用scroll方案

吸顶tab列表:没有好的解决方案,暂用牺牲无缝切换的方案

整页iScroll是一个冒险方案,页面复杂的话,不要轻易尝试,即便页面不复杂,也难保以后不会变得复杂

参考资料

android的吸顶效果,吸顶效果解决方案相关推荐

  1. vue键盘抬起_vue实现编辑器键盘抬起时内容跟随光标距顶位置向上滚动效果

    最近遇到了之前没有碰到过的一个问题:编辑器输入内容时,最好让内容一直保持在可视区域,比如如果区域超出的话,就在键盘抬起时向上滚动一定距离. 这个和聊天发消息还有一定的区别,聊天的话是只要点开输入框,就 ...

  2. Android 使用 ellipsize 实现文字横向移动效果(跑马灯效果)

    实现的效果图如下 ellipsize 可以设置跑马灯效果 具体代码设置如下 <TextViewandroid:layout_width="match_parent"andro ...

  3. Android 图片合成:添加蒙板效果 不规则相框 透明度渐变效果的实现

    Android 图片合成:添加蒙板效果 不规则相框 透明度渐变效果的实现 暂时还未有时间开发这效果,所以先贴出来. 先贴一张效果图,这是一张手机截屏: 左上方的风景图:背景图片 右上方的人物图:前景图 ...

  4. android 小球效果,Android开发实现跟随手指的小球效果示例

    本文实例讲述了android开发实现跟随手指的小球效果.分享给大家供大家参考,具体如下: 配置drawview类用于绘制小球 public class drawview extends view { ...

  5. android 自定义刷新控件,Android开发中MJRefresh自定义刷新动画效果

    有时候我们对自己开发的项目经常不满意,但是我们要达到自定义刷新动画的效果有一定的难度,别着急,下面爱站技术频道和大家分享Android开发中MJRefresh自定义刷新动画效果,一起来学习吧! [一] ...

  6. android led闪烁功能,如何在Android应用层中制作一个LED指示灯效果

    如何在Android应用层中制作一个LED指示灯效果 发布时间:2020-12-08 16:12:59 来源:亿速云 阅读:86 作者:Leah 本篇文章给大家分享的是有关如何在Android应用层中 ...

  7. android电池充电动画,Android 开机充电图标和充电动画效果

    首先驱动需要先获取到2个power supply kernel\msm-3.18\drivers\usb\phy\phy-msm-usb.c motg->usb_psy.name = " ...

  8. android让字体左右对齐,Android 模仿微信读书文字左右对齐效果

    原标题:Android 模仿微信读书文字左右对齐效果 本文作者 作者:Amter https://www.jianshu.com/p/020786e22a6f 左右对齐的文字效果,很常见,在大多数文章 ...

  9. android 仿ios动画效果代码,Android仿IOS上拉下拉弹性效果的实例代码

    用过iphone的朋友相信都体验过页面上拉下拉有一个弹性的效果,使用起来用户体验很好:Android并没有给我们封装这样一个效果,我们来看下在Android里如何实现这个效果.先看效果,感觉有些时候还 ...

  10. android动画送礼物,Android开发仿映客送礼物效果

    这里写链接内容仿映客送小礼物的特效,顺便复习一下属性动画,话不多说先看效果图. 需求分析 可以看到整个动画有几部分组成,那我们就把每个部分拆分出来各个击破. 1.要显示那些内容以及内容间的位置关系? ...

最新文章

  1. 基于TensorRT的BERT实时自然语言理解(下)
  2. Zookeeper整理(一)- 写操作产生事件,写操作与Watcher对应关系
  3. 字字带泪——写在三十岁到来这一天
  4. 自学python编程免费教程-Python十分钟入门 自学python基础教程送你参考
  5. MySQL5.0安装图文教程
  6. pandas常用数据处理函数整理
  7. 初生牛犊不怕虎的我记录一次 web面试
  8. 奥鹏计算机基础18秋在线作业答案,1056《 计算机基础》20秋西南大学在线作业答案答案...
  9. 自己设计的一个android返回键
  10. 基于Fortran的结构力学位移法编程求解
  11. 实现两个分数的加减法编写一个C程序,
  12. 操作系统实验5 设备管理
  13. 海外资产配置要注意什么?
  14. Git忽略文件及文件夹
  15. Python基础-类变量和实例变量
  16. MyBatis---插件
  17. 【JavaWeb-遇错】继承或者实现Servlet相关时总是报红或者包导不进来
  18. TokenInsight 对话首席——市场回暖,挖矿or买币?(完整稿)
  19. 中南大学汪炼成教授课题组:三维金属-半导体-金属AlN深紫外探测器
  20. c# winfrom GDI+ DrawString怎么画不同颜色的字

热门文章

  1. 基于大疆dij_irp.exe进行红外测温
  2. Raid控制器-megacli 命令简易使用介绍
  3. (zz)楚王何故好细腰
  4. C++输入大写字母转小写字母
  5. 洛谷P1563 玩具谜题
  6. ODM操作MongoDB
  7. CodeForces 1009D Relatively Prime Graph 贪心+枚举
  8. 菠萝狗四足机器人使用手册
  9. ansys怎么使用anand模型_ansys粘塑性分析-Anand模型.pdf
  10. 阿里P9面试官分享:应聘阿里全流程