rem自适应方案
longyiyiyu opened this issue · 39 comments
H5自适应改造方案——rem方案
原理
之前我们H5页面使用的方案是设置viewport meta头,让浏览器帮我们把页面缩放,使得页面看起来好像是自适应。实际上这不是自适应,只是在中小屏设备上,看起来差距不大,问题不明显而已。
现在大屏高清设备流行,自适应的问题也越来越明显了。在大屏设备上,课程封面小,title被拉长,文字小,按钮扁等问题越来越突出,已经达到不能忍受的程度,因此需要一套自适应的方案。
页面缩放
在viewport meta头里,取消让浏览器自动缩放页面,页面的自适应由页面自身管理。
因为有dpr的问题,为了统一管理,让浏览器帮我们根据dpr缩小页面,比如dpr=2,就缩小0.5让页面统一处在dpr=1的环境中。
rem
rem是一个半相对单位,它相对的是html(或body)元素的font-size值,例如有html { font-size: 10px; },则1rem = 10px。
当html元素的font-size是根据设备宽度自适应时,使用rem的页面也就会有自适应的特性。
文字
根据以下两个原因,对于文字使用px:
- 在大屏设备希望看到更多的文字
- 中文点阵最好是在12px,14px,16px这种尺寸,使用rem就会无法避免使用13px,15px尺寸,这样文字会显示的很奇怪
没有浏览器帮助我们缩放页面,在高清设备里面需要我们手动对文字进行缩放,为了方便这个而不需要写media query,页面在计算html的font-size值的同时,会设置一个data-dpr的属性。这时文字的media query就可以这样写:
p { font-size: 12px; } /* dpr = 1 */
[data-dpr="2"] p { font-size: 24px; } /* dpr = 2 */
[data-dpr="3"] p { font-size: 36px; } /* dpr = 3 */
规范
-
在head头引入初始化js脚本,可以使用两种代码:
- 淘宝移动端自适应方案开源代码,注:这里的因子是10,即font-size = W/10
- 腾讯课堂公众号最新代码里面(路径:src/inline/rem.html),里面的代码是淘宝现网代码copy下来的,与开源代码对比过,大致一样。注:这里的因子是16,即font-size = W/16
-
开发时,假如视觉稿宽度是640,则最好使用第二种方案,选择16作为因子,则比例为640/16=40。那么,页面所有的rem数值的换算公式为:在视觉稿中的px数值/40。
以后会开发一个fis插件,在开发时只需填入视觉稿中的px数值,由fis插件帮助我们自动换算,在插件开发出来之前,先人工计算吧。
-
文字使用px单位,同时需要写media query,借助html元素上面的data-dpr属性,详见原理部分。
good job,解决了我周四的问题
实践所得——重构公众号首页
- 在重构前,针对设计稿评估是否真的需要用到rem方案,如果存在以下两点都需要考虑使用rem方案
- 稀疏布局
由前面的【原理】可知,非自适应的页面通过浏览器的缩放在不同手机之间的显示差不多,关键只在于这些差异能不能容忍,如果可以容忍,那么完全可以不用自适应方案。
稀疏布局不像列表结构,页面元素不多。其中某些元素需要宽度自适应(否则太窄),这时高度也必须跟着自适应(否则太扁),那么里面的字体也必须跟着自适应(否则太空旷,除非多几行) - font-size < 12px
font-size小于12px的字体在3倍屏下面会显得很小
- 稀疏布局
- 一般来说,640的稿子量出来的字体是data-dpr="2"的,750(ip6)也是data-dpr="2"的,data-dpr="1"和data-dpr="3"的按倍数计算,同时可以做一下微调。
一个640px宽的屏幕,它可能是6401,也可能是3202,不管是哪一种,页面的布局(使用rem单位)长得都是一样的,那字体要怎么度量?这个问题放在以前就是一个@Medie的事情,但是现在不想这样做,希望通过[data-dpr="xx"]来实现,只有2个临界点,那么问题是,你怎么知道640的页面是1dpr还是2dpr?这个只能通过普遍机型的经验来确定,一般640,750都是2dpr的,因此对于640的稿子量出来的字体大小是属于data-dpr="2"的。
如果我们的页面需要适应pad,那么有两个方案,一个是定宽;另一个就是在html元素上面再加上一个data-device了,因为640*1会在pad中出现。 - 图片需要3倍高清,需要视觉稿提供,多倍图(包括课程封面)注意
- css实现时,可以和font-size的处理一样,通过[data-dpr="xx"]来设置不同的图片
- js实现也可以通过html的data-dpr属性值来设置。
- 首屏图片最好用css,使用background,如果需要img,则只能内嵌js代码
- 非首屏图片的话img和background都可以用,在lazyload里面实现
- 小数点问题
- 导致 |width - background-size| = 1,因此会出现截边问题,因此需要设置background-size: cover。因为只相差1px,对background-position影响不大,因此依然使用rem
- 用css拼出来的图标也会出问题。图标问题有3个方案:
- 图片:需要多倍图,在一些性能要求高的页面需要在不同屏使用不同清晰度的图片,多倍图维护起来是很麻烦的。
- svg:android 2.3不支持,什么时候可以抛弃android 2.3,就可以使用svg了。
- icofont:只支持灰度图,较简单,需要svg制作,比较麻烦。
相比较而已,还是支持icofont方案,原因如下:- 大小,颜色,底色可控
- 支持内嵌与外链两种方式,而且在移动端,可以避免pc端的许多问题
- 使用icofont有以下建议:
- 把字符资源当成一般的图片资源即可
- 需要共享使用外链,不需要使用内嵌
- 外链时,字符文件用gzip压缩
- 只需要trueType(.ttf)格式
- 一个字符资源不要包含太多图标,测试时,3个5k,10个7k
- js计算css的时候,需要完全动态计算,结果不一定需要使用rem单位,如果需要使用rem单位,则记住换算公式:1rem = W/16px
- 不需要使用rem的属性(为以后的自动计算工具做准备)
- font-size
- border系,除了border-radius
- 自动计算工具设计
- 配置:
- 设计稿宽度,默认640
- rem换算因子,默认16
- dpr,默认2
- 不自动转换为rem的属性正则,默认[/^font-size$/, /^border/]
- 自动转换为rem的属性正则,默认[/^border-radius$/]
- 逻辑
- background-size自动设置为background-size: cover;
- 所有的px单位都转换为相应的rem,除了配置项
- 所有包含font-size的规则,补齐另外2种屏的值
- 规范
- 配置:
//规范在实现时可改
.test {
font-size: 12px#r; /* 转换为rem */
margin: 5px#nr; /* 不转换为rem */
}
.test-a {
font-size: 12px#22|34;
}
//自动生成以下代码,假设配置dpr: 1
.test-a { font-size: 12px; }
[data-dpr="2"] .test-a { font-size: 22px; }
[data-dpr="3"] .test-a { font-size: 34px; }
good!很好的分享实践
为什么font-size和border不需要设置rem?
@ousiri 这里主要是考虑后续我们希望能够直接通过工具生成rem或者font-size。
为什么咋 安卓上 布局会变大阿 怎么解决阿
@xrds 具体指哪里?详细描述下场景,展示和屏幕尺寸有关。
@herbertliu dpr的问题 第一次用不太了解。。。 谢谢
@xrds dpr本身是表示显示像素和物理像素的比。一般我们用的是2倍像素,这里借助data-dpr设置,来手动管理手机分辨率(再去掉了meta viewport二倍像素设置后)。根据这个data-dpr的设置,可以在css中设置对应的想要设置的值,如:
@herbertliu 谢谢,河伯详细讲解 我现在已经有了大概的了解了。。。
好腻害,,,这能写个插件刁刁哒
background-position用rem定位雪碧图的话会出现偏差,请问你们是怎么处理了,是用px加dpr?
@luckymore 插件我们看看尽快能否输出
@herbertliu 划擦O(∩_∩)O,,,河伯大爱无疆,期待
@qc-zhan 图片问题@longyiyiyu回头再补充一下, 图片一般不用rem,直接用backgrunt-size 来解决
@luckymore 因为rem是比例的,会出现小数点(0.3px之类的),浏览器不支持的话,就会默认成1px
@herbertliu 目前我自己的方案是用px,然后根据dpr控制background-size 和 background-position,不知你们是否也是这样,还是有更好的解决方案
@luckymore 河伯也说了rem是等比例的,雪碧图定位用rem的话,会出现错位的
@luckymore 目前说的错位是我之前把background-position用rem方案会出现sprite图定位不准确。至于设置一个div之类的宽高没有什么错位的
@qc-zhan 我已经搞定啦,设置gulp.spritesmith的模板就可以了,公式如下:
{{#sprites}}
.icon-{{name}}:before {
background-position: 0 {{offset_y}}/({{height}}-{{total_height}})*100%;
}
{{/sprites}}
Hi I am not interested to get emails from regarding your projects
Thanks
On Mon, Sep 14, 2015 at 7:03 PM, br notifications@github.com wrote:
@qc-zhan https://github.com/qc-zhan
我已经搞定啦,设置gulp.spritesmith的模板就可以了,公式如下:{{#sprites}}
.icon-{{name}}:before {
background-position: 0 {{offset_y}}/({{height}}-{{total_height}})*100%;
}
{{/sprites}}—
Reply to this email directly or view it on GitHub
#3 (comment).
@banrikun 简直太赞,看了你的文章了,学习了。目前完美解决这个问题,但目前只在几台手机测试过。
之前我是用dpr控制background-size 和 background-position,虽然不会有错位问题,但不是用rem就无法做到自适应了,而且图标量一多,生成的css代码量就很大,根据dpr方法编译后的代码大概如下。
a {
display: block;
width: 28px;
height: 28px;
background-image: url('../img/icons-s1fc22bf1d4.png');
background-repeat: no-repeat;
background-position-y: 0;
background-position-x: -575px;
background-size: 2053px;
}
[data-dpr="2"] a {
width: 56px;
height: 56px;
background-size: 4106px;
background-position-x: -1150px;
}
[data-dpr="3"] a {
width: 84px;
height: 84px;
background-position-x: -1725px;
background-size: 6159px;
}
看了确实蛋疼。
1080*1920
请问我怎么判断。。我这图属于什么范围内?html [font-size] 应该是多少?
谢谢!
@luckymore font-size是根据你自己的页面来,没有固定的值。一般按经验来算,采用1rem=10px(即html [font-size]为10px),比较好计算,宽度为:1080/10=108rem。不过这样一来,每个rem数字较大,这时采用1rem=40px(即html [font-size]为40px)。那么宽度为:1080/40=27rem,也是OK的。
河伯,我没表达清楚。。。
html的**[font-size]**是js根据手机的大小决定的,比如说iPhone6 375 × 627,js计算出来的值是这样的:
<html lang="en" data-dpr="2" style="font-size: 75px;">
现在我不理解的是,我从拿到一个1080 × 1920设计稿开始,为它选择一个font-size基 ‘ s’ 来计算:
设计稿里有个300 × 100 的按钮,则:
.btn {
width: (300/s)rem;
heigth: (100/s)rem;
}
这其中的**’s‘**值是怎么确定的。。。有点白痴的问题呢😄
@luckymore 你说的是用那个js设置吧。首先根据iPhone6 375 × 627,
dpr为2,然后页面实际像素宽度
这里采用的dpr倍数是:10,所以宽度为计算出来的宽度是75px
那么,实际开发中。从上面的分析可以看到,倍数是10,,针对1080 × 1920。1080->750(iphone6为例)->10rem;所以这里1rem=108px(这里指的是视觉稿1rem对应的108px)。因此针对,300 × 100的按钮。对应的rem为300/108=2.78rem。
另外,我们采用的是倍数是16,即:1rem=46.875px(iphone6为例),视觉稿中:1rem=67.5px。
说得很好
已经解决,应用这个js头部的它是需要去掉的,js会自动添加
<meta content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no" name="viewport">
demo:http://www.love85g.com/code/
p { font-size: 12px; } /* dpr = 1 */
下边两句为什么在我测试页面不起作用,求解
[data-dpr="2"] p { font-size: 24px; } /* dpr = 2 /
[data-dpr="3"] p { font-size: 36px; } / dpr = 3 */
@majiang666 效果是什么样子?有测试路径吗?
开发时,假如视觉稿宽度是640,则最好使用第二种方案,选择16作为因子,则比例为640/16=40。那么,页面所有的rem数值的换算公式为:在视觉稿中的px数值/40
这里为什么要使用16做为因子? 如果是640下设计稿,根字体计算出来为100,这样不是更好计算rem的大小吗?
@git-lt 其实这里的用多少没关系的,而且计算这个可以通过插件来直接支持,开发仍然只需关注px,查看fis-parser-rem。
html 后面那个font-size可以动态取值的;
图片自适应怎么办?根据dpr设计不同的图吗,有没有什么好方法()
@herbertliu 链接打不开404
@suming1016 OK了
没看到border怎么适配啊