47

问题概述

问题1:H5 web 移动端 输入框, 键盘唤起后fixed定位好的元素跟随页面滚动了起来… fixed属性失效了!满屏任性横飞, 如下图:

clipboard.png

问题2:有第三方输入法的ios机还会出现键盘弹出延迟,导致普通布局 输入框(input/textarea等) 位置靠下的被键盘挡住, 如下图:

(这个'完成'出来, 然后'键盘'再顶起)

clipboard.png

2016-11-04完美解决方案

// CSS
.scrollWrapper {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    top:0;
}
bottomInput {
    position: absolute;
    bottom:0;
    left:0;
    right: 0;
}

// HTML
<body>
    <div class="scrollWrapper">
        <div class="bottomInput">
            <input type="text" placeholder="input"/>
        </div>
    </div>
</body>

// javascript
// 在输入框获取焦点, 键盘弹起后, 真的是一行代码
var interval = setInterval(function() {
    document.body.scrollTop = document.body.scrollHeight
}, 100)

注意: 下面解决ios键盘问题的是之前的旧方法, 还是有瑕疵, 可跳过看其他

解决思路

问题1:

  • 不让页面整体滚动, 绝对布局滚动内容, 局部滚动.

问题2:

  1. 键盘完全弹出时, 判断键盘是否在可视区域(即屏幕除去键盘占用的区域)

  2. 通过js来调整输入框的位置;

  3. 键盘完全收起后, 调整键盘到页面底部;

相关代码

问题1:

// HTML
<body> 
    <!-- 可以滚动的区域 -->
    <main className='scrollWrapper'>
        <!-- 内容在这里... -->
    </main>
    
    <!-- fixed定位在底部的输入框 -->
    <footer>
       <div className='inputBox' contenteditable='true' placeholder='请输入评论'></div>
    </footer>
</body>
// CSS
.scrollWrapper {
    position: absolute;/* 绝对定位,进行内部滚动 */
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
    overflow-y: atuo;/* 或者scroll */
    -webkit-overflow-scrolling: touch;/* 解决ios滑动不流畅问题 */
}
footer {
    position: fixed;
}

问题2:

原因如下面两张图所示, 其实稍微注意一下, 可以看到原生输入法比第三方输入法少了一个tool bar, 就是这个罪魁祸首:

clipboard.png

     // 输入框获取焦点, 键盘完全弹出再调整输入框位置(因ios键盘弹出不会触发resize事件, 故延时600ms)
     // 选择setInterval轮询几次更好
     setTimeout(() => {
        // 挂载this上, 或者声明一个全局变量, 用于在失去焦点时, 要不要执行调整代码(非第三方不调整)
        this.inputIsNotInView = this.notInView()
        
        if (this.inputIsNotInView) {
            // Width, Height: 分别是键盘没有弹出时window.innerWidth和window.innerHeight
            // 88: 是第三方输入法比原生输入法多的那个tool bar(输入时显示带选项) 的高度, 做的不是太绝, 高度是统一的
            // ios第三方输入法的tool bar 甚至 键盘也被当作可视区域了(包含在键盘弹出时的window.innerHeight)
            if (Width != 750) {
                let bottomAdjust = (Height - window.innerHeight - 88) + 'px'
                $(this.inputBoxContainer).css('bottom', bottomAdjust)
            }
            else {
                // 'iphone 6 6s, 需要额外减去键盘高度432(见下图), 还算有良心, 高度和原生保持一致')
                let bottomAdjust = (Height - window.innerHeight - 88 - 432) + 'px'
                $(this.inputBoxContainer).css('bottom', bottomAdjust)
            }
        }
    }, 600)

--------------------------------------------------------------------------------------
   
    // 失去焦点, 键盘开始收起, 隐藏inputBox; 等键盘完全收起, 再显示inputBox, 设置在底部, 避免闪跳
    if (this.inputIsNotInView) {
        // display和opacity + bottom 会有闪跳
        $(this.inputBoxContainer).css({ 'opacity': 0, bottom: 0 })
        setTimeout(() => {
            $(this.inputBoxContainer).css('opacity', 1)
        }, 600)
    }

--------------------------------------------------------------------------------------
    //判断元素是否在可视区域,不在的话返回true, 在返回false
    notInView() {
        // getBoundingClientRect 是获取定位的,很怪异, (iphone 6s 10.0 bate版表现特殊)
        // top: 元素顶部到窗口(可是区域)顶部
        // bottom: 元素底部到窗口顶部
        // left: 元素左侧到窗口左侧
        // right: 元素右侧到窗口左侧
        // width/height 元素宽高
           let bottom = this.inputBoxContainer.getBoundingClientRect().bottom
           
           // 可视区域高度 - 元素底部到窗口顶部的高度 < 0, 则说明被键盘挡住了
        if (window.innerHeight - bottom < 0) {
            return true
        }
        return false
    }

iphone 6 和 6s 奇葩现象

clipboard.png

部分低端android机, 键盘收起后, 键盘区域显示空白, 需重新设置height, 如图:

clipboard.png

    // android, 键盘弹起/收回会触发resize事件
    window.onresize = function () {
        // Height: 键盘没有弹出时window.innerHeight
        if (Height == window.innerHeight) {
            $(this.scrollWrapper).css('height', window.innerHeight + 'px')
        }
    }

另外需要注意的是

  1. js拿不到键盘的 弹起/收起 事件;

  2. ios上键盘 弹起/收回 不会触发window.resize事件;

  3. android 4.4 以下, 键盘唤起时, 不仅会触发resize, 而且会触发scroll事件;
    (如果有需要滑动失去焦点这个需求, 选择touchMove, 不要选择scroll)

  4. ios之所以会遮挡输入框, 是因为, 第三方输入法的tool bar 或者 键盘也被当做可视区域了(包含在键盘弹出时的window.innerHeight)

总结

最后建议(ios已经完美解决, 此建议可酌情忽略了), 类似这种需求,尽量不要放在屏幕下50%

  1. 转场输入评论, 微博等;

  2. 弹窗到可视区域上50%区域, 3G门户;

clipboard.png

你可能感兴趣的

44 条评论
ea · 2017年07月13日

用这个,完美解决

        var interval;
        //消息框获取焦点
        $('#J_text').focus(function(){
            interval = setInterval(function() {
                scrollToEnd();
            }, 500)
        })

        //消息框失去焦点
        $('#J_text').blur(function(){
            clearInterval(interval);
        })

//滚动到底部
function scrollToEnd(){

document.body.scrollTop = document.body.scrollHeight;

}

+5 回复

0

布局用fixed

ea · 2017年07月13日
0

谢谢,很好用,问题已解决

牙牙 · 2017年07月26日
0

很好用

我明涛 · 2017年07月26日
李淼 · 2017年02月08日

太棒了。解决了我的问题。

+1 回复

rand · 2016年08月12日

多谢研究,我也一直遇到这个问题,不过没有时间去细致研究,最后给出的建议很中肯,转场输入是个不错的主意

回复

learn_shifeng 作者 · 2016年08月12日

嗯, 我也是前几天遇到了这个问题, 但是PM说必须这样实现, 只能花时间研究研究, 解决后总结一下

回复

learn_shifeng 作者 · 2016年11月04日

已有完美解决办法了, 请看下更新, ?

回复

MollyM · 2016年11月16日

想请问一下你,2016年11月4日完美解决的,是不是没有写footer啊 我现在就是ios上有问题,主体是main,底部是footer,应该怎么写呢

回复

learn_shifeng 作者 · 2016年11月16日

这个解决的是固定在底部的输入框, 第三方键盘弹起时遮挡了输入框问题. 不过, 你可以把input改成footer啊, 不过我觉得, 移动端footer固定在底部的不太好吧...

回复

somnus_13 · 2017年03月02日

图裂了。。

回复

0

我这没有啊, 是网络的原因吧?

learn_shifeng 作者 · 2017年03月07日
ziazan_5808f707588d6 · 2017年03月17日

赞,刚好遇到这个坑。感谢

回复

muzi13 · 2017年03月23日

setInterval是神器

回复

微风 · 2017年03月29日

这个方法好,必须好评

回复

Jnfes · 2017年04月18日

setinterval 可以去掉,focus时处理就可以了、还有iOS下overflow:scroll会卡住这个bug怎么解决

回复

0

-webkit-overflow-scrolling: touch;

huanglp47 · 2018年10月09日
zhoujingchao · 2017年07月05日

小学僧表示不服啊,这方案我用了无效啊

回复

0

楼主 快救我真的莫有用啊!

zhoujingchao · 2017年07月05日
0

我只有一个iphone 6s机子,呜呜呜

zhoujingchao · 2017年07月05日
薛定谔的猫 · 2017年09月13日

你这个布局会导致 ios 系统自带的点击屏幕顶部 页面自动滚动到顶部 功能失效

回复

THIS · 2017年10月16日

但是这个会出现 下面在输入框跟 虚拟键盘有一段的距离啊 这个怎么破

回复

zinglabs · 2017年10月23日

使用这个方法 输入框出现闪动问题 是为什么呀?

回复

0

ios11引起的,我也遇到了这个问题,还在解决中,敢问兄台解决了吗?

最悲哥 · 2017年10月26日
0

找到了解决方案,根据ios版本,去掉滚动到底部的js,直接键盘就弹起就可以顶起来浮动。

最悲哥 · 2017年10月26日
最悲哥 · 2017年10月26日

楼1,这个ios11引起的,会闪动情况,用js ios版本识别,ios上去掉这段代码就好了。亲测好了。哈哈哈哈哈

回复

0

并不行。。。去掉代码以后,也不是每次都可以弹起的输入框的

哈喽安德烈 · 2018年02月11日
ludd · 2017年11月13日

ios11 屏幕闪动怎么解决

回复

叶秋 · 2017年11月16日

仅仅在iphone X 上失效了啊,去掉滚动到底部的js,直接键盘就弹起也不行啊,求解惑。。。

回复

河蟹 · 2017年11月16日

ios11这个完美解决方案似乎失效了。。。

回复

0

ios11没用,请问你解决了吗

ludd · 2017年11月24日
0

同求

_57e0dc16e61a9 · 2017年12月08日
0

@ludd 你有解决方案了吗

_57e0dc16e61a9 · 2017年12月08日
载入中...