移动端网页开发必须要知道的概念
一、viewport
1.layout-viewport





<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
width | 设置视口宽度(layout-viewport)为设备的屏幕宽度,为一个正整数或字符串"device-width"。device-width其实就是我们前面所说的visual-viewport |
initial-scale | 设置页面的初始缩放值(以 ideal viewport做参考进行缩放),为一个数字,可以带小数。 缩放值越大,当前viewport的宽度就会越小,页面模糊得越来越厉害 |
minimum-scale | 允许用户的最小缩放值,为一个数字,可以带小数 |
maximum-scale | 允许用户的最大缩放值,为一个数字,可以带小数 |
height | 设置layout viewport 的高度,这个属性对我们并不重要,很少使用 |
user-scalable | 是否允许用户进行缩放,值为"no"或"yes", no 代表不允许,yes代表允许 |
<meta name="viewport" content="width=400, initial-scale=1">
浏览器会取它们两个中较大的那个值。例如,当width=400,屏幕宽度为320时,取的是400。
可通过document.documentElement.clientWidth获取到viewport的宽度
通过window.screen.width获取
DPR的作用主要是确定一个逻辑像素用多少个物理像素来显示,一个逻辑像素是一个坐标点,假如dpr是2,则在x轴上和y轴上各用2个物理像素点来显示。
通过window.devicePixelRatio获取
三、高清屏下html中1px的边框比视觉图中的粗
设计师在视觉标注图上标明边框为1像素,于是你在css中很愉快的写下border:1px,结果悲剧了,在iphone6这种高清屏中看起来1px比较粗。
原因还是上面第2点的知识,1px不等于1个物理像素,在iphone6中1px等于2个物理像素,看着就会比视觉稿上的粗。
四、视觉稿如何还原?
为了适配高清屏,UI一般会以Iphone6的物理分辨率来设计视觉稿,即视觉图的宽度为750px,为什么会选iphone6呢?因为iphone6的尺寸在手机屏幕尺寸中算是一个中间值。
还原视觉稿时,简单粗暴的做法是直接将标注的尺寸除以2来确定宽高(除以2是因为iphone6的dpr为2,750个物理像素的宽度,在iphone6上只需要375个独立像素就能铺满了),这么做在屏幕尺寸更大的手机上,两边就会留白,而在更小尺寸的屏幕上最会显示不全。
解决办法有两种:
1. 使用media query根据不同的屏幕分辨率来进行适配的问题:
- 屏幕分辨率分区间:区间内无法进行区分,无法实现100%兼容,一般是用主流分辨率来进行划分;
- 额外的工作量:响应式布局的工作都是需要开发者去实现的,带来了额外的开放量;
- 不适合功能复杂的页面:响应式一般适合用于资讯类页面,功能复杂的网站对于页面的整体排版和样式要求较高(特别是对比PC和H5);
2. 使用rem单位:
rem是css3中的一个倍数单位,当为html根元素设置字体大小后,其它元素就可以根据这个字体大小,计算出自身大小。假设html
的font-size为12px
,1rem等于12px,那么一个宽度为2rem
的div元素则为24px
。
使用rem替代px时,思路如下:
首先需要计算出当前设备下,1rem等于多少px
根据效果图的宽度(一般是750px),定义1rem等于多少个px,假设1rem等于100px(假设为多少都可以,方便计算就行),那么,当设备宽度是375时,实际宽度相较效果图宽度,缩小了1倍,因此在375px时,1rem = 50px;
(function () { const designWidth = 750; // 设计稿宽度(根据实际情况设置) const baseFontSize = 100; // 设计稿中 1rem 对应的基准值(通常为 100px) function setFontSize() { const viewportWidth = document.documentElement.clientWidth; // 获取当前设备的视口宽度 const fontSize = (viewportWidth / designWidth) * baseFontSize; // 动态计算 html 的 font-size document.documentElement.style.fontSize = fontSize + 'px'; // 设置 html 的 font-size } setFontSize(); // 初始化设置字体大小 window.addEventListener('resize', setFontSize); // 监听窗口变化,实时调整 })();
其次需解决人工换算单位问题
比如效果图上一个div标注是200px,换算出等于多少rem? 有以下方法:
- 使用 Less 或 Sass 的函数来动态转换
px
为rem
。
@base: 100; // 基准值,1rem = 100px(根据设计稿设置) // px 转 rem 函数 .px2rem(@px) { @rem: @px / @base; return: ~"@{rem}rem"; } // 示例样式 .box { width: .px2rem(200); // 自动将 200px 转为 2rem height: .px2rem(100); // 自动将 100px 转为 1rem }
- 使用
postcss-pxtorem
插件,在项目打包时自动转换
module.exports = { plugins: { 'postcss-pxtorem': { rootValue: 100, // 基准值,1rem = 100px propList: ['*'], // 要转换的属性,* 表示全部 unitPrecision: 5 // 保留的小数位数 } } };
书写时还是使用px做为单位,效果图上标准的是多少,就写多少,不用考虑换算
.box { width: 200px; /* 自动转换为 2rem */ height: 100px; /* 自动转换为 1rem */ }
最后,设置meta头,inital-scale始终为1,不需要根据dpr进行换算动态设置缩放比
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
- 五、移动端图片模糊的原因
位图像素是栅格图像(如:png,jpg,gif等)最小的数据单元。每一个位图像素都包含着一些自身的显示信息。(如:显示位置,颜色值,透明度等)
理论上来说,1个位图像素对应1个物理像素,图片才能达到清晰的展示。
因为dpr的缘故,在高清屏上1个位图像素会对应多个物理像素,由于单个位图像素已经是最小的数据单位了,它不能再被进行切割。于是为了能够显示出来,就只能就近取色插值,从而导致所谓的图片模糊问题。
如何解决?
很明显,由于位图像素不够分而产生模糊的情况,解决的办法十分简单,就是使用跟dpr同个倍数大小的图片。比如iphone6,一个200x300的img
标签,原图就要提供400x600的大小。那么当加载到img
标签中,浏览器会自动对每1px的css像素减半,可以理解为此时还是维持着1:1的css像素:物理像素,不产生模糊。这就是UI切图时为什么会给@2x图的原因。
但是在普通屏幕下,使用@2x图也会产生问题,原本1个位图像素对应1个物理像素,但是现在一个物理像素点对应4个位图像素点,所以它的取色也只能通过一定的算法进行缩减,显示结果就是一张只有原图像素总数四分之一,肉眼看上去虽然图片不会模糊,但是会觉得有点色差。(其实就是模糊的逆向过程)。
那能不能让img标签根据设备的dpr,自动加载相应的倍图呢?答案是可以的,使用img srcset属性