iOS下的 Fixed + Input 調用鍵盤的時候fixed無效問題html
拖動頁面時 header 和 footer 已經定位在了對應的位置,目測沒問題了web
但接下來問題就來了!若是底部輸入框軟鍵盤被喚起之後,再次滑動頁面,就會看到以下圖所示:瀏覽器
咱們看到 fixed 定位好的元素跟隨頁面滾動了起來… fixed 屬性失效了!ide
這是爲何呢?簡單解釋下: > 軟鍵盤喚起後,頁面的 fixed 元素將失效(即沒法浮動,也能夠理解爲變成了 absolute 定位),因此當頁面超過一屏且滾動時,失效的 fixed 元素就會跟隨滾動了。函數
這即是 iOS 上 fixed 元素和輸入框的 bug 。其中不只限於 type=text 的輸入框,凡是軟鍵盤(好比時間日期選擇、select 選擇等等)被喚起,都會遇到一樣地問題。佈局
雖然 isScroll.js 能夠很好的解決 fixed 定位滾動的問題,可是不在萬不得已的狀況下,咱們儘可能嘗試一下不依賴第三方庫的佈局方案,以簡化實現方式。這裏拋磚引玉做爲參考。測試
既然在 iOS 下因爲軟鍵盤喚出後,頁面 fixed 元素會失效,致使跟隨頁面一塊兒滾動,那麼假如——頁面不會過長出現滾動,那麼即使 fixed 元素失效,也沒法跟隨頁面滾動,也就不會出現上面的問題了。字體
那麼按照這個思路,若是使 fixed 元素的父級不出現滾動,而將原 body 滾動的區域域移到 main 內部,而 header 和 footer 的樣式不變,代碼以下:網站
1 <body class="layout-scroll-fixed"> 2 <!-- fixed定位的頭部 (absolute絕對定位也能夠)--> 3 <header> 4 5 </header> 6 7 <!-- 能夠滾動的區域 --> 8 <main> 9 <div class="content"> 10 <!-- 內容在這裏... --> 11 </div> 12 </main> 13 14 <!-- fixed定位的底部 (absolute絕對定位也能夠)--> 15 <footer> 16 <input type="text" placeholder="Footer..."/> 17 <button class="submit">提交</button> 18 </footer> 19 </body> 20 header, footer, main { 21 display: block; 22 } 23 24 header { 25 position: fixed;//或者absolute 26 height: 50px; 27 left: 0; 28 right: 0; 29 top: 0; 30 } 31 32 footer { 33 position: fixed;//或者寫成absolute 34 height: 34px; 35 left: 0; 36 right: 0; 37 bottom: 0; 38 } 39 40 main { 41 /* main絕對定位,進行內部滾動 */ 42 position: absolute; 43 top: 50px; 44 bottom: 34px; 45 /* 使之能夠滾動 */ 46 overflow-y: scroll; 47 /* 增長該屬性,能夠增長彈性,是滑動更加順暢 */ 48 -webkit-overflow-scrolling: touch; 49 } 50 51 main .content { 52 height: 2000px; 53 }
另外,這裏的 header 和 footer 使用的是 fixed 定位,若是考慮到更老一些的 iOS 系統不支持 fixed 元素,徹底能夠把 fixed 替換成 absolute 。測試後效果是同樣的。this
按照上面佈局,就不會出現問題了!
網站當中常常會遇到圖片加載失敗的問題,img中有地址,可是地址打開是錯誤的。狀況以下:
不一樣瀏覽器處理錯誤圖片是不同的,有的乾脆就顯示差號,例如IE,有的顯示一張破碎的圖片,有的則是給一張高度比較大的默認圖,例如PC端的火狐,IOS中Safari,還有安卓中的UC瀏覽器。這樣在手機中就會致使左右兩側圖片高度不一致!以下圖:
其實這裏解決很簡單,判斷當圖片加載失敗的時候給一個默認圖就能夠了,不讓瀏覽器使用其自帶的默認圖。
由於圖片加載失敗進入默認圖,那麼默認圖再加載失敗怎麼辦呢?這不是進入一個死循環嗎?
最簡單的一個解決辦法是,onerror中的圖保證能打開,保證比較小!不會出現問題!。這個方法也是最有效的方法!
假如你不能保證,那麼,只能靠函數來解決這個問題了!
思路是:
當圖片加載失敗,進入onerror的時候,判斷onerror的圖片是否是能加載,在onerror中的圖片觸發onerror的時候,設置onerror爲null。
代碼以下:
一、安卓UC爲表明的瀏覽器不支持部分CSS3屬性,例如calc等width:90%;width:calc(ssadft)
二、滾動事件不會觸發touchmove事件
一、彈出層touchmove滾動,會觸發touch滾動(出現前提是body中有滾動軸)
手機網站表層div滑動,致使底層body滑動(touchmove的阻止)
body很長,能夠滑動,body頭部有一個模擬下拉的選擇框。下拉選擇有滾動軸,以下圖。
我給body一個overflow:hidden和高度是沒有用的。手機網站上背景仍是能夠滑動,而後我給body一個touchmove的preventdefault()阻止事件,body滑動阻止了,PC上面是能夠了,可是手機上面滑動div仍是會致使底部body的滑動,我給div 一個阻止冒泡的事件stopPropagation(),手機網站上面仍是不能夠。
我通過反覆測試,發現滾動軸滾到底部的時候,會觸發body的滑動,那麼我就在事件滾到底部的時候對錶層的div作一個touchmove的阻止。到達滾動軸底部,向下滑動,阻止事件,向上滑動,開啓事件。爲此就要判斷touchmove的方向了。
1 var startX ,startY; 2 $("body").on("touchstart", function(e) { 3 e.preventDefault(); 4 startX = e.originalEvent.changedTouches[0].pageX, 5 startY = e.originalEvent.changedTouches[0].pageY; 6 }); 7 $("body").on("touchmove", function(e) { 8 e.preventDefault(); 9 var moveEndX = e.originalEvent.changedTouches[0].pageX, 10 moveEndY = e.originalEvent.changedTouches[0].pageY, 11 X = moveEndX - startX, 12 Y = moveEndY - startY; 13 14 if ( Math.abs(X) > Math.abs(Y) && X > 0 ) { 15 alert("left 2 right"); 16 } 17 else if ( Math.abs(X) > Math.abs(Y) && X < 0 ) { 18 alert("right 2 left"); 19 } 20 else if ( Math.abs(Y) > Math.abs(X) && Y > 0) { 21 alert("top 2 bottom"); 22 } 23 else if ( Math.abs(Y) > Math.abs(X) && Y < 0 ) { 24 alert("bottom 2 top"); 25 } 26 else{ 27 alert("just touch"); 28 } 29 });
上面的方法是判斷touchmove的滑動方向。
除了上面方法判斷手機端手機滑動方向,我這裏再介紹一個方案,就是封裝一個角度函數,經過角度函數來判斷也還不錯!我這裏僅僅把這種方式實現上滑下滑左滑右滑列舉一下!
1 var startx, starty; 2 //得到角度 3 function getAngle(angx, angy) { 4 return Math.atan2(angy, angx) * 180 / Math.PI; 5 }; 6 7 //根據起點終點返回方向 1向上 2向下 3向左 4向右 0未滑動 8 function getDirection(startx, starty, endx, endy) { 9 var angx = endx - startx; 10 var angy = endy - starty; 11 var result = 0; 12 13 //若是滑動距離過短 14 if (Math.abs(angx) < 2 && Math.abs(angy) < 2) { 15 return result; 16 } 17 18 var angle = getAngle(angx, angy); 19 if (angle >= -135 && angle <= -45) { 20 result = 1; 21 } else if (angle > 45 && angle < 135) { 22 result = 2; 23 } else if ((angle >= 135 && angle <= 180) || (angle >= -180 && angle < -135)) { 24 result = 3; 25 } else if (angle >= -45 && angle <= 45) { 26 result = 4; 27 } 28 29 return result; 30 } 31 //手指接觸屏幕 32 document.addEventListener("touchstart", function(e) { 33 startx = e.touches[0].pageX; 34 starty = e.touches[0].pageY; 35 }, false); 36 //手指離開屏幕 37 document.addEventListener("touchend", function(e) { 38 var endx, endy; 39 endx = e.changedTouches[0].pageX; 40 endy = e.changedTouches[0].pageY; 41 var direction = getDirection(startx, starty, endx, endy); 42 switch (direction) { 43 case 0: 44 alert("未滑動!"); 45 break; 46 case 1: 47 alert("向上!") 48 break; 49 case 2: 50 alert("向下!") 51 break; 52 case 3: 53 alert("向左!") 54 break; 55 case 4: 56 alert("向右!") 57 break; 58 default: 59 } 60 }, false);
知道滑動方向如何判斷,那麼解決這個問題咱們能夠判斷是否滑動到底部或者頂部,假如滑動到底部,再往下滑動,就阻止滑動,往上滑動,就開啓滑動!滑動到頂部一個道理!總結代碼以下:
1 $('#haorooms底層背景').bind("touchmove", function (e) { 2 e.preventDefault(); 3 }); 4 $(".滾動的父親").bind("touchstart", function (events) { 5 startY = events.originalEvent.changedTouches[0].pageY; 6 }); 7 $(".滾動的父親 ul").bind("touchmove", function (e) { 8 var ulheight = $(this).height(); 9 var scrollTop = $(this).scrollTop(); 10 var scrollheight = $(this)[0].scrollHeight; 11 if (ulheight + scrollTop + 20 >= scrollheight) { //滾到底部20px左右 12 $(".滾動的父親").bind("touchmove", function (event) { 13 moveEndY = event.originalEvent.changedTouches[0].pageY, 14 theY = moveEndY - startY; 15 if (Math.abs(theY) > Math.abs(theX) && theY > 0) { //用上面的abs()更加準確!這裏是判斷上滑仍是下滑!能夠用角度函數也能夠用上面絕對值方式! 16 $(".滾動的父親").unbind("touchmove");//滑動到底部再往上滑動,解除阻止! 17 } 18 if (Math.abs(theY) > Math.abs(theX) && theY < 0) { 19 event.preventDefault();//滑動到底部,再往下滑動,阻止滑動! 20 } 21 }) 22 } 23 if (scrollTop < 20) {//滾到頂部20px左右 24 $(".滾動的父親").bind("touchmove", function (event) { 25 moveEndY = event.originalEvent.changedTouches[0].pageY, 26 theY = moveEndY - startY; 27 if (Math.abs(theY) > Math.abs(theX) && theY > 0) { 28 event.preventDefault(); 29 } 30 if (Math.abs(theY) > Math.abs(theX) && theY < 0) { 31 $(".滾動的父親").unbind("touchmove"); 32 } 33 }) 34 } 35 });
以上方法基本上可以阻止body的滾動,可是,有時候仍是會有問題,期待更好的解決方案!
下面是張鑫旭的一個解決辦法,這裏簡單的借用一下!
CSS代碼:
.noscroll, .noscroll body { overflow: hidden; } .noscroll body { position: relative; }
js代碼:
1 $.smartScroll = function(container, selectorScrollable) { 2 // 若是沒有滾動容器選擇器,或者已經綁定了滾動時間,忽略 3 if (!selectorScrollable || container.data('isBindScroll')) { 4 return; 5 } 6 7 // 是不是搓瀏覽器 8 // 本身在這裏添加判斷和篩選 9 var isSBBrowser; 10 11 var data = { 12 posY: 0, 13 maxscroll: 0 14 }; 15 16 // 事件處理 17 container.on({ 18 touchstart: function (event) { 19 var events = event.touches[0] || event; 20 21 // 先求得是否是滾動元素或者滾動元素的子元素 22 var elTarget = $(event.target); 23 24 if (!elTarget.length) { 25 return; 26 } 27 28 var elScroll; 29 30 // 獲取標記的滾動元素,自身或子元素皆可 31 if (elTarget.is(selectorScrollable)) { 32 elScroll = elTarget; 33 } else if ((elScroll = elTarget.parents(selectorScrollable)).length == 0) { 34 elScroll = null; 35 } 36 37 if (!elScroll) { 38 return; 39 } 40 41 // 當前滾動元素標記 42 data.elScroll = elScroll; 43 44 // 垂直位置標記 45 data.posY = events.pageY; 46 data.scrollY = elScroll.scrollTop(); 47 // 是否能夠滾動 48 data.maxscroll = elScroll[0].scrollHeight - elScroll[0].clientHeight; 49 }, 50 touchmove: function () { 51 // 若是不足於滾動,則禁止觸發整個窗體元素的滾動 52 if (data.maxscroll <= 0 || isSBBrowser) { 53 // 禁止滾動 54 event.preventDefault(); 55 } 56 // 滾動元素 57 var elScroll = data.elScroll; 58 // 當前的滾動高度 59 var scrollTop = elScroll.scrollTop(); 60 61 // 如今移動的垂直位置,用來判斷是往上移動仍是往下 62 var events = event.touches[0] || event; 63 // 移動距離 64 var distanceY = events.pageY - data.posY; 65 66 if (isSBBrowser) { 67 elScroll.scrollTop(data.scrollY - distanceY); 68 elScroll.trigger('scroll'); 69 return; 70 } 71 72 // 上下邊緣檢測 73 if (distanceY > 0 && scrollTop == 0) { 74 // 往上滑,而且到頭 75 // 禁止滾動的默認行爲 76 event.preventDefault(); 77 return; 78 } 79 80 // 下邊緣檢測 81 if (distanceY < 0 && (scrollTop + 1 >= data.maxscroll)) { 82 // 往下滑,而且到頭 83 // 禁止滾動的默認行爲 84 event.preventDefault(); 85 return; 86 } 87 }, 88 touchend: function () { 89 data.maxscroll = 0; 90 } 91 }); 92 93 // 防止屢次重複綁定 94 container.data('isBindScroll', true); 95 };
html以下:
<aside id="aside" class="aside"> <i class="aside-overlay hideAside"></i> <div class="aside-content"> <div class="module module-filter-list"> <div class="module-main scrollable"> <ul id="filters" class="sort-ul"> ....... </ul> </div> </div> </div> </aside>
使用:
$('#aside').addClass('active'); $.smartScroll($('#aside'), '.scrollable'); $('html').addClass('noscroll');
能夠測試一下!
二、假如整個頁面用rem字體,部分安卓瀏覽器出現字體過大的狀況(給父級加個默認的font-size)
三、部分安卓瀏覽器對margin要求比較苛刻(可以使用padding)