适配不同尺寸的移动端

flex布局

......

rem

使用媒体查询分别给不同尺寸手机的根元素(html)设置初始值大小(font-size属性):

@media screen and (max-width:374px){html{font-size:85.6px}}
@media screen and (min-width:375px) and (max-width:413px){html{font-size:100px}}
@media screen and (min-width:414px) and (max-width:639px){html{font-size:110.7px}}
@media screen and (min-width:640px) and (max-width:719px){html{font-size:170px}}
@media screen and (min-width:720px) and (max-width:749px){html{font-size:192px}}
@media screen and (min-width:750px) and (max-width:799px){html{font-size:200px}}
@media screen and (min-width:800px){html{font-size:213px}}

经过以上设置,页面中的元素大小可以采用rem单位来设置:

line-height: 0.4rem;   /* 即40px*/
font-size: 0.16rem;   /* 即16px*/

 viewport

meta的viewport (视口)标签首先是由苹果公司在其safari浏览器中引入的,目的就是解决移动设备的viewport问题,后来安卓以及各大浏览器厂商也都纷纷效仿,引入对meta viewport的支持。

meta viewport 有6个属性:

width:设置layout viewport 的宽度,为一个正整数,或字符串"width-device";
initial-scale:设置页面的初始缩放比例,为一个数字,可以带小数;
minimum-scale:允许用户的最小缩放值,为一个数字,可以带小数;
maximum-scale:允许用户的最大缩放值,为一个数字,可以带小数;
height:设置layout viewport 的高度,这个属性对我们并不重要,很少使用;
user-scalable:是否允许用户进行缩放,值为"no"或"yes", no 代表不允许,yes代表允许;

设置理想视口:把默认的layout viewport的宽度设为移动设备的屏幕宽度,得到理想视口(ideal viewport):

// 设置理想视口,使得DOM宽度(layout viewport)与屏幕宽度(visual viewport)一样大,DOM文档主宽度即为屏幕宽度,1个CSS像素(1px)由多少设备像素显示由具体设备而不同;
<meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0">

viewport + dpr

动态设置视口缩放为1/dpr,可以解决移动端一像素边框问题!!!

对于安卓,所有设备缩放设为1,对于IOS,根据dpr不同,设置其缩放为dpr倒数,设置页面缩放可以使得1个CSS像素(1px)由1个设备像素来显示,从而提高显示精度;因此,设置1/dpr的缩放视口,可以画出1px的边框;

不管页面中有没有设置viewport,若无,则设置;若有,则改写,设置其scale为1/dpr:

(function (doc, win) {
  var docEl = win.document.documentElement;
  var resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize';
  var metaEl = doc.querySelector('meta[name="viewport"]');
  var dpr = 0;
  var scale = 0;

  // 对iOS设备进行dpr的判断,对于Android系列,始终认为其dpr为1
  if (!dpr && !scale) {
    var isAndroid = win.navigator.appVersion.match(/android/gi);
    var isIPhone = win.navigator.appVersion.match(/[iphone|ipad]/gi);
    var devicePixelRatio = win.devicePixelRatio;

    if(isIPhone) {
      dpr = devicePixelRatio;
    } else {
      drp = 1;
    }
    
    scale = 1 / dpr;
  }

  /**
    * ================================================
    *   设置data-dpr和viewport
    × ================================================
    */

  docEl.setAttribute('data-dpr', dpr);
  // 动态改写meta:viewport标签
  if (!metaEl) {
    metaEl = doc.createElement('meta');
    metaEl.setAttribute('name', 'viewport');
    metaEl.setAttribute('content', 'width=device-width, initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
    document.documentElement.firstElementChild.appendChild(metaEl);
  } else {
    metaEl.setAttribute('content', 'width=device-width, initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
  }

})(document, window);

viewport + rem

rem相对于根元素,rem定义是根元素的font-size,以rem为单位,其数值与px的关系,需相对于根元素<html>的font-size计算,比如设置根元素font-size=16px,则表示1rem=16px;

选取一个设备宽度作为基准,设置其根元素大小,其他设备根据此比例计算其根元素大小,比如使得iphone6根元素font-size=16px;

根元素fontSize公式:width/fontSize = baseWidth/baseFontSize;
其中,baseWidth, baseFontSize是选为基准的设备宽度及其根元素大小,width, fontSize为所求设备的宽度及其根元素大小;

// 以320px的屏幕为基准
const oHtml = document.getElementsByTagName('html')[0]
const width = oHtml.clientWidth;
// 320px的屏幕基准像素为12px
oHtml.style.fontSize = (12 * width / 320) + "px";
/**
  * 以下这段代码是用于根据移动端设备的屏幕分辨率计算出合适的根元素的大小
  * 当设备宽度为375(iPhone6)时,根元素font-size=16px; 依次增大;
  * 限制当为设备宽度大于768(iPad)之后,font-size不再继续增大
  * scale 为meta viewport中的缩放大小
  */
(function (doc, win) {
  var docEl = win.document.documentElement;
  var resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize';
  /**
    * ================================================
    *   设置根元素font-size
    * 当设备宽度为375(iPhone6)时,根元素font-size=16px; 
    × ================================================
    */
  var refreshRem = function () {
    var clientWidth = win.innerWidth
                      || doc.documentElement.clientWidth
                      || doc.body.clientWidth;

    console.log(clientWidth)
    if (!clientWidth) return;
    var fz;
    var width = clientWidth;
    fz = 16 * width / 375;
    docEl.style.fontSize = fz + 'px';
  };

  if (!doc.addEventListener) return;
  win.addEventListener(resizeEvt, refreshRem, false);
  doc.addEventListener('DOMContentLoaded', refreshRem, false);
  refreshRem();

})(document, window);

rem计算

 对于需要使用rem来适配不同屏幕的元素,使用rem来作为CSS单位,为了方便,可以借助sass写一个函数计算px转化为rem,写样式时不必一直手动计算;

/* 
 * 此处 $base-font-size 具体数值根据设计图尺寸而定
 * flexible中设置的标准是【fontSize=16px, when 屏幕宽度=375】,因此,按此标准进行计算,
 * 若设计图为iPhone6(375*667)的二倍稿,则$base-font-size=32px
 *
 */ 
@function px2rem($px, $base-font-size: 32px) {
  @if (unitless($px)) {
    @warn "Assuming #{$px} to be in pixels, attempting to convert it into pixels for you";
    @return px2rem($px + 0px); // That may fail.
  } @else if (unit($px) == rem) {
    @return $px;
  }
  @return ($px / $base-font-size) * 1rem;
}

// 使用,eg:
font-size: px2rem(18px);

适配不同屏幕宽度以及不同dpr,通过动态设置viewport(scale=1/dpr) + 根元素fontSize + rem, 辅助使用vw/vh等来达到适合的显示;

若无需适配可显示1px线条,也可以不动态设置scale,只使用动态设置根元素fontSize + rem + 理想视口;



 

原文:https://www.jianshu.com/p/b13d811a6a76

posted @ 2020-04-11 09:54  seeBetter  阅读(389)  评论(0编辑  收藏  举报