本文介绍了移动端适配的3种方法,以及移动端图片模糊问题和1px细线问题的解决方法。当然了,在这之前先整理了与这些方法相关的知识:物理像素、设备独立像素、设备像素比和viewport。

>>>>物理像素、设备独立像素和设备像素比

  在CSS中我们一般使用px作为单位,需要注意的是,CSS样式里面的px和物理像素并不是相等的。CSS中的像素只是一个抽象的单位,在不同的设备或不同的环境中,CSS中的1px所代表的物理像素是不同的。在PC端,CSS的1px一般对应着电脑屏幕的1个物理像素,但在移动端,CSS的1px等于几个物理像素是和屏幕像素密度有关的。

物理像素(physical pixel)

  物理像素又被称为设备像素、设备物理像素,它是显示器(电脑、手机屏幕)最小的物理显示单位,每个物理像素由颜色值和亮度值组成。所谓的一倍屏、二倍屏(Retina)、三倍屏,指的是设备以多少物理像素来显示一个CSS像素,也就是说,多倍屏以更多更精细的物理像素点来显示一个CSS像素点,在普通屏幕下1个CSS像素对应1个物理像素,而在Retina屏幕下,1个CSS像素对应的却是4个物理像素(参照下文田字示意图理解)。

设备独立像素(device-independent pixel)

  设备独立像素又被称为CSS像素,是我们写CSS时所用的像素,它是一个抽像的单位,主要使用在浏览器上,用来精确度量Web页面上的内容。

设备像素比(device pixel ratio)

  设备像素比简称为dpr,定义了物理像素和设备独立像素的对应关系:设备像素比 = 物理像素 / 设备独立像素。

  CSS的1px等于几个物理像素,除了和屏幕像素密度dpr有关,还和用户缩放有关系。例如,当用户把页面放大一倍,那么CSS中1px所代表的物理像素也会增加一倍;反之把页面缩小一倍,CSS中1px所代表的物理像素也会减少一倍。关于这点,在文章后面的1px细线问题部分还会讲到。

>>>>viewport

  viewport就是设备上用来显示网页的那一块区域,但viewport又不局限于浏览器可视区域的大小,它可能比浏览器的可视区域要大,也可能比浏览器的可视区域要小。在默认情况下,一般来讲,移动设备上的viewport都是要大于浏览器可视区域的,这是因为考虑到移动设备的分辨率相对于桌面电脑来说都比较小,所以为了能在移动设备上正常显示那些传统的为桌面浏览器设计的网站,移动设备上的浏览器都会把自己默认的viewport设为980px或1024px(也可能是其它值,这个是由设备自己决定的),但带来的后果就是浏览器会出现横向滚动条,因为浏览器可视区域的宽度是比这个默认的viewport的宽度要小的。

明确三种不同的viewport视口:

  visual viewport 可见视口,指屏幕宽度

  layout viewport 布局视口,指DOM宽度

  ideal viewport 理想适口,使布局视口就是可见视口即为理想适口

获取屏幕宽度(visual viewport)的尺寸:

window. innerWidth/Height

获取DOM宽度(layout viewport)的尺寸:

document. documentElement. clientWidth/Height

设置理想视口ideal viewport:

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

该meta标签的作用是让layout viewport的宽度等于visual viewport的宽度,同时不允许用户手动缩放,从而达到理想视口。

  meta[name="viewport"]里各参数的含义为:

  width: 设置layout viewport 的宽度,为一个正整数,或字符串”width-device”。

  initial-scale: 设置页面的初始缩放值,为一个数字,可以带小数。

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

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

  height: 设置layout viewport 的高度,这个属性对我们并不重要,很少使用。

  user-scalable: 是否允许用户进行缩放,值为“no”或“yes”。

>>>>rem适配方案

  适配是为了使页面在不同手机设备上,相对保持统一的效果。移动端自适应方案很多,有百分比布局,弹性盒模型布局等,但是最好用的要数rem布局了。

rem是相对于根元素的字体大小的单位,我们可以根据设备宽度动态设置根元素的font-size,使得以rem为单位的元素在不同终端上以相对一致的视觉效果呈现。下面介绍3种根据屏幕宽度设置rem基准值的方法。(注:为了换算方便,以下三种方法都用1:100的比例,即1rem=100px。)

用JS设置rem基准值

/* 设计稿是750,采用1:100的比例,用1rem表示100px,font-size为100 * (clientWidth / 750) */
(function(doc, win) {
var docEl = doc.documentElement,
resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
recalc = function() {
var clientWidth = docEl.clientWidth;
if (!clientWidth) return;
docEl.style.fontSize = 100 * (clientWidth / 750) + 'px';
};
if (!doc.addEventListener) return;
win.addEventListener(resizeEvt, recalc, false);
doc.addEventListener('DOMContentLoaded', recalc, false);
})(document, window);

用密集的媒体查询设置font-size

/* 设计稿是750,采用1:100的比例,用1rem表示100px,100*(100/750)=13.333 以min-width: 750px时font-size: 100px为基准,
min-width每缩小100px,font-size就缩小13.3333px,如需更密集的媒体查询可以按照这个对照关系设置。*/
@media screen and (min-width: 320px) {
html {
font-size: 42.6667px;
}
}
@media screen and (min-width: 375px) {
html {
font-size: 50px;
}
}
@media screen and (min-width: 425px) {
html {
font-size: 56.6667px;
}
}
@media screen and (min-width: 768px) {
html {
font-size: 102.4px;
}
}

用单位vw设置font-size

  1vw等于屏幕可视区宽度(的可视区域的百分之一。

/* 设计稿是750,采用1:100的比例,用1rem表示100px,font-size为100*(100vw/750) */
html {
font-size: 13.3334vw;
}

注:兼容性不是很好。

  了解了物理像素、设备独立像素、设备像素比和viewport这几个重要概念后,来看一下移动端开发中,由于屏幕分辨率导致的两个经典问题:图片模糊问题和1px细线问题。(注:为了叙述简洁,以下多倍屏均只叙述2倍Retina屏,其它屏幕同理。)

>>>>图片模糊问题

  一个位图像素是栅格图像(如:png, jpg, gif等)最小的数据单元。每一个位图像素都包含着一些自身的显示信息(如:显示位置,颜色值,透明度等)。理论上,1个位图像素对应于1个物理像素,图片才能得到完美清晰的展示。对于dpr=2的Retina屏幕而言,1个位图像素对应于4个物理像素,由于单个位图像素不可以再进一步分割,所以只能就近取色,导致图片看起来比较模糊,如下图。

  对于图片模糊问题,比较好的方案就是用多倍图片(@2x)。如:一个200×300(CSS pixel)的img标签,对于dpr=2的屏幕,用400×600的图片,如此一来,位图像素点个数就是原来的4倍,在Retina屏幕下,位图像素点个数就可以跟物理像素点个数形成 1 : 1的比例,图片自然就清晰了。

  如果普通屏幕下,也用了两倍图片,会怎样呢?

  在普通屏幕下,200×300(CSS pixel)img标签,所对应的物理像素个数就是200×300个,而两倍图片的位图像素个数是200×300×4个,所以就出现一个物理像素点对应4个位图像素点,但它的取色也只能通过一定的算法取某一个位图像素点上的色值,这个过程叫做(downsampling),肉眼看上去虽然图片不会模糊,但是会觉得图片缺少一些锐利度,或者是有点色差,如下图。

  所以最好的解决办法是:不同的dpr下,加载不同的尺寸的图片。不管是通过CSS媒体查询,还是通过JS条件判断都是可以的。

>>>>1px细线问题

  在上文我们已经知道,CSS像素为1px宽的直线,对应的物理像素是不同的,可能是2px或者3px,而设计师想要的1px宽的直线,其实就是1物理像素宽,如下图。

  对于CSS而言,可以认为是border: 0.5px;,这是多倍屏下能显示的最小单位。然而,并不是所有手机浏览器都能识别border: 0.5px,有的系统里,0.5px会被当成为0px处理,那么如何实现这0.5px呢?网上有很多解决方法,比如border-image 图片、background-image 渐变、box-shadow 等,因为这些方案不太好,所以不做赘述了,我推荐两种方法:用媒体查询根据dpr用“伪元素+transform”对边框进行缩放;用JS根据屏幕尺寸和dpr精确地设置不同屏幕所应有的rem基准值和initial-scale缩放值。

伪元素+transform

构建1个伪元素, border为1px, 再以transform缩放到50%。

/* 设计稿是750,采用1:100的比例,font-size为100*(100vw/750) */
.border-1px {
position: relative;
}
@media screen and (-webkit-min-device-pixel-ratio: 2) {
.border-1px:before {
content: " ";
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 1px;
border-top: 1px solid #D9D9D9;
color: #D9D9D9;
-webkit-transform-origin: 0 0;
transform-origin: 0 0;
-webkit-transform: scaleY(0.5);
transform: scaleY(0.5);
}
}

用JS计算rem基准值和viewport缩放值

/* 设计稿是750,采用1:100的比例,font-size为100 * (docEl.clientWidth * dpr / 750) */
var dpr, rem, scale;
var docEl = document.documentElement;
var fontEl = document.createElement('style');
var metaEl = document.querySelector('meta[name="viewport"]');
dpr = window.devicePixelRatio || 1;
rem = 100 * (docEl.clientWidth * dpr / 750);
scale = 1 / dpr;
// 设置viewport,进行缩放,达到高清效果
metaEl.setAttribute('content', 'width=' + dpr * docEl.clientWidth + ',initial-scale=' + scale + ',maximum-scale=' + scale + ', minimum-scale=' + scale + ',user-scalable=no');
// 设置data-dpr属性,留作的css hack之用,解决图片模糊问题和1px细线问题
docEl.setAttribute('data-dpr', dpr);
// 动态写入样式
docEl.firstElementChild.appendChild(fontEl);
fontEl.innerHTML = 'html{font-size:' + rem + 'px!important;}';

  相较与于上文rem适配方案里“用JS计算rem基准值”的方案,这个“用JS计算rem基准值和viewport缩放值”的方案可以解决1px细线问题。表格以2倍Retina屏做比较,其他多倍屏同理。

  用JS根据屏幕尺寸和dpr精确地设置不同屏幕所应有的rem基准值和initial-scale缩放值,这个JS方案已经在完美解决了1px细线问题,我们不需要再做任何事情,至于图片模糊问题,只需要根据data-dpr的值动态加载不同尺寸的图就可以了。

分享一个公众号-----前端麻辣烫 ,一个专注于前端技术学习与交流的公众号~

微信搜索“WebSnacks”,或者扫描下方二维码。

移动端高清适配方案(解决图片模糊问题、1px细线问题)的更多相关文章

  1. webapp:移动端高清、多屏适配方案(zz)

    来源: http://sentsin.com/web/1212.html 移动端高清.多屏适配方案 背景 开发移动端H5页面 面对不同分辨率的手机 面对不同屏幕尺寸的手机 视觉稿 在前端开发之前,视觉 ...

  2. 移动端高清、多屏适配方案 [来源:http://div.io/topic/1092]

    Lovesueee 发布于 8 月前 移动端高清.多屏适配方案 背景 开发移动端H5页面 面对不同分辨率的手机 面对不同屏幕尺寸的手机 视觉稿 在前端开发之前,视觉MM会给我们一个psd文件,称之为视 ...

  3. css图片高清适配

    同一张图片,在普通屏显示正常,但高清屏出现模糊.原因是原来一个像素的点分成的四个像素的点进行了显示. 解决方案:在高清屏中把图片变成二倍图,前提是二倍的高清图已经存在. .icon{ backgrou ...

  4. 基于REM的移动端响应式适配方案

    视口 在前一段时间,我曾经写过一篇关于viewport的文章.最近由于在接触移动端开发,对viewport有了新的理解.于是,打算重新写一篇文章,介绍移动端视口的相关概念. 关于这篇文章说到的所有知识 ...

  5. 如何录制高清GIF格式的图片

    如何录制高清GIF格式的图片 工具:傲软GIF 下载地址:https://www.apowersoft.cn/gif 特点:质量高,能够一帧一帧的修改 使用简单.就不说了.自行尝试.这里只是提供一个制 ...

  6. 基于rem的移动端响应式适配方案(详解) 移动端H5页面的设计稿尺寸大小规范

    基于rem的移动端响应式适配方案(详解) : https://www.jb51.net/article/118067.htm 移动端H5页面的设计稿尺寸大小规范 http://www.tuyiyi.c ...

  7. 移动端高清、多屏适配方案——rem

    背景: 开发移动端H5页面 一套设计图 不同尺寸的手机 不同分辨率的手机 方案:使用rem作为单位解决一套设计图适应不同分辨率,不同尺寸的手机. 概念: REM(font size of the ro ...

  8. jquery图片延迟加载方案解决图片太多加载缓慢问题

    当在做一个图片展示站的时候,一个页面加载的图片过多会,如果服务器的带宽跟不上,明显会感觉到页面很卡,严重的浏览器也会崩溃,所以我推荐采用即看即所得的模式,当滚动到下一屏时才进行加载图片. 注意:即便如 ...

  9. 移动端Web页面适配方案

    概念理解 viewport视口 visual viewport 可见视口,设备屏幕的宽度  windw.innerWidth/Height layout viewport 布局视口,DOM宽度 doc ...

随机推荐

  1. PostgreSQL 10 如何使用 PgAdmin3

    自从 PgAdmin4 出来以后,PgAdmin3 就停止开发了,PgAdmin 官网下载的 PgAdmin3 无法支持 PostgreSQL 10 或者更高版本的数据库服务器端. 但是 PgAdmi ...

  2. Oracle 常用的查询操作

    –1. 查询系统所有对象select owner, object_name, object_type, created, last_ddl_time, timestamp, statusfrom db ...

  3. (网页)JQuery 对 Select option 的操作(转)

    转自博客园: <select id="selectID" > <option value="1">1</option> &l ...

  4. [20171113]修改表结构删除列相关问题2.txt

    [20171113]修改表结构删除列相关问题2.txt --//测试看看修改表结构删除列产生的redo向量,对这些操作细节不了解,分析redo看看. 1.环境:SCOTT@book> @ &am ...

  5. Vue状态管理

    1.导出Vuex import Vuex from 'vuex' 2.定义store /*状态管理*/ const store = new Vuex.Store({ state: { headerSh ...

  6. centos6.5下oracle11g开机自动启动方法一

    转裁于 方法一 https://blog.csdn.net/wx5040257/article/details/77875690 方法二  https://blog.csdn.net/wx504025 ...

  7. python 报错RuntimeError: dictionary changed size during iteration

    a = {':0} for b in list(a.keys()): if a[b] == 0: del a[b] print(a) 报错是因为在字典迭代期间改变字典大小 我们可以通过取出字典的键值, ...

  8. 机器学习中学习曲线的 bias vs variance 以及 数据量m

    关于偏差.方差以及学习曲线为代表的诊断法: 在评估假设函数时,我们习惯将整个样本按照6:2:2的比例分割:60%训练集training set.20%交叉验证集cross validation set ...

  9. tidb在DDL语句方面的测试

    Mysql与tidb测试数据为8000万行. 1.修改一个字段的列名,比如将“ctime”修改为“cctime”. Tidb测试: MySQL测试: 2.同一属性之间切换,即修改一个字段的属性大小.比 ...

  10. Alpha冲刺! Day7 - 砍柴

    Alpha冲刺! Day7 - 砍柴 今日已完成 晨瑶:列了各模块目前的进度情况:确定了纯多媒体流星预览页的显示方式:给工具包函数列表新增了与服务器端的交互:玩华为软件云发现刚好可以试试它的测试,于是 ...