使用 rem dpr 实现移动端的自适应布局应该注意的问题

我们在上一篇  《使用 rem 实现移动端的自适应布局》介绍了如何使用 rem 实现移动端自适应布局的问题,然而在实际项目中还有许多问题需要解决。前端之所以称为前端,就是冲锋陷阵的前方,作品直接对接真实用户,前端产品的质量直接影响用户的体验,也直接体现了整个产品的质量。所以对于前端工程师来说,要把产品做到尽善尽美。

首先看看页面字体问题,根据之前做法,页面中的字体大小可以根据设计稿的大小,通过  px2rem 这个方法得到其相对大小,但是由于我们采用的rem的基准值是屏幕宽度(如 6s 的 375px),这个值比较大,而页面文字的font-size值一般都比较小,计算后的相对值就会很小(如16 / 375 ≈ 0.04266667),这会导致最后显示的字体大小不准确!

其实这个问题可以通过缩小基准值(html 标签的 font-size)得到解决,具体如下(缩小40倍):

var el = document.getElementsByTagName("html")[0];
rem = el.clientWidth / 40;
el.style["fontSize"] = rem + "px";

然后 sass 中设定的基准值也要跟着缩小

$design-doc-width:750px; //视觉稿采用宽度
$base-rem-value:$design-doc-width / 40; // 基准值
@function px2rem($px:0px) {
    @return $px / $base-rem-value * 1rem;
}

然而大多数产品经理并不认同这种做法,他们的需求是无论在任何屏幕大小的设备上,所显示的字体大小都是统一的(都是16px),针对这种需求,对于字体而言,应该使用 px2px 方法:

$design-doc-dpr:2; //视觉稿采用的基准dpr
@function px2px($px:0px) {
    @return round($px / $design-doc-dpr);
}

还有就是 1px 的问题:视觉稿给出的 border-width 为 1px。

使用 rem dpr 实现移动端的自适应布局应该注意的问题_第1张图片

然而我们知道视觉稿的基准宽度是实际设备屏幕宽度的2倍(iphone6s),那么 1px 在 2倍屏中就相当于 0.5 px

使用 rem dpr 实现移动端的自适应布局应该注意的问题_第2张图片

所以,设计师想要的二倍屏下 border: 1px; ,其实就是1物理像素宽,对于css而言,可以认为是 border: 0.5px; ,这是二倍屏下(dpr=2)下能显示的最小单位

.btn{
    border:0.5px solid #555;
}

然而,无奈并不是所有手机浏览器都能识别 border: 0.5px; ,ios7以下,android等其他系统里,0.5px 会被当成为 0px 处理,那么如何实现这 0.5px 呢?

现阶段比较受推崇的方法是通过设置页面的 initial-scale,我们可以通过 window.devicePixelRatio 获得设备的 dpr,然后将页面缩放相应的倍数,如 iPhone6s 的 dpr = 2,那么将页面缩放 2倍后,1px 的宽度就变成了 0.5px,就可以百分百还原视觉稿了。

var dpr = window.devicePixelRatio;
var scale = 1 / dpr;
document.querySelector("meta[name=viewport]").setAttribute(
			'content',
			'width=device-width,initial-scale=' + scale + ', maximum-scale=' + scale + ', user-scalable=no');

如上图,使用缩放处理和未使用缩放处理,差距还是挺明显的,然而,页面的缩放,必然会带来一些问题:

  1. 字体大小会被缩放;
  2. 页面布局会被缩放(如: div的宽高等)
  3. 媒体查询(@media)无法确定

对于字体大小会被缩放的问题,解决的思路是:由于页面缩放的倍数是由 设备的 dpr 决定的,那么我们可以 给根标签设置一个 data-dpr 属性,然后使用属性选择器让其在不同的设备上显示相应大小的字体即可;

/**
 * 给跟标签加上 data-dpr 属性
 */
function setDpr() {
    dpr = window.devicePixelRatio || 1;
	var docEl = document.documentElement;
	docEl.setAttribute('data-dpr', dpr);
}

然后修改一下 px2px 方法,改为 mixin 方式 

$design-doc-dpr:2; //视觉稿采用的基准dpr
@mixin px2px($name, $px:0px) {
    #{$name}: round($px / $design-doc-dpr);
    [data-dpr="2"] & {
        #{$name}: round($px * 2 / $design-doc-dpr);
    }
    // for mx3
    [data-dpr="2.5"] & {
        #{$name}: round($px * 2.5 / $design-doc-dpr);
    }
    // for 小米note
    [data-dpr="2.75"] & {
        #{$name}: round($px * 2.75 / $design-doc-dpr);
    }
    [data-dpr="3"] & {
        #{$name}: round($px * 3 / $design-doc-dpr);
    }
    // for 三星note4
    [data-dpr="4"] & {
        #{$name}: $px * 4 / $design-doc-dpr;
    }
}

@mixin fontSize($px:0px) {
    @include px2px("font-size", $px);
}

这样,就可以实现在不同 dpr 设备字体的一致了,请注意,最后得到文字的 font-size 是不一样的。如下图

使用 rem dpr 实现移动端的自适应布局应该注意的问题_第3张图片使用 rem dpr 实现移动端的自适应布局应该注意的问题_第4张图片

针对页面布局会被缩放问题,只要设置宽度时转为 使用百分比(100vw、100vh)或者 使用 px2rem 函数即可;

针对 媒体查询(@media)无法确定 问题,由于页面缩放后,原来媒体查询限定的max-width、min-width 也会跟着被缩放,所以 @media 的媒体参数是不能写死的,但是可以根据处理字体缩放的问题的思路,针对不同的dpr设备,通过属性选择器为其加载不同的 css 即可:

@mixin mediaQuery($minWidth, $maxWidth) {
    @each $dpr in (1, 2, 2.5, 2.75, 3, 4) {
        @media screen #{if($minWidth,"and (min-width:" + ($minWidth * $dpr) ")","") +             
            if($maxWidth,"and (max-width:" + ($maxWidth * $dpr) + ")","")} {
              [data-dpr="#{$dpr}"] & {
                @content;
            }
        }
    }
}

需要时这样使用:

@include mediaQuery(512px, null) {
        .image {
            float: left;
            width: 50vw;
        }
        .content {
            margin-left: 50vw;
        }
   }

关于移动端布局的适配问题,就写到这里,如有疏忽错漏之处,还请指正,万分感谢!

 

你可能感兴趣的:(前端布局)