当前位置: 首页 > Web前端 > CSS

iOS下固定定位带来的问题深入探究

时间:2023-03-30 17:18:20 CSS

讨论背景众所周知,IOS下固定元素的性能不好,在滚动页面使用固定元素时会出现各种奇怪的问题,尤其是使用时它们在微信浏览器中甚至(如:页面滚动,固定元素脱离页面;页面滚动,固定元素消失等)。这些表现太过离奇和不合逻辑,一时间很难找到相应的解决办法。于是笔者决定从一个简单的列表页面入手,将遇到的各种奇葩问题一一罗列出来,探究其发生的原因。为了避免在开发过程中出现这些问题。假设我们的需求是做一个列表页,在列表页的顶部放置一些“其他”信息,底部放置一个“创建”按钮,中间显示“项目”列表的内容。设计稿大概是这样的。实施方案根据需求,我们分别制定了三种方案。他们使用固定定位将“按钮”放置在滚动区域的“项目列表”之外,解决方案示例1。使用固定定位将“按钮”放置在滚动区域的“项目列表”中,解决方案示例2。使用绝对定位,将“按钮”放在滚动区域的“项目列表”中,使用“项目列表”填充其占用的内容,方案示例3。分别在PC和IOS浏览器中运行这些demo,我们发现这些demo在PC上的表现符合设计要求。但是在IOS浏览器中运行时,会出现各种问题,对应这些现象。解决方案示例1:从“其他”内容区触摸屏幕,滚动页面,“按钮”脱离页面内容区。解决方案示例2:从“其他”内容区触摸屏幕滚动页面,“按钮”消失。解决方案示例3:“其他”区域完全消失了。要解释这些现象,我们需要从颜色填充说起。Colorforscrollfill颜色填充示例1.关键代码:本例中我们不限制“itemlist”的高度,让内容直接在body中滚动。然后将主体的背景颜色设置为橙色。操作:进入页面后,直接将页面往上拉,直到无法拖动为止。现象:我们发现在“物品列表”的绿色区域下,body的底色是橙红色的。注意:填充的颜色可以自定义。问:这个颜色填充的区域会不会是身体的延伸?颜色填充示例2关键代码:去掉Body的背景色,改成body的背景图并平铺。操作:同上例。现象:我们发现在“物品列表”的绿色区域下方,仍然填充了body的背景色,而不是body的背景图。注意:填充的部分不属于Body标签本身。问题:如果我们去掉body的背景颜色并添加到html中会怎么样?颜色填充示例3、关键代码:去掉body的背景色。操作:同上例。现象:这次填充的颜色是html的背景色。解释:这再次证明填充的部分不是元素的固定内容,不是元素的扩展。并且显示系统从滚动区域一步步寻找颜色,直到找到为止。问题:如果去掉body和html的背景色,会显示什么颜色?颜色填充示例4关键代码:去掉body和html的背景色。操作:同上例。现象:可以看到填充物是白色的。注意:默认填充颜色为白色。回到颜色填充示例1关键代码:同示例1操作:这次我们在微信中打开,改变操作方式,先上拉显示橙色填充内容,再下拉显示黑色微信边框(即显示顶部“本页由XXX提供”文案)。再往上拉,直到拖不动为止。现象:原来下拉填充的橙色变成了黑色。而且无论你怎么做,它都不会重新显示橙色。注:微信内置浏览器修改了默认颜色填充。摘要滚动填充颜色是可定制的。滚动填充的内容不是标签的延伸,它只是填充了纯色。滚动填充的颜色是通过逐步查找滚动区域的背景颜色来确定的。滚动填充颜色默认为白色。微信会修改滚动填充的颜色值。iOS滚动回弹机制我们知道IOS有一个滚动回弹机制(就是滚动的时候,滚动到顶部或者底部显示一个回弹动画,我们上面说的滚动颜色填充就是这个机制的具体实现)前面的问题解决方案示例1中遇到的(“按钮”'离开'页面内容区域)就是这种机制造成的。下面我们就来探究一下这种滚动回弹机制的具体运行过程。以下操作均在方案示例1下进行,关键操作如下:首先在IOS自带浏览器Safari中打开示例代码。用两根手指捏合整个页面(即类似图片的缩小操作)。现象:我们发现页面可以缩小。页面的外部是纯色。说明:有一个包装我们页面的容器。该容器通常用于在窗口缩放时填充颜色。反复用两根手指慢慢捏合,使整个页面放松。注意页面变化。现象:当页面第一次缩小时,外层容器的颜色与滚动填充索引的颜色(粉红色)相同。现象:当页面逐渐缩小时,外层容器的颜色会逐渐从索引色变为白色(这个颜色和我们上面讨论的默认填充色是一样的)。先在微信内置浏览器中打开示例代码,重复上述操作。用两根手指捏合整个页面(即类似图片的缩小操作)。现象:外容器颜色变黑,容器顶部出现“本页由XXX提供”字样。说明:在微信下,为了显示“本页面由XXX提供”的提示,微信重写了该机制中的颜色,设置为黑色。反复用两根手指慢慢捏合,使整个页面放松。注意页面变化。现象:外容器颜色在黑色和粉色之间闪烁。现象:页面越放松,闪烁越频繁。说明:微信重置颜色的机制与原生滚动回弹中减少页面渐变色的机制冲突。说明:无论是缩小页面还是恢复页面大小,微信都会尝试将容器背景色设置为黑色。打开页面,先滚动到底部显示粉色,然后滚动到微信提示文案顶部显示黑色,再滚动到底部显示微信修改后的黑色,然后缩小页面,滚动至底部。现象:底部显示的颜色是粉红色。注意:原渐变色的终止会覆盖微信重置颜色的机制。在之前操作的前提下,重新滚动到顶部,显示微信提示文字,再滚动回到底部。(整个过程没有缩放)现象:底部显示的颜色重置回黑色。注意:只要滚动到顶部,为了在微信顶部显示提示文案,就会触发微信的颜色修改机制。注意:由于页面没有缩放,所以不会触发原生渐变机制,原生部分的颜色也不会被重置。这一系列操作解释了这些问题:为什么在微信中,页面向上滚动再向下滚动时,颜色填充变成了黑色,而不是正文的背景色。因为微信重载了外部容器的背景色。为什么在解决方案示例1中,“按钮”在页面上看起来“关闭”了。因为微信设置了外部容器的背景色为黑色,当滚动到底部回弹时,页面内容和按钮之间的区域(即颜色填充区域)变成黑色。而黑色给人一种“空虚”的感觉,让我感觉到“按钮”与页面内容分离的错觉。在safari中不会改成黑色,即填充色与Body的背景色相同。所以不会黑,不会有微信。“按钮”与页面内容分离的错觉。Fixed定位参考值问题在刚才的例子运行中,不知道大家有没有发现一个奇怪的问题。页面缩放过程中,固定元素和其他元素在不同的展示层渲染?重新执行之前的操作流程。我们发现固定元素的定位并不是以手机屏幕为准,因为在缩放过程中,“按钮”随着缩放向上移动。fixed元素的定位并不是基于body元素,因为从回弹机制来看,“按钮”已经离开了body区域(红框标注的暗粉色方块是body的底色)).固定元素的引用值其实就是两者之间的一个显示窗口(类似于viewPort)。这个显示窗口等于浏览器窗口大小,没有缩放。在缩放的情况下,显示窗口看起来像这样。当正文内容超过显示窗口时形成回弹部分。所以其实如果我们滑动到页面的左右两部分,也是有回弹效果的。只不过这个手势操作被IOS写成了页面上的“前进”和“后退”两个功能。如果我们将html的宽度设置为110%,小心滑动,就可以重现左右反弹的效果。左右弹跳的示例。因此,在页面缩放过程中,“固定元素与其他元素呈现在不同显示层”的虚假图像仅仅是由于body相对于显示窗口在横坐标方向和纵坐标方向上的位移所致。左右两部分的回弹色填充就形成了。固定元素基于显示窗口固定,不发生位移。分层假设形成了。这解释了为什么固定元素停留在底部而不是在弹跳机制下与主体一起滚动。IOS下位置显示深度失效最后一个问题是最简单也是最离奇的。在IOS中,元素除了设置z-index外,只是根据元素在代码中出现的顺序来决定其显示深度。布局格式不会更改元素的显示深度。分别在PC和IOS上运行布局示例。在PC上,由于“按钮”固定定位和“其他”绝对定位脱离文档流。因此,它的显示级别高于“项目列表”,因此被覆盖在“项目列表”之外。在iOS中,元素仅根据元素在代码中出现的顺序来确定其显示深度。即:布局格式不改变元素的显示深度。所以“项目列表”覆盖“其他”和“按钮”。这就解释了最后一个问题(“其他”字段消失了)。这是因为“项目列表”的填充顶部覆盖了“其他”区域。至于为什么要这样设计,后面再说。也解释了第二个问题(页面滚动,“按钮”消失)。第二个问题是,由于显示深度没有改变,“按钮”仍然在“项目列表”容器内。“按钮”的定位是基于显示容器,而不是body,所以滚动时不会随body移动,必须在底部。滚动时,“按钮”超出“项目列表”的显示区域,“项目列表”设置为溢出,不在其显示区域的不显示。于是在滚动过程中,“按钮”逐渐消失。多余的部分由回弹机构填充。所以会有一种颜色盖住“按钮”的错觉。常规的解决方案说了这么多,那么有什么办法可以规避上面的问题呢?既然固定布局问题那么多,那我们就改用绝对布局吧。我们换成absoluteExample1。但是滚动了很多次之后,我们又发现了一个问题。滚动时,“itemlist”的滚动很容易和externalbody下的滚动冲突。特别是在非“项目列表”区域(如“其他”或“按钮”)触摸其他内容时,会触发body的滚动,而“项目列表”无法滚动,违反了操作意愿.为了降低bodyscrolling的触发概率,可以使用“itemlist”的padding值来占据“other”和“button”区域。获取绝对示例2。此时,即使您从“其他”区域或“按钮”区域触摸并滚动,“项目列表”中的内容仍然滚动。不触发body的滚动弹跳。这既是好事,也是错误的现象。因为这时候,移动“按钮”和“其他”区域。同时滚动项目列表。这不符合我们的设计。而以上两种方案都存在另一个操作问题,如果“项目列表”滚动到顶部,或者滚动到底部。停顿1秒左右(即等待滚动趋势结束),然后向同一方向强制滚动(例如向下滚动到最低点,等待1秒,再向下滚动)。此时滚动回弹不会在“物品列表”中进行,而是放在body区域。这个时候,身体的滚动趋势还没有结束,不管你怎么滚动。会在体内触发。与用户期望的滚动不匹配。FINALSOLUTION上面的所有内容都是由页面最外层的回滚引起的。有没有办法禁止页面最外层的滚动回弹?抱歉,作者没有找到。但!作者找到了不显示滚动回弹颜色填充内容的方法。那是固定的大法。将整个身体直接设置到位置:固定。此时,整个身体以显示窗口为基准进行定位。回滚内容将不再显示。固定示例1。但是,这只是不显示颜色填充的内容。滚动回弹其实还是存在的,只是被body挡住了,无法显示。页面还是存在以上两个问题。最外面的滚动弹跳仍然会与项目列表区域发生冲突。如何解决冲突?删除-webkit-overflow-scrolling:touch;“项目列表”的样式并运行代码。固定示例2.冲突解决。但是滚动卡住了。该怎么办?更改为平滑滚动实现,例如IScroll。固定示例3