;(function(win, lib) {
var doc = win.document;
var docEl = doc.documentElement;
var metaEl = doc.querySelector('meta[name="viewport"]');
var flexibleEl = doc.querySelector('meta[name="flexible"]');
var dpr = 0;
var scale = 0;
var tid;
var flexible = lib.flexible || (lib.flexible = {});
if (metaEl) {
console.warn('将根據已有的meta标簽來設定縮放比例');
var match = metaEl.getAttribute('content').match(/initial\-scale=([\d\.]+)/);
if (match) {
scale = parseFloat(match[1]);
dpr = parseInt(1 / scale);
}
} else if (flexibleEl) {
var content = flexibleEl.getAttribute('content');
if (content) {
var initialDpr = content.match(/initial\-dpr=([\d\.]+)/);
var maximumDpr = content.match(/maximum\-dpr=([\d\.]+)/);
if (initialDpr) {
dpr = parseFloat(initialDpr[1]);
scale = parseFloat((1 / dpr).toFixed(2));
}
if (maximumDpr) {
dpr = parseFloat(maximumDpr[1]);
scale = parseFloat((1 / dpr).toFixed(2));
}
}
}
if (!dpr && !scale) {
var isAndroid = win.navigator.appVersion.match(/android/gi);
var isIPhone = win.navigator.appVersion.match(/iphone/gi);
var devicePixelRatio = win.devicePixelRatio;
//var isRegularDpr = devicePixelRatio.toString().match(/^[1-9]\d*$/g);
if (isIPhone) {
// 對于2和3的屏,用2倍的方案,其餘的用1倍方案
if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {
dpr = 3;
} else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){
dpr = 2;
} else {
dpr = 1;
}
} else {
// 其他裝置下,仍舊使用1倍的方案
dpr = 1;
}
scale = 1 / dpr;
}
docEl.setAttribute('data-dpr', dpr);
if (!metaEl) {
metaEl = doc.createElement('meta');
metaEl.setAttribute('name', 'viewport');
//Android target-densitydpi=device-dpi
var attribute = 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no';
//判斷是否是WebView
var app = getCookie('chelun_appName');
if(app) {
attribute = 'width=device-width,'+attribute;
}
metaEl.setAttribute('content', attribute);
if (docEl.firstElementChild) {
docEl.firstElementChild.appendChild(metaEl);
} else {
var wrap = doc.createElement('div');
wrap.appendChild(metaEl);
doc.write(wrap.innerHTML);
}
}
function getCookie(name){
var maps = {};
var cookArr = document.cookie.split(';')
for(var i in cookArr){
var tmp = cookArr[i].replace(/^\s*/, '');
if(tmp){
var nv = tmp.split('=');
maps[nv[0]] = nv[1] || '';
}
}
return maps[name];
}
function refreshRem(){
var width = docEl.getBoundingClientRect().width;
if (width / dpr > 540) {
width = 540 * dpr;
}
var rem = width / 10;
docEl.style.fontSize = rem + 'px';
flexible.rem = win.rem = rem;
}
win.addEventListener('resize', function() {
clearTimeout(tid);
tid = setTimeout(refreshRem, 300);
}, false);
win.addEventListener('pageshow', function(e) {
if (e.persisted) {
clearTimeout(tid);
tid = setTimeout(refreshRem, 300);
}
}, false);
if (doc.readyState === 'complete') {
//doc.body.style.fontSize = 12 * dpr + 'px';
} else {
doc.addEventListener('DOMContentLoaded', function(e) {
//doc.body.style.fontSize = 12 * dpr + 'px';
}, false);
}
refreshRem();
flexible.dpr = win.dpr = dpr;
flexible.refreshRem = refreshRem;
flexible.rem2px = function(d) {
var val = parseFloat(d) * this.rem;
if (typeof d === 'string' && d.match(/rem$/)) {
val += 'px';
}
return val;
}
flexible.px2rem = function(d) {
var val = parseFloat(d) / this.rem;
if (typeof d === 'string' && d.match(/px$/)) {
val += 'rem';
}
return val;
}
})(window, window['lib'] || (window['lib'] = {}));
引入flexible.js
這一步其實非常簡單,隻要把flexible.js的内容複制出來,在本地建立一個flexible.js的檔案,打開粘貼進去就可以了,我把這個檔案放在了js/lib下面:
接着在html頁面裡面,盡可能早的引入這個js檔案(為了讓适配的效果更快):
注:使用lib-flexible,通常不要寫:
複制代碼代碼如下: <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"/>
交給flexible.js自動處理。
然後在chrome的模拟器裡面,選擇iphone6,應該就能看到html的font-size已經被設定為font-size: 75px了:
3. 編寫CSS
基本要求:
1)除font-size外,其它大小都根據750标注稿的尺寸,轉換成rem機關的值,轉換方法為:标注稿尺寸 / 标注稿基準字型大小;
2)标注稿基準字型大小 = 标注稿寬度 / 10,如标注稿寬為750,标注稿基準字型大小為75;标注稿寬為640,标注稿基準字型大小為64;(是以淘寶這個方案是可以在任意設計稿尺寸下使用的)
3)如果需要設定font-size,可跟據html的data-dpr屬性來處理,類似下面的寫法:
?
1 2 3 4 5 6 7 | |
以安卓下載下傳按鈕的樣式為例,說明這種用法。android.png的尺寸為:414*80,是以css這麼寫:
?
1 2 3 4 | |
由于用了less,事先定義了一個變量來儲存标注稿基準字型大小:
@font-size-base: 75;
是以px2rem的轉換變得非常容易,如上所示。less編譯之後,會将正确的rem值計算出來:
?
1 2 3 4 | |
到此,lib-flexible的基本實踐就結束了,不過還有一個問題,就是retina屏的問題,到現在都還沒提到@3x下圖的那些切圖怎麼辦,其實很簡單,借助html元素的data-dpr屬性,可以輕松實作另一種媒介查詢,以便在devicePixelRatio>=2的時候啟用@3x下的圖檔,還是以安卓下載下傳按鈕的樣式為例,寫法是:
?
1 2 3 4 5 6 | |
這下就OK了,原先還不知道data-dpr有什麼作用,現在看看,作用還是挺大的。
注:
- 1) 由于使用了grunt建構,是以需要先安裝node ,git,再通過npm安裝grunt 和bower
- 2)考慮到将來可能要做全屏滾動的效果,是以這頁面一開始就是用fullpage.js來做的,通過bower引入了jquery跟fullpage.js的庫
- 3) 子產品化用到了requirejs
- 4)運作grunt default完成建構,再運作grunt server啟動靜态伺服器預覽。
以上就是實作淘寶彈性布局方案lib-flexible實踐的全部過程,希望對大家的學習有所啟發。