一直在用阿里的 flexible 布局,但是从来没总结过,今天看到一篇总结的不错就搬过来记录下。
<!--more-->
使用起来很简单,把下面的 js 直接引入就好了
https://github.com/amfe/lib-flexible
代码原理
这是阿里团队的高清方案布局,所谓高清方案就是根据设备屏幕的 DPR(设备像素比,又称 DPPX,比如 dpr=2 时,表示一个 css 像素由四个物理像素点组成。)
动态设置 html 的 font-size,同时根据设备的 DPR 调整页面的缩放值,进而达到效果。
有何优势
引用简单,布局简单
根据设备屏幕的 DPR,自动设置最合适的高清缩放。
保证了不同设备下的视觉体验的一致性。
有效解决移动端真实 1px 问题(这里的 1px 时设备屏幕下的物理像素)
如何使用
重要的事情说三遍! 绝不是每个地方都要用 rem,rem 只适用于固定尺寸! 绝不是每个地方都要用 rem,rem 只适用于固定尺寸! 绝不是每个地方都要用 rem,rem 只适用于固定尺寸!
在相当数量的布局情境中(比如底部导航元素平分屏幕宽,大尺寸元素),你必须使用百分比或者 flex 才能完美布局!
此方案也是默认 1rem = 100px,所以你布局的时候,完全可以按照设计师给你的效果图写各种尺寸啦。 比如你在效果图上量取的某个按钮元素长 55px, 宽 37px ,那你直接可以这样写样式:
.myBtn {
width: 0.55rem;
height: 0.37rem;
}
常见问题说明
- 为啥手机网页效果图宽度是要 640 或者 750 的,我非得弄个 666 的不行咩?
答:老实说当然可以,不过为了规范,640 或者 750 是相对合适的。 拿 Iphone 5s 举例,它的 css 像素宽度是 320px,由于它的 dpr=2,所以它的物理像素宽度为 320 × 2 = 640px,这也就是为什么,你在 5s 上截了一张图,在电脑上打开,它的原始宽度是 640px 的原因。 那 iphone 6 的截图宽度呢? 375 × 2 = 750 那 iphone 6 sp 的截图宽度呢? 414 × 3 = 1242 以此类推,你现在能明白效果图为什么一般是 640 ,750 甚至是 1242 的原因了么?(真没有歧视安卓机的意思。。。) - 宽度用 rem 写的情况下, 在 iphone6 上没问题, 在 iphone5 上会有横向滚动条,何解?
答:假设你的效果图宽度是 750,在这个效果图上可能有一个宽度为 7rem(高清方案默认 1rem = 100px)的元素。我们知道,高清方案的特点就是几乎完美还原效果图,也就是说,你写了一个宽度为 7rem 的元素,那么在目前主流移动设备上都是 7rem。然而,iphone 5 的宽度为 640,也就是 6.4rem。于是横向滚动条不可避免的出现了。 怎么办呢? 这是我目前推荐的比较安全的方式:如果元素的宽度超过效果图宽度的一半(效果图宽为 640 或 750),果断使用百分比宽度,或者 flex 布局。就像把等屏宽的图片宽度设为 100%一样。 - 不是 1rem = 100px 吗,为什么我的代码写了一个宽度为 3rem 的元素,在电脑端的谷歌浏览器上宽度只有 150px?
答:先说高清方案代码,再次强调咱们的高清方案代码是根据设备的 dpr 动态设置 html 的 font-size, 如果 dpr=1(如电脑端),则 html 的 font-size 为 50px,此时 1rem = 50px 如果 dpr=2(如 iphone 5 和 6),则 html 的 font-size 为 100px,此时 1rem = 100px 如果 dpr=3(如 iphone 6 sp),则 html 的 font-size 为 150px,此时 1rem = 150px 如果 dpr 为其他值,即便不是整数,如 3.4 , 也是一样直接将 dpr 乘以 50 。
再来说说效果图,一般来讲,我们的效果图宽度要么是 640,要么是 750,无论哪一个,它们对应设备的 dpr=2,此时,1 rem = 50 × 2 = 100px。这也就是为什么高清方案默认 1rem = 100px。而将 1rem 默认 100px 也是好处多多,可以帮你快速换算单位,比如在 750 宽度下的效果图,某元素宽度为 53px,那么 css 宽度直接设为 53/100=0.53rem 了。
然而极少情况下,有设计师将效果图宽定为 1242px,因为他手里只有一个 iphone 6 sp (dpr = 3),设计完效果图刚好可以在他的 iphone 6 sp 里查看调整。一切完毕之后,他将这个效果图交给你来切图。由于这个效果图对应设备的 dpr=3,也就是 1rem = 50 × 3 = 150px。所以如果你量取了一个宽度为 90px 的元素,它的 css 宽度应该为 90/150=0.6rem。由于咱们的高清方案默认 1rem=100px,为了还原效果图,你需要这样换算。当然,一个技巧就是你可以直接修改咱们的高清方案的默认设置。在代码的最后 你会看到 flex(100, 1) ,将其修改成 flex(66.66667, 1)就不用那么麻烦的换算了,此时那个 90px 的直接写成 0.9rem 就可以了。 - 高清方案在微信上,有时候字体会不受控制变的很大,怎么办?
https://github.com/ant-design/ant-design-mobile/issues/732
问题原因:
在 X5 新内核 Blink 中,在排版页面的时候,会主动对字体进行放大,会检测页面中的主字体,当某一块字体在 我们的判定规则中,认为字号较小,并且是页面中的主要字体,就会采取主动放大的操作。然而这不是我们想要的,可以采取给最大高度解决
后续:经过项目实践,还是决定给 max-height 一个具体数值比较好,之前给的是 100% ,但有自身的局限性,比如 antd 的轮播组件在 max-height:100% 的情况下就不能正常显示。
- 我在底部导航用的 flex 感觉更合适一些,请问这样子混着用可以吗?
咱们的 rem 适合写固定尺寸。其余的根据需要换成 flex 或者百分比。源码示例中就有这三种的综合运用。 - 在高清方案下,一个标准的,较为理想的宽度为 640 的页面效果图应该是怎样的?

源码:
'use strict';/**
- @param {Number} [baseFontSize = 100] - 基础 fontSize, 默认 100px;
- @param {Number} [fontscale = 1] - 有的业务希望能放大一定比例的字体; */ const win = window; export default win.flex = (baseFontSize, fontscale) => { const _baseFontSize = baseFontSize || 100; const _fontscale = fontscale || 1;
const doc = win.document; const ua = navigator.userAgent; const matches = ua.match(/Android[\S\s]+AppleWebkit/(\d{3})/i); const UCversion = ua.match(/U3/((\d+|.){5,})/i); const isUCHd = UCversion && parseInt(UCversion[1].split('.').join(''), 10) >= 80; const isIos = navigator.appVersion.match(/(iphone|ipad|ipod)/gi); let dpr = win.devicePixelRatio || 1; if (!isIos && !(matches && matches[1] > 534) && !isUCHd) { // 如果非 iOS, 非 Android4.3 以上, 非 UC 内核, 就不执行高清, dpr 设为 1; dpr = 1; } const scale = 1 / dpr;
let metaEl = doc.querySelector('meta[name="viewport"]'); if (!metaEl) { metaEl = doc.createElement('meta'); metaEl.setAttribute('name', 'viewport'); doc.head.appendChild(metaEl); } metaEl.setAttribute('content',
width=device-width,user-scalable=no,initial-scale=${scale},maximum-scale=${scale},minimum-scale=${scale}); doc.documentElement.style.fontSize =${_baseFontSize / 2 * dpr * _fontscale}px; };
demo:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- 阿里高清方案 -->
<script>!function(e){function t(a){if(i[a])return i[a].exports;var n=i[a]={exports:{},id:a,loaded:!1};return e[a].call(n.exports,n,n.exports,t),n.loaded=!0,n.exports}var i={};return t.m=e,t.c=i,t.p="",t(0)}([function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=window;t["default"]=i.flex=function(e,t){var a=e||100,n=t||1,r=i.document,o=navigator.userAgent,d=o.match(/Android[\S\s]+AppleWebkit\/(\d{3})/i),l=o.match(/U3\/((\d+|\.){5,})/i),c=l&&parseInt(l[1].split(".").join(""),10)>=80,p=navigator.appVersion.match(/(iphone|ipad|ipod)/gi),s=i.devicePixelRatio||1;p||d&&d[1]>534||c||(s=1);var u=1/s,m=r.querySelector('meta[name="viewport"]');m||(m=r.createElement("meta"),m.setAttribute("name","viewport"),r.head.appendChild(m)),m.setAttribute("content","width=device-width,user-scalable=no,initial-scale="+u+",maximum-scale="+u+",minimum-scale="+u),r.documentElement.style.fontSize=a/2*s*n+"px"},e.exports=t["default"]}]);
flex(100, 1);</script>
<!-- 字形图标 -->
<script src="https://use.fontawesome.com/f47f4563cb.js"></script>
<style>
* {
box-sizing: border-box;
}
*:before, *:after {
box-sizing: border-box;
}
*, *:before, *:after {
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, address, cite, code, del, dfn, em, img, ins, kbd, q, samp, small, strong, sub, sup, var, b, i, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td {
border: 0 none;
font-size: inherit;
color: inherit;
margin: 0;
padding: 0;
vertical-align: baseline;
/* 在X5新内核Blink中,在排版页面的时候,会主动对字体进行放大,会检测页面中的主字体,当某一块字体在我们的判定规则中,认为字号较小,并且是页面中的主要字体,就会采取主动放大的操作。然而这不是我们想要的,可以采取给最大高度解决 */
max-height: 100000px;
}
h1, h2, h3, h4, h5, h6 {
font-weight: normal;
}
em, strong {
font-style: normal;
}
ul, ol, li {
list-style: none;
}
body {
font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","\5FAE\8F6F\96C5\9ED1",Arial,sans-serif;
line-height: 1.5;
color: #333;
background-color: #f2f2f2;
font-size: 0.24rem;
}
a {
text-decoration: none;
}
.box {
position: relative;
max-width: 10rem;
margin: 0 auto;
}
.navRoot {
position: fixed;
z-index: 50;
bottom: 0;
left:0;
width: 100%;
height: 1rem;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
border-top: 0.01rem solid #ccc;
background:#f2f2f2;
}
.navLink {
font-size: 0.42rem;
-webkit-box-flex: 1;
-ms-flex: auto;
flex: auto;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
line-height: 1;
color: #666;
}
.navLink.active {
color: #1abc9c
}
.navLinkIco {
display: block;
margin-bottom: 0.1rem;
}
.navLinkText {
display: block;
line-height: 1;
font-size: 0.24rem;
}
.img-responsive {
width: 100%;
}
</style>
</head>
<body>
<div class="box">
<div class="box-content">
<img src="http://temp.im/640x260/444/fff" class="img-responsive">
<ul style="font-size:0.3rem; padding: 0.2rem">
<li style="font-size:0.4rem"><a href="http://www.jianshu.com/p/985d26b40199">rem布局(进阶版)的一些说明</a></li>
<li>1,大家先把这个页面在不同设备模式下浏览下,感受下。</li>
<li>2,一般来说我们的手机端效果图是640px或750px。</li>
<li>3,对于上图这类需要等屏宽的图片,只需让其宽度设为 100% 即可。</li>
<li>4,该布局方案要求凡是涉及尺寸的,单位都是rem,比如,height width margin paddint top border-radius 等等。你只需要按照效果图上标注的尺寸布局即可。</li>
</ul>
</div>
<div class="navRoot">
<a href="#" class="navLink active">
<i class="fa fa-home navLinkIco" aria-hidden="true"></i>
<span class="navLinkText">首页</span>
</a>
<a href="#" class="navLink">
<i class="fa fa-home navLinkIco" aria-hidden="true"></i>
<span class="navLinkText">好店</span>
</a>
<a href="#" class="navLink">
<i class="fa fa-home navLinkIco" aria-hidden="true"></i>
<span class="navLinkText">简单</span>
</a>
<a href="#" class="navLink">
<i class="fa fa-home navLinkIco" aria-hidden="true"></i>
<span class="navLinkText">复杂</span>
</a>
<a href="#" class="navLink">
<i class="fa fa-home navLinkIco" aria-hidden="true"></i>
<span class="navLinkText">异步</span>
</a>
</div>
</div>
</body>
</html>
参考: http://www.jianshu.com/p/985d26b40199
http://www.w3cplus.com/mobile/lib-flexible-for-html5-layout.html