Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

使用Flexible实现手淘H5页面的终端适配 #17

Open
airen opened this issue Nov 19, 2015 · 279 comments
Open

使用Flexible实现手淘H5页面的终端适配 #17

airen opened this issue Nov 19, 2015 · 279 comments

Comments

@airen
Copy link
Contributor

airen commented Nov 19, 2015

更新(2019-01-16)

由于viewport单位得到众多浏览器的兼容,lib-flexible这个过渡方案已经可以放弃使用,不管是现在的版本还是以前的版本,都存有一定的问题。建议大家开始使用viewport来替代此方案。vw的兼容方案可以参阅《如何在Vue项目中使用vw实现移动端适配》一文。

曾几何时为了兼容IE低版本浏览器而头痛,以为到Mobile时代可以跟这些麻烦说拜拜。可没想到到了移动时代,为了处理各终端的适配而乱了手脚。对于混迹各社区的偶,时常发现大家拿手机淘宝的H5页面做讨论——手淘的H5页面是如何实现多终端的适配

那么趁此Amfe阿里无线前端团队双11技术连载之际,用一个实战案例来告诉大家,手淘的H5页面是如何实现多终端适配的,希望这篇文章对大家在Mobile的世界中能过得更轻松。

目标

拿一个双11的Mobile页面来做案例,比如你实现一个类似下图的一个H5页面:

Flexible实现手淘H5页面的终端适配

目标很清晰,就是做一个这样的H5页面。

DEMO

请用手机扫下面的二维码

DEMO

痛点

虽然H5的页面与PC的Web页面相比简单了不少,但让我们头痛的事情是要想尽办法让页面能适配众多不同的终端设备。看看下图你就会知道,这是多么痛苦的一件事情:

Flexible实现手淘H5页面的终端适配

点击这里查看更多终端设备的参数。

再来看看手淘H5要适配的终端设备数据:

Flexible实现手淘H5页面的终端适配

看到这些数据,是否死的心都有了,或者说为此捏了一把汗出来。

手淘团队适配协作模式

早期移动端开发,对于终端设备适配问题只属于Android系列,只不过很多设计师常常忽略Android适配问题,只出一套iOS平台设计稿。但随着iPhone6,iPhone6+的出现,从此终端适配问题不再是Android系列了,也从这个时候让移动端适配全面进入到“杂屏”时代。

Flexible实现手淘H5页面的终端适配

上图来自于paintcodeapp.com

为了应对这多么的终端设备,设计师和前端开发之间又应该采用什么协作模式?或许大家对此也非常感兴趣。

而整个手淘设计师和前端开发的适配协作基本思路是:

  • 选择一种尺寸作为设计和开发基准
  • 定义一套适配规则,自动适配剩下的两种尺寸(其实不仅这两种,你懂的)
  • 特殊适配效果给出设计效果

还是上一张图吧,因为一图胜过千言万语:

Flexible实现手淘H5页面的终端适配

在此也不做更多的阐述。在手淘的设计师和前端开发协作过程中:手淘设计师常选择iPhone6作为基准设计尺寸,交付给前端的设计尺寸是按750px * 1334px为准(高度会随着内容多少而改变)。前端开发人员通过一套适配规则自动适配到其他的尺寸。

根据上面所说的,设计师给我们的设计图是一个750px * 1600px的页面:

Flexible实现手淘H5页面的终端适配

前端开发完成终端适配方案

拿到设计师给的设计图之后,剩下的事情是前端开发人员的事了。而手淘经过多年的摸索和实战,总结了一套移动端适配的方案——flexible方案

这种方案具体在实际开发中如何使用,暂时先卖个关子,在继续详细的开发实施之前,我们要先了解一些基本概念。

一些基本概念

在进行具体实战之前,首先得了解下面这些基本概念(术语):

视窗 viewport

简单的理解,viewport是严格等于浏览器的窗口。在桌面浏览器中,viewport就是浏览器窗口的宽度高度。但在移动端设备上就有点复杂。

移动端的viewport太窄,为了能更好为CSS布局服务,所以提供了两个viewport:虚拟的viewportvisualviewport和布局的viewportlayoutviewport。

George Cummins在Stack Overflow上对这两个基本概念做了详细的解释

而事实上viewport是一个很复杂的知识点,上面的简单描述可能无法帮助你更好的理解viewport,而你又想对此做更深的了解,可以阅读PPK写的相关教程

物理像素(physical pixel)

物理像素又被称为设备像素,他是显示设备中一个最微小的物理部件。每个像素可以根据操作系统设置自己的颜色和亮度。正是这些设备像素的微小距离欺骗了我们肉眼看到的图像效果。

Flexible实现手淘H5页面的终端适配

设备独立像素(density-independent pixel)

设备独立像素也称为密度无关像素,可以认为是计算机坐标系统中的一个点,这个点代表一个可以由程序使用的虚拟像素(比如说CSS像素),然后由相关系统转换为物理像素。

CSS像素

CSS像素是一个抽像的单位,主要使用在浏览器上,用来精确度量Web页面上的内容。一般情况之下,CSS像素称为与设备无关的像素(device-independent pixel),简称DIPs。

屏幕密度

屏幕密度是指一个设备表面上存在的像素数量,它通常以每英寸有多少像素来计算(PPI)。

设备像素比(device pixel ratio)

设备像素比简称为dpr,其定义了物理像素和设备独立像素的对应关系。它的值可以按下面的公式计算得到:

设备像素比 = 物理像素 / 设备独立像素

在JavaScript中,可以通过window.devicePixelRatio获取到当前设备的dpr。而在CSS中,可以通过-webkit-device-pixel-ratio-webkit-min-device-pixel-ratio-webkit-max-device-pixel-ratio进行媒体查询,对不同dpr的设备,做一些样式适配(这里只针对webkit内核的浏览器和webview)。

dip或dp,(device independent pixels,设备独立像素)与屏幕密度有关。dip可以用来辅助区分视网膜设备还是非视网膜设备。

缩合上述的几个概念,用一张图来解释:

Flexible实现手淘H5页面的终端适配

众所周知,iPhone6的设备宽度和高度为375pt * 667pt,可以理解为设备的独立像素;而其dpr为2,根据上面公式,我们可以很轻松得知其物理像素为750pt * 1334pt

如下图所示,某元素的CSS样式:

width: 2px;
height: 2px;

在不同的屏幕上,CSS像素所呈现的物理尺寸是一致的,而不同的是CSS像素所对应的物理像素具数是不一致的。在普通屏幕下1个CSS像素对应1个物理像素,而在Retina屏幕下,1个CSS像素对应的却是4个物理像素。

有关于更多的介绍可以点击这里详细了解。

看到这里,你能感觉到,在移动端时代屏幕适配除了Layout之外,还要考虑到图片的适配,因为其直接影响到页面显示质量,对于如何实现图片适配,再此不做过多详细阐述。这里盗用了@南宮瑞揚根据mir.aculo.us翻译的一张信息图:

Flexible实现手淘H5页面的终端适配

meta标签

<meta>标签有很多种,而这里要着重说的是viewport的meta标签,其主要用来告诉浏览器如何规范的渲染Web页面,而你则需要告诉它视窗有多大。在开发移动端页面,我们需要设置meta标签如下:

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

代码以显示网页的屏幕宽度定义了视窗宽度。网页的比例和最大比例被设置为100%。

留个悬念,因为后面的解决方案中需要重度依赖meta标签。

CSS单位rem

W3C规范中是这样描述rem的:

font size of the root element.

简单的理解,rem就是相对于根元素<html>font-size来做计算。而我们的方案中使用rem单位,是能轻易的根据<html>font-size计算出元素的盒模型大小。而这个特色对我们来说是特别的有益处。

前端实现方案

了解了前面一些相关概念之后,接下来我们来看实际解决方案。在整个手淘团队,我们有一个名叫lib-flexible的库,而这个库就是用来解决H5页面终端适配的。

lib-flexible是什么?

lib-flexible是一个制作H5适配的开源库,可以点击这里下载相关文件,获取需要的JavaScript和CSS文件。

当然你可以直接使用阿里CDN:

<script src="http://g.tbcdn.cn/mtb/lib-flexible/{{version}}/??flexible_css.js,flexible.js"></script>

将代码中的{{version}}换成对应的版本号0.3.4

使用方法

lib-flexible库的使用方法非常的简单,只需要在Web页面的<head></head>中添加对应的flexible_css.js,flexible.js文件:

第一种方法是将文件下载到你的项目中,然后通过相对路径添加:

<script src="build/flexible_css.debug.js"></script>
<script src="build/flexible.debug.js"></script>

或者直接加载阿里CDN的文件:

<script src="http://g.tbcdn.cn/mtb/lib-flexible/0.3.4/??flexible_css.js,flexible.js"></script>

另外强烈建议对JS做内联处理,在所有资源加载之前执行这个JS。执行这个JS后,会在<html>元素上增加一个data-dpr属性,以及一个font-size样式。JS会根据不同的设备添加不同的data-dpr值,比如说2或者3,同时会给html加上对应的font-size的值,比如说75px

如此一来,页面中的元素,都可以通过rem单位来设置。他们会根据html元素的font-size值做相应的计算,从而实现屏幕的适配效果。

除此之外,在引入lib-flexible需要执行的JS之前,可以手动设置meta来控制dpr值,如:

<meta name="flexible" content="initial-dpr=2" />

其中initial-dpr会把dpr强制设置为给定的值。如果手动设置了dpr之后,不管设备是多少的dpr,都会强制认为其dpr是你设置的值。在此不建议手动强制设置dpr,因为在Flexible中,只对iOS设备进行dpr的判断,对于Android系列,始终认为其dpr1

if (!dpr && !scale) {
    var isAndroid = win.navigator.appVersion.match(/android/gi);
    var isIPhone = win.navigator.appVersion.match(/iphone/gi);
    var devicePixelRatio = win.devicePixelRatio;
    if (isIPhone) {
        // iOS下,对于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;
}

flexible的实质

flexible实际上就是能过JS来动态改写meta标签,代码类似这样:

var metaEl = doc.createElement('meta');
var scale = isRetina ? 0.5:1;
metaEl.setAttribute('name', 'viewport');
metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
if (docEl.firstElementChild) {
    document.documentElement.firstElementChild.appendChild(metaEl);
} else {
    var wrap = doc.createElement('div');
    wrap.appendChild(metaEl);
    documen.write(wrap.innerHTML);
}

事实上他做了这几样事情:

  • 动态改写<meta>标签
  • <html>元素添加data-dpr属性,并且动态改写data-dpr的值
  • <html>元素添加font-size属性,并且动态改写font-size的值

案例实战

了解Flexible相关的知识之后,咱们回到文章开头。我们的目标是制作一个适配各终端的H5页面。别的不多说,动手才能丰衣足食。

创建HTML模板

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta content="yes" name="apple-mobile-web-app-capable">
        <meta content="yes" name="apple-touch-fullscreen">
        <meta content="telephone=no,email=no" name="format-detection">
        <script src="http://g.tbcdn.cn/mtb/lib-flexible/0.3.4/??flexible_css.js,flexible.js"></script>
        <link rel="apple-touch-icon" href="favicon.png">
        <link rel="Shortcut Icon" href="favicon.png" type="image/x-icon">
        <title>再来一波</title>
    </head>
    <body>
        <!-- 页面结构写在这里 -->
    </body>
</html>

正如前面所介绍的一样,首先加载了Flexible所需的配置:

<script src="http://g.tbcdn.cn/mtb/lib-flexible/0.3.4/??flexible_css.js,flexible.js"></script>

这个时候可以根据设计的图需求,在HTML文档的<body></body>中添加对应的HTML结构,比如:

<div class="item-section" data-repeat="sections">
    <div class="item-section_header">
        <h2><img src="{brannerImag}" alt=""></h2>
    </div>
    <ul>
        <li data-repeat="items" class="flag" role="link" href="{itemLink}">
            <a class="figure flag-item" href="{itemLink}">
                <img src="{imgSrc}" alt="">
            </a>
            <div class="figcaption flag-item">
                <div class="flag-title"><a href="{itemLink}" title="">{poductName}</a></div>
                <div class="flag-price"><span>双11价</span><strong>¥{price}</strong><small>({preferential})</small></div>
                <div class="flag-type">{activityType}</div>
                <a class="flag-btn" href="{shopLink}">{activeName}</a>
            </div>
        </li>
    </ul>
</div>

这仅是一个示例文档,大家可以根据自己风格写模板

为了能更好的测试页面,给其配置一点假数据:

//define data
var pageData = {
    sections:[{
        "brannerImag":"http://xxx.cdn.com/B1PNLZKXXXXXaTXXXXXXXXXXXX-750-481.jpg",
        items:[{
            "itemLink": "##",
            "imgSrc": "https://placeimg.com/350/350/people/grayscale",
            "poductName":"Carter's1年式灰色长袖连体衣包脚爬服全棉鲸鱼男婴儿童装115G093",
            "price": "299.06",
            "preferential": "满400减100",
            "activityType": "1小时内热卖5885件",
            "shopLink":"##",
            "activeName": "马上抢!"
        }
            ....
        }]
    }]
}

接下来的工作就是美化工作了。在写具体样式之前,有几个点需要先了解一下。

把视觉稿中的px转换成rem

读到这里,大家应该都知道,我们接下来要做的事情,就是如何把视觉稿中的px转换成rem。在此花点时间解释一下。

首先,目前日常工作当中,视觉设计师给到前端开发人员手中的视觉稿尺寸一般是基于640px750px以及1125px宽度为准。甚至为什么?大家应该懂的(考虑Retina屏)。

正如文章开头显示的示例设计稿,他就是一张以750px为基础设计的。那么问题来了,我们如何将设计稿中的各元素的px转换成rem

Flexible实现手淘H5页面的终端适配

我厂的视觉设计师想得还是很周到的,会帮你把相关的信息在视觉稿上标注出来

目前Flexible会将视觉稿分成**100份**(主要为了以后能更好的兼容vhvw),而每一份被称为一个单位a。同时1rem单位被认定为10a。针对我们这份视觉稿可以计算出:

1a   = 7.5px
1rem = 75px 

那么我们这个示例的稿子就分成了10a,也就是整个宽度为10rem<html>对应的font-size75px

Flexible实现手淘H5页面的终端适配

这样一来,对于视觉稿上的元素尺寸换算,只需要原始的px值除以rem基准值即可。例如此例视觉稿中的图片,其尺寸是176px * 176px,转换成为2.346667rem * 2.346667rem

如何快速计算

在实际生产当中,如果每一次计算px转换rem,或许会觉得非常麻烦,或许直接影响大家平时的开发效率。为了能让大家更快进行转换,我们团队内的同学各施所长,为px转换rem写了各式各样的小工具。

CSSREM

CSSREM是一个CSS的px值转rem值的Sublime Text3自动完成插件。这个插件是由@正霖编写。先来看看插件的效果:

Flexible实现手淘H5页面的终端适配

有关于CSSREM如何安装、配置教程可以点击这里查阅

CSS处理器

除了使用编辑器的插件之外,还可以使用CSS的处理器来帮助大家处理。比如说Sass、LESS以及PostCSS这样的处理器。我们简单来看两个示例。

Sass

使用Sass的同学,可以使用Sass的函数、混合宏这些功能来实现:

@function px2em($px, $base-font-size: 16px) {
    @if (unitless($px)) {
        @warn "Assuming #{$px} to be in pixels, attempting to convert it into pixels for you";
        @return px2em($px + 0px); // That may fail.
    } @else if (unit($px) == em) {
        @return $px;
    }
    @return ($px / $base-font-size) * 1em;
}

除了使用Sass函数外,还可以使用Sass的混合宏:

@mixin px2rem($property,$px-values,$baseline-px:16px,$support-for-ie:false){
    //Conver the baseline into rems
    $baseline-rem: $baseline-px / 1rem * 1;
    //Print the first line in pixel values
    @if $support-for-ie {
        #{$property}: $px-values;
    }
    //if there is only one (numeric) value, return the property/value line for it.
    @if type-of($px-values) == "number"{
        #{$property}: $px-values / $baseline-rem;
    }
    @else {
        //Create an empty list that we can dump values into
        $rem-values:();
        @each $value in $px-values{
            // If the value is zero or not a number, return it
            @if $value == 0 or type-of($value) != "number"{
                $rem-values: append($rem-values, $value / $baseline-rem);
            }
        }
        // Return the property and its list of converted values
        #{$property}: $rem-values;
    }
}

有关于更多的介绍,可以点击这里进行了解。

PostCSS(px2rem)

除了Sass这样的CSS处理器这外,我们团队的@颂奇同学还开发了一款npm的工具px2rem。安装好px2rem之后,可以在项目中直接使用。也可以使用PostCSS。使用PostCSS插件postcss-px2rem

var gulp = require('gulp');
var postcss = require('gulp-postcss');
var px2rem = require('postcss-px2rem');

gulp.task('default', function() {
    var processors = [px2rem({remUnit: 75})];
    return gulp.src('./src/*.css')
        .pipe(postcss(processors))
        .pipe(gulp.dest('./dest'));
});

除了在Gulp中配置外,还可以使用其他的配置方式,详细的介绍可以点击这里进行了解。

配置完成之后,在实际使用时,你只要像下面这样使用:

.selector {
    width: 150px;
    height: 64px; /*px*/
    font-size: 28px; /*px*/
    border: 1px solid #ddd; /*no*/
}

px2rem处理之后将会变成:

.selector {
    width: 2rem;
    border: 1px solid #ddd;
}
[data-dpr="1"] .selector {
    height: 32px;
    font-size: 14px;
}
[data-dpr="2"] .selector {
    height: 64px;
    font-size: 28px;
}
[data-dpr="3"] .selector {
    height: 96px;
    font-size: 42px;
}

在整个开发中有了这些工具之后,完全不用担心px值转rem值影响开发效率。

文本字号不建议使用rem

前面大家都见证了如何使用rem来完成H5适配。那么文本又将如何处理适配。是不是也通过rem来做自动适配。

显然,我们在iPhone3G和iPhone4的Retina屏下面,希望看到的文本字号是相同的。也就是说,我们不希望文本在Retina屏幕下变小,另外,我们希望在大屏手机上看到更多文本,以及,现在绝大多数的字体文件都自带一些点阵尺寸,通常是16px24px,所以我们不希望出现13px15px这样的奇葩尺寸

如此一来,就决定了在制作H5的页面中,rem并不适合用到段落文本上。所以在Flexible整个适配方案中,考虑文本还是使用px作为单位。只不过使用[data-dpr]属性来区分不同dpr下的文本字号大小。

div {
    width: 1rem; 
    height: 0.4rem;
    font-size: 12px; // 默认写上dpr为1的fontSize
}
[data-dpr="2"] div {
    font-size: 24px;
}
[data-dpr="3"] div {
    font-size: 36px;
}

为了能更好的利于开发,在实际开发中,我们可以定制一个font-dpr()这样的Sass混合宏:

@mixin font-dpr($font-size){
    font-size: $font-size;

    [data-dpr="2"] & {
        font-size: $font-size * 2;
    }

    [data-dpr="3"] & {
        font-size: $font-size * 3;
    }
}

有了这样的混合宏之后,在开发中可以直接这样使用:

@include font-dpr(16px);

当然这只是针对于描述性的文本,比如说段落文本。但有的时候文本的字号也需要分场景的,比如在项目中有一个slogan,业务方希望这个slogan能根据不同的终端适配。针对这样的场景,完全可以使用rem给slogan做计量单位。

CSS

本来想把这个页面的用到的CSS(或SCSS)贴出来,但考虑篇幅过长,而且这么简单的页面,我想大家也能轻而易举搞定。所以就省略了。权当是给大家留的一个作业吧,感兴趣的可以试试Flexible能否帮你快速完成H5页面终端适配。

效果

最后来看看真机上显示的效果吧。我截了两种设备下的效果:

iPhone4

Flexible实现手淘H5页面的终端适配

iPhone6+

Flexible实现手淘H5页面的终端适配

总结

其实H5适配的方案有很多种,网上有关于这方面的教程也非常的多。不管哪种方法,都有其自己的优势和劣势。而本文主要介绍的是如何使用Flexible这样的一库来完成H5页面的终端适配。为什么推荐使用Flexible库来做H5页面的终端设备适配呢?主要因为这个库在手淘已经使用了近一年,而且已达到了较为稳定的状态。除此之外,你不需要考虑如何对元素进行折算,可以根据对应的视觉稿,直接切入。

当然,如果您有更好的H5页面终端适配方案,欢迎在下面的评论中与我们一起分享。如果您在使用这个库时,碰到任何问题,都可以在Github给我们提Issue。我们团队会努力解决相关需Issues。

Update

同学反馈说需要一个在线的DEMO,那么随便写了一个DEMO,希望对大家有所帮助。没有测试所有设备,可能不同的设备有细节上的差异。

DEMO

请用手机扫下面的二维码

DEMO

Update【2016年01月13日】

首先,由衷的感谢@完颜(@SMbey0nd) 帮忙踩了这个坑,回想起iOS从78,从89,都踩过只至少一个坑,真的也是醉了。

手淘这边的flexible方案临时升级如下:

  • 针对OS 9_3的UA,做临时处理,强制dpr1,即scale也为1,虽然牺牲了这些版本上的高清方案,但是也只能这么处理了
  • 这个版本不打算发布到CDN(也不发不到tnpm),所以大家更新的方式,最好手动复制代码内联到html中,具体代码可以点击这里下载
@chesihui
Copy link

非常实用!

@hongru
Copy link
Contributor

hongru commented Nov 19, 2015

沙发地板,高质量文章点赞

@cristicmf
Copy link

要细细品味~

@wssgcg1213
Copy link

前排

@westke
Copy link

westke commented Nov 19, 2015

占座

@cqgsm
Copy link

cqgsm commented Nov 19, 2015

好东西啊 谢谢无私分享

@fsy0718
Copy link

fsy0718 commented Nov 19, 2015

占座

@cxyn
Copy link

cxyn commented Nov 19, 2015

感谢分享,非常受用!准备在项目中尝试运用。

@ghost
Copy link

ghost commented Nov 19, 2015

之前好多疑惑的地方,一次性解决了,大赞!!!

@jincdream
Copy link

我厂的视觉设计师想得还是很周到的,会帮你把相关的信息在视觉稿上标注出来。

这才是我想要的设计师。不说了,我去哭会。
Markman 都是自费的。.

最近我们也做了这个适配方案的研究。~占位,明天放链接

@jincdream
Copy link

为什么字体不能用rem ?

我们不希望文本在Retina屏幕下变小,另外,我们希望在大屏手机上看到更多文本,以及,现在绝大多数的字体文件都自带一些点阵尺寸,通常是16px和24px,所以我们不希望出现13px和15px这样的奇葩尺寸。

换句话说,如果使用rem,那么字体的单行数量显示,在不同的尺寸和像素比的屏幕上都是一样的。但真的不能用吗?未必呀( ⊙ o ⊙ )!!设计稿可能会有这样的需求:我这一行字必须就是这几个(其实就是标题),这时候,你总不能说,噢~介个iphone6 plusd的像素比这么高,像素这么多,就让它多显示几个字的标题吧吧吧吧吧...

所以,有时候并不是不能用,而是要选择合适的时候使用合适的单位吧。

如此一来,就决定了在制作H5的页面中,rem并不适合用到段落文本上。所以在Flexible整个适配方案中,考虑文本还是使用px作为单位。只不过使用[data-dpr]属性来区分不同dpr下的文本字号大小

当然这只是针对于描述性的文本,比如说段落文本。但有的时候文本的字号也需要分场景的,比如在项目中有一个slogan,业务方希望这个slogan能根据不同的终端适配。针对这样的场景,完全可以使用rem给slogan做计量单位。

@zeyongTsai
Copy link

干货,又有新东西用了。😊

@mootee
Copy link

mootee commented Nov 19, 2015

👍

@terrykingcha
Copy link
Member

人工点赞

@meiyzeng
Copy link

用这套方案做适配的话有没有遇上在ios环境下fontsize无法控制emoji表情(unicode)编码的问题呢?

@GavinHans
Copy link

好文要顶

@yuzhe927
Copy link

受教了

@shawyon
Copy link

shawyon commented Nov 20, 2015

讲得很细,重新学习了Flexible

@inarol
Copy link

inarol commented Nov 20, 2015

请教一下,如果遇到雪碧图的icon,改如何适配。background-size对rem的适配好像很差吧

@floraluo
Copy link

虽然我现在还没做移动端,但是对这一方面关注已久了。flexible方案之前看过,这里一讲就更清楚了。另外我再想问一问,关于网易的移动端适配方案和flexible相比,针对项目不同的复杂度,这两个各自的优势劣势是什么呢?

@tangjinzhou
Copy link

先赞后看

@floraluo
Copy link

@linjinying雪碧图的话,那就要做两个,或者三个,看你要适配那种,dpr=2的雪碧图也要 X2

@UphkcRNqmafQWcSSSSSS
Copy link

@floraluo 如果你不想做两个或者三个... 你可以做一个最大的...

@inarol
Copy link

inarol commented Nov 20, 2015

@floraluo @hzh1990 就假设拿到是最大的,那最终要通过什么样的策略达到适配效果。目前我是通过background-size+媒体查询来实现的。感觉效果不是很好。

@chenerlang666
Copy link

占坑

@magele758
Copy link

文章既然已经讲到了CSS像素和物理像素的区分,其实可以在这个地方做文章,却又走上了rem得路子上去,其实思路是一样的,却多做了一步。

@AlexBai1991
Copy link

顶!d=====( ̄▽ ̄*)b

@zzbo
Copy link

zzbo commented Nov 20, 2015

nice~

@JingwenTian
Copy link

@mark

@liuxiaoxiao1
Copy link

liuxiaoxiao1 commented May 4, 2019

Update【2016年01月13日】
手淘这边的flexible方案临时升级如下:

针对OS 9_3的UA,做临时处理,强制dpr为1,即scale也为1,虽然牺牲了这些版本上的高清方案,但是也只能这么处理了

请教一下,这个是什么坑,导致要强制 dpr 为1,scale 也为 1,有没有大神告知一下

@huranLi
Copy link

huranLi commented Jul 22, 2019

这个现在还能使用吗,amfe-flexible是最新的用法吗

@iJay
Copy link

iJay commented Aug 13, 2019

我使用flexible标签后 在dpr=2的时候audio标签样式缩小不能调节大小了 请问如何解决?

@zhengdongzhe
Copy link

受益匪浅!

@weisen520
Copy link

更新(2019-01-16)

由于viewport单位得到众多浏览器的兼容,lib-flexible这个过渡方案已经可以放弃使用,不管是现在的版本还是以前的版本,都存有一定的问题。建议大家开始使用viewport来替代此方案。vw的兼容方案可以参阅《如何在Vue项目中使用vw实现移动端适配》一文。

曾几何时为了兼容IE低版本浏览器而头痛,以为到Mobile时代可以跟这些麻烦说拜拜。可没想到到了移动时代,为了处理各终端的适配而乱了手脚。对于混迹各社区的偶,时常发现大家拿手机淘宝的H5页面做讨论——手淘的H5页面是如何实现多终端的适配

那么趁此Amfe阿里无线前端团队双11技术连载之际,用一个实战案例来告诉大家,手淘的H5页面是如何实现多终端适配的,希望这篇文章对大家在Mobile的世界中能过得更轻松。

目标

拿一个双11的Mobile页面来做案例,比如你实现一个类似下图的一个H5页面:

Flexible实现手淘H5页面的终端适配

目标很清晰,就是做一个这样的H5页面。

DEMO

请用手机扫下面的二维码

DEMO

痛点

虽然H5的页面与PC的Web页面相比简单了不少,但让我们头痛的事情是要想尽办法让页面能适配众多不同的终端设备。看看下图你就会知道,这是多么痛苦的一件事情:

Flexible实现手淘H5页面的终端适配

点击这里查看更多终端设备的参数。

再来看看手淘H5要适配的终端设备数据:

Flexible实现手淘H5页面的终端适配

看到这些数据,是否死的心都有了,或者说为此捏了一把汗出来。

手淘团队适配协作模式

早期移动端开发,对于终端设备适配问题只属于Android系列,只不过很多设计师常常忽略Android适配问题,只出一套iOS平台设计稿。但随着iPhone6,iPhone6+的出现,从此终端适配问题不再是Android系列了,也从这个时候让移动端适配全面进入到“杂屏”时代。

Flexible实现手淘H5页面的终端适配

上图来自于paintcodeapp.com

为了应对这多么的终端设备,设计师和前端开发之间又应该采用什么协作模式?或许大家对此也非常感兴趣。

而整个手淘设计师和前端开发的适配协作基本思路是:

  • 选择一种尺寸作为设计和开发基准
  • 定义一套适配规则,自动适配剩下的两种尺寸(其实不仅这两种,你懂的)
  • 特殊适配效果给出设计效果

还是上一张图吧,因为一图胜过千言万语:

Flexible实现手淘H5页面的终端适配

在此也不做更多的阐述。在手淘的设计师和前端开发协作过程中:手淘设计师常选择iPhone6作为基准设计尺寸,交付给前端的设计尺寸是按750px * 1334px为准(高度会随着内容多少而改变)。前端开发人员通过一套适配规则自动适配到其他的尺寸。

根据上面所说的,设计师给我们的设计图是一个750px * 1600px的页面:

Flexible实现手淘H5页面的终端适配

前端开发完成终端适配方案

拿到设计师给的设计图之后,剩下的事情是前端开发人员的事了。而手淘经过多年的摸索和实战,总结了一套移动端适配的方案——flexible方案

这种方案具体在实际开发中如何使用,暂时先卖个关子,在继续详细的开发实施之前,我们要先了解一些基本概念。

一些基本概念

在进行具体实战之前,首先得了解下面这些基本概念(术语):

视窗 viewport

简单的理解,viewport是严格等于浏览器的窗口。在桌面浏览器中,viewport就是浏览器窗口的宽度高度。但在移动端设备上就有点复杂。

移动端的viewport太窄,为了能更好为CSS布局服务,所以提供了两个viewport:虚拟的viewportvisualviewport和布局的viewportlayoutviewport。

George Cummins在Stack Overflow上对这两个基本概念做了详细的解释

而事实上viewport是一个很复杂的知识点,上面的简单描述可能无法帮助你更好的理解viewport,而你又想对此做更深的了解,可以阅读PPK写的相关教程

物理像素(physical pixel)

物理像素又被称为设备像素,他是显示设备中一个最微小的物理部件。每个像素可以根据操作系统设置自己的颜色和亮度。正是这些设备像素的微小距离欺骗了我们肉眼看到的图像效果。

Flexible实现手淘H5页面的终端适配

设备独立像素(density-independent pixel)

设备独立像素也称为密度无关像素,可以认为是计算机坐标系统中的一个点,这个点代表一个可以由程序使用的虚拟像素(比如说CSS像素),然后由相关系统转换为物理像素。

CSS像素

CSS像素是一个抽像的单位,主要使用在浏览器上,用来精确度量Web页面上的内容。一般情况之下,CSS像素称为与设备无关的像素(device-independent pixel),简称DIPs。

屏幕密度

屏幕密度是指一个设备表面上存在的像素数量,它通常以每英寸有多少像素来计算(PPI)。

设备像素比(device pixel ratio)

设备像素比简称为dpr,其定义了物理像素和设备独立像素的对应关系。它的值可以按下面的公式计算得到:

设备像素比 = 物理像素 / 设备独立像素

在JavaScript中,可以通过window.devicePixelRatio获取到当前设备的dpr。而在CSS中,可以通过-webkit-device-pixel-ratio-webkit-min-device-pixel-ratio-webkit-max-device-pixel-ratio进行媒体查询,对不同dpr的设备,做一些样式适配(这里只针对webkit内核的浏览器和webview)。

dip或dp,(device independent pixels,设备独立像素)与屏幕密度有关。dip可以用来辅助区分视网膜设备还是非视网膜设备。

缩合上述的几个概念,用一张图来解释:

Flexible实现手淘H5页面的终端适配

众所周知,iPhone6的设备宽度和高度为375pt * 667pt,可以理解为设备的独立像素;而其dpr为2,根据上面公式,我们可以很轻松得知其物理像素为750pt * 1334pt

如下图所示,某元素的CSS样式:

width: 2px;
height: 2px;

在不同的屏幕上,CSS像素所呈现的物理尺寸是一致的,而不同的是CSS像素所对应的物理像素具数是不一致的。在普通屏幕下1个CSS像素对应1个物理像素,而在Retina屏幕下,1个CSS像素对应的却是4个物理像素。

有关于更多的介绍可以点击这里详细了解。

看到这里,你能感觉到,在移动端时代屏幕适配除了Layout之外,还要考虑到图片的适配,因为其直接影响到页面显示质量,对于如何实现图片适配,再此不做过多详细阐述。这里盗用了@南宮瑞揚根据mir.aculo.us翻译的一张信息图:

Flexible实现手淘H5页面的终端适配

meta标签

<meta>标签有很多种,而这里要着重说的是viewport的meta标签,其主要用来告诉浏览器如何规范的渲染Web页面,而你则需要告诉它视窗有多大。在开发移动端页面,我们需要设置meta标签如下:

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

代码以显示网页的屏幕宽度定义了视窗宽度。网页的比例和最大比例被设置为100%。

留个悬念,因为后面的解决方案中需要重度依赖meta标签。

CSS单位rem

W3C规范中是这样描述rem的:

font size of the root element.

简单的理解,rem就是相对于根元素<html>font-size来做计算。而我们的方案中使用rem单位,是能轻易的根据<html>font-size计算出元素的盒模型大小。而这个特色对我们来说是特别的有益处。

前端实现方案

了解了前面一些相关概念之后,接下来我们来看实际解决方案。在整个手淘团队,我们有一个名叫lib-flexible的库,而这个库就是用来解决H5页面终端适配的。

lib-flexible是什么?

lib-flexible是一个制作H5适配的开源库,可以点击这里下载相关文件,获取需要的JavaScript和CSS文件。

当然你可以直接使用阿里CDN:

<script src="http://g.tbcdn.cn/mtb/lib-flexible/{{version}}/??flexible_css.js,flexible.js"></script>

将代码中的{{version}}换成对应的版本号0.3.4

使用方法

lib-flexible库的使用方法非常的简单,只需要在Web页面的<head></head>中添加对应的flexible_css.js,flexible.js文件:

第一种方法是将文件下载到你的项目中,然后通过相对路径添加:

<script src="build/flexible_css.debug.js"></script>
<script src="build/flexible.debug.js"></script>

或者直接加载阿里CDN的文件:

<script src="http://g.tbcdn.cn/mtb/lib-flexible/0.3.4/??flexible_css.js,flexible.js"></script>

另外强烈建议对JS做内联处理,在所有资源加载之前执行这个JS。执行这个JS后,会在<html>元素上增加一个data-dpr属性,以及一个font-size样式。JS会根据不同的设备添加不同的data-dpr值,比如说2或者3,同时会给html加上对应的font-size的值,比如说75px

如此一来,页面中的元素,都可以通过rem单位来设置。他们会根据html元素的font-size值做相应的计算,从而实现屏幕的适配效果。

除此之外,在引入lib-flexible需要执行的JS之前,可以手动设置meta来控制dpr值,如:

<meta name="flexible" content="initial-dpr=2" />

其中initial-dpr会把dpr强制设置为给定的值。如果手动设置了dpr之后,不管设备是多少的dpr,都会强制认为其dpr是你设置的值。在此不建议手动强制设置dpr,因为在Flexible中,只对iOS设备进行dpr的判断,对于Android系列,始终认为其dpr1

if (!dpr && !scale) {
    var isAndroid = win.navigator.appVersion.match(/android/gi);
    var isIPhone = win.navigator.appVersion.match(/iphone/gi);
    var devicePixelRatio = win.devicePixelRatio;
    if (isIPhone) {
        // iOS下,对于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;
}

flexible的实质

flexible实际上就是能过JS来动态改写meta标签,代码类似这样:

var metaEl = doc.createElement('meta');
var scale = isRetina ? 0.5:1;
metaEl.setAttribute('name', 'viewport');
metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
if (docEl.firstElementChild) {
    document.documentElement.firstElementChild.appendChild(metaEl);
} else {
    var wrap = doc.createElement('div');
    wrap.appendChild(metaEl);
    documen.write(wrap.innerHTML);
}

事实上他做了这几样事情:

  • 动态改写<meta>标签
  • <html>元素添加data-dpr属性,并且动态改写data-dpr的值
  • <html>元素添加font-size属性,并且动态改写font-size的值

案例实战

了解Flexible相关的知识之后,咱们回到文章开头。我们的目标是制作一个适配各终端的H5页面。别的不多说,动手才能丰衣足食。

创建HTML模板

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta content="yes" name="apple-mobile-web-app-capable">
        <meta content="yes" name="apple-touch-fullscreen">
        <meta content="telephone=no,email=no" name="format-detection">
        <script src="http://g.tbcdn.cn/mtb/lib-flexible/0.3.4/??flexible_css.js,flexible.js"></script>
        <link rel="apple-touch-icon" href="favicon.png">
        <link rel="Shortcut Icon" href="favicon.png" type="image/x-icon">
        <title>再来一波</title>
    </head>
    <body>
        <!-- 页面结构写在这里 -->
    </body>
</html>

正如前面所介绍的一样,首先加载了Flexible所需的配置:

<script src="http://g.tbcdn.cn/mtb/lib-flexible/0.3.4/??flexible_css.js,flexible.js"></script>

这个时候可以根据设计的图需求,在HTML文档的<body></body>中添加对应的HTML结构,比如:

<div class="item-section" data-repeat="sections">
    <div class="item-section_header">
        <h2><img src="{brannerImag}" alt=""></h2>
    </div>
    <ul>
        <li data-repeat="items" class="flag" role="link" href="{itemLink}">
            <a class="figure flag-item" href="{itemLink}">
                <img src="{imgSrc}" alt="">
            </a>
            <div class="figcaption flag-item">
                <div class="flag-title"><a href="{itemLink}" title="">{poductName}</a></div>
                <div class="flag-price"><span>双11价</span><strong>¥{price}</strong><small>({preferential})</small></div>
                <div class="flag-type">{activityType}</div>
                <a class="flag-btn" href="{shopLink}">{activeName}</a>
            </div>
        </li>
    </ul>
</div>

这仅是一个示例文档,大家可以根据自己风格写模板

为了能更好的测试页面,给其配置一点假数据:

//define data
var pageData = {
    sections:[{
        "brannerImag":"http://xxx.cdn.com/B1PNLZKXXXXXaTXXXXXXXXXXXX-750-481.jpg",
        items:[{
            "itemLink": "##",
            "imgSrc": "https://placeimg.com/350/350/people/grayscale",
            "poductName":"Carter's1年式灰色长袖连体衣包脚爬服全棉鲸鱼男婴儿童装115G093",
            "price": "299.06",
            "preferential": "满400减100",
            "activityType": "1小时内热卖5885件",
            "shopLink":"##",
            "activeName": "马上抢!"
        }
            ....
        }]
    }]
}

接下来的工作就是美化工作了。在写具体样式之前,有几个点需要先了解一下。

把视觉稿中的px转换成rem

读到这里,大家应该都知道,我们接下来要做的事情,就是如何把视觉稿中的px转换成rem。在此花点时间解释一下。

首先,目前日常工作当中,视觉设计师给到前端开发人员手中的视觉稿尺寸一般是基于640px750px以及1125px宽度为准。甚至为什么?大家应该懂的(考虑Retina屏)。

正如文章开头显示的示例设计稿,他就是一张以750px为基础设计的。那么问题来了,我们如何将设计稿中的各元素的px转换成rem

Flexible实现手淘H5页面的终端适配

我厂的视觉设计师想得还是很周到的,会帮你把相关的信息在视觉稿上标注出来

目前Flexible会将视觉稿分成**100份**(主要为了以后能更好的兼容vhvw),而每一份被称为一个单位a。同时1rem单位被认定为10a。针对我们这份视觉稿可以计算出:

1a   = 7.5px
1rem = 75px 

那么我们这个示例的稿子就分成了10a,也就是整个宽度为10rem<html>对应的font-size75px

Flexible实现手淘H5页面的终端适配

这样一来,对于视觉稿上的元素尺寸换算,只需要原始的px值除以rem基准值即可。例如此例视觉稿中的图片,其尺寸是176px * 176px,转换成为2.346667rem * 2.346667rem

如何快速计算

在实际生产当中,如果每一次计算px转换rem,或许会觉得非常麻烦,或许直接影响大家平时的开发效率。为了能让大家更快进行转换,我们团队内的同学各施所长,为px转换rem写了各式各样的小工具。

CSSREM

CSSREM是一个CSS的px值转rem值的Sublime Text3自动完成插件。这个插件是由@正霖编写。先来看看插件的效果:

Flexible实现手淘H5页面的终端适配

有关于CSSREM如何安装、配置教程可以点击这里查阅

CSS处理器

除了使用编辑器的插件之外,还可以使用CSS的处理器来帮助大家处理。比如说Sass、LESS以及PostCSS这样的处理器。我们简单来看两个示例。

Sass

使用Sass的同学,可以使用Sass的函数、混合宏这些功能来实现:

@function px2em($px, $base-font-size: 16px) {
    @if (unitless($px)) {
        @warn "Assuming #{$px} to be in pixels, attempting to convert it into pixels for you";
        @return px2em($px + 0px); // That may fail.
    } @else if (unit($px) == em) {
        @return $px;
    }
    @return ($px / $base-font-size) * 1em;
}

除了使用Sass函数外,还可以使用Sass的混合宏:

@mixin px2rem($property,$px-values,$baseline-px:16px,$support-for-ie:false){
    //Conver the baseline into rems
    $baseline-rem: $baseline-px / 1rem * 1;
    //Print the first line in pixel values
    @if $support-for-ie {
        #{$property}: $px-values;
    }
    //if there is only one (numeric) value, return the property/value line for it.
    @if type-of($px-values) == "number"{
        #{$property}: $px-values / $baseline-rem;
    }
    @else {
        //Create an empty list that we can dump values into
        $rem-values:();
        @each $value in $px-values{
            // If the value is zero or not a number, return it
            @if $value == 0 or type-of($value) != "number"{
                $rem-values: append($rem-values, $value / $baseline-rem);
            }
        }
        // Return the property and its list of converted values
        #{$property}: $rem-values;
    }
}

有关于更多的介绍,可以点击这里进行了解。

PostCSS(px2rem)

除了Sass这样的CSS处理器这外,我们团队的@颂奇同学还开发了一款npm的工具px2rem。安装好px2rem之后,可以在项目中直接使用。也可以使用PostCSS。使用PostCSS插件postcss-px2rem

var gulp = require('gulp');
var postcss = require('gulp-postcss');
var px2rem = require('postcss-px2rem');

gulp.task('default', function() {
    var processors = [px2rem({remUnit: 75})];
    return gulp.src('./src/*.css')
        .pipe(postcss(processors))
        .pipe(gulp.dest('./dest'));
});

除了在Gulp中配置外,还可以使用其他的配置方式,详细的介绍可以点击这里进行了解。

配置完成之后,在实际使用时,你只要像下面这样使用:

.selector {
    width: 150px;
    height: 64px; /*px*/
    font-size: 28px; /*px*/
    border: 1px solid #ddd; /*no*/
}

px2rem处理之后将会变成:

.selector {
    width: 2rem;
    border: 1px solid #ddd;
}
[data-dpr="1"] .selector {
    height: 32px;
    font-size: 14px;
}
[data-dpr="2"] .selector {
    height: 64px;
    font-size: 28px;
}
[data-dpr="3"] .selector {
    height: 96px;
    font-size: 42px;
}

在整个开发中有了这些工具之后,完全不用担心px值转rem值影响开发效率。

文本字号不建议使用rem

前面大家都见证了如何使用rem来完成H5适配。那么文本又将如何处理适配。是不是也通过rem来做自动适配。

显然,我们在iPhone3G和iPhone4的Retina屏下面,希望看到的文本字号是相同的。也就是说,我们不希望文本在Retina屏幕下变小,另外,我们希望在大屏手机上看到更多文本,以及,现在绝大多数的字体文件都自带一些点阵尺寸,通常是16px24px,所以我们不希望出现13px15px这样的奇葩尺寸

如此一来,就决定了在制作H5的页面中,rem并不适合用到段落文本上。所以在Flexible整个适配方案中,考虑文本还是使用px作为单位。只不过使用[data-dpr]属性来区分不同dpr下的文本字号大小。

div {
    width: 1rem; 
    height: 0.4rem;
    font-size: 12px; // 默认写上dpr为1的fontSize
}
[data-dpr="2"] div {
    font-size: 24px;
}
[data-dpr="3"] div {
    font-size: 36px;
}

为了能更好的利于开发,在实际开发中,我们可以定制一个font-dpr()这样的Sass混合宏:

@mixin font-dpr($font-size){
    font-size: $font-size;

    [data-dpr="2"] & {
        font-size: $font-size * 2;
    }

    [data-dpr="3"] & {
        font-size: $font-size * 3;
    }
}

有了这样的混合宏之后,在开发中可以直接这样使用:

@include font-dpr(16px);

当然这只是针对于描述性的文本,比如说段落文本。但有的时候文本的字号也需要分场景的,比如在项目中有一个slogan,业务方希望这个slogan能根据不同的终端适配。针对这样的场景,完全可以使用rem给slogan做计量单位。

CSS

本来想把这个页面的用到的CSS(或SCSS)贴出来,但考虑篇幅过长,而且这么简单的页面,我想大家也能轻而易举搞定。所以就省略了。权当是给大家留的一个作业吧,感兴趣的可以试试Flexible能否帮你快速完成H5页面终端适配。

效果

最后来看看真机上显示的效果吧。我截了两种设备下的效果:

iPhone4

Flexible实现手淘H5页面的终端适配

iPhone6+

Flexible实现手淘H5页面的终端适配

总结

其实H5适配的方案有很多种,网上有关于这方面的教程也非常的多。不管哪种方法,都有其自己的优势和劣势。而本文主要介绍的是如何使用Flexible这样的一库来完成H5页面的终端适配。为什么推荐使用Flexible库来做H5页面的终端设备适配呢?主要因为这个库在手淘已经使用了近一年,而且已达到了较为稳定的状态。除此之外,你不需要考虑如何对元素进行折算,可以根据对应的视觉稿,直接切入。

当然,如果您有更好的H5页面终端适配方案,欢迎在下面的评论中与我们一起分享。如果您在使用这个库时,碰到任何问题,都可以在Github给我们提Issue。我们团队会努力解决相关需Issues。

Update

同学反馈说需要一个在线的DEMO,那么随便写了一个DEMO,希望对大家有所帮助。没有测试所有设备,可能不同的设备有细节上的差异。

DEMO

请用手机扫下面的二维码

DEMO

Update【2016年01月13日】

首先,由衷的感谢@完颜(@SMbey0nd) 帮忙踩了这个坑,回想起iOS从78,从89,都踩过只至少一个坑,真的也是醉了。

手淘这边的flexible方案临时升级如下:

  • 针对OS 9_3的UA,做临时处理,强制dpr1,即scale也为1,虽然牺牲了这些版本上的高清方案,但是也只能这么处理了
  • 这个版本不打算发布到CDN(也不发不到tnpm),所以大家更新的方式,最好手动复制代码内联到html中,具体代码可以点击这里下载

@gugegev5
Copy link

在不同的屏幕上,CSS像素所呈现的物理尺寸是一致的

ios上默认的viewport下 物理尺寸不一样啊?

@HaoyuA
Copy link

HaoyuA commented Aug 26, 2020

细细品味一下 好文章

@lyh0371
Copy link

lyh0371 commented Nov 12, 2020

为什么你引入的flexible和官方的https://github.com/amfe/lib-flexible 这个里面的代码不一样?

@renwanjun
Copy link

initial-dpr设置那段好像没有什么意义啊

@Cinux-Chosan
Copy link

文章说:

     目前Flexible会将视觉稿分成**100份**(主要为了以后能更好的兼容vh和vw),而每一份被称为一个单位a。同时1rem单位被认定为10a。针对我们这份视觉稿可以计算出:
1a   = 7.5px
1rem = 75px 

那么我们这个示例的稿子就分成了10a,也就是整个宽度为10rem,对应的font-size为75px


照这么说来,视觉稿已经给定了是 750px,那html的 font-size 就永远都是 75 px 咯?demo 貌似不是根据视觉稿来设置的 html 的 font-size 的呀。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests