金沙棋牌官方平台

当前位置:金沙棋牌 > 金沙棋牌官方平台 > 浅谈前端移动端页面开发,茴字的四种写法

浅谈前端移动端页面开发,茴字的四种写法

来源:http://www.logblo.com 作者:金沙棋牌 时间:2019-11-21 10:11

茴字的四种写法——浅谈移动前端适配

2018/04/16 · 基础技术 · 移动端

原文出处: tomc   

话说我刚工作的时候,就开始用rem了,过了没多久,接触到了flexible,系统化且支持iOS的retina屏迅速征服了我,最近又看到了大漠大神的vw。所以本文想完成一篇一站式的文章,可以系统的了解前端适配的演进。闲话少叙,马上开始。

web屏幕适配(一):https://segmentfault.com/a/1190000004524243
web屏幕适配(二):https://segmentfault.com/a/1190000004538413
前端乱炖:http://www.html-js.com/article/Mobile-terminal-H5-mobile-terminal-HD-multi-screen-adaptation-scheme%203041

前言的一些碎碎念:最近一直在写移动端的页面,不过一直是用的别人造好的轮子,很多时候并没有想那是为什么,那是怎么样要那么写,就跟着别人的文档去了。本以为自己对移动端的那一丢丢理解,结果很多东西都特么有问题,所以,今天停下了手中的一些东西,来谈下移动端的布局方案吧

浅谈前端移动端页面开发(布局篇)

时间:2015-05-27 编辑:observernote 来源:本站整理

 

前言的一些碎碎念:最近一直在写移动端的页面,不过一直是用的别人造好的轮子,很多时候并没有想那是为什么,那是怎么样要那么写,就跟着别人的文档去了。本以为自己对移动端的那一丢丢理解,结果很多东西都特么有问题,所以,今天停下了手中的一些东西,来谈下移动端的布局方案吧

内容有些长,这也是我第一次写博客,不足之处还请严厉指出

1. 什么是前端适配

从UI展现层面上:
我们期望不同尺寸的设备,页面可以自适应的展示或者进行等比缩放,从而在不同的尺寸的设备下看起来协调或者差不多

从代码实现层面上:
我们希望前端适配可以用用尽可能简洁的代码来实现。最好一套代码实现兼容所有设备,而不是对每个或每种设备都写一套方案,不是次次都选用最无奈的方案(Android和iOS分开编写)。

核心:

一、利用rem来处理尺寸(width、height、margin、padding等)。
二、物理像素border的实现,viewport、物理像素、css像素概念。
三、vw、vh、vmin、vmax、% (vw不兼容安卓4.3以下浏览器)。
四、一物理像素border实现两种方法:
(1)整个页面缩放,viewport 设置 scale
(2)单个元素缩放,transform scale
五、术语概念:

* 物理像素:买手机的时候会有一个 nm 的分辨率,那是屏幕的nm个呈像的点,一个点(小方格)为一个物理像素。它是屏幕能显示的最小粒度

* CSS像素:就是CSS里的Px,上面已经讲了是viewport中的一个小方格。

* 

像素密度:即dpi或ppi,屏幕每英寸所占的物理像素点。

dpi:设备像素比。

viewport:屏幕的视口宽高,在css中,1px是指viewport中的一个小方格,而viewport的宽度是可以任意设置的。有两个,一个实际窗口,一个虚拟窗口。
* device-width:设备宽度。

而CSS像素与物理像素之间是有一个转换关系的。即是:
六、device-width:device-width的宽度值单位是CSS像素。
当viewport设置为device-width时,此时它是手机横向分辨率 / 转换系数。即:

七、viewport设置:


(1)头部信息设置:虚拟窗口;模仿实际的窗口;还有个缩放;
<meta charset="UTF-8" name="viewport" content="width=device-width,
initial-scale=1.0,maximum-scale=1.0, user-scalable=no"/>


(2)js部分设置:

<script>
//适应移动设备和pc设备屏幕的文档默认字体设置;
var dpr = window.devicePixelRatio;
document.documentElement.style.fontSize = dpr*window.innerWidth / 10 + 'px'; var meta = document.querySelector('meta');
meta.setAttribute('content', 'initial-scale=' + 1/dpr + ', ' +
'maximum-scale=' + 1/dpr + ', minimum-scale=' + 1/dpr + ', user-scalable=no');
</script>


1.移动端适配的是什么?
我们讨论的是网页适配多种尺寸屏幕,让网页效果看起来和设计师的设计稿一样。
说白了就是同一套代码在不同分辨率的手机上跑时,页面元素间的间距,留白,以及图片大小会随着变化,在比例上跟设计稿一致。

结论:明白了,所以padding,margin,图片等的大小基本都要做适配

2.那有什么方法可以做到这种适配?
关键要找到一种长度单位,使得一样的取值,在不同尺寸的屏幕上的大小按比例缩放。
1.网页在viewport中布局,viewport被分成一个个小方块,一个CSS像素占一个方块;
2.在设置了viewport宽度等于设备宽度的情况下,通过某种算法,在不同大小的屏幕上,1个CSS像素所占屏幕的物理尺寸是一样大的既然1个CSS像素在不同屏幕上物理尺寸一样大,那px肯定不能做为适配的方法了 ;
结论:
(1)长度单位rem是相对于html标签的font-size来计算的。例如html标签设置font-size:36px,同时div设置width:1.2rem。那么这个div的宽度就是1.2rem=36px*1.2=43.2px
(2)奥秘就在于结合px的固定尺寸和rem的相对尺寸!

3.适配具体执行方案(阿里flexible):

1. 设置viewport为设备宽度(这里不一定,但目前先这样足矣);

2. 将viewport分成10rem,并计算出1rem在当前浏览器的像素值,把它赋予html标签的font-size(分成10rem只是为了方便计算而已);

3. 写CSS代码时,遇到要适配的地方,比如width,margin,padding等,就不要再用px了,改成用rem;

JS和Html代码如下:
<!DOCTYPE html><html lang="zh-cn">

<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, height=device-height">
<title>啃先生的网</title>

<script type="text/javascript">
    var cssEl = document.createElement('style');
    document.documentElement.firstElementChild.appendChild(cssEl);

    function setPxPerRem(){
        var dpr = 1;
        //把viewport分成10份的rem,html标签的font-size设置为1rem的大小;
        var pxPerRem = document.documentElement.clientWidth * dpr / 10;
        cssEl.innerHTML = 'html{font-size:' + pxPerRem + 'px!important;}';
    }
    setPxPerRem();
</script></head><body>

</body></html>
CSS代码做了类似如下的修改:

运行结果如下:边距和头像图片都随屏幕变化而变化了260400的屏幕、 380400的屏幕;

对精益求精的项目,有以下问题:
1.图1的屏幕的尺寸较小,因此头像应该小些,话题左边的空白也应该小一些。
2.图片应该保持正方形,而且两张图之间的边距应该随屏幕变化而变化
结论:所以padding,margin,图片等的大小基本都要做适配

4.px与rem之间的单位换算 例如:
现有设计师提供宽度为400px的设计稿,其中某个图片的宽度设计为20px,那么,CSS的写法就是img{width: 0.5rem;},怎么得出这个结果的呢?

1. 设计稿的宽度视同手机宽度,即假设有一个viewport为400px的手机

2. 将它分成10rem,每个rem为40px;

3. 

那么图片宽度20px自然就是0.5rem;

5.手动换算太麻烦怎么办:编辑器插件;
6.参考链接:
1. 使用Flexible实现手淘H5页面的终端适配(https://github.com/amfe/article/issues/17)

2. 移动端高清、多屏适配方案(http://www.html-js.com/article/Mobile-terminal-H5-mobile-terminal-HD-multi-screen-adaptation-scheme%203041)

3. A tale of two viewports(http://www.quirksmode.org/mobile/viewports.html)

内容有些长,这也是我第一次写博客,不足之处还请严厉指出

一. viewport

什么是viewport

 

简单来讲,viewport就是浏览器上,用来显示网页的那一部分区域了,也就是说,浏览器的实际宽度,是和我们手机的宽度不一样的,无论你的手机宽度是320px,还是640px,在手机浏览器内部的宽度,始终会是浏览器本身的viewport。如今的浏览器,都会给自己的本身提供一个viewport的默认值,可能是980px,或者是其他值。就以手机来说吧,目前,新版本的手机浏览器,绝大部分是以980px作为默认的viewport值的。我这里对新版本的不同平台下的浏览器做了测试,经过测试,iphone下的默认viewport为980px,安卓下的浏览器,目前主流的最新浏览器(比如chrome,还有很多国产的像qq,uc)的viewport也是980px了。

 

viewport是用来干什么的

 

viewport的默认值,一般来说是大于手机屏幕的。这样就可以做到当我们在浏览桌面端网页的时候,可以让桌面端端网页正常显示(我们普通页面设计的时候,一般页面的主区域是以960px来做的,所以980px这个值,可以做到桌面端网页的正常显示)。但是,其实我们手机的屏幕宽度是没有960px的,因此浏览器会出现横向滚动条。同时,即使是基于980的viewport,我们在移动端浏览我们的桌面页面的体验其实也并不好,所以,一般的,我们会专门给浏览器设计一个移动端的页面。

 

对viewport的控制

 

如今可以绝大部分浏览器里(即主流的安卓浏览器和ios),都支持对viewport的一个控制了。一般的,我们会这么写。

 

viewport默认有6个属性

 

  1. width: 设置viewport的宽度(即之前所提及到的,浏览器的宽度详),这里可以为一个整数,又或者是字符串"width-device"
  2. initial-scale: 页面初始的缩放值,为数字,可以是小数
  3. minimum-scale: 允许用户的最小缩放值,为数字,可以是小数
  4. maximum-scale: 允许用户的最大缩放值,为数字,可以是小数
  5. height: 设置viewport的高度(我们一般而言并不能用到)
  6. user-scalable: 是否允许用户进行缩放,'no'为不允许,'yes'为允许

我们把这个标签是在head里面,像这样

<meta name="viewport" content="initial-scale=1">

这样就可以做到对viewport的控制了

2. 关键字

如果你了解这些关键字,那么这段大可以跳过,如果后面遇到了问题,感觉有些疑惑,也可以再回来查阅。

一. viewport

二. 关于我们的设备

 

三个需要了解的概念:

 

PPI: 可以理解为屏幕的显示密度

DPR: 设备物理像素和逻辑像素的对应关系,即物理像素/逻辑像素

Resolution: 就是我们常说的分辨率

 

物理像素与逻辑像素

 

看了我们上面内容一的第一点之后,或许有些人会有些疑问,我的安卓手机,或者iphone6plus(目前应该仅限于这一款机型吧),买回来的是1920x1080的或者其他更高的,比我之前所谓的那个viewport默认的980px要大。

 

这样的问题,也就是我之前所说的物理像素与逻辑像素的关系了(即DPR)。以1920x1080为例,1080为物理像素,而我们在viewport中,获取到的,比如"width-device",是逻辑像素。所以之前viewport的默认值,所比对的大小,其实是逻辑像素的大小,而非物理像素的大小。

 

以iphone6为例,在不做任何缩放的条件下,iphone6的获取到的'width-device'为375px,为屏幕的逻辑像素。而购买时我们所知的750px,则为屏幕的物理像素。

 

CSS的问题

 

有了上面第二点的一些基础,还是以iphone6为例,我们可以知道,其实我们所写的1px,在iphone6上为2px的物理像素。所以,最后的,给出一个结论。就是我们写的1px,在移动端,是逻辑像素的1px,而非物理像素的1px。

 

2.1 Viewport/视口

通俗的讲,移动设备上的viewport就是设备的屏幕上能用来显示我们的网页的那一块区域[1],但不一定是我们可见的区域。具体来说,分为以下三种。

什么是viewport

三. 使用rem布局

简单说下rem

rem是根据页面的根元素的font-size的一个相对的单位,即

html{

font-size: 16px;

}

比如当我们在一个div中,如此写

div{

width: 2rem;

}

那么我们的width,是16*2 = 32px

 

rem做到适配不同分辨率

这个是现在手机淘宝的移动端的解决方案,即使用rem的特性,来对页面进行布局。

 

下面举一个例子

 

假定设计稿的大小为750,那么我们则将整个图分成100份来看(下面的题外话会说明为什么会分成100份来看)

 

那么,我们现在就让根部元素的font-size为75px

html{

font-size: 75px;

}

那么,我们现在就可以比对设计稿,比如设计稿中,有一个div元素,宽度,高度都为75px,那么我们这样写即可

div{

height: 1rem;

width: 1rem;

}

可能看到这里,一些人还是不明白怎么用rem做到适配不同的分辨率,那么我们再来

 

现在,我们换设备了,不用这个设备是一个width为640的手机

那么这个时候,我们的rem单位就起到作用了。

 

我们的rem全是根据html的font-size来改变的,所以说,这个时候,我们只需要把html下的font-size改成64px。那么,我们之前的div,因为是根据html下的font-size动态变化的,那么。此时也就变成了宽度和高度都为64px的东西了。这样,就可以做到适配不同的屏幕分辨率了。(其实就是个等比缩放)

 

总结一下,我们的解决方案,其实就是 设计稿的像素/html的font-size = 用来代替px的rem。

这一个步骤,我们需要通过JS来进行操作。

对于js的操作在下面会提到。

DPR的问题

视觉姐姐给了我们设计稿,并交由我们实现,那么,我们应该去认真的实现:-)(试想你做了一张图,而前端很多地方并没有按照你所想的,你所给的去做,而是私自改变了很多东西,你肯定会不高兴的)

那么1px会出现什么问题呢。

还记得我们第二大点讲的,我们的设备,是有物理像素和逻辑像素的。而假设我们的设计稿是750的,同时还是以iphone6为例,此时如果我们的viewport是这样的

<meta name="viewport" content="initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">

之前说过,在不做任何缩放的条件下,iphone6获取到的viewport为375px。

然后我们的页面中有个div,他有一个边框值,如下

div{

height: 5rem;

widht:5rem;

border: 1px solid #000

}

此时我们写的1px,实际上是逻辑像素,而我们在iphone6上看到的是物理像素,于是这个时候,我们眼睛所看到的其实是2px(参考第二点第三个问题)

所以此时我们需要在viewport上做文章了,此时先明确,如果要获取到真正的1px,那么我们需要这么做,将viewport改为

<meta name="viewport" content="initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no">

即对屏幕做0.5倍的缩放。这样,我们就能得到实际的1px。

所以到这里,我们还要明确一点,viewport的meta标签,我们这里也只能通过js来动态生成。

同时,这样写,据说还可以避免比如inline的SVG等元素按照逻辑像素的渲染。避免了整个页面清晰度的打折(其实我并不能看出来)

文字适配问题

最近深深纠结与rem与px做字体单位的问题,还是先分别谈下二者吧。

rem与px的特点:

 

以rem作为字体单位:我们可以让页面整体的文字,也跟随着html的font-size来进行改变,这样,在不同的屏幕下,可以做到文字相对屏幕的比例是一样的。

 

 

以px作为字体单位: 这个是目前很多网站还是依然采用的方法。因为以上面所写的,以rem作为字体单位。无论在任何屏幕下面,我们的文字都会根据屏幕做一个适应。试想这样一个场景。你买了一个大屏手机(5.7寸的),而别人用的是4寸的手机。以rem作为字体单位的话,那大屏手机看到的文字多少和小屏手机确实一样的了。这样来做,其实并不符合我们买大屏手机的期待。同时,以rem作为字体单位,可能会导致出现很多奇怪的字体大小(毕竟是根据html的font-size动态变化的嘛),同时这其中还涉及到了一个点阵尺寸的概念,这个在下面来讲。

 

字体大小引发的系列问题:

 

字体大小:我们平时也看过,很多网站,是不以奇数作为字体大小的。我稍微查了些东西,在知乎上的现在网页设计中的为什么少有人用 11px、13px、15px 等奇数的字体?问题下,有一些比较好的解答,我就不再多说(我也并不能比这个问题说的更多),总的来说,其实就是偶数宽度的字体能够显得均衡,以及一个点阵的问题。不过因为要谈及点阵,所以我拿上面回答中的一个内容举例。

 

倘若一个字体,只提供了12px,14px,16px的点阵。那么当你写13px,15px,17px的时候。就并没有其字体大小所对应的点阵。那么这样就造成了一个问题。他们会使用其相邻的点阵,比如对应使用了12px,14px,16px的点阵,而导致一个问题,文字占用的大小确实改变,但点阵却并没有改变。

文字适配的解决方案:

上面说了这么多,我们总要有一套解决方案吧

对于一些标题性的文字,我们依然可以用rem。让他随着屏幕来进行缩放,因为标题性文字一般较大,而较大的文字,点阵对其影响就越小。这样,即使出现奇怪的尺寸,也能够让字体得到很好的渲染。

对于一些正文内容的文字(即站在使用者的角度,你不希望他进行缩放的文字)。我们采用px来进行处理。

2.1.1 Visual Viewport

Visual Viewport: 可见视口。就是移动设备上可以被我们看见的部分。宽度在移动端通过window.innerWidth获得(仅限移动端,PC上哪怕是chrome模拟也会有不同的结果)。

图片 1

简单来讲,viewport就是浏览器上,用来显示网页的那一部分区域了,也就是说,浏览器的实际宽度,是和我们手机的宽度不一样的,无论你的手机宽度是320px,还是640px,在手机浏览器内部的宽度,始终会是浏览器本身的viewport。如今的浏览器,都会给自己的本身提供一个viewport的默认值,可能是980px,或者是其他值。就以手机来说吧,目前,新版本的手机浏览器,绝大部分是以980px作为默认的viewport值的。我这里对新版本的不同平台下的浏览器做了测试,经过测试,iphone下的默认viewport为980px,安卓下的浏览器,目前主流的最新浏览器(比如chrome,还有很多国产的像qq,uc)的viewport也是980px了。

四.安卓与ios不得不说的问题(解决篇)

 

在 三.使用rem布局 里面,我们给出了各种情况的解决方案,并且,在我举例的时候,热衷于使用iphone来举例,但其实,上面的所有问题,不是仅仅iphone会出现的问题,安卓也是一样。但是,如果你已经看完了上面,那么这里,才是真正给出我们解决方案的地方,并且,这个解决方案并不完善。

 

 

谈谈iphone的r屏与安卓的各种屏

 

rem布局也好,用viewport进行缩放也罢,文字的适配问题也是,都是基于我们想对各个不同的设备所进行的匹配。这套方案很好,然而也有其兼顾不到的地方。即安卓和ios的屏幕的一些问题,当然,细的东西我们不谈,我们只谈dpr。

 

 

先谈iphone

 

其实iphone为开发者考虑到了很多东西,为了让开发者便于开发,在6plus出现之前,iphone的dpr始终也就是2(即前面所谈的物理像素/逻辑像素=2),即使是6plus出现了,iphone到底其实也就只有2,3这两个dpr。我们很容易对其做到兼顾。

 

再谈安卓

 

安卓并没有对自己的屏幕叫做r屏,但是其原理和iphone的r屏可以说是一样。r屏做的是什么,把两个(三个)物理像素,丢到了一个逻辑像素里面,让屏幕展现的更清晰(当然,这是我片面的理解,不过我觉得大体来说并没有错,我们也不用去深入探讨r屏还有什么东西,我也并不懂)。而安卓也是一样,他也同样把n个物理像素丢到了一个逻辑像素里面。而这里的n,也就是dpr值(所以当我看到好多人问安卓为什么不采用r屏的时候,我真的也是……醉了?)。而安卓的dpr值,并不像iphone那样,就只有两个值。安卓的dpr是千奇百怪的,可能是1.5,2,3,4,2.5等等的都有。(甚至我还看到了1.7之类的,安卓的各个设备商,玩的真尼玛high啊。怎么高兴怎么来。)

 

所以,对安卓的屏幕的dpr的处理,其实是很头疼的,因为,他和我们对字体的处理,有了很大的冲突。这个在下面提及

首先看看手淘的解决方案

 

rem布局

 

用js获取到页面的宽度,然后对其进行宽度/10的处理,再将其写到html的font-size中。手淘的flexible.js里面的这一部分,并为了方便看懂做了些改写。大体就是这样的

 

function refreshRem(){

  var docEl = window.document.documentElement;

    var width = docEl.documentElement.getBoundingClientRect().width;

 

    var rootSize = width/10;

    docEl.style.fontSize = rootSize + 'px';

}

 

dpr的配置

 

首先,在引入flexible.js之前,我们可以对dpr进行手动的配置,即使用自定义的meta标签来配置dpr(看清楚是flexible,而非viewport)

 

<meta name="flexible" content="initial-dpr=2,maximum-dpr=3" />

 

iniital-dpr是把dpr强制设定为给定的值,而maximum-dpr则是给出一个最大的dpr限制,然后对其和系统的dpr做一个比较。

 

 

然后依然为了方便阅读我把flexble.js这一部分的代码抽象出来,

 

    var doc = window.document

    var metaEl = doc.querySelector('meta[name="viewport"]');

var flexibleEl = doc.querySelector('meta[name="flexible"]');

var dpr = 0;

var scale = 0; //缩放比例

//在meta标签中,已经有了viewport,则使用已有的viewport,并根据meta标签,对dpr进行设置

if (metaEl) {

console.warn('将根据已有的meta标签来设置缩放比例');

var match = metaEl.getAttribute('content').match(/initial-scale=([d.]+)/);

if (match) {

scale = parseFloat(match[1]);

dpr = parseInt(1 / scale);

}

//如果在meta标签中,我们手动配置了flexible,则使用里面的内容

} else if (flexibleEl) {

var content = flexibleEl.getAttribute('content');

if (content) {

var initialDpr = content.match(/initial-dpr=([d.]+)/);

var maximumDpr = content.match(/maximum-dpr=([d.]+)/);

if (initialDpr) {

     dpr = parseFloat(initialDpr[1]);

     scale = parseFloat((1 / dpr).toFixed(2));    

}

 

if (maximumDpr) {
dpr = parseFloat(maximumDpr[1]);
scale = parseFloat((1 / dpr).toFixed(2));
}
}
}

 

这样,我们通过flexible的分析与获取,对dpr进行了书写。不过其实这里,是有个问题的。即在书写maximum的的情况下,其实根本没有像文档中给我们的说法一样,做一个比较,而是做了和initialDpr一样的一个处理。不过这里也不对其做一个探讨了。

 

然后,这套解决方案,然后当我们在meta标签里面并没有对viewport以及flexible两个的任意一个进行书写的时候,他也是会自动获取一个dpr值的

 

if (!dpr && !scale) {

var isAndroid = window.navigator.appVersion.match(/android/gi);

var isIPhone = window.navigator.appVersion.match(/iphone/gi);、

//devicePixelRatio这个属性是可以获取到设备的dpr的

var devicePixelRatio = win.devicePixelRatio;

if (isIPhone) {

// iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案

if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {                

     dpr = 3;

} else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){

     dpr = 2;

} else {

     dpr = 1;

}

} else {

// 其他设备下,仍旧使用1倍的方案

dpr = 1;

}

scale = 1 / dpr;

}

 

这里我们可以看到,手机淘宝并没有对安卓的dpr进行一个适配,原因之后再讲。

 

然后到了这里,我们获取到了我们需要的dpr值,并根据dpr值获取到了我们所需要的缩放值(即scale)

 

然后我们要做的,就是在并没有viewport的meta标签对情况下自己动态将这个标签写进我们的header,形式是这样的

 

<meta name="viewport" content="initial-scale=scale, maximum-scale=scale, minimum-scale=scale, user-scalable=no">

 

这样,dpr的配置,也就完成了,当然,安卓设备并没有对dpr进行一个配置(上面的动态生成就不给出js了)

 

 

文字的解决方案

 

由于手淘暂时并没有对安卓做一个处理,所以,这里,只是对iphone做了一个处理

 

即在html上,加入了一个自定义属性,data-dpr。

 

<html data-dpr='dpr'></html>

 

还是以750的设计稿为例(即iphone6)

 

假如设计稿上某a标签是32px,那么,我们要这么写

 

a{

font-size: 16px

}

/*iphone6*/

[data-dpr='2'] a{

font-size: 32px

}

/*iphone6plus*/

[data-dpr='3'] a{

font-size: 32px

}

 

 

现在的一些问题

 

正如我们看到的,手淘目前的方案里面,是没有考虑到安卓dpr的问题的。即,这套方案,只对于iphone的r屏做了一个处理,而对于安卓,并没有做dpr的处理。我们来分析下原因吧(个人拙见)。

 

我们希望字体能够以px来展现,同时,我们也希望我们的东西能对dpr做一个适配。对于ios,这自然是可行的,即采用了data-dpr的自定义属性来调整文字。4到6写一套字体大小,6p写一套字体大小,然后在对dpr为1的屏幕写一套字体大小。其实这种写法还是很恶心,不过基于对dpr的适配,这样写也算是个解决方案了。

 

不过同样的解决方案到安卓就不行了,安卓的dpr有时候会很乱(比如现在在goole的手机测试里面可以看到,安卓的dpr,lg的某些设备还采用了1.7那样的奇怪dpr)。而当1.7dpr这种不规范的数字出现的时候,我们就不能采用之前的解决方案了,比如

 

[data-dpr='1.7'] a{

font-size: 25px

}

 

这样的东西是不可能去写的,那万一还有2.25,2.5之类的呢?我们都要拿去匹配么?

 

其实现在,因为我们通过devicePixelRatio可以获取到安卓的dpr值,即可以做到对安卓设备的dpr一个匹配。但是,文字如果采用px的话,确实是很难做到匹配的。

 

即总结一下,就是说,对于安卓的dpr匹配,目前来说,是没有什么问题的,但是,对于dpr匹配之后的字体,那肯定是有问题的。

 

常见的dpr下的字体,我们依然可以解决,但是不常见的dpr,我们确实很难做到对dpr的解决。那如何解决这些问题呢。目前以我本人这个不太灵光的脑袋,确实也不晓得该如何进行一个处理了,起码做不到很好的解决。

 

不过,还是丢上些个人的观点吧。

 

在之前的对dpr的判断中,是根据了设备进行判断,即安卓不对dpr进行改变,仅对ios的设备进行改变。那么,我们其实可不可以以dpr的值来做一个处理呢?即像这样写

 

if (!dpr && !scale) {

//devicePixelRatio这个属性是可以获取到设备的dpr的

var devicePixelRatio = win.devicePixelRatio;

//判断dpr是否为整数

var isRegularDpr = devicePixelRatio.toString().match(/^[1-9]d*$/g)

if (isRegularDpr) {

// 对于是整数的dpr,对dpr进行操作

  if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {                

     dpr = 3;

} else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){

     dpr = 2;

} else {

     dpr = 1;

}

} else {

// 对于其他的dpr,人采用dpr为1的方案

dpr = 1;

}

scale = 1 / dpr;

}

 

我们对这里做了一点点修改,即来判断dpr是否是规则的,也就是是否是我们常见的1,2,3等,然后,我们只对规则的dpr,来进行一个字体的处理。这样,iphone依然还是用之前的匹配方案。而其实目前安卓,很多的设备还是比较常见的dpr了,所以我们这里,将之前对设备的判断,转变成对dpr是否是整数的一个判断。其他地方不变,可以解决对安卓dpr的部分匹配。

 

同样,开发的时候,如果并不在乎字体的问题的话,大可以直接使用rem。那样是可以做到dpr和文字都适配的问题。不过正如我们讲到字体的时候所说的,使用rem是很多用户不希望的(大屏机还是和小屏机看到一样多的内容),同时,还有点阵的问题。

 

好,东西写到这里,也将近到了尾声。第一次写这么长的东西,感觉好累啊=_=。嗯还有篇2000字的检讨要写,默默匿了去写检讨了。

 

2.2.2 Layout Viewport

Layout Viewport: 布局视口。

图片 2

如果把PC上的页面放到移动端,以iphone8为例,如果只展示为可见视口的宽度(375px),那么页面会被压缩的特别窄而显示错乱,所以移动浏览器就决定默认情况下把viewport设为一个较宽的值,比如980px,这样的话即使是那些为桌面设计的网站也能在移动浏览器上正常显示了。[1]

而事实上,我们一般看不到如上图这样出现横向滚动条的界面;在手机上访问页面时,往往是下图的样子:图片 3

这是由于页面body宽度设置了100%而没有指定一个具体的宽度导致的,从而使页面被等比缩放了。由于用户可以缩放,所以还算能正常浏览。

viewport是用来干什么的

参考

手机淘宝的flexible设计与实现

2.2.3 Ideal Viewport

Ideal Viewport:理想视口,其实就是设备的可见区域,和可见视口一致。

设置Ideal Viewport的好处是,只要按照Ideal Viewport来设计样式稿,用户就不用能最完美的查看网站的内容——既不用左右滑动,也不用放大缩小。

设置理想视口:

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"/>

1
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"/>

这段代码的意思是将布局视口的宽度设置为设备宽度,初始缩放比例为1,最大缩放比例为1,用户不能缩放。

viewport的默认值,一般来说是大于手机屏幕的。这样就可以做到当我们在浏览桌面端网页的时候,可以让桌面端端网页正常显示(我们普通页面设计的时候,一般页面的主区域是以960px来做的,所以980px这个值,可以做到桌面端网页的正常显示)。但是,其实我们手机的屏幕宽度是没有960px的,因此浏览器会出现横向滚动条。同时,即使是基于980的viewport,我们在移动端浏览我们的桌面页面的体验其实也并不好,所以,一般的,我们会专门给浏览器设计一个移动端的页面。

题外话:

 

iphone6plus很有趣的地方

 

iphone6plus照理来说的,其实际dpr是2.87左右的,不过,为了方便开发者来开发,iphone6plus对其做了一个调整,将dpr调整为3,然后在对屏幕进行了一个缩放。这样做,自然是方便了开发者前去开发,然而,这样做,也有了一些性能上的损失。(iphone为开发者考虑的还是挺周全的,看看隔壁安卓,dpr怎么爽怎么来,都特么自己玩自己的)

 

 

有意思的vh和vw

 

vh,vw目前还存在很大程度的兼容性问题,所以还并没有采用。

 

vh,vw有什么特点呢

 

这两个元素分别会把屏幕上的可视高度(说通俗点就是你手机屏幕那个框框头装起的东西),宽度,分成100份来看,比如先前我们用rem来处理的地方,我们需要在html元素下写上font-size: 75px,然后再在div下写上width:1rem。而有了vh,vw之后,我们如此处理html的font-size就好。

 

html {

font-size: 10vw;

}

 

这样写,省去了一部js操作的步骤。

 

2.2 像素

对viewport的控制

2.2.1 物理像素

物理像素:一个物理像素是显示器(手机屏幕)上最小的物理显示单元,在操作系统的调度下,每一个设备像素都有自己的颜色值和亮度值。[2]

如今可以绝大部分浏览器里(即主流的安卓浏览器和ios),都支持对viewport的一个控制了。一般的,我们会这么写。

2.2.2 设备独立像素

设备独立像素:又称为CSS像素,就是我们日常代码中使用的像素。浏览器内的一切长度都是以CSS像素为单位的,CSS像素的单位是px。

viewport默认有6个属性

2.2.3 设备像素比

设备像素比(简称dpr)定义了物理像素和设备独立像素的对应关系。比如说对于iOS的retina屏,一个设备独立像素就对应着4个物理像素。这样的设计可以使画面更加清晰锐利,如下图:
图片 4

width: 设置viewport的宽度(即之前所提及到的,浏览器的宽度详),这里可以为一个整数,又或者是字符串"width-device"

3. 业界的解决方案

OK,LongLongAgo的前缀之后,终于到了正题。回到我们最开始的初心:我们只是想要通过一套代码,实现一个可以在不同页面尺寸上展示差不多的页面。在这一块,现在主要有三种方案。

initial-scale: 页面初始的缩放值,为数字,可以是小数

3.1 Rem的解决方案

DPR一致时,px在不同的屏幕尺寸上会展示为定宽,这就导致我们的页面可能会出现滚动条或者占不满的情况。而通过rem来设置div的宽高,可以保证页面可以通过调整html的font-size来整体放大或者缩小,从而达到不管屏幕宽度是多少,页面都能完美展示的效果。

例如,针对750*1334的设计稿:

<meta name="viewport" content="initial-scale=1,maximum-scale=1, minimum-scale=1"> <script> document.documentElement.style.fontSize = window.innerWidth / 7.5 + 'px'; </script>

1
2
3
4
<meta name="viewport" content="initial-scale=1,maximum-scale=1, minimum-scale=1">
<script>
    document.documentElement.style.fontSize = window.innerWidth / 7.5 + 'px';
</script>

这样,所有的设备的宽度都是7.5rem,只需要把设计稿上的px值统一除以100,就可以得到相应的rem值了。

网易也采用的这种方法。

minimum-scale: 允许用户的最小缩放值,为数字,可以是小数

3.2 Flexible.js

Flexible是阿里团队开发的前端适配方案,也是用的rem的方法。那么第一种方法其实已经能解决前端适配问题了,为什么阿里还要开发一个Flexible呢?

在第一种方法中,dpr=1时没有任何问题,但是在dpr=2或者更高的手机屏幕上,因为物理像素的增加,存在小于1px的显示空间。如果采用第一种方法,因为它统一对scale设置为1,那么我们假如想要实现0.5px, 就只能通过transform的方式。如果有多个这样的样式,代码就会变得很麻烦。

.scale{ position: relative; } .scale:after{ content:""; position: absolute; bottom:0px; left:0px; right:0px; border-bottom:1px solid #ddd; -webkit-transform:scaleY(.5); -webkit-transform-origin:0 0; }

1
2
3
4
5
6
7
8
9
10
11
12
13
.scale{
    position: relative;
}
.scale:after{
    content:"";
    position: absolute;
    bottom:0px;
    left:0px;
    right:0px;
    border-bottom:1px solid #ddd;
    -webkit-transform:scaleY(.5);
    -webkit-transform-origin:0 0;
}

因此,阿里的flexible方案充分考虑了这种情况,动态的设置了fontsize和scale, 从而使得CSS中的1px等于物理像素中的1px,在IOS下得到最清晰的体验。

if (!dpr && !scale) { var isAndroid = win.navigator.appVersion.match(/android/gi); var isIPhone = win.navigator.appVersion.match(/iphone/gi); var devicePixelRatio = win.devicePixelRatio; if (isIPhone) { // iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案 if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) { dpr = 3; } else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){ dpr = 2; } else { dpr = 1; } } else { // 其他设备下,仍旧使用1倍的方案 dpr = 1; } scale = 1 / dpr; } 最终在iphone8下页面的header被设置为: <meta name="viewport" content="initial-scale=0.5,maximum-scale=0.5,minimum-scale=0.5,user-scalable=no">

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
if (!dpr && !scale) {
    var isAndroid = win.navigator.appVersion.match(/android/gi);
    var isIPhone = win.navigator.appVersion.match(/iphone/gi);
    var devicePixelRatio = win.devicePixelRatio;
    if (isIPhone) {
        // iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案
        if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {                
            dpr = 3;
        } else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){
            dpr = 2;
        } else {
            dpr = 1;
        }
    } else {
        // 其他设备下,仍旧使用1倍的方案
        dpr = 1;
    }
    scale = 1 / dpr;
}
 
最终在iphone8下页面的header被设置为:
<meta name="viewport" content="initial-scale=0.5,maximum-scale=0.5,minimum-scale=0.5,user-scalable=no">

具体的大家可以看《使用Flexible实现手淘H5页面的终端适配》

另外需要指出的一点是:Flexible将页面分成了100份,页面的宽度是10rem,对于750的设计稿,我们需要用相应的px数除以75来得到。手动计算是愚蠢的,不同的编译器都可以下载pix2rem插件(可以直接写px然后自动转换为相应的rem值),直接使用sass或者postcss打包也能达到同样的功能。

总结一下上面两种rem方法,主要思想为:

  • 根据dpr的值来修改html的font-size,从而使用rem实现等比缩放
  • 根据dpr的值来修改viewport实现1px的线

但是Flexible也有它的局限性,具体表现为:

  • 不能与响应式布局兼容
  • 对Android没有做处理,导致1px和backgroudImage还要额外做处理的问题[4]

所以我们有了第三种解决方案——vw。

maximum-scale: 允许用户的最大缩放值,为数字,可以是小数

3.3 vw

vw是基于Viewport视窗的长度单位,在CSS3中和Viewport相关的单位有四个,分别为vw、vh、vmin和vmax。

  • vw: 是Viewport’s width的简写,1vw等于window.innerWidth的1%
  • vh:和vw类似,是Viewport’s height的简写,1vh等于window.innerHeihgt的1%
  • vmin: vmin的值是当前vw和vh中较小的值
  • vmax: vmax的值是当前vw和vh中较大的值

其实vw的方案的写法和flexible方案的写法一致——因为flexible其实就是用hack的手段模拟了vw的实现而已。

具体写法:针对750px的设计稿,将相应的px值除以75就是vw的值。

因为此方法不会改变可见视口的宽度,所以可以和media query通用了,另外,也支持了Android上高分辨率屏的展示。

尽管在某些Android机型上还存在兼容问题,我们也可以使用Viewport Units Buggyfill,具体见《如何在Vue项目中使用vw实现移动端适配》

height: 设置viewport的高度(我们一般而言并不能用到)

总结

正如大漠所说,flexible模拟vw的时代已经过去,真正的酋长vw已经归来

user-scalable: 是否允许用户进行缩放,'no'为不允许,'yes'为允许

参考文档:

  1. 《移动前端开发之viewport的深入理解》
  2. 《移动端高清、多屏适配方案》
  3. 《再聊移动端页面的适配》
  4. 《基于淘宝弹性布局方案lib-flexible的问题研究》
  5. 《如何在Vue项目中使用vw实现移动端适配》

    1 赞 收藏 评论

图片 5

我们把这个标签是在head里面,像这样

<meta name="viewport" content="initial-scale=1">

这样就可以做到对viewport的控制了

二. 关于我们的设备

三个需要了解的概念:

PPI: 可以理解为屏幕的显示密度

DPR: 设备物理像素和逻辑像素的对应关系,即物理像素/逻辑像素

Resolution: 就是我们常说的分辨率

物理像素与逻辑像素

看了我们上面内容一的第一点之后,或许有些人会有些疑问,我的安卓手机,或者iphone6plus(目前应该仅限于这一款机型吧),买回来的是1920x1080的或者其他更高的,比我之前所谓的那个viewport默认的980px要大。

这样的问题,也就是我之前所说的物理像素与逻辑像素的关系了(即DPR)。以1920x1080为例,1080为物理像素,而我们在viewport中,获取到的,比如"width-device",是逻辑像素。所以之前viewport的默认值,所比对的大小,其实是逻辑像素的大小,而非物理像素的大小。

以iphone6为例,在不做任何缩放的条件下,iphone6的获取到的'width-device'为375px,为屏幕的逻辑像素。而购买时我们所知的750px,则为屏幕的物理像素。

css的问题

有了上面第二点的一些基础,还是以iphone6为例,我们可以知道,其实我们所写的1px,在iphone6上为2px的物理像素。所以,最后的,给出一个结论。就是我们写的1px,在移动端,是逻辑像素的1px,而非物理像素的1px。

三. 使用rem布局

简单说下rem

rem是根据页面的根元素的font-size的一个相对的单位,即

html{

 font-size: 16px;

比如当我们在一个div中,如此写

div{

 width: 2rem;

}

那么我们的width,是16*2 = 32px

rem做到适配不同分辨率

这个是现在手机淘宝的移动端的解决方案,即使用rem的特性,来对页面进行布局。

下面举一个例子

假定设计稿的大小为750,那么我们则将整个图分成100份来看(下面的题外话会说明为什么会分成100份来看)

那么,我们现在就让根部元素的font-size为75px

html{

 font-size: 75px;

}

那么,我们现在就可以比对设计稿,比如设计稿中,有一个div元素,宽度,高度都为75px,那么我们这样写即可

div{

 height: 1rem;

 width: 1rem;

}

可能看到这里,一些人还是不明白怎么用rem做到适配不同的分辨率,那么我们再来

现在,我们换设备了,不用这个设备是一个width为640的手机

那么这个时候,我们的rem单位就起到作用了。

我们的rem全是根据html的font-size来改变的,所以说,这个时候,我们只需要把html下的font-size改成64px。那么,我们之前的div,因为是根据html下的font-size动态变化的,那么。此时也就变成了宽度和高度都为64px的东西了。这样,就可以做到适配不同的屏幕分辨率了。(其实就是个等比缩放)

总结一下,我们的解决方案,其实就是 设计稿的像素/html的font-size = 用来代替px的rem。

这一个步骤,我们需要通过js来进行操作。

对于js的操作在下面会提到。

DPR的问题

视觉姐姐给了我们设计稿,并交由我们实现,那么,我们应该去认真的实现:-)(试想你做了一张图,而前端很多地方并没有按照你所想的,你所给的去做,而是私自改变了很多东西,你肯定会不高兴的)

那么1px会出现什么问题呢。

还记得我们第二大点讲的,我们的设备,是有物理像素和逻辑像素的。而假设我们的设计稿是750的,同时还是以iphone6为例,此时如果我们的viewport是这样的

<meta name="viewport" content="initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">

之前说过,在不做任何缩放的条件下,iphone6获取到的viewport为375px。

然后我们的页面中有个div,他有一个边框值,如下

div{

 height: 5rem;

 widht:5rem;

 border: 1px solid #000

}

此时我们写的1px,实际上是逻辑像素,而我们在iphone6上看到的是物理像素,于是这个时候,我们眼睛所看到的其实是2px(参考第二点第三个问题)

所以此时我们需要在viewport上做文章了,此时先明确,如果要获取到真正的1px,那么我们需要这么做,将viewport改为

<meta name="viewport" content="initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no">

即对屏幕做0.5倍的缩放。这样,我们就能得到实际的1px。

所以到这里,我们还要明确一点,viewport的meta标签,我们这里也只能通过js来动态生成。

同时,这样写,据说还可以避免比如inline的SVG等元素按照逻辑像素的渲染。避免了整个页面清晰度的打折(其实我并不能看出来)

文字适配问题

最近深深纠结与rem与px做字体单位的问题,还是先分别谈下二者吧。

rem与px的特点:

以rem作为字体单位:我们可以让页面整体的文字,也跟随着html的font-size来进行改变,这样,在不同的屏幕下,可以做到文字相对屏幕的比例是一样的。

以px作为字体单位: 这个是目前很多网站还是依然采用的方法。因为以上面所写的,以rem作为字体单位。无论在任何屏幕下面,我们的文字都会根据屏幕做一个适应。试想这样一个场景。你买了一个大屏手机(5.7寸的),而别人用的是4寸的手机。以rem作为字体单位的话,那大屏手机看到的文字多少和小屏手机确实一样的了。这样来做,其实并不符合我们买大屏手机的期待。同时,以rem作为字体单位,可能会导致出现很多奇怪的字体大小(毕竟是根据html的font-size动态变化的嘛),同时这其中还涉及到了一个点阵尺寸的概念,这个在下面来讲。

字体大小引发的系列问题:

字体大小:我们平时也看过,很多网站,是不以奇数作为字体大小的。我稍微查了些东西,在知乎上的现在网页设计中的为什么少有人用 11px、13px、15px 等奇数的字体?问题下,有一些比较好的解答,我就不再多说(我也并不能比这个问题说的更多),总的来说,其实就是偶数宽度的字体能够显得均衡,以及一个点阵的问题。不过因为要谈及点阵,所以我拿上面回答中的一个内容举例。

倘若一个字体,只提供了12px,14px,16px的点阵。那么当你写13px,15px,17px的时候。就并没有其字体大小所对应的点阵。那么这样就造成了一个问题。他们会使用其相邻的点阵,比如对应使用了12px,14px,16px的点阵,而导致一个问题,文字占用的大小确实改变,但点阵却并没有改变。

文字适配的解决方案:

上面说了这么多,我们总要有一套解决方案吧

对于一些标题性的文字,我们依然可以用rem。让他随着屏幕来进行缩放,因为标题性文字一般较大,而较大的文字,点阵对其影响就越小。这样,即使出现奇怪的尺寸,也能够让字体得到很好的渲染。

对于一些正文内容的文字(即站在使用者的角度,你不希望他进行缩放的文字)。我们采用px来进行处理。

四.安卓与ios不得不说的问题(解决篇)

在 三.使用rem布局 里面,我们给出了各种情况的解决方案,并且,在我举例的时候,热衷于使用iphone来举例,但其实,上面的所有问题,不是仅仅iphone会出现的问题,安卓也是一样。但是,如果你已经看完了上面,那么这里,才是真正给出我们解决方案的地方,并且,这个解决方案并不完善。

谈谈iphone的r屏与安卓的各种屏

rem布局也好,用viewport进行缩放也罢,文字的适配问题也是,都是基于我们想对各个不同的设备所进行的匹配。这套方案很好,然而也有其兼顾不到的地方。即安卓和ios的屏幕的一些问题,当然,细的东西我们不谈,我们只谈dpr。

先谈iphone

其实iphone为开发者考虑到了很多东西,为了让开发者便于开发,在6plus出现之前,iphone的dpr始终也就是2(即前面所谈的物理像素/逻辑像素=2),即使是6plus出现了,iphone到底其实也就只有2,3这两个dpr。我们很容易对其做到兼顾。

再谈安卓

安卓并没有对自己的屏幕叫做r屏,但是其原理和iphone的r屏可以说是一样。r屏做的是什么,把两个(三个)物理像素,丢到了一个逻辑像素里面,让屏幕展现的更清晰(当然,这是我片面的理解,不过我觉得大体来说并没有错,我们也不用去深入探讨r屏还有什么东西,我也并不懂)。而安卓也是一样,他也同样把n个物理像素丢到了一个逻辑像素里面。而这里的n,也就是dpr值(所以当我看到好多人问安卓为什么不采用r屏的时候,我真的也是……醉了?)。而安卓的dpr值,并不像iphone那样,就只有两个值。安卓的dpr是千奇百怪的,可能是1.5,2,3,4,2.5等等的都有。(甚至我还看到了1.7之类的,安卓的各个设备商,玩的真尼玛high啊。怎么高兴怎么来。)

所以,对安卓的屏幕的dpr的处理,其实是很头疼的,因为,他和我们对字体的处理,有了很大的冲突。这个在下面提及

首先看看手淘的解决方案

rem布局

用js获取到页面的宽度,然后对其进行宽度/10的处理,再将其写到html的font-size中。手淘的flexible.js里面的这一部分,并为了方便看懂做了些改写。大体就是这样的

function refreshRem(){

  var docEl = window.document.documentElement;

    var width = docEl.documentElement.getBoundingClientRect().width;

 

    var rootSize = width/10;

    docEl.style.fontSize = rootSize + 'px';

}

dpr的配置

首先,在引入flexible.js之前,我们可以对dpr进行手动的配置,即使用自定义的meta标签来配置dpr(看清楚是flexible,而非viewport)

<meta name="flexible" content="initial-dpr=2,maximum-dpr=3" />

iniital-dpr是把dpr强制设定为给定的值,而maximum-dpr则是给出一个最大的dpr限制,然后对其和系统的dpr做一个比较。

然后依然为了方便阅读我把flexble.js这一部分的代码抽象出来,

    var doc = window.document

    var metaEl = doc.querySelector('meta[name="viewport"]');

 var flexibleEl = doc.querySelector('meta[name="flexible"]');

 var dpr = 0;

 var scale = 0; //缩放比例

 //在meta标签中,已经有了viewport,则使用已有的viewport,并根据meta标签,对dpr进行设置

 if (metaEl) {

  console.warn('将根据已有的meta标签来设置缩放比例');

  var match = metaEl.getAttribute('content').match(/initial-scale=([d.]+)/);

  if (match) {

   scale = parseFloat(match[1]);

   dpr = parseInt(1 / scale);

  }

 //如果在meta标签中,我们手动配置了flexible,则使用里面的内容

 } else if (flexibleEl) {

  var content = flexibleEl.getAttribute('content');

  if (content) {

   var initialDpr = content.match(/initial-dpr=([d.]+)/);

   var maximumDpr = content.match(/maximum-dpr=([d.]+)/);

   if (initialDpr) {

       dpr = parseFloat(initialDpr[1]);

       scale = parseFloat((1 / dpr).toFixed(2));    

   }

if (maximumDpr) {

dpr = parseFloat(maximumDpr[1]);

scale = parseFloat((1 / dpr).toFixed(2));

}

}

}

这样,我们通过flexible的分析与获取,对dpr进行了书写。不过其实这里,是有个问题的。即在书写maximum的的情况下,其实根本没有像文档中给我们的说法一样,做一个比较,而是做了和initialDpr一样的一个处理。不过这里也不对其做一个探讨了。

然后,这套解决方案,然后当我们在meta标签里面并没有对viewport以及flexible两个的任意一个进行书写的时候,他也是会自动获取一个dpr值的

if (!dpr && !scale) {

 var isAndroid = window.navigator.appVersion.match(/android/gi);

 var isIPhone = window.navigator.appVersion.match(/iphone/gi);、

 //devicePixelRatio这个属性是可以获取到设备的dpr的

 var devicePixelRatio = win.devicePixelRatio;

 if (isIPhone) {

 // iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案

 if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {                

     dpr = 3;

 } else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){

     dpr = 2;

 } else {

     dpr = 1;

 }

} else {

 // 其他设备下,仍旧使用1倍的方案

 dpr = 1;

 }

 scale = 1 / dpr;

}

这里我们可以看到,手机淘宝并没有对安卓的dpr进行一个适配,原因之后再讲。

然后到了这里,我们获取到了我们需要的dpr值,并根据dpr值获取到了我们所需要的缩放值(即scale)

然后我们要做的,就是在并没有viewport的meta标签对情况下自己动态将这个标签写进我们的header,形式是这样的

<meta name="viewport" content="initial-scale=scale, maximum-scale=scale, minimum-scale=scale, user-scalable=no">

这样,dpr的配置,也就完成了,当然,安卓设备并没有对dpr进行一个配置(上面的动态生成就不给出js了)

文字的解决方案

由于手淘暂时并没有对安卓做一个处理,所以,这里,只是对iphone做了一个处理

即在html上,加入了一个自定义属性,data-dpr。

<html data-dpr='dpr'></html>

还是以750的设计稿为例(即iphone6)

假如设计稿上某a标签是32px,那么,我们要这么写

a{

 font-size: 16px

}

/*iphone6*/

[data-dpr='2'] a{

 font-size: 32px

}

/*iphone6plus*/

[data-dpr='3'] a{

 font-size: 32px

}

现在的一些问题

正如我们看到的,手淘目前的方案里面,是没有考虑到安卓dpr的问题的。即,这套方案,只对于iphone的r屏做了一个处理,而对于安卓,并没有做dpr的处理。我们来分析下原因吧(个人拙见)。

我们希望字体能够以px来展现,同时,我们也希望我们的东西能对dpr做一个适配。对于ios,这自然是可行的,即采用了data-dpr的自定义属性来调整文字。4到6写一套字体大小,6p写一套字体大小,然后在对dpr为1的屏幕写一套字体大小。其实这种写法还是很恶心,不过基于对dpr的适配,这样写也算是个解决方案了。

不过同样的解决方案到安卓就不行了,安卓的dpr有时候会很乱(比如现在在goole的手机测试里面可以看到,安卓的dpr,lg的某些设备还采用了1.7那样的奇怪dpr)。而当1.7dpr这种不规范的数字出现的时候,我们就不能采用之前的解决方案了,比如

[data-dpr='1.7'] a{

 font-size: 25px

}

这样的东西是不可能去写的,那万一还有2.25,2.5之类的呢?我们都要拿去匹配么?

其实现在,因为我们通过devicePixelRatio可以获取到安卓的dpr值,即可以做到对安卓设备的dpr一个匹配。但是,文字如果采用px的话,确实是很难做到匹配的。

即总结一下,就是说,对于安卓的dpr匹配,目前来说,是没有什么问题的,但是,对于dpr匹配之后的字体,那肯定是有问题的。

常见的dpr下的字体,我们依然可以解决,但是不常见的dpr,我们确实很难做到对dpr的解决。那如何解决这些问题呢。目前以我本人这个不太灵光的脑袋,确实也不晓得该如何进行一个处理了,起码做不到很好的解决。

不过,还是丢上些个人的观点吧。

在之前的对dpr的判断中,是根据了设备进行判断,即安卓不对dpr进行改变,仅对ios的设备进行改变。那么,我们其实可不可以以dpr的值来做一个处理呢?即像这样写

if (!dpr && !scale) {

 //devicePixelRatio这个属性是可以获取到设备的dpr的

 var devicePixelRatio = win.devicePixelRatio;

 //判断dpr是否为整数

 var isRegularDpr = devicePixelRatio.toString().match(/^[1-9]d*$/g)

 if (isRegularDpr) {

 // 对于是整数的dpr,对dpr进行操作

  if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {                

     dpr = 3;

 } else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){

     dpr = 2;

 } else {

     dpr = 1;

 }

} else {

 // 对于其他的dpr,人采用dpr为1的方案

 dpr = 1;

 }

 scale = 1 / dpr;

我们对这里做了一点点修改,即来判断dpr是否是规则的,也就是是否是我们常见的1,2,3等,然后,我们只对规则的dpr,来进行一个字体的处理。这样,iphone依然还是用之前的匹配方案。而其实目前安卓,很多的设备还是比较常见的dpr了,所以我们这里,将之前对设备的判断,转变成对dpr是否是整数的一个判断。其他地方不变,可以解决对安卓dpr的部分匹配。

同样,开发的时候,如果并不在乎字体的问题的话,大可以直接使用rem。那样是可以做到dpr和文字都适配的问题。不过正如我们讲到字体的时候所说的,使用rem是很多用户不希望的(大屏机还是和小屏机看到一样多的内容),同时,还有点阵的问题。

好,东西写到这里,也将近到了尾声。第一次写这么长的东西,感觉好累啊=_=。嗯还有篇2000字的检讨要写,默默匿了去写检讨了。

参考

手机淘宝的flexible设计与实现

题外话:

iphone6plus很有趣的地方

iphone6plus照理来说的,其实际dpr是2.87左右的,不过,为了方便开发者来开发,iphone6plus对其做了一个调整,将dpr调整为3,然后在对屏幕进行了一个缩放。这样做,自然是方便了开发者前去开发,然而,这样做,也有了一些性能上的损失。(iphone为开发者考虑的还是挺周全的,看看隔壁安卓,dpr怎么爽怎么来,都特么自己玩自己的)

有意思的vh和vw

vh,vw目前还存在很大程度的兼容性问题,所以还并没有采用。

vh,vw有什么特点呢

这两个元素分别会把屏幕上的可视高度(说通俗点就是你手机屏幕那个框框头装起的东西),宽度,分成100份来看,比如先前我们用rem来处理的地方,我们需要在html元素下写上font-size: 75px,然后再在div下写上width:1rem。而有了vh,vw之后,我们如此处理html的font-size就好。

html {

 font-size: 10vw;

}

这样写,省去了一部js操作的步骤。

本文由金沙棋牌发布于金沙棋牌官方平台,转载请注明出处:浅谈前端移动端页面开发,茴字的四种写法

关键词:

上一篇:损害了复用性,不适合复杂的前端项目

下一篇:没有了