1. 程式人生 > >移動端web頁面文字框+fixed

移動端web頁面文字框+fixed

  • 還是保留之前的態度,依然不推薦在 Android下使用 iScroll。在開發專案時,可以考慮分為兩個版本:iOS下使用 iScroll的解決方案,Android下使用 position:fixed。

    移動端業務開發,iOS 下經常會有 fixed 元素和輸入框(input 元素)同時存在的情況。 但是 fixed 元素在有軟鍵盤喚起的情況下,會出現許多莫名其妙的問題。 這篇文章裡就提供一個簡單的有輸入框情況下的 fixed 佈局方案。

    iOS下的 Fixed + Input BUG現象

    讓我們先舉個栗子,最直觀的說明一下這個 BUG 的現象。 常規的 fixed 佈局,可能使用如下佈局(以下僅示意程式碼):

    <body class="layout-fixed">
        <!-- fixed定位的頭部 -->
        <header>
            
        </header>
        
        <!-- 可以滾動的區域 -->
        <main>
            <!-- 內容在這裡... -->
        </main>
        
        <!-- fixed定位的底部 -->
        <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
    }
    

    然後看起來就是下面這個樣子。拖動頁面時 header 和 footer 已經定位在了對應的位置,目測沒問題了。

    fixed定位

    fixed定位

    但接下來問題就來了!如果底部輸入框軟鍵盤被喚起以後,再次滑動頁面,就會看到如下圖所示:

    fixed定位 fixed定位

    我們看到 fixed 定位好的元素跟隨頁面滾動了起來… fixed 屬性失效了!

    這是為什麼呢?簡單解釋下: > 軟鍵盤喚起後,頁面的 fixed 元素將失效(即無法浮動,也可以理解為變成了 absolute 定位),所以當頁面超過一屏且滾動時,失效的 fixed 元素就會跟隨滾動了。

    這便是 iOS 上 fixed 元素和輸入框的 bug 。其中不僅限於 type=text 的輸入框,凡是軟鍵盤(比如時間日期選擇、select 選擇等等)被喚起,都會遇到同樣地問題。

    雖然 isScroll.js 可以很好的解決 fixed 定位滾動的問題,但是不在萬不得已的情況下,我們儘量嘗試一下不依賴第三方庫的佈局方案,以簡化實現方式。這裡拋磚引玉作為參考。

    解決思路:

    既然在 iOS 下由於軟鍵盤喚出後,頁面 fixed 元素會失效,導致跟隨頁面一起滾動,那麼假如——頁面不會過長出現滾動,那麼即便 fixed 元素失效,也無法跟隨頁面滾動,也就不會出現上面的問題了

    那麼按照這個思路,如果使 fixed 元素的父級不出現滾動,而將原 body 滾動的區域域移到 main 內部,而 header 和 footer 的樣式不變,程式碼如下:

    <body class="layout-scroll-fixed">
        <!-- fixed定位的頭部 -->
        <header>
            
        </header>
        
        <!-- 可以滾動的區域 -->
        <main>
            <div class="content">
            <!-- 內容在這裡... -->
            </div>
        </main>
        
        <!-- fixed定位的底部 -->
        <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;
    }
    

    這樣再來看一下:

    fixed定位

    fixed定位

    在原始輸入法下, fixed 元素可以定位在頁面的正確位置。滾動頁面時,由於滾動的是 main 內部的 div,因此 footer 沒有跟隨頁面滾動。

    上面貌似解決了問題,但是如果在手機上實際測試一下,會發現 main 元素內的滾動非常不流暢,滑動的手指鬆開後,滾動立刻停止,失去了原本的流暢滾動特性。百度一下彈性滾動的問題,發現在 webkit 中,下面的屬性可以恢復彈性滾動。

    -webkit-overflow-scrolling: touch;

    在 main 元素上加上該屬性,嗯,絲般順滑的感覺又回來了!

    main {
        /* main絕對定位,進行內部滾動 */
        position: absolute;
        top: 50px;
        bottom: 34px;
        /* 使之可以滾動 */
        overflow-y: scroll;
        /* 增加該屬性,可以增加彈性 */
        -webkit-overflow-scrolling: touch;
    }
    

    另外,這裡的 header 和 footer 使用的是 fixed 定位,如果考慮到更老一些的 iOS 系統不支援 fixed 元素,完全可以把 fixed 替換成 absolute 。測試後效果是一樣的。

    至此一個不依賴第三方庫的 fixed 佈局就完成了。

    Android 下佈局

    談到了 iOS ,也來簡單說一下 Android 下的佈局吧。

    在 Android2.3+ 中,因為不支援 overflow-scrolling ,因此部分瀏覽器內滾動會有不流暢的卡頓。但是目前發現在 body 上的滾動還是很流暢的,因此使用第一種在 iOS 出現問題的 fixed 定位的佈局就可以了。

    如果需要考慮 Android2.3 以下系統,因為不支援 fixed 元素,所以依然要需要考慮使用 isScroll.js 來實現內部滾動。

    其實在 fixed 和輸入框的問題上,基本思路就是: > 由於 fixed 在軟鍵盤喚起後會失效,導致在頁面可以滾動時,會跟隨頁面一起滾動。因此如果頁面無法滾動,那麼 fixed 元素即使失效,也不會滾動,也就不會出現 bug 了。

    所以可以在這個方面去考慮解決問題。

    其他的一些細節處理

    在細節處理上,其實還有很多要注意的,挑幾個實際遇到比較大的問題來說一下: