前端系列——与众不同的移动端底部固定栏 fixed、absolute 兼容 iOS 和 Android 方案

本文主要是介绍前端系列——与众不同的移动端底部固定栏 fixed、absolute 兼容 iOS 和 Android 方案,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

相信我,我分享的和你在其他博客上看到的终极方案是如此的与众不同!

做过移动端开发的同学,对底部DOM定位出现的各种奇葩情况已经深恶痛绝了吧,底部DOM设置不同的position,在Android和ios上表现都不一样。

为了兼容Android和ios,很多人都煞费苦心,也包括我。

打开你做的H5,尤其是在微信上打开看看,是不是觉得很恶心,如果自我感觉很恶心,那么请往下看这篇文章,不恶心说明你成功了,可以走了!

最终还是成功解决了,这篇文章记录一下兼容2种设备的方案。

第一种情况

据我所知,网上还找不到一个能够真正解决这个问题的教程,因为大多数人都是只考虑在body scroll的情况下,设置底部为fixed或者absolute,然后设置滚动区域padding-bottom的值,这种做法反正我是无法接受的,体验太不爽了,也没有兼容Android和ios。

下图是第一种情况,滚动区域有表单,底部一个固定栏,当填写表单的时候,我们看看ios和Android的表现情况:

1、底部定位为fixed的情况下

ios:激活输入框时,底部不会弹出来(合理)。
Android:激活输入框时,底部会跟着输入框弹出来(不合理)。

2、底部定位为absolute的情况下

ios:激活输入框时,底部不会弹出来(合理)。
Android:激活输入框时,底部会跟着输入框弹出来(不合理)。

android后遗症:输入框失焦的时候,可能导致底部显示在浏览器中间某个位置,回不到原位置。

absolute后遗症:底部按钮和输入框区域一起随着body滚动,不再置顶独立。当滚动区域超过一屏幕时,底部输入框定位出现错乱。

clipboard.png

传统解决办法

通常将底部设置为fixed,当激活输入框的时候,将底部定位改为relative,即可兼容ios和Android。

第二种情况

底部如果是个输入框的情况下,我们肯定需要输入框在激活的时候弹出来,和第一种情况是相反的。

1、底部定位为fixed的情况下

ios:激活输入框时,底部不会弹出来(不合理)。
Android:激活输入框时,底部会跟着输入框弹出来(合理)。

2、底部定位为absolute的情况下

ios:当滚动区域超过一屏幕时,底部输入框定位出现错乱(不合理)。
Android:当滚动区域超过一屏幕时,底部输入框定位出现错乱(不合理)。

clipboard.png

传统解决办法:

仍旧是采用fixed定位

ios:在激活输入框的时候,执行下面代码

setTimeout(() => document.body.scrollTop = document.body.scrollHeight, 500)

android: 表现正常

传统解决方案的后遗症

除了抖动问题,还有就是微信端滚动body会显示微信浏览器背景,也就是超出滚动边界回弹效应,还有一个恶心的问题是当有弹框的时候,弹框和body滚动累加的双重滚动会有点击穿透造成的卡顿问题。

由此,如果你还寄希望于body滚动,那么你的移动端开发体验真的一塌糊涂。

搭建真正的移动端滚动架构

看到这里,你可以暂时把上面的传统解决方案统统忘记。

下面我将会分享移动端最舒适的架构方案。

1、你可能听过Iscroll,这个东西是我们今天要用到的框架的鼻祖,但我们不是用它,而是我曾经另外一篇文章介绍到的JRoll框架(比IScroll更加轻量和兼容的移动端滚动框架)。

2、使用这款框架对我们解决底部定位问题还有优化弹框体验有什么帮助呢?他可以完美解决传统解决方案的后遗症,因为他并不是使用body滚动,而是使用css3滚动,采用GPU加速,在ios和Android上测试并不卡顿。如果你想做出像app一样流程的H5,别再用那恶心的body滚动了。

源码(复制查看效果,别忘了导入js插件)

下面的源码你可以直接复制到一个html文件上测试,代码中我提供了多种功能的解决方案:

1、采用滚动框架时,何时获取滚动区域的高度(看源码)

2、输入框底部固定时,在该框架中兼容ios和Android的方法(看源码)

3、采用DocumentFragment动态渲染5000个列表元素,说到这个有点意思,记得腾讯某部门的社招面试题就是考察这个知识点,一般人可能采用的是for循环加innerHTML的方法(看源码)

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=0.5, minimum-scale=0.5, maximum-scale=0.5, user-scalable=no"><title>Title</title><style>* {padding: 0;margin: 0;}body, html {font-size: 24px;height: 100%;}ul {padding-bottom: 1rem;}ul li {list-style: none;}.bottom {position: fixed;bottom: 0;left: 0;width: 100%;height: 4.0833rem;}.bottom > input {width: 100%;border: 0;outline: 0;background: rgb(246, 246, 246);color: rgb(255, 255, 255);text-align: center;line-height: 4.0833rem;font-size: 1.25rem;}</style>
</head>
<body>
<div id="scroll-body"><ul></ul>
</div>
<div class="bottom"><input type="text" placeholder="请输入内容" onfocus="evocation()"></div>
<script src="./js/jroll.js"></script>
<script>function getClientHeight() {
//        获取移动端屏幕高度var winHeightif (window.innerHeight) {winHeight = window.innerHeight;} else if ((document.body) && (document.body.clientHeight)) {winHeight = document.body.clientHeight;} else if (document.documentElement && document.documentElement.clientHeight && document.documentElement.clientWidth) {winHeight = document.documentElement.clientHeight;}return winHeight}var scrollBody = document.querySelector('#scroll-body') //获取滚动区域的DOMvar bottom = document.querySelector('.bottom') //获取底部DOMfunction renderLi() {//渲染li列表,采用DocumentFragment方案var ul = document.querySelector('ul')var dFrag = document.createDocumentFragment()var startTime = new Date().getTime()for (var i = 0; i < 5000; i++) {var li = document.createElement("li")li.textContent = idFrag.appendChild(li)}ul.appendChild(dFrag)var endTime = new Date().getTime()console.log('渲染耗时:', endTime-startTime, 'ms')}function evocation() {//ios唤出弹框,Android的不需要setTimeout(() => document.body.scrollTop = document.body.scrollHeight, 500)}renderLi()document.addEventListener('DOMContentLoaded', function() {var height = getClientHeight() - bottom.offsetHeight //获取滚动区域高度scrollBody.style.height = height + 'px' //计算出实际的滚动区域的高度,然后设置new JRoll(scrollBody) //实例化JRoll插件})
</script>
</body>
</html>

总结

使用上面提供的框架,你在移动端开发中,不再需要担心底部固定的问题,不再需要担心滚动造成的一系列问题,不再需要担心弹框滚动以及点击弹框造成的穿透问题等。

而且,不知道你发现没有,底部固定栏你现在可以尝试使用fixed、absolute、relative等设置,不再局限于只能使用fixed了。感兴趣就好好研究一下代码吧!

但是

在IOS11版本中,我发现了document.body.scrollTop = document.body.scrollHeight无效的bug,目前还没找到原因,小于IOS11一切正常。

这里也封装了React版本的插件,可以下载使用:react-roll-container

转载https://segmentfault.com/a/1190000012310521

这篇关于前端系列——与众不同的移动端底部固定栏 fixed、absolute 兼容 iOS 和 Android 方案的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/509401

相关文章

React实现原生APP切换效果

《React实现原生APP切换效果》最近需要使用Hybrid的方式开发一个APP,交互和原生APP相似并且需要IM通信,本文给大家介绍了使用React实现原生APP切换效果,文中通过代码示例讲解的非常... 目录背景需求概览技术栈实现步骤根据 react-router-dom 文档配置好路由添加过渡动画使用

Android数据库Room的实际使用过程总结

《Android数据库Room的实际使用过程总结》这篇文章主要给大家介绍了关于Android数据库Room的实际使用过程,详细介绍了如何创建实体类、数据访问对象(DAO)和数据库抽象类,需要的朋友可以... 目录前言一、Room的基本使用1.项目配置2.创建实体类(Entity)3.创建数据访问对象(DAO

Java解析JSON的六种方案

《Java解析JSON的六种方案》这篇文章介绍了6种JSON解析方案,包括Jackson、Gson、FastJSON、JsonPath、、手动解析,分别阐述了它们的功能特点、代码示例、高级功能、优缺点... 目录前言1. 使用 Jackson:业界标配功能特点代码示例高级功能优缺点2. 使用 Gson:轻量

Redis KEYS查询大批量数据替代方案

《RedisKEYS查询大批量数据替代方案》在使用Redis时,KEYS命令虽然简单直接,但其全表扫描的特性在处理大规模数据时会导致性能问题,甚至可能阻塞Redis服务,本文将介绍SCAN命令、有序... 目录前言KEYS命令问题背景替代方案1.使用 SCAN 命令2. 使用有序集合(Sorted Set)

使用Vue.js报错:ReferenceError: “Vue is not defined“ 的原因与解决方案

《使用Vue.js报错:ReferenceError:“Vueisnotdefined“的原因与解决方案》在前端开发中,ReferenceError:Vueisnotdefined是一个常见... 目录一、错误描述二、错误成因分析三、解决方案1. 检查 vue.js 的引入方式2. 验证 npm 安装3.

vue如何监听对象或者数组某个属性的变化详解

《vue如何监听对象或者数组某个属性的变化详解》这篇文章主要给大家介绍了关于vue如何监听对象或者数组某个属性的变化,在Vue.js中可以通过watch监听属性变化并动态修改其他属性的值,watch通... 目录前言用watch监听深度监听使用计算属性watch和计算属性的区别在vue 3中使用watchE

MyBatis延迟加载的处理方案

《MyBatis延迟加载的处理方案》MyBatis支持延迟加载(LazyLoading),允许在需要数据时才从数据库加载,而不是在查询结果第一次返回时就立即加载所有数据,延迟加载的核心思想是,将关联对... 目录MyBATis如何处理延迟加载?延迟加载的原理1. 开启延迟加载2. 延迟加载的配置2.1 使用

python解析HTML并提取span标签中的文本

《python解析HTML并提取span标签中的文本》在网页开发和数据抓取过程中,我们经常需要从HTML页面中提取信息,尤其是span元素中的文本,span标签是一个行内元素,通常用于包装一小段文本或... 目录一、安装相关依赖二、html 页面结构三、使用 BeautifulSoup javascript

Android WebView的加载超时处理方案

《AndroidWebView的加载超时处理方案》在Android开发中,WebView是一个常用的组件,用于在应用中嵌入网页,然而,当网络状况不佳或页面加载过慢时,用户可能会遇到加载超时的问题,本... 目录引言一、WebView加载超时的原因二、加载超时处理方案1. 使用Handler和Timer进行超

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义