找回密码
 立即注册

QQ登录

只需一步,快速开始

断天涯大虾
社区贡献组   /  发表于:2017-3-21 11:37  /   查看:4994  /  回复:0
本帖最后由 断天涯大虾 于 2017-3-21 11:55 编辑

移动端Web页面,即常说的H5页面、手机页面、webview页面等。
手机设备屏幕尺寸不一,这里总结的是针对移动端设备的页面,设计与前端实现怎样做能更好地适配不同屏幕宽度的移动设备。

适配的效果
引用一文章的描述:
在不同尺寸的手机设备上,页面“相对性的达到合理的展示(自适应)”或者“保持统一效果的等比缩放(看起来差不多)”。

概念理解
viewport视口
viewport是严格的等于浏览器的窗口。
获取viewport的尺寸:document. documentElement. clientWidth/Height。
不缩放的视口设置:
  1. <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
复制代码

物理像素(physical pixel)
物理像素又被称为设备像素,他是显示设备中一个最微小的物理部件。每个像素可以根据操作系统设置自己的颜色和亮度。所谓的一倍屏、二倍屏(Retina)、三倍屏,指的是设备以多少物理像素来显示一个CSS像素,也就是说,多倍屏以更多更精细的物理像素点来显示一个CSS像素点,在普通屏幕下1个CSS像素对应1个物理像素,而在Retina屏幕下,1个CSS像素对应的却是4个物理像素。

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

设备像素比dpr(device pixel ratio)
设备像素比简称为dpr,其定义了物理像素和设备独立像素的对应关系。它的值可以按下面的公式计算得到:
设备像素比 = 物理像素 / 设备独立像素
也就是说,二倍屏的dpr是2, 三倍屏是3。

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

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

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

rem(CSS单位)
font size of the root element.
相对于根元素<html>的font-size计算,因此可以通过设置根元素的font-size使得以rem为单位的元素在不同终端上以相对一致的视觉效果呈现。
设 备
设备宽度/pt
根元素font-size/px
宽度/rem
iPhone53201620
iPhone637518.7520
i6 Plus414 20
360 20
根元素fontSize计算公式:Width/fontSize = baseWidth/baseFontSize
其中,baseWidth, baseFontSize是选为基准的设备宽度及其根元素大小。

缺点:
  • 某些Android设备会丢掉 rem 小数部分。


flex布局
vm/vh(view-width, view-height)
视区宽度/高度为100vw/100vh
视区指浏览器内部的可视区域大小:window.innerWidth/Height

upsampling/downsampling
DownSampling: 大图放入比图片尺寸小的容器中时,出现像素分割成就近色
不同scale显示同一图片基本无问题;
同一sacle,不同倍数图,存在色差(Downsampling)

实现方案
设计与前端协作方案:

前端实现方案:淘宝手淘:
  • 动态改写<meta name="viewport">标签
  • 给<html>元素添加data-dpr属性,并且动态改写data-dpr的值
  • 给<html>元素添加font-size属性,并且动态改写font-size的值


各种元素(文本、图片)处理方案参考:

方案说明:
通过一段JS代码根据设备的屏幕宽度、dpr设置根元素的data-dpr和font-size, 这段JS代码要在所有资源加载之前执行,建议做内联处理。
动态设置data-dpr和meta:viewport
  1. // 对iOS设备进行dpr的判断,对于Android系列,始终认为其dpr为1。
  2. if (!dpr && !scale) {
  3.     var isAndroid = win.navigator.appVersion.match(/android/gi);
  4.     var isIPhone = win.navigator.appVersion.match(/iphone/gi);
  5.     var devicePixelRatio = win.devicePixelRatio;
  6.     if (isIPhone) {
  7.         // iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案
  8.         if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {               
  9.             dpr = 3;
  10.         } else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){
  11.             dpr = 2;
  12.         } else {
  13.             dpr = 1;
  14.         }
  15.     } else {
  16.         // 其他设备下,仍旧使用1倍的方案
  17.         dpr = 1;
  18.     }
  19.     scale = 1 / dpr;
  20. }
复制代码
  1. // 动态改写meta:viewport标签
  2. var metaEl = doc.createElement('meta');
  3. var scale = isRetina ? 0.5:1;
  4. metaEl.setAttribute('name', 'viewport');
  5. metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
  6. if (docEl.firstElementChild) {
  7.     document.documentElement.firstElementChild.appendChild(metaEl);
  8. } else {
  9.     var wrap = doc.createElement('div');
  10.     wrap.appendChild(metaEl);
  11.     documen.write(wrap.innerHTML);
  12. }
复制代码
px转rem的计算
  1. // 为了方便单位转换,写一个px转换rem的函数
  2. // 淘宝手淘的方案里,i6(375pt)屏幕宽度为10rem,即font-size=75px, scale=0.5 因设计图为二倍图,$base-font-size=75px
  3. @function px2em($px, $base-font-size: 16px) {
  4.     @if (unitless($px)) {
  5.         @warn "Assuming #{$px} to be in pixels, attempting to convert it into pixels for you";
  6.         @return px2em($px + 0px); // That may fail.
  7.     } @else if (unit($px) == em) {
  8.         @return $px;
  9.     }
  10.     @return ($px / $base-font-size) * 1em;
  11. }
复制代码
  1. // 使用sass的混合宏
  2. @mixin px2rem($property,$px-values,$baseline-px:16px,$support-for-ie:false){
  3.     //Conver the baseline into rems
  4.     $baseline-rem: $baseline-px / 1rem * 1;
  5.     //Print the first line in pixel values
  6.     @if $support-for-ie {
  7.         #{$property}: $px-values;
  8.     }
  9.     //if there is only one (numeric) value, return the property/value line for it.
  10.     @if type-of($px-values) == "number"{
  11.         #{$property}: $px-values / $baseline-rem;
  12.     }
  13.     @else {
  14.         //Create an empty list that we can dump values into
  15.         $rem-values:();
  16.         @each $value in $px-values{
  17.             // If the value is zero or not a number, return it
  18.             @if $value == 0 or type-of($value) != "number"{
  19.                 $rem-values: append($rem-values, $value / $baseline-rem);
  20.             }
  21.         }
  22.         // Return the property and its list of converted values
  23.         #{$property}: $rem-values;
  24.     }
  25. }
复制代码

正文文字
  • 在所有设备大小一样,
  • 在更大的设备可以显示更多文字
  • 不希望出现13px,15px这样的尺寸,而是14px, 16px

  1. .a{
  2.   font-size:12px;
  3. }
  4. [data-dpr="2"] .a{
  5.   font-size: 24px;
  6. }
  7. [data-dpr="3"] .a{
  8.   font-size: 36px;
  9. }
复制代码

为什么要设置viewport和dpr?
适配高密度屏幕手机的px单位,使得不同设备下的px显示一样的长度。
CSS像素和缩放、dpr都有关系:在普通手机上,.a字体设置为12px;
在dpr是2的手机上,[data-dpr="2"].a字体为24px,又因为页面缩放50%,字体为还是12px。
  1. // 不适合用rem适配的字体大小
  2. @mixin font-dpr($font-size){
  3.     font-size: $font-size;

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

  7.     [data-dpr="3"] & {
  8.         font-size: $font-size * 3;
  9.     }
  10. }

  11. // 使用:
  12. @include font-dpr(6px);
复制代码

其他设置根元素fontSize的代码片段
  1. // JS设置viewport和rem, 整个片段也是以i6(750=375*2)为基准,屏幕宽度分为16rem
  2. var fixScreen = function() {
  3.     var metaEl = doc.querySelector('meta[name="viewport"]'),
  4.         metaCtt = metaEl ? metaEl.content : '',
  5.         matchScale = metaCtt.match(/initial\-scale=([\d\.]+)/),
  6.         matchWidth = metaCtt.match(/width=([^,\s]+)/);

  7.     if ( !metaEl ) { // REM
  8.         var docEl = doc.documentElement,
  9.             maxwidth = docEl.dataset.mw || 750, // 每 dpr 最大页面宽度
  10.             dpr = isIos ? Math.min(win.devicePixelRatio, 3) : 1,
  11.             scale = 1 / dpr,
  12.             tid;

  13.         docEl.removeAttribute('data-mw');
  14.         docEl.dataset.dpr = dpr;
  15.         metaEl = doc.createElement('meta');
  16.         metaEl.name = 'viewport';
  17.         metaEl.content = 'initial-scale=' + ratio + ',maximum-scale=' + ratio + ', minimum-scale=' + scale;
  18.         docEl.firstElementChild.appendChild(metaEl);

  19.         var refreshRem = function() {
  20.             var width = docEl.getBoundingClientRect().width;
  21.             if (width / dpr > maxwidth) {
  22.                 width = maxwidth * dpr;
  23.             }
  24.             var rem = width / 16;
  25.             docEl.style.fontSize = rem + 'px';
  26.         };

  27.         //...

  28.         refreshRem();
  29.     }
  30. }
复制代码

小结
  • 对于多倍屏,通过rem为单位,viewport: scale=1/dpr来达到适合的显示;
  • 使用iPhone6(375pt, 750px)二倍设计图:750px为基准;
  • 切图使用三倍精度图,以适应三倍屏
  • css单位综合使用:适配元素rem比例显示,正文字体宜用px+dpr缩放
  • 配合scss函数,简化px2rem转换,且易于维护(若需修改$base-font-size, 无需手动重新计算所有rem单位)



   
关于葡萄城:全球最大的控件提供商,世界领先的企业应用定制工具、企业报表和商业智能解决方案提供商,为超过75%的全球财富500强企业提供服务。

1 个回复

倒序浏览
您需要登录后才可以回帖 登录 | 立即注册
返回顶部