一、思考
在移動端越來越重要的背景下,每位web開發者對移動適配都有自己的想法。是移動優先,還是PC優先,還是兩者兼得?在實際開發中這個問題是和專案產品定位有關的,也涉及到UI的設計,不是開發者能決定。但不管產品如何定位,作為開發者總是要提供最優的解決方案,是用一套樣式還是多套樣式?網上一搜,有靜態佈局、流式佈局,響應式佈局,自適應佈局,彈性佈局等一堆,雲裡霧裡,到底要怎麼選呢?看完這篇文章相信心中就有數了。
二、viewport的使用
1、最常見的設定,大多數的框架(如bootstrap)和知名的站點基本是這個配置
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no" />
2、這個配置重點在width=device-width,就是讓視視窗等於設配寬度,也就是我們開發中能用document的寬度,其它幾個“初始縮放大小”“最大縮放大小”“最小縮放大小”和“是否允許使用者縮放”可以理解為用來“固定”這個設定不被破壞的。
3、這個設定很簡單,但同時也會帶來一些需要解決的問題。
a、現在的手機都是兩倍三倍的Retina高清屏,1px實際的效果是不止一個畫素的,對不同的裝置設定不同
的initial-scale可以有比較好的效果,比如在2倍Retina的iphone6(6s,7,8)中設定為0.5。一旦
動態設定這個,也就意味這視視窗不同了,需要不同樣式適配。這也是分配樣式的一套基準,如何分配樣式
後面會有更詳細的講解。
b、在PC端如果有最小寬度的限制,同樣需要配置不同的width值。
三、單位的使用
1、css中單位很多,這裡只介紹最常用的幾種:
(1) px:這個可以理解為“基準”單位,就是不管在什麼裝置中其值是不會變的,就像cm,kg這些一樣
(2) em:這個是相對父容器的單位,一般用在字型font-size中比較好。如父容器font-size為16px,則
1em=16px
(3) rem:相對於根元素html的單位,如html的font-size為16px,則1rem=16px
(4) vw/vh: 視口寬高為100vw/100vh,這個和百分比類似,只是百分比是相對於父容器,其相對於視口
2、移動適配最常用的應該是rem,很多框架和淘寶的flexible適配都是基於這個單位,而自己做的話,一般
在首頁載入時全域性js設定html的font-size即可,程式碼如下:
(function (doc, win) { var docEl = doc.documentElement, resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize', recalc = function () { var clientWidth = docEl.clientWidth; if (!clientWidth) return; //這裡根據設計稿為750,設定1rem=100px, docEl.style.fontSize = 100 * (clientWidth / 375) + 'px'; }; // Abort if browser does not support addEventListener if (!doc.addEventListener) return; win.addEventListener(resizeEvt, recalc, false); doc.addEventListener('DOMContentLoaded', recalc, false); })(document, window);
3.如果用了sass/less等預編譯語言可以更靈活的配置的,在上面方法內配置(設計稿為750的情況下):
docEl.style.fontSize = 40 * (clientWidth / 750) + 'px';
在編譯函式中配置:
@function px2rem($px, $base-font-size: 20px) {
@return ($px / $base-font-size) * 1rem;
}
這樣我們就可以直接使用設計稿的尺寸,如:px2rem(100px),省去了自己計算,如果沒用預編譯語言(推
薦使用),編輯器也有外掛支援單位轉化。
4.上面是基於螢幕寬度來設定根元素font-size,如果設定不同的initial-scale,我們需要基於裝置畫素比設定,通過window.devicePixelRatio獲取。
四、頁面佈局方式
1.理解html的文件流方式,其實就是流式佈局,即橫向需要我們設定,縱向自動疊加。這個和移動端的設計體驗方式是比較像的。在寬度中就要用自適應的方式,如百分比,有設定相對單位的,可用相對單位,靈活使用,css3的display:flex也是很好的選擇,現代瀏覽器和移動裝置基本都支援了。
2.剛才說到體驗,很明顯移動端和pc端的體驗真的很不同,所以光有上面的自適應是遠遠不夠,是不是需要對這兩個完全不同的體驗方式響應不同的佈局和樣式。
五、媒體查詢
1.我們除了可以用js來判斷不同的裝置,設定相對單位所用的根元素。另一個強大的方式是可以通過css3強大的媒體查詢來指定不同的樣式。
2.媒體查詢的規則
@media all and ([min-width|max-width|orientation|min-device-width|...]) { ... }
中括號[]中表示需要新增的條件,可匹配寬高/橫豎屏/裝置型別等,比如min-width:750px,表示最小寬度為750px,{}是在匹配模式下的樣式。也有邏輯判斷and/or/not連線不同的規則
3.要是引入整個檔案,可以在link標籤中使用
<link rel="stylesheet" media="screen and (min-width:900px)" href="big.css" type="text/css" />
表示:當螢幕大於或等於900px時,將採用big.css樣式來渲染Web頁面。
4.Bootstrap響應式設計這類柵格佈局採用的就是這套方式。
六、1px畫素邊框問題
1.除了上面說到在viewport中設定縮放外,直接設定一個空元素縮放也是可以的
p{ width: 100px; height: 1px; background: red; display: block; transform: scaleY(.5); }
不足:圓角無法實現,實現4條邊框比較麻煩,並且只能單獨實現,如果巢狀,會對包含的效果產生不想要的效果,所以此方案配合:after和before獨立使用較多
2.利用CSS對陰影處理的方式實現0.5px的效果
box-shadow:0 1px 1px -1px rgba(0, 0, 0, 0.5);
不足:顏色不好處理, 黑色 rgba(0,0,0,1) 最深的情況了。有陰影出現,不好用大量使用box-shadow可能會導致效能瓶頸。四條邊框實現效果不理想。
3.圖片實現,使用 background-image 實現1px有兩種方式: 漸變 linear-gradient 或直接使用圖片(base64)。漸變 linear-gradient (50%有顏色,50%透明)
div{ height: 1px; background-image:-webkit-linear-gradient(top,transparent 50%,#000 50%); background-position: top left; background-repeat: no-repeat; background-size: 100% 1px; }
不足:大量使用漸變可能導致效能瓶頸,程式碼量大,多背景圖片有相容性問題
七、圖片高清化
1.可以使用srcset屬性設定,使用看https://www.zhangxinxu.com/wordpress/2014/10/responsive-images-srcset-size-w-descriptor/
2.背景圖高清
a.使用上面介紹的媒體查詢,如:
/* 普通螢幕(裝置畫素比例小於等於1)使用1倍的圖 */ .css{ background-image: url(img_1x.png); } /* 高清螢幕(裝置畫素比例大於等於2)使用2倍圖 */ @media only screen and (-webkit-min-device-pixel-ratio:2){ .css{ background-image: url(img_2x.png); } } /* 高清螢幕(裝置畫素比例大於等於3)使用3倍圖 */ @media only screen and (-webkit-min-device-pixel-ratio:3){ .css{ background-image: url(img_3x.png); } }
b.image-set 實現高清化
.css { background-image: url(1x.png); /*不支援image-set的情況下顯示*/ background: -webkit-image-set( url(1x.png) 1x,/* 支援image-set的瀏覽器的[普通螢幕]下 */ url(2x.png) 2x,/* 支援image-set的瀏覽器的[2倍Retina螢幕] */ url(3x.png) 3x/* 支援image-set的瀏覽器的[3倍Retina螢幕] */ ); }
c.很多網頁端對圖片的要求還是沒那麼高的,不像app那樣,圖片一般用一張2倍高清圖就行,最新的裝置對以上屬性的支援還是可以的,對於要求高的應用使用
八、移動端click螢幕產生300ms的延時響應
1.原因:在瀏覽器需要如何判斷快速點選上,當使用者在螢幕上單擊某一個元素時候,例如跳轉連結<a href="#"></a>,此處瀏覽器會先捕獲該次單擊,但瀏覽器不能決定使用者是單純要點選連結還是要雙擊該部分割槽域進行縮放操作,所以,捕獲第一次單擊後,瀏覽器會先Hold一段時間t,如果在t時間區間裡使用者未進行下一次點選,則瀏覽器會做單擊跳轉連結的處理,如果t時間裡使用者進行了第二次單擊操作,則瀏覽器會禁止跳轉,轉而進行對該部分割槽域頁面的縮放操作。那麼這個時間區間t有多少呢?在IOS safari下,大概為300毫秒。這就是延遲的由來。造成的後果使用者純粹單擊頁面,頁面需要過一段時間才響應,給使用者慢體驗感覺,對於web開發者來說是,頁面js捕獲click事件的回撥函式處理,需要300ms後才生效,也就間接導致影響其他業務邏輯的處理。
2.解決方案:
(1)使用fastclick.js,只要全域性加入該檔案並設定如下:
FastClick.attach(document.body);
(2) zepto的touch模組,tap事件也是為了解決在click的延遲問題
九、更改預設樣式
//使用appearance改變webkit瀏覽器的預設外觀 input,select { -webkit-appearance:none; appearance: none; } //winphone下,使用偽元素改變表單元素預設外觀 //1.禁用select預設箭頭,::-ms-expand修改表單控制元件下拉箭頭,設定隱藏並使用背景圖片來修飾 select::-ms-expand { display:none; } //2.禁用radio和checkbox預設樣式,::-ms-check修改表單核取方塊或單選框預設圖示,設定隱藏並使用背景圖片來修飾 input[type=radio]::-ms-check, input[type=checkbox]::-ms-check { display:none; } //3.禁用pc端表單輸入框預設清除按鈕,::-ms-clear修改清除按鈕,設定隱藏並使用背景圖片來修飾 input[type=text]::-ms-clear, input[type=tel]::-ms-clear, input[type=number]::-ms-clear { display:none; } // 禁止長按連結與圖片彈出選單 a,img { -webkit-touch-callout: none } // 禁止ios和android使用者選中文字 html,body {-webkit-user-select:none; user-select: none; } // 改變輸入框placeholder的顏色值 ::-webkit-input-placeholder { /* WebKit browsers */ color: #999; } :-moz-placeholder { /* Mozilla Firefox 4 to 18 */ color: #999; } ::-moz-placeholder { /* Mozilla Firefox 19+ */ color: #999; } :-ms-input-placeholder { /* Internet Explorer 10+ */ color: #999; } input:focus::-webkit-input-placeholder{ color:#999; } // android上去掉語音輸入按鈕 input::-webkit-input-speech-button {display: none}
十、總結
1.網站適配的終端可以用js或媒體查詢的方式獲取,分配對應的樣式。
2.佈局上採用相對單位,百分比和flex的彈性方式。
3.對移動端的特殊性進行適配,如1px問題,預設樣式等。