本文作者:
本文地址:本文由 @文蔺 创作,转载请保留此声明。所有权利保留,请勿用于商业目的。【资源一】基础知识恕不回顾
基础知识参考以下两篇博客:
【资源二】淘宝m站首页的动态实现
学习 首页的实现。
最近读到的新文章《》,和本部分有点关系。暂且加上来以供参考。(updated 2015-11-24)
源码进行美化、解读之后,基本布局部分的代码已经被我还原出来了:(2016-01-13补充:后来才发现,早就开源在上了)
! function(win, lib) { var timer, doc = win.document, docElem = doc.documentElement, vpMeta = doc.querySelector( 'meta[name="viewport"]'), flexMeta = doc.querySelector( 'meta[name="flexible"]'), dpr = 0, scale = 0, flexible = lib.flexible || (lib.flexible = {}); // 设置了 viewport meta if (vpMeta) { console.warn("将根据已有的meta标签来设置缩放比例"); var initial = vpMeta.getAttribute("content").match(/initial\-scale=([\d\.]+)/); if (initial) { scale = parseFloat(initial[1]); // 已设置的 initialScale dpr = parseInt(1 / scale); // 设备像素比 devicePixelRatio } } // 设置了 flexible Meta else if (flexMeta) { var flexMetaContent = flexMeta.getAttribute("content"); if (flexMetaContent) { var initial = flexMetaContent.match(/initial\-dpr=([\d\.]+)/), maximum = flexMetaContent.match( /maximum\-dpr=([\d\.]+)/); if (initial) { dpr = parseFloat(initial[1]); scale = parseFloat((1 / dpr).toFixed(2)); } if (maximum) { dpr = parseFloat(maximum[1]); scale = parseFloat((1 / dpr).toFixed(2)); } } } // viewport 或 flexible // meta 均未设置 if (!dpr && !scale) { // QST // 这里的 第一句有什么用 ? // 和 Android 有毛关系 ? var u = (win.navigator.appVersion.match(/android/gi), win.navigator.appVersion.match(/iphone/gi)), _dpr = win.devicePixelRatio; // 所以这里似乎是将所有 Android 设备都设置为 1 了 dpr = u ? ( (_dpr >= 3 && (!dpr || dpr >= 3)) ? 3 : (_dpr >= 2 && (!dpr || dpr >= 2)) ? 2 : 1 ) : 1; scale = 1 / dpr; } docElem.setAttribute( "data-dpr", dpr); // 插入 viewport meta if (!vpMeta) { vpMeta = doc.createElement( "meta"); vpMeta.setAttribute( "name", "viewport"); vpMeta.setAttribute( "content", "initial-scale=" + scale + ", maximum-scale=" + scale + ", minimum-scale=" + scale + ", user-scalable=no"); if (docElem.firstElementChild) { docElem.firstElementChild.appendChild(vpMeta) } else { var div = doc.createElement("div"); div.appendChild(vpMeta); doc.write(div.innerHTML); } } function setFontSize() { var winWidth = docElem.getBoundingClientRect().width; if (winWidth / dpr > 540) { (winWidth = 540 * dpr); } // 根节点 fontSize 根据宽度决定 var baseSize = winWidth / 10; docElem.style.fontSize = baseSize + "px"; flexible.rem = win.rem = baseSize; } // 调整窗口时重置 win.addEventListener( "resize", function() { clearTimeout(timer); timer = setTimeout(setFontSize, 300); }, false); // 这一段是我自己加的 // orientationchange 时也需要重算下吧 win.addEventListener( "orientationchange", function() { clearTimeout(timer); timer = setTimeout(setFontSize, 300); }, false); // pageshow // keyword: 倒退 缓存相关 win.addEventListener( "pageshow", function(e) { if (e.persisted) { clearTimeout(timer); timer = setTimeout(setFontSize, 300); } }, false); // 设置基准字体 if ("complete" === doc.readyState) { doc.body.style.fontSize = 12 * dpr + "px"; } else { doc.addEventListener( "DOMContentLoaded", function() { doc.body.style.fontSize = 12 * dpr + "px"; }, false); } setFontSize(); flexible.dpr = win.dpr = dpr; flexible.refreshRem = setFontSize; flexible.rem2px = function(d) { var c = parseFloat(d) * this.rem; if ("string" == typeof d && d.match(/rem$/)) { c += "px"; } return c; }; flexible.px2rem = function(d) { var c = parseFloat(d) / this.rem; if ("string" == typeof d && d.match(/px$/)) { c += "rem"; } return c; } }( window, window.lib || (window.lib = {})); |
注意:
淘宝首页在iPhone4上设置的initial-scale是0.5(其他尺寸类似)。因此,这句在iPhone4上得出的结果是640:
var winWidth = docElem.getBoundingClientRect().width; |
正是因为淘宝这种独特的设置,使得 ios 上 1px边框的问题完美解决(1px变2px, 又被 initial-scale=0.5
缩小了一半)。
【资源三】常规情况下js根据屏幕宽度动态计算
使用js动态计算:
!( function(doc, win) { var docEle = doc.documentElement, evt = "onorientationchange" in window ? "orientationchange" : "resize", fn = function() { var width = docEle.clientWidth; width && (docEle.style.fontSize = 20 * (width / 320) + "px"); }; win.addEventListener(evt, fn, false); doc.addEventListener( "DOMContentLoaded", fn, false); }( document, window)); |
【资源四】媒体查询较密集的断点
使用css3 media query 实现
@ media screen and (min-width: 320px) { html { font-size: 14px;} } @ media screen and (min-width: 360px) { html { font-size: 16px;} } @ media screen and (min-width: 400px) { html { font-size: 18px;} } @ media screen and (min-width: 440px) { html { font-size: 20px;} } @ media screen and (min-width: 480px) { html { font-size: 22px;} } @ media screen and (min-width: 640px) { html { font-size: 28px;} } |
【资源五】强大的单位——vw
使用单位 vw 实现动态计算。
html { font-size: 31.25vw; /* 表达式:100*100vw/320 */ } |
不过考虑到国内兼容性的问题,还是结合媒体查询来使用比较好。(媒体查询的断点暂时是借用上面的例子)
@ media screen and (min-width: 320px) { html { font-size: 100px; } } @ media screen and (min-width: 360px) { html { font-size: 112.5px; } } @ media screen and (min-width: 400px) { html { font-size: 125px; } } @ media screen and (min-width: 440px) { html { font-size: 137.5px; } } @ media screen and (min-width: 480px) { html { font-size: 150px; } } @ media screen and (min-width: 640px) { html { font-size: 200px; } } html { font-size: 31.25vw; } |
【总结】
对以上种种方法的综合:
1、meta:viewport, 还是initial-scale为 1;
2、320px屏幕下,把页面根元素html的字体大小设置为50px;
3、鉴于我们拿到的设计图目前是640px宽的基准,这样我们就不用每次自己除以2了,直接在PS中量就好;
4、宽度什么的最好还是用百分比处理;涉及到高度、字体大小之类的则用rem。
eg:
设计稿上,div高度为40px;那么css就是div {height: 0.4rem;}
结果就只剩下一步转换:设计稿上量的长度转化为小数。 50% => 0.5
这种计算,不要太简单。。。
【方法一】纯粹css,支持calc函数的动态计算;不支持的用css媒体查询断点,优雅降级。
@ media screen and (min-width: 320px) { html { font-size: 50px; } } @ media screen and (min-width: 360px) { html { font-size: 56px; } } @ media screen and (min-width: 400px) { html { font-size: 63px; } } @ media screen and (min-width: 440px) { html { font-size: 69px; } } @ media screen and (min-width: 480px) { html { font-size: 75px; } } /** * 2016-01-13 订正 * 做适当限制 * 大于640的屏幕 固定为100px * 同时需要对body或者最外层wrapper做max-width: 640px的限制 */ /* @media screen and (min-width: 640px) { html { font-size: 100px; } } html { font-size: 15.625vw; } */ html { font-size: 15.625vw; } @ media screen and (min-width: 640px) { html { font-size: 100px; } } |
【方法二】脚本动态计算
大前提:
1、initial-scale 为 1;
2、在项目css中(注意不要被公共的base、common之类的影响了,资源加载顺序也是蛮重要的),先把html的fontSize设置为 50px(或者加上媒体查询代码), 避免加载未完成时候样式错乱;
/* css */ html { font-size: 50px;} |
/* javascript */ !( function(win, doc){ function setFontSize() { // 获取window 宽度 // zepto实现 $(window).width()就是这么干的 var winWidth = window.innerWidth; // doc.documentElement.style.fontSize = (winWidth / 640) * 100 + 'px' ; // 2016-01-13 订正 // 640宽度以上进行限制 需要css进行配合 var size = (winWidth / 640) * 100; doc.documentElement.style.fontSize = (size < 100 ? size : 100) + 'px' ; } var evt = 'onorientationchange' in win ? 'orientationchange' : 'resize'; var timer = null; win.addEventListener(evt, function () { clearTimeout(timer); timer = setTimeout(setFontSize, 300); }, false); win.addEventListener( "pageshow", function(e) { if (e.persisted) { clearTimeout(timer); timer = setTimeout(setFontSize, 300); } }, false); // 初始化 setFontSize(); }( window, document)); |
嗯。。。
就这么愉快地结束了。。。
不知道解读了某宝首页的一点点代码,然后发在这里,会不会有什么后果。。。
==================================================
2016年1月13日补充
写过这篇博客之后,又陆续读过几篇关于布局的文章。
具体已经忘了,大约是大漠的文章,还有一篇应该是搜车前端的博文,另外应该还有关于手淘首页的分析的文章。
另外,自己也用rem布局实践过几个项目。
不得不说,个人觉得rem布局现在已经可以放弃了。flex
布局已经很好用了,早已有之的百分比布局等稍用点心思也并不难。
这篇博客一直想改。但懒惰总是占据着我的身体。
最后再说下,字体大小自适应是错误的,字体大小自适应是错误的,字体大小自适应是错误的。
rem 布局,可以告别了。
迎接 flex 布局吧。
=========================================