京东h5移动端适配(REM)

我的第一次移动端页面制作 — 总结与思考

by 饮水机隔壁的小刘 on 2016-11-08

技术涉及

REM

移动端采用 rem 布局方式。通过动态修改 html 的 font-size 实现自适应。

实现方式

REM 布局有两种实现方式:CSS 媒介查询和 JavaScript 动态修改。由于 JavaScript 更为灵活,因此现在更多地采用此方式。

JavaScript

凹凸的实现方式是:在 head 标签末加入以下代码

<script type="text/javascript">
    !function(){
      var maxWidth=750;
      document.write('<style id="o2HtmlFontSize"></style>');
      var o2_resize=function(){
          var cw,ch;
          if(document&&document.documentElement){
              cw=document.documentElement.clientWidth,ch=document.documentElement.clientHeight;
          }
          if(!cw||!ch){
              if(window.localStorage["o2-cw"]&&window.localStorage["o2-ch"]){
                  cw=parseInt(window.localStorage["o2-cw"]),ch=parseInt(window.localStorage["o2-ch"]);
              }else{
                  chk_cw();//定时检查
                  return ;//出错了
              }
          }

          var zoom=maxWidth&&maxWidth<cw?maxWidth/375:cw/375,zoomY=ch/603;//由ip6 weChat
          window.localStorage["o2-cw"]=cw,window.localStorage["o2-ch"]=ch;
          //zoom=Math.min(zoom,zoomY);//保证ip6 wechat的显示比率
          window.zoom=window.o2Zoom=zoom;
          document.getElementById("o2HtmlFontSize").innerHTML='html{font-size:'+(zoom*20)+'px;}.o2-zoom,.zoom{zoom:'+(zoom/2)+';}.o2-scale{-webkit-transform: scale('+zoom/2+'); transform: scale('+zoom/2+');} .sq_sns_pic_item,.sq_sns_picmod_erea_img{-webkit-transform-origin: 0 0;transform-origin: 0 0;-webkit-transform: scale('+zoom/2+');transform: scale('+zoom/2+');}';
      },
      siv,
      chk_cw=function(){
          if(siv)return ;//已经存在
          siv=setInterval(function(){
              //定时检查
              document&&document.documentElement&&document.documentElement.clientWidth&&document.documentElement.clientHeight&&(o2_resize(),clearInterval(siv),siv=undefined);
          },100);
      };
      o2_resize();//立即初始化
      window.addEventListener("resize",o2_resize);
  }();
  </script>

从以上代码可得出以下信息:

  1. 以 iPhone 6 为基准,iPhone 6 的缩放比 zoom 为 1
  2. 由于只针对移动端,因此最大宽度为768(恰好等于 iPad 的竖屏宽度)
  3. 通过 document.documentElement.clientWidth 获取视口宽度
  4. resize 事件主要考虑横竖屏切换和你在PC上调试时?
  5. zoom 系数是 20。系数决定了在宽度 375 的 iPhone6 下,1 rem 的值是多少 px(20px)。当然如果想过渡到 vw,可以将 zoom 系数设置为 3.75,那么 100rem 就是 375px 了

为什么要用

有人说 rem 布局是 vw 和 vh 的替换方案,当 vw 和 vh 成熟时,两者可能会各司其职吧。

 

vw 的兼容性:在安卓 4.3 及以下是不支持的。

 

哪些地方要用

 

由于 rem 布局是相对于视口宽度,因此任何需要根据屏幕大小进行变化的元素(width、height、position 等)都可以用 rem 单位。

但 rem 也有它的缺点——不精细(在下一节阐述),其实这涉及到了浏览器渲染引擎的处理。因此,对于需要精细处理的地方(如通过 CSS 实现的 icon),可以用 px 等绝对单位,然后再通过 transform: scale() 方法等比缩放。

字体

那 font-size 是否也要用 rem 单位呢? 这也是我曾经纠结的地方。如果不等比缩放,对不起设计师,而且对于小屏幕,一些元素内的字体会换行或溢出。当然这可以通过 CSS3 媒介查询解决这种状况。

字体不采用 rem 的好处是:在大屏手机下,能显示更多字体。

看到 网易新闻 和 聚划算 的字体大小都采用 rem 单位,我就不纠结了。当然,也有其它网站是采用绝对单位的,两者没有绝对的对与错,取决于你的实际情况。

缺点

小数点(不精细,有间隙)

由于 rem 布局是基于某一设备实现的(目前一般采用 iPhone6),对于 375 倍数宽的设备无疑会拥有最佳的显示效果。而对于非 375 倍数宽的设备,zoom 就可能是拥有除不尽的小数,根元素的字体大小也相应会有小数。而浏览器对小数的处理方式不一致,导致该居中的地方没完全居中,但你又不能为此设置特定样式(如 margin-top: *px;),因为浏览器多如牛毛,这个浏览器微调居中了,而原本居中的浏览器变得不居中了。

对于图标 icon,rem 的不精细导致通过多个元素(伪元素)组合而成的 icon 会形成错位/偏差。因此,在这种情况下,需要

权衡是否需要使用 CSS 实现了。

SASS

SASS 无疑增强了原本声明式的 CSS,为 CSS 注入了可编程等能力。在这次项目,算是我第一次使用 SASS,由于构建工具和基础库的完善,只需通过查看/模仿已有项目的 SASS 用法,就能快速上手。后续还是要系统地学习,以更合理地使用 SASS。

使用 SASS 的最大问题是:层级嵌套过深,这也是对 SASS 理解不深入的原因。可以关注一下转译后的 CSS。

兼容性

这次项目的 APP 采用手机自带浏览器内核,而这些浏览器内核依赖于系统版本等因素。另外,国产机也会对这些内核进行定制和修改。特别是华为、OPPO。

下面列出我所遇到的兼容性问题(不列具体机型,因为这些兼容性处理终会过时,不必死记硬背,遇到了能解决就好(要求基础扎实)):

  • flexbox:在构建工具处理下(实现了新旧语法)可以大胆用,但个别设备不支持 flex-wrap: wrap。因此对于想使用 flex-wrap 实现自动分行的情况,建议使用其他实现。如果个数固定(如 N 行,每行 M 个),则可使用 N 个 flexbox(这样就可以使用 flexbox 的特性了)。flexbox 的其他属性也有支持不好的情况,可以通过显式声明 display、overflow、width、height 等方法解决。
  • background-size:需要单独写,否则在 安卓 4.3 及以下,IOS 6.1及以下不兼容
  • 渐变:线性渐变大胆使用,径向渐变有兼容性问题。但是不建议对整体背景使用,会有性能问题(可简单地通过 1px 高的图片替代,注意,不要 background-size: 100% auto; 应该采用 background-size: 100% 1px; 因为有些浏览器(视口宽度较小)会忽略小数点【auto = img.Height * (screen.Width/img.Width)】,导致图片未显示)。另外,需要注意的是:透明的色标在iOS 默认是黑色的,即 transparent 等于 rgba(0,0,0,0)。因此即使是完全透明的色标,也要指定颜色。否则后果如下:

 

        此处输入图片的描述

 

  • classlist.remove(String[, String]),传递多个参数时,会有不兼容的情况。建议每次写一个。add (String[, String])同理。
  • 根节点 html font-size 渲染错误:在华为、魅族的某设备上(手Q),会出现一个非常奇葩的渲染 Bug,同一个网页,“扫一扫”打开 html 的 font-size 正常,直接点击链接会出现渲染出来的 html font-size 会比设置得值大(如:设置25.8,渲染出来是 29),因此导致整体变大,且布局错乱。
    我的方法是:为 html font-size 重新设置大小:渲染字体大小 - (渲染与正常差值)

function getStyle(ele, style) {
    return document.defaultView.getComputedStyle(ele, null)[style]
}
;(function fixFontSize() {
    var target = window.o2Zoom * 20
    var cur = parseInt(getStyle(document.documentElement, "fontSize"))
    while(cur - target >= 1) {
        document.documentElement.style["fontSize"] = target - (cur - target) + "px"
        cur = parseInt(getStyle(document.documentElement, "fontSize"))
    }          
})();

有网友提供这个方法 <meta name="wap-font-scale" content="no">,经测试不可行。此方法是针对 UC 浏览器的。

上面主要列出了对使用有影响的兼容性问题,有些由于浏览器渲染引擎导致的问题(不影响使用),若无法通过 transform、z-index 等解决,也许只能通过 JavaScript 解决或进行取舍了。

其他一些知识点

图片占位元素:对于宽高比例固定的坑位(如商品列表项),通过将图片放置在占位元素中,可避免图片加载时引起的页面抖动和图片尺寸不一致而导致的页面布局错乱。代码实现:

.img_placeholder {
  position: relative;
  height: 0;
  overflow: hidden;
  padding-top: placeholder 的高/宽%; // padding-top/bottom: 百分比; 是基于父元素的宽度
  img {
      width: 100%;
      height: auto;
      position: absolute;
      left: 0;
      top: 0;
  }
}

1px:在 retina 屏幕下,1 CSS像素是用 4 个物理像素表示,为了在该屏幕下显示更精细,通过为 ::after 应用以下代码(以上边框为例):

div {
    position: relative;
    &::after {
        content: '';
        position: absolute;
        z-index: 1;
        pointer-events: none;
        background: $borderColor;
        height: 1px;left: 0;right: 0;top: 0;
        @media only screen and (-webkit-min-device-pixel-ratio:2) {
            &{
                -webkit-transform: scaleY(0.5);
                -webkit-transform-origin: 50% 0%;
            }
        }
    }
}

根据元素个数应用特定样式:

/* one item */
li:first-child:nth-last-child(1) {
    width: 100%;
}
/* two items */
li:first-child:nth-last-child(2),
li:first-child:nth-last-child(2) ~ li {
    width: 50%;
}
/* three items */
li:first-child:nth-last-child(3),
li:first-child:nth-last-child(3) ~ li {
    width: 33.3333%;
}
/* four items */
li:first-child:nth-last-child(4),
li:first-child:nth-last-child(4) ~ li {
    width: 25%;
}
  • 应用样例有:根据元素个数自适应标签样式。
    根据元素个数自适应标签样式
    而对于反方向标签,可先首先对整体 transform: scale(-1),然后再对字体 transform: scale(-1) 恢复从左向右的方向。效果如下:
    标签反向

  • 卡券:『带孔且背景是渐变的卡券』在复杂背景中的实现。由于背景是复杂的(非纯色),因此孔不能简单地通过覆盖(与背景同色)产生。这里可以应用径向渐变 background-image: radial-gradient(rem(189/2) 100%, circle, transparent 0, transparent 3px, #fa2c66 3px);,其中 3px 是孔的半径。另外,卡券的上下部分是线性渐变的,因此可以在上下部分分别通过伪类元素添加 background-image: linear-gradient(to top, #fa2e67 0, #fb5584 100%);,当然,要从离外上/下边界 3px 的地方开始。虽然这不能完美地从最边界开始,但效果还是可以的。但由于径向渐变的兼容性问题,我最终还是用图片替换了这种实现。?
    带孔且背景是渐变的卡券
  • 多行文本的多行padding:让背景只出现在有文字的地方,可直接设置 display: inline;,但还会存在一个问题是:padding 只会出现在多行文本的首和尾,对于需要为每行文本的首尾都需要相同的 padding,可以参考这篇文章:《multi-line-padded-text》 。该文章提供了多种实现方式,根据具体情况选择一种即可。另外,对于每行的间距,可通过设置 line-height 和 padding-top/bottom 实现,其中 line-height 要大于(字体高度+padding-top/bottom)。
    此处输入图片的描述
    此处输入图片的描述
  • 最小字体限制:PC上最小字体是 12px、移动端最小是 8px,当然可通过 transform:scale() 突破限制。

不止页面页面制作

  1. 基础:合理运用 CSS 的威力更好地完成对设计稿的重现目的。
  2. 沟通:由于分工较细,只负责页面制作的同学,需要与产品和设计沟通,以达到交给开发后更少修改的目的。如哪些地方可跳转、哪些地方最多显示几行文字、超出如何处理(直接隐藏/省略号等)、坑位中的图片摆放(顶部对齐/居中等)等等。
  3. 代码上的沟通:HTML 注释要写好、HTML 与 CSS 代码要规范(命名等)清晰。

思考

由于工具的成熟,我不需要考虑构建工具的搭建。
由于发布方式的成熟,页面制作和开发能更好地分离,页面制作者负责输出 HTML、CSS,开发负责 copy html 代码和引入 CSS 页面片。CSS 页面片由页面制作者更新发布,开发无需关心。这达到了互不干扰、多线程并行的效果。
成熟的基础设施让我们免除了非代码相关的烦恼,但这也让我担心:假如有一天我脱离了这些基础设施,我该如何保持高效。

延伸:页面片是什么?

CSS 页面片

1  <!-- #include virtual="/folder/branch.shtml" -->
2  <link combofile="/folder/branch.shtml" rel="stylesheet" href="//website/folder/gb.min_1151b5b0.css,/folder/branch.min_925332fc.css" />

JS 页面片

1  <!-- #include virtual="/folder/branch_js.shtml" -->
2  <script combofile="/folder/branch.shtml" src="//website/path/branch.min_8971778a.js"></script>

 

 

Combo Handler是Yahoo!开发的一个Apache模块,它实现了开发人员简单方便地通过URL来合并JavaScript和CSS文件,从而大大减少文件请求数。 http://www.cnblogs.com/zhengyun_ustc/archive/2012/07/18/combo.html

感谢您的阅读,本文由 饮水机隔壁的小刘 原创提供。Designed by 凹凸实验室 @京东用户体验设计部

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值