什么是经典的 “移动端 1px” 问题?为何会在不同分辨率下呈现不同粗细?viewport 是如何解决该问题?
1. 移动端 1px 问题
问题一:如何理解 css 的 1px 并不等于设备的 1px?
在早期,手机屏幕中的 1px 确实等于 css 的 1px。后来随着科技发展,尽管手机的整体大小变化不大,但是分辨率却在提高。
这期间的变化,参考如上图,假设灰色区域相当于手机屏幕,黑色方块相当于 css 初始的 1px(也相当于设备的 1px)。当手机屏幕宽度不变,分辨率提高一倍后,一个css像素等于两个设备像素(蓝色方块);分辨率提高两倍后,一个css像素等于四个设备像素(绿色方块)…也就是说,css 一直都是 1px,但是其代表的真实像素点,却在不断变多。
这就导致了同样的代码(css 的 1px),在不同分辨率的屏幕上会 呈现不同粗细,这便是移动端的 1px 问题。
同理,缩放也会引起 css 的 1px 所代表的设备像素的变化。
且称 css 像素为独立像素,而设备真实像素称为物理像素。
问题二:响应式的原理
假设能知道独立像素与物理像素的比值,就能计算出在设备上的实际像素值,准确地在不同分辨率的机子上显示。
问题三:如何获取当前设备中,独立像素与物理像素的比值?
window.devicePixelRatio
:物理像素与独立像素的比例。- 通过该比例,我们就可以知道某台设备上,一个css像素代表多少物理像素
但是,devicePixelRatio
在不同浏览器中存在兼容性问题,由此引出 viewport 解决方法。
2. 三个 viewport
1)layout viewport
:浏览器默认 viewport
- 为了让桌面用的网站放在移动端上能正常显示,浏览器会默认把 viewport 的值设得比设备宽度大许多,如下图
- 通过
document.documentElement.clientWidth
获取layout viewport
的宽度
2)visual viewport
:可视区域
- 通过
window.innerWidth
获取可视区域宽度
3)ideal viewport
:移动端的理想viewport
完美适配的条件:
- 用户无需缩放和横向滚动,就能查看网站的所有内容
- 显示的文字大小合适,不会因为分辨率的改变而差异巨大
- 比如所有
iphone
的ideal viewport
宽度都是 320px,则无论他分辨率像素是 320 还是 640,一个被 css 定义为 14px 大小的字体,显示出来的大小都是差不多的,不会因为分辨率增大而字体变小。 - 不同设备的
ideal viewport
不同,https://viewportsizes.com/ 该网站收录了许多机型的ideal viewport
3. 设置 viewport
通过如下代码,得到 ideal viewport
:让当前 viewport 的宽度等于设备的宽度,同时允许用户缩放(如不设置,浏览器会默认按照 layout viewport
的尺寸,就会导致出现横向滚动条)
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
4. 备注
-
meta 中同时配置了
width
和initial-scale
,浏览器会取较大值为准进行显示。 -
initial-scale 默认值
- 安卓:没有默认值,需要写才会起作用
- iPhone & iPad:会自动计算 initial-scale,以保证缩放后刚好是浏览器的可视区域宽度,而不会出现横向滚动条
-
动态修改
meta viewport
标签- 写法一:
document.write('<meta id="testViewport" name="viewport" content="width=device-width,initial-scale=1">')
- 写法二:
document.getElementById('testViewport').setAttribute('content','width=480');
- 写法一:
5. 总结
- 移动端1px问题:屏幕分辨率不同,导致1px表现出来的粗细不同
- 解决方法:
- 方法一:通过
window.devicePixelRatio
获取物理像素与独立像素的比例,再进行像素换算; - 方法二:通过
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
设置理想宽度 - 方法三:通过媒体查询,获取当前设备宽高,并设置对应比例的
viewport + rem
- 方法一:通过