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

rem自适应方案 #3

Open
longyiyiyu opened this issue Apr 27, 2015 · 39 comments
Open

rem自适应方案 #3

longyiyiyu opened this issue Apr 27, 2015 · 39 comments

Comments

@longyiyiyu
Copy link
Contributor

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 */

规范

  1. 在head头引入初始化js脚本,可以使用两种代码:

    • 淘宝移动端自适应方案开源代码,注:这里的因子是10,即font-size = W/10
    • 腾讯课堂公众号最新代码里面(路径:src/inline/rem.html),里面的代码是淘宝现网代码copy下来的,与开源代码对比过,大致一样。注:这里的因子是16,即font-size = W/16
  2. 开发时,假如视觉稿宽度是640,则最好使用第二种方案,选择16作为因子,则比例为640/16=40。那么,页面所有的rem数值的换算公式为:在视觉稿中的px数值/40。

    以后会开发一个fis插件,在开发时只需填入视觉稿中的px数值,由fis插件帮助我们自动换算,在插件开发出来之前,先人工计算吧。

  3. 文字使用px单位,同时需要写media query,借助html元素上面的data-dpr属性,详见原理部分。

@miniflycn
Copy link
Member

good job,解决了我周四的问题

@longyiyiyu
Copy link
Contributor Author

实践所得——重构公众号首页

  1. 在重构前,针对设计稿评估是否真的需要用到rem方案,如果存在以下两点都需要考虑使用rem方案
    • 稀疏布局
      由前面的【原理】可知,非自适应的页面通过浏览器的缩放在不同手机之间的显示差不多,关键只在于这些差异能不能容忍,如果可以容忍,那么完全可以不用自适应方案。
      稀疏布局不像列表结构,页面元素不多。其中某些元素需要宽度自适应(否则太窄),这时高度也必须跟着自适应(否则太扁),那么里面的字体也必须跟着自适应(否则太空旷,除非多几行)
    • font-size < 12px
      font-size小于12px的字体在3倍屏下面会显得很小
  2. 一般来说,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. 图片需要3倍高清,需要视觉稿提供,多倍图(包括课程封面)注意
    • css实现时,可以和font-size的处理一样,通过[data-dpr="xx"]来设置不同的图片
    • js实现也可以通过html的data-dpr属性值来设置。
    • 首屏图片最好用css,使用background,如果需要img,则只能内嵌js代码
    • 非首屏图片的话img和background都可以用,在lazyload里面实现
  4. 小数点问题
    • 导致 |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端的许多问题
  5. 使用icofont有以下建议:
    • 把字符资源当成一般的图片资源即可
    • 需要共享使用外链,不需要使用内嵌
    • 外链时,字符文件用gzip压缩
    • 只需要trueType(.ttf)格式
    • 一个字符资源不要包含太多图标,测试时,3个5k,10个7k
  6. js计算css的时候,需要完全动态计算,结果不一定需要使用rem单位,如果需要使用rem单位,则记住换算公式:1rem = W/16px
  7. 不需要使用rem的属性(为以后的自动计算工具做准备)
    • font-size
    • border系,除了border-radius
  8. 自动计算工具设计
    • 配置:
      • 设计稿宽度,默认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; }

@litten
Copy link

litten commented May 5, 2015

good!很好的分享实践

@ousiri
Copy link
Contributor

ousiri commented Jun 9, 2015

为什么font-size和border不需要设置rem?

@herbertliu
Copy link
Member

@ousiri 这里主要是考虑后续我们希望能够直接通过工具生成rem或者font-size。

@xrds
Copy link

xrds commented Jul 8, 2015

为什么咋 安卓上 布局会变大阿 怎么解决阿

@herbertliu
Copy link
Member

@xrds 具体指哪里?详细描述下场景,展示和屏幕尺寸有关。

@xrds
Copy link

xrds commented Jul 14, 2015

@herbertliu dpr的问题 第一次用不太了解。。。 谢谢

@herbertliu
Copy link
Member

@xrds dpr本身是表示显示像素和物理像素的比。一般我们用的是2倍像素,这里借助data-dpr设置,来手动管理手机分辨率(再去掉了meta viewport二倍像素设置后)。根据这个data-dpr的设置,可以在css中设置对应的想要设置的值,如:
image

@xrds
Copy link

xrds commented Jul 20, 2015

@herbertliu 谢谢,河伯详细讲解 我现在已经有了大概的了解了。。。

@luckymore
Copy link

好腻害,,,这能写个插件刁刁哒

@qc-zhan
Copy link

qc-zhan commented Sep 10, 2015

background-position用rem定位雪碧图的话会出现偏差,请问你们是怎么处理了,是用px加dpr?

@herbertliu
Copy link
Member

@luckymore 插件我们看看尽快能否输出

@luckymore
Copy link

@herbertliu 划擦O(∩_∩)O,,,河伯大爱无疆,期待

@luckymore
Copy link

@qc-zhan 图片大小不是确定的么。。。为啥不用px定位,rem控制大小background-size。
-----我是一枚小菜鸟,萌的不要不要的

@herbertliu
Copy link
Member

@qc-zhan 图片问题@longyiyiyu回头再补充一下, 图片一般不用rem,直接用backgrunt-size 来解决

@herbertliu
Copy link
Member

@luckymore 因为rem是比例的,会出现小数点(0.3px之类的),浏览器不支持的话,就会默认成1px

@qc-zhan
Copy link

qc-zhan commented Sep 11, 2015

@herbertliu 目前我自己的方案是用px,然后根据dpr控制background-size 和 background-position,不知你们是否也是这样,还是有更好的解决方案

@qc-zhan
Copy link

qc-zhan commented Sep 11, 2015

@luckymore 河伯也说了rem是等比例的,雪碧图定位用rem的话,会出现错位的

@luckymore
Copy link

@qc-zhan 有个疑问,,,按比例的话,div之类的宽高不会错位么

@qc-zhan
Copy link

qc-zhan commented Sep 11, 2015

@luckymore 目前说的错位是我之前把background-position用rem方案会出现sprite图定位不准确。至于设置一个div之类的宽高没有什么错位的

@banrikun
Copy link

@qc-zhan 我已经搞定啦,设置gulp.spritesmith的模板就可以了,公式如下:

{{#sprites}}
.icon-{{name}}:before {
    background-position: 0 {{offset_y}}/({{height}}-{{total_height}})*100%;
}
{{/sprites}}

地址:https://github.com/banrikun/webLog/issues/1

@Medie
Copy link

Medie commented Sep 14, 2015

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).

@qc-zhan
Copy link

qc-zhan commented Sep 15, 2015

@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;
}

看了确实蛋疼。

@luckymore
Copy link

1080*1920
请问我怎么判断。。我这图属于什么范围内?html [font-size] 应该是多少?
谢谢!

@herbertliu
Copy link
Member

@luckymore font-size是根据你自己的页面来,没有固定的值。一般按经验来算,采用1rem=10px(即html [font-size]为10px),比较好计算,宽度为:1080/10=108rem。不过这样一来,每个rem数字较大,这时采用1rem=40px(即html [font-size]为40px)。那么宽度为:1080/40=27rem,也是OK的。

@luckymore
Copy link

@herbertliu

河伯,我没表达清楚。。。
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‘**值是怎么确定的。。。有点白痴的问题呢😄

@herbertliu
Copy link
Member

@luckymore 你说的是用那个js设置吧。首先根据iPhone6 375 × 627,
image
dpr为2,然后页面实际像素宽度
image
这里采用的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。

@luckymore
Copy link

@herbertliu

谢谢啦

小弟比较愚钝,,还请河伯不要烦我。。

@ronyland
Copy link

ronyland commented Nov 6, 2015

说得很好

@majiang666
Copy link

已经解决,应用这个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 */

@herbertliu
Copy link
Member

@majiang666 效果是什么样子?有测试路径吗?

@majiang666
Copy link

@git-lt
Copy link

git-lt commented May 7, 2016

开发时,假如视觉稿宽度是640,则最好使用第二种方案,选择16作为因子,则比例为640/16=40。那么,页面所有的rem数值的换算公式为:在视觉稿中的px数值/40

这里为什么要使用16做为因子? 如果是640下设计稿,根字体计算出来为100,这样不是更好计算rem的大小吗?

@herbertliu
Copy link
Member

herbertliu commented May 9, 2016

@git-lt 其实这里的用多少没关系的,而且计算这个可以通过插件来直接支持,开发仍然只需关注px,查看fis-parser-rem

@suming1016
Copy link

html 后面那个font-size可以动态取值的;
图片自适应怎么办?根据dpr设计不同的图吗,有没有什么好方法()

@suming1016
Copy link

@herbertliu 链接打不开404

@herbertliu
Copy link
Member

@suming1016 OK了

@SKing7
Copy link

SKing7 commented Jan 5, 2018

没看到border怎么适配啊

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