1、挪動端的字體
最最先的的計劃是:
body {
font-family: 'Helvetica Neue', Helvetica, 'microsoft yahei', sans-serif;
}
晉級后的計劃:
body {
font-family: -apple-system, BlinkMacSystemFont, "PingFang SC","Helvetica Neue",STHeiti,"Microsoft Yahei",Tahoma,Simsun,sans-serif;
}
之前iOS版本降級運用 Helvetica。 中筆墨體設置為漢文黑體STHeiTi, iOS 9+ 就最先支撐 -apple-system 參數了, Chrome 運用 BlinkMacSystemFont ,兼容 iOS/MacOS。
如今許多設想師的字體都是PingFang,所以這裏做了一個兼容。 趁便用”Microsoft Yahei”兼容了一下Window體系。
原生 Android 下中筆墨體與英筆墨體都挑選默許的無襯線字體。 然則由於安卓體系能夠去改體系的默許字體,而且每一個手機廠家也會內置字體,所以直接讓他去挑選默許的吧。不必零丁去折騰安卓的字體了。
2、挪動端的適配
挪動端的適配計劃各個廠商都一套計劃,然則如今主流的計劃是阿里的flexible,詳細能夠去看下這篇文章: 《運用Flexible完成手淘H5頁面的終端適配》。
阿里的計劃我用過一段時候,然則關於每一個device pixel ratio 都要寫一個款式,雖然能夠用sass、less的mixmin用法來處置懲罰,然則差別品尺寸屏幕下所顯現的筆墨個數不一致的題目(以下圖:商品的題目),往往會致使用戶以為這是一個bug。
iPhone4的襯着圖
iPhone6的襯着圖
所以背面的開闢就揚棄了這個計劃,選中在之前項目中運用到的計劃,思緒是跟淘寶的思緒大體上是一樣的,依據750px的設想稿來換算成rem,1px == 0.01rem;
CSS單元rem
在W3C範例中是如許形貌rem的:
font size of the root element.
也就是根節點的字體的大小,簡樸的明白,rem就是相干於根元素<html>的font-size來做盤算。而我們的計劃中運用rem單元,是能隨意馬虎的依據<html>的font-size盤算出元素的盒模子大小。
詳細怎樣換算呢?
把750px的設想稿 1px對應0.01rem即可
思緒:
var html=document.querySelector("html");
html.style.fontSize=html.offsetWidth/7.5+"px"
window.onresize=function(){
var a=document.querySelector("html");a.style.fontSize=a.offsetWidth/7.5+"px";
};
注重:並非一切的處所都用rem來處置懲罰。
挪動端的1px邊框。
在處置懲罰挪動端1px邊框的時刻有兩種計劃,个中一種計劃就是將initial-scale=0.5另有一種計劃就是經由過程偽類來處置懲罰。
父級 {
positon: relative;
}
父級:after {
content: " ";
width: 200%;
height: 200%;
position: absolute;
top: -1px;//之所要寫成-1px而不是0是由於這個會將全部框下移1px,所以為了防備全部題目將元素上移1px
left: 0;
z-index: 1;
border: 1px solid #ddd;
border-bottom: 1px solid #ddd;
-webkit-transform: scale(0.5);
transform: scale(0.5);
-webkit-transform-origin: 0 0;
transform-origin: 0 0;
}
優化后的計劃:
;(function(designWidth, rem2px, fixedWidth) {
//容錯
designWidth = designWidth || 750;//傳入設想稿的寬度
rem2px = rem2px || 100;//rem to px 的關聯
fixedWidth = fixedWidth || 0;//牢固最大寬度
//獵取當前html文檔
var docEl = document.documentElement;
//獵取body
var body = document.querySelector("body");
//設置牢固寬度的大小
if (!Number(fixedWidth)) {
//不存在牢固值,或許牢固值為0
body.style.maxWidth = designWidth / rem2px + 'rem';
} else {
body.style.maxWidth = fixedWidth / rem2px + 'rem';
}
body.style.margin = 'auto';
//這裏不設置body的position,為了底部存在能夠讓positon:absolute的能夠吸在鍵盤上
//屏幕的寬度
var tempWidth = window.screen.width;
var tempHeight = window.screen.height;
//最小的寬度,以這個寬度來襯着,能夠保證扭轉的時刻字體大小穩定 為何不必文檔的寬度, 由於瀏覽器或許默許的app有時刻會佔用導航欄,
//這個時刻寬度和高度就會被裁剪一部份,然則這個時刻屏幕的寬高是不會由於瀏覽器或許app的導航欄而被裁剪
var minWidth = tempWidth > tempHeight ? tempHeight : tempWidth;
//手機方向
var orientation = window.orientation;
//獵取當前默許字體的大小,由於安卓能夠設置默許字體的大小來舉行盤算
var tempDom = window.document.createElement('div');
tempDom.style.width = '1rem';
tempDom.style.display = "none";
var head = window.document.getElementsByTagName('head')[0];
head.appendChild(tempDom);
var defaultFontSize = parseFloat(window.getComputedStyle(tempDom, null).getPropertyValue('width'));
tempDom.remove();
//設置字體的大小
window.onresize = function() {
//延時是由於屏幕扭轉獵取新的高度須要肯定的時候去從新獵取高度和寬度
setTimeout(function() {
if (typeof(orientation) == "undefined") {
//假如不支撐orientation 那末就依據屏幕的寬高來推斷
var newWidth = window.screen.width;
if (newWidth != tempWidth) {
tempWidth = newWidth
//假如屏幕的寬度值轉變了
ReSetFontSize();
}
}
else {
if (orientation != window.orientation) {
//設置最新的屏幕方向 為何要耽誤,由於文檔去從新而且襯着高度是有一個時候段的
orientation = window.orientation;
ReSetFontSize();
}
}
}, 100);
};
function ReSetFontSize() {
//設置body的高度,body的高度不能直接設置成100%會致使重繪,同時為了防備fiex的bug(鍵盤彈出)
body.style.height = docEl.clientHeight + "px";
//設置字體大小
docEl.style.fontSize = minWidth / designWidth * rem2px / defaultFontSize * 100 + "%";
}
ReSetFontSize();
document.body.classList.remove('vhidden');
})(750, 100, 750);
3、挪動端的line-height
為何這個要零丁講呢,由於這個題目在挪動端湧現的概率是100%,寫習慣了PC端頁面的開闢者剛最先上手挪動端常常會碰到文本垂直居中的題目,明顯在谷歌模擬器內里看到文本是垂直居中的,然則為何在手機上看到筆墨向上偏移的,而且安卓的題目比較大。transform雖然能夠完成,然則覺得寫起來卻非常的煩瑣。
供應兩種要領,
1、padding
p{
/*高度為90px*/
font-size: .26rem;
padding: 0.22rem;
}
雖然上面的要領能夠完成,然則用起來的時刻常常每次都要去盤算高度(padding值即是設想高度減去font-size今後再/2),如許就比較貧苦,而且,在針對多行的時刻還得盤算,因而我又採用了下面的體式格局。
運用 css3 flex規劃的特徵。
p{
font-size: .26rem;
height: 0.9rem;
display: flex;
display: -webkit-flex;
-webkit-align-items:center;
align-items:center;
box-pack-align: center;
-webkit-box-pack-align: center;
}
//同時程度居中也能夠用下面的css3屬性
box-pack: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center;
4、挪動端的規劃
挪動端的規劃狀況有點多, 牢記挪動端最好不要運用postion:fixed,由於這個屬性會在ios下發生許多bug。終究我依據之前的項目履歷簡樸做了以下2種分類:
- 無牢固欄頁面
什麼叫無牢固項,所謂的無牢固項頁面就是全部網頁從上到下沒有沒有牢固在頁面上的按鈕,頭部沒有牢固的按鈕,底部沒有牢固的按鈕,擺布兩側也沒有側邊欄。用戶唯一的操縱就是滑動頁面到底部。這一類直接跟寫PC一樣的寫法就好了。
- 牢固項欄頁面
基本上市面上所看到的挪動端的頁面都是牢固頭部和底部,少許的會到場側邊工具欄。這裏主要講牢固頭部和底部的。
下面的例子主要把頁面分為頭部,內容,底部三部份。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>test</title>
<meta name="keywords" content="test">
<meta name="description" content="test">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
</head>
<style>
* {
margin: 0;
padding: 0;
line-height: 1;
border: 0;
tap-highlight-color: transparent;
-webkit-tap-highlight-color: transparent;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
body {
font-size: 0;
overflow: hidden;
background-color: #f2f2f2;
}
.vhidden {
visibility: hidden;
}
.flex-box {
display: flex;
display: -webkit-flex;
}
.vertical-center {
box-pack: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center;
}
.horizontal-center {
-webkit-box-align: center;
align-items: center;
}
input {
display: block;
height: 0.88rem;
font-size: 0.26rem;
border: none;
width: 100%;
text-align: center;
}
input:focus {
border: none;
outline: none;
}
header {
height: 1rem;
position: relative;
z-index: 1;
background-color: #fff;
}
header div {
box-flex: 1;
-webkit-box-flex: 1;
font-size: 0.26rem;
width: 100%;
}
main {
-webkit-overflow-scrolling: touch;
height: calc(100% - 2rem);
overflow-y: scroll;
overflow-x: hidden;
position: relative;
z-index: 1;
}
main::-webkit-scrollbar {
display: none;
}
main p {
padding: 0.2rem;
font-size: 0.26rem;
color: #333;
}
footer {
height: 1rem;
position: relative;
z-index: 1;
background-color: #fff;
}
footer div {
height: 0.88rem;
font-size: 0.26rem;
}
footer.bottom-input {
position: absolute;
left: 0;
right: 0;
bottom: 0;
z-index: 2;
}
.test1 {
font-size: .26rem;
padding: 0.22rem;
text-align: center;
background-color: #fff;
margin: 0.1rem auto;
}
.test2 {
font-size: .26rem;
height: 0.9rem;
display: flex;
display: -webkit-flex;
-webkit-box-align: center;
align-items: center;
box-pack: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center;
background-color: #fff;
margin: 0.1rem auto;
}
</style>
<body class="vhidden">
<header class="flex-box">
<div class="flex-box vertical-center horizontal-center">導航欄一</div>
<div class="flex-box vertical-center horizontal-center">導航欄二</div>
</header>
<main>
<div class="test1">
這是內容部份1
</div>
<div class="test2">
這是內容部份2
</div>
<p>這是內容部份</p>
<p>這是內容部份</p>
<p>這是內容部份</p>
<p>這是內容部份</p>
<p>這是內容部份</p>
<p>這是內容部份</p>
<p>這是內容部份</p>
<p>這是內容部份</p>
<p>這是內容部份</p>
<p>這是內容部份</p>
<p>這是內容部份</p>
<p>這是內容部份</p>
<p>這是內容部份</p>
<p>這是內容部份</p>
<p>這是內容部份</p>
<p>這是內容部份</p>
<input class="flex-box vertical-center horizontal-center" type="text" name="" id="Input" placeholder="輸入點什麼">
<p>這是內容部份</p>
<p>這是內容部份</p>
<p>這是內容部份</p>
<p>這是內容部份</p>
<p>這是內容部份</p>
<p>這是內容部份</p>
<p>這是內容部份</p>
<p>這是內容部份</p>
<p>這是內容部份</p>
<p>這是內容部份</p>
<p>這是內容部份</p>
<p>這是內容部份</p>
<p>這是內容部份</p>
<p>這是內容部份</p>
<p>這是內容部份</p>
<p>這是內容部份</p>
<p>這是內容部份</p>
<p>這是內容部份</p>
<p>這是內容部份</p>
<p>這是內容部份</p>
<p>這是內容部份</p>
<p>這是內容部份</p>
<p>這是內容部份</p>
<p>這是內容部份</p>
<p>這是內容部份</p>
</main>
<!-- <footer class="flex-box vertical-center horizontal-center">
<div class="flex-box vertical-center horizontal-center" id="tt">底部按鈕</div>
</footer> -->
<!-- <footer class="flex-box vertical-center horizontal-center bottom-input">
<input class="flex-box vertical-center horizontal-center" type="text" name="" id="Input" placeholder="輸入點什麼">
</footer> -->
</body>
<script>
(function(designWidth, rem2px, fixedWidth) {
//容錯
designWidth = designWidth || 750;//傳入設想稿的寬度
rem2px = rem2px || 100;//rem to px 的關聯
fixedWidth = fixedWidth || 0;//是不是牢固最大寬度,牢固寬度
//假如沒有肯定就默許設想稿的寬度
//獵取當前html文檔
var docEl = document.documentElement;
//獵取body
var body = document.querySelector("body");
//設置牢固寬度的大小
if (!Number(fixedWidth)) {
//不存在牢固值,或許牢固值為0
body.style.maxWidth = designWidth / rem2px + 'rem';
} else {
body.style.maxWidth = fixedWidth / rem2px + 'rem';
}
body.style.margin = 'auto';
//這裏不設置body的position,為了底部存在能夠讓positon:absolute的能夠吸在鍵盤上
//屏幕的寬度
var tempWidth = window.screen.width;
var tempHeight = window.screen.height;
//最小的寬度,以這個寬度來襯着,能夠保證扭轉的時刻字體大小穩定 為何不必文檔的寬度, 由於瀏覽器或許默許的app有時刻會佔用導航欄,
//這個時刻寬度和高度就會被裁剪一部份,然則這個時刻屏幕的寬高是不會由於瀏覽器或許app的導航欄而被裁剪
var minWidth = tempWidth > tempHeight ? tempHeight : tempWidth;
//手機方向
var orientation = window.orientation;
//獵取當前默許字體的大小,由於安卓能夠設置默許字體的大小來舉行盤算
var tempDom = window.document.createElement('div');
tempDom.style.width = '1rem';
tempDom.style.display = "none";
var head = window.document.getElementsByTagName('head')[0];
head.appendChild(tempDom);
var defaultFontSize = parseFloat(window.getComputedStyle(tempDom, null).getPropertyValue('width'));
tempDom.remove();
//設置字體的大小
window.onresize = function() {
//延時是由於屏幕扭轉獵取新的高度須要肯定的時候去從新獵取高度和寬度
setTimeout(function() {
if (typeof(orientation) == "undefined") {
//假如不支撐orientation 那末就依據屏幕的寬高來推斷
var newWidth = window.screen.width;
if (newWidth != tempWidth) {
tempWidth = newWidth
//假如屏幕的寬度值轉變了
ReSetFontSize();
}
} else {
if (orientation != window.orientation) {
//設置最新的屏幕方向 為何要耽誤,由於文檔去從新而且襯着高度是有一個時候段的
orientation = window.orientation;
ReSetFontSize();
}
}
}, 100);
};
function ReSetFontSize() {
//設置body的高度,body的高度不能直接設置成100%會致使重繪,同時為了防備fiex的bug(鍵盤彈出)
body.style.height = docEl.clientHeight + "px";
//設置字體大小
docEl.style.fontSize = minWidth / designWidth * rem2px / defaultFontSize * 100 + "%";
}
ReSetFontSize();
document.body.classList.remove('vhidden');
})(750, 100, 750);
</script>
</html>
Phone手機在滑動overflow-y: scroll的元素上滑動的時刻會頓卡,須要到場以下的css代碼就能夠了
-webkit-overflow-scrolling:touch;
上面的demo在中心部門有輸入框而且在底部的時刻去點擊輸入框,彈出的鍵盤會把輸入框擋住,只要在輸入部份內容今後輸入框才會出如今視窗中。碰到這類狀況須要到場以下代碼。
var element = document.getElementById("box");
element.scrollIntoView();
//element.scrollIntoView(false);
//scrollIntoView 可選參數是 true false,默許是true
//true 元素的頂端將和其地點轉動區的可視地區的頂端對齊。
//false 元素的底端將和其地點轉動區的可視地區的底端對齊。
5、挪動端的bfc
這個bfc不是花樣化上下文,而是back forward cache(往複緩存),這個特徵最早出如今Firefox和Opera瀏覽器上,能夠在用戶運用瀏覽器的“退卻”和“行進”按鈕時加速頁面的轉換速率。
道理就是瀏覽器會把之前接見的頁面緩存到瀏覽器內存內里,當用在舉行“退卻”和“行進”操縱的時刻,瀏覽器會直接從緩存內里把頁面展示到前台,從而不去革新頁面。
然則如許會致使用戶在子頁面與上一個頁面之前存在治理的時刻,操縱后返回上個頁面的狀況並沒有變動。
這個時刻我們就須要去檢測頁面是不是是從緩存內里讀取出來的頁面。
$(window).on('pageshow', function(event) {
if (event.persisted) {
location.reload(true);
}
});
或許
window.addEventListener("pageshow", funtion(event){
if (event.persisted) {
location.reload(true);
}
});
6、挪動端與客戶端的交互
如今內嵌H5開闢的頁面越來越多,前端跟客戶端的交互也就越來越多,如今運用得最多的體式格局是用JSBridge
來通訊,其主要道理就是就是經由過程某種體式格局觸發一個url(iframe)
的轉變,原生捕獲到url,舉行剖析,獲得本身想要的數據信息。
之所以要斟酌用JSBridge
來通訊是斟酌到Android4.2
以下,addJavascriptInterface
體式格局有平安遺漏
iOS7以下,沒法用到ios供應給前端最新的api messageHandlers
由於現有的手機基本上都是4.2以上以及iOS7以上,所以我們能夠放心大膽運用上面兩個屬性。
var ua = navigator.userAgent.toLowerCase();
window.isAndroid = /android/.test(ua);
window.HtmlWebviewCallNative = function(par) {
if (/客戶端ua標識/.test(ua)) {
//推斷是不是在客戶端翻開的頁面
if (isAndroid) {
//Android這個是安卓向瀏覽器注入的對象,這個看安卓客戶端給的是什麼
Android.HTMLCallNative(JSON.stringify(par));
} else {
window.webkit.messageHandlers.HTMLCallNative.postMessage(par);
}
} else {
console.log(JSON.stringify(par))
}
};
//挪用要領eg
HTMLCallNative({
functionName: 'callPhone',
params: ['13883785984', '18323270482'],
callback: 'callbackFunctionName'
});
道理以及參數申明
1.經由過程向window
註冊一個名字為HTMLCallNative
的對象,今後每次向這個函數通報要通訊的函數名和函數所需的參數即可;安卓是經由過程addJavascriptInterface
直接注入頁面,ios是經由過程WKWebView
的新特徵MessageHandler
來這個對象來完成JS挪用原生要領。
2.商定HTMLCallNative
這個要領名為app中默許用來接收新交互劃定規矩的進口函數,安卓和ios離別拿到HTMLCallNative
傳過來的function
名字和參數。
3.客戶端經由過程反射機制,查找字符串函數名對應的函數並實行函數,此時通訊勝利。
4.functionName
: 必為字符串,駝峰式定名,這個字符串為真正挪用的要領,須要前端跟客戶端共同來定義。
5.params
:要領須要的參數,無需對參數舉行encodeURI
和encodeURIComponent
, 支撐字符串,array
,object
。
6.callback
: 有回調函數時,傳入這個參數,只須要傳入函數稱號即可,若回調函數須要傳入參數,app端在挪用的時刻傳入即可,跟當時營業相干,這裏就不商定花樣了。
比擬JSBridge
的長處:
1.在JS中寫起來簡樸,不必再用建立iframe
然後觸發URL的體式格局那末貧苦了。
2.JS通報參數更輕易。運用阻攔URL的體式格局通報參數,只能把參數拼接在背面,假如碰到要通報的參數中有特別字符,如&、=、?等,必須得轉換,不然參數剖析肯定會失足。
比方通報的url是如許的:
http://www.baidu.com/share/op…
運用阻攔URL 的JS挪用體式格局
loadURL("firstClick://shareClick?title=分享的題目&content=分享的內容&url=鏈接地點&imagePath=圖片地點"); }
將上面的url 放入鏈接地點這裏后,基礎沒法辨別share_uuid
是其他參數,照樣url里附帶的參數。
然則運用MessageHandler
就能夠防備特別字符引發的題目。
7、挪動端喚起手機app
起首,我們看下安卓的配置文件和Scheme
<activity android:name = ".MainActivity">
<intent-filter>
<action android:name = "android.intent.action.MAIN" />
<category android:name = "android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:host="xxx.com" android:scheme="abraham"/>
</intent-filter>
</activity>
重點關<data android:host="xxx.com" android:scheme="abraham"/>
,前端就須要依據這個字來喚起app
<a href="abraham:/xxx.com/?pid=1">翻開app</a>
schema拼接協定的花樣:[scheme]://[host]/[path]?[query]
固然ios的也有本身的協定,通常在寫喚起app之前須要跟客戶端的同事舉行對接一下,拿到他們的協定。
注重schema協定要小寫,不然會有不能相應的非常!
固然我們能夠整合一下代碼,把ios的也加進來:
var u = navigator.userAgent;var isAndroid = u.indexOf('Android') > -1 || u.indexOf('Linux') > -1; //android終端或許uc瀏覽器var isiOS2 = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios終端if (isAndroid) {
window.location.href = "安卓供應協定url";
/***翻開app的協定,有安卓同事供應***/
window.setTimeout(function() {
window.location.href = '下載的地點';
}, 2000);
} else if (isiOS2) {
window.location.href = "IOS供應協定url";
/***翻開app的協定,有ios同事供應***/
window.setTimeout(function() {
window.location.href = '下載的地點';
}, 2000);
} else {
window.location.href = '下載的地點';
}
簡樸的喚起要領沒有解決在其他運用喚起的bug,能夠經由過程下面的喚起 [https://github.com/sunhaikuo/js-arouse-app][4]