简介:以下解决方案仅限于固定布局有输入框的情况。在 iOS Safari 5-7 中,位置:固定将移动到窗口中心,焦点事件在子文本输入字段上。在 Android 4.0-4.3 位置:固定在 iframe 内会导致意外行为.原创:Web Mobile Fixed Layout Solutions 移动业务开发,在iOS下,经常会出现固定元素和输入框(输入元素)同时存在的情况。但是,当固定元素被软键盘唤起时,就会出现很多莫名其妙的问题。本文提供了一个简单的带有输入框的固定布局方案。 iOS下的Fixed + Input BUG现象我们先举个栗子,最直观的解释一下BUG现象。对于常规的固定布局,可以采用如下布局(以下代码仅作说明):
<body class="layout-fixed"> <header> </header> <main> </main> <footer> <input type="text" placeholder="Footer..."/> <button class="submit">提交</button> </footer> </body>
对应的样式如下:
header, footer, main { display: block; } header { position: fixed; height: 50px; left: 0; right: 0; top: 0; } footer { position: fixed; height: 34px; left: 0; right: 0; bottom: 0; } main { margin-top: 50px; margin-bottom: 34px; height: 2000px }
然后它看起来像这样。拖动页面时,页眉和页脚已经定位到相应位置,视觉上没有问题。
固定定位
但是问题来了!如果底部输入框的软键盘被唤醒,再次滑动页面,会看到如下图:
我们看到固定定位的元素随着页面滚动……固定属性不起作用!为什么是这样?简单说明: > 软键盘唤醒后,页面的固定元素会失效(即不能浮动,也可以理解为绝对定位),所以当页面超过一屏滚动时,无效的固定元素将跟随滚动。这是 iOS 上固定元素和输入字段的错误。不限于type=text的输入框,任何软键盘(如时间日期选择、选择选择等)被唤醒,都会遇到同样的问题。虽然 isScroll.js 可以很好的解决固定定位和滚动的问题,但是我们尽量尝试了一种不依赖第三方库的布局方案来简化实现。这是一个参考指南。解决方法:由于iOS下软键盘调出后页面的固定元素会失效,导致随页面滚动fixed 定位内容可滑动,那么如果页面不滚动太久,那么即使固定元素失效,也无法跟随页面滚动。不会出现上述问题。那么按照这个思路,如果固定元素的父级不滚动,而是将原body的滚动区域移到main里面,而header和footer的样式保持不变,代码为如下:
<body class="layout-scroll-fixed"> <header> </header> <main> <div class="content"> </div> </main> <footer> <input type="text" placeholder="Footer..."/> <button class="submit">提交</button> </footer> </body>
header, footer, main { display: block; } header { position: fixed; height: 50px; left: 0; right: 0; top: 0; } footer { position: fixed; height: 34px; left: 0; right: 0; bottom: 0; } main { /* main绝对定位,进行内部滚动 */ position: absolute; top: 50px; bottom: 34px; /* 使之可以滚动 */ overflow-y: scroll; } main .content { height: 2000px; }
再看一遍:
固定定位
在原输入法下,固定元素可以定位在页面上的正确位置。滚动页面的时候,因为main里面的div是滚动的,所以footer不随页面滚动。以上看似解决了问题,但如果你实际在手机上测试,你会发现主元素中的滚动很不流畅。滑动手指松开后,滚动立即停止,失去了原本流畅的滚动特性。百度了一下弹性滚动问题,发现在webkit中,以下属性可以恢复弹性滚动。 -webkit-溢出滚动:触摸;在主元素上加上这个属性,嗯,丝滑又回来了!
main {
/* main绝对定位,进行内部滚动 */
position: absolute;
top: 50px;
bottom: 34px;
/* 使之可以滚动 */
overflow-y: scroll;
/* 增加该属性,可以增加弹性 */
-webkit-overflow-scrolling: touch;
}
另外,这里的页眉和页脚使用固定定位。如果你认为旧的 iOS 系统不支持固定元素fixed 定位内容可滑动,你完全可以用 absolute 替换 fixed 。测试后效果是一样的。至此,一个不依赖第三方库的固定布局就完成了。 Android下的布局讲了iOS,我们简单说一下Android下的布局。在Android2.3+中,由于不支持overflow-scrolling,在某些浏览器中滚动可能不流畅。但是发现body上的滚动还是很流畅的,所以使用iOS中出现问题的第一个固定定位布局就可以了。如果需要考虑Android2.3以下的系统,由于不支持固定元素,还是需要考虑使用isScroll.js实现内部滚动。其实在固定和输入框的问题上,基本思路是: > 由于固定在软键盘被唤醒后会失效,所以在页面可以滚动的情况下会随着页面滚动。因此,如果页面不能滚动,即使固定元素失效,也不会滚动,不会出现bug。所以我们可以考虑解决这方面的问题。其他一些细节处理的很详细。其实还有很多需要注意的地方。挑几个实际遇到的问题:有时候输入框对焦后,软键盘会挡住输入框。当你可以尝试输入元素的 scrollIntoView 来修复它。在iOS下使用第三方输入法时,输入法在被唤醒时往往会覆盖输入框,输入框只有在输入一段文字后才会出现。目前,我不知道有什么好的方法可以在输入框被唤起时让它正确显示。这暂时是iOS下的一个坑。一些第三方浏览器底部的工具栏浮动在页面顶部,所以底部固定定位会被工具栏挡住。解决方案也比较简单粗暴——适配不同的浏览器,调整固定元素与底部的距离。最好禁用页眉和页脚元素的 touchmove 事件,以防止在它上面滚动触发某些浏览器的全屏模式切换,导致顶部地址栏和底部工具栏遮挡页眉和页脚元素。当页面滚动到上下边缘时,如果继续拖动,整个View会一起被拖走,导致页面“底部曝光”。
固定定位
为了防止页面底部暴露,当页面拖动到边缘时,可以通过判断拖动方向以及是否是边缘来阻止touchmove事件,防止页面继续被拖。以上面的 layout-scroll-fixed 布局为例,给出一段代码供参考:
// 防止内容区域滚到底后引起页面整体的滚动 var content = document.querySelector('main'); var startY; content.addEventListener('touchstart', function (e) { startY = e.touches[0].clientY; }); content.addEventListener('touchmove', function (e) { // 高位表示向上滚动 // 底位表示向下滚动 // 1容许 0禁止 var status = '11'; var ele = this; var currentY = e.touches[0].clientY; if (ele.scrollTop === 0) { // 如果内容小于容器则同时禁止上下滚动 status = ele.offsetHeight >= ele.scrollHeight ? '00' : '01'; } else if (ele.scrollTop + ele.offsetHeight >= ele.scrollHeight) { // 已经滚到底部了只能向上滚动 status = '10'; } if (status != '11') { // 判断当前的滚动方向 var direction = currentY - startY > 0 ? '10' : '01'; // 操作方向和当前允许状态求与运算,运算结果为0,就说明不允许该方向滚动,则禁止默认事件,阻止滚动 if (!(parseInt(status, 2) & parseInt(direction, 2))) { stopEvent(e); } } });
暂无评论内容