移动端适配

566 阅读9分钟

移动端适配基本概念

基础概念

  • 物理像素(设备像素):代表屏幕的实际像素点,比如 1080x2340 像素的屏幕表示屏幕由 1080x2340 个像素点构成。
  • 逻辑像素(独立像素):表示屏幕的视觉尺寸。相同大小的屏幕,物理像素越多,一个逻辑像素对应的物理像素就越多,屏幕就越清晰。
  • 设备像素比(dpr):物理像素与逻辑像素的比。

当放大浏览器(Ctrl + 鼠标滚轮)的时候,并不是将它的 CSS 像素放大,而是改变它的计算方式,将一个 CSS 像素对应为多个物理像素。例如,一个元素的宽度是 128px,把屏幕放大至 200% 时,元素的宽度不会从原来的 128px 变为 256px,而是将一个 CSS 像素对应的物理像素设置为原来的两倍,即这个元素占据了 256 物理像素的空间。

desktop browser

screen size

可以使用 screen.width 和 screen.height 来获取用户的屏幕的宽高,它们代表屏幕的物理像素,是显示器的属性而非浏览器的属性。

window size

可以使用 window.innerWidth 和 window.innerHeight 来获取浏览器窗口大小。

img

它代表浏览器窗口的 CSS 像素大小,当用户放大浏览器(Ctrl + 鼠标滚轮)的时候,浏览器里面的元素是会变大的,但是浏览器窗口所占的物理像素是不变的,也就是说同样大小的窗口,一屏展示的元素变少了,一个 CSS 像素对应的物理像素变多了,获取到的 window.innerWidth 和 window.innerHeight 的值也会变小。注意:window.innerWidth 和 window.innerHeight 的值会包含滚动条的宽度。

(但是也有例外:Opera 浏览器,当缩放浏览器的时候,它的 window.innerWidth 和 window.innerHeight 的值就不会变,因为它是使用物理像素来计算的,其他浏览器则是使用 CSS 像素计算。)

document.documentElement.clientWidth 也可表示窗口的大小,它和 window.innerWidth 的区别是 window.innerWidth 包括滚动条的宽度,但是 document.documentElement.clientWidth 不包括。在改变窗口大小(拖动使浏览器窗口大小发生变化)或者缩放窗口(Ctrl + 鼠标滚轮缩放页面)的时候它们都是会改变的。

the viewport

理论上,html 元素的宽度就等于视口的宽度,它受视口宽度的限制,视口的宽度在这里也就是窗口的宽度。视口并不是 HTML 的一部分,所以不能通过 CSS 来改变它。当缩放页面时,html 的宽度一直都是视口宽度,我们可以通过 document.documentElement.clientWidth 来测量视口的宽度(也就是 html 元素的宽度)。

img

假设页面有一个宽度为 100% 的蓝色 div header,还有一些其他的内容,它存在于 body 元素中,它的宽度为 body 元素的 100%,也就是 html 元素的 100%。当我放大页面至出现滚动条时,此时其他内容超出页面,被隐藏在页面之外,拖动滚动条,可以让其他内容被隐藏的部分展示出来,但是,我们可以发现,header 的宽度并没有因为放大页面而变长,它刚好占满视口的宽度,当拖动滚动条时,发现它的右边是白色的,而我们给它设置的宽度就是 html 元素的 100%,也就是说 html 元素的宽度就是视口的宽度,它并不会因为页面放大而变宽,即使它里面的内容溢出,它也只是将多余的部分隐藏在滚动条之外,并不会改变自己的宽度。

document width

那么如何得到整个 document 的大小呢?通过 document.documentElement.offsetWidth 和 document.documentElement.offsetHeight。它获取的是整个文档的宽高,包括隐藏在 html 元素之外的内容。

mobile browser

two viewports

可视视口(visual viewport)指的是在页面中显示的那一部分视口。可以通过滚动条来调整可视视口的位置,让我们看到不同部分的内容,或者通过缩放来改变可视视口的大小。

布局视口(layout viewport)指的是页面的原本布局视口,是页面的 CSS 布局,通常它比可视视口要大。对于不同的浏览器,它的 layout viewport 初始值不同,例如:Safari iPhone 是 980px,Opera 是 850px,Android WebKit 是 800px,IE 是 974px。很多移动端浏览器在刚进入页面的时候默认是缩放至最小的,这个时候,layout viewport 和 visual viewport 是一样大。当放大页面的时候,layout viewport 是不变的,始终等于缩放至最小时的值,但是 visual viewport 是会变化的,随着我们不断放大,它的值越来越小。

假设你有一张没有改变形状和大小的大图片,它被放在一个小窗口中。你只能看到这张图片的一部分。你看到的这一部分就是 visual viewport,而这张图片实际占据的空间则是 layout viewport。

measuring two viewport

在桌面浏览器中,window.innerWidth 和 document.documentElement.clientWidth 相等,因为对于桌面浏览器,layout viewport 和 visual viewport 始终是相等的。但是在移动端浏览器,layout viewport 一般要比 visual viewport 大。我们可以通过 document.documentElement.clientWidth 来测量 layout viewport 的宽度,它也是 html 元素的宽度,通过 window.innerWidth 来测量 visual viewport 的宽度。

zooming

layout viewport 和 visual viewport 都是通过 CSS 像素计算的,当缩放页面时,visual viewport 是会变化的,因为视口大小没变,视口所包含的物理像素不变,但是页面中的元素的尺寸变大了,也就是一个 CSS 像素对应的物理像素变多了,那么这个视口(visual viewport)所占据的 CSS 像素也会变小。而 layout viewport 是不变的,我们给元素定义的 CSS 像素不会因为页面的缩放而改变。

那么如何测量缩放比例呢?没有一个属性直接存储了它的值。但是可以通过 scree.width / window.innerWidth 来计算,即理想视口宽度 / 可视视口宽度zoom factor = ideal viewport width / visual viewport width

scrolling offset

如果你想得到 visual viewport 相对于 layout viewport 的位置,可以通过 window.pageXOffset 与 window.pageYOffset 来获取。

img

media query

在媒体查询中,使用 width/height 来查询 document.documentElement.clientWidth/clientHeight,使用 device-width/device-height 来查询 screen.width/height

img

媒体查询一般用来判断当前所处的设备环境,是在桌面、平板还是在移动设备上面。

event coordinate

event.pageX/Y 是相对于页面(layout viewport)的位置,通过 CSS 像素计算。

img

event.clientX/Y 是相对于 visual viewport 的位置,也是通过 CSS 像素计算的。

event.screenX/Y 是相对于屏幕的位置,它是使用屏幕的物理像素来计算的。

img

meta viewport

<meta name="viewport" content="width=320"> 它的意思是设置 layout viewport 的宽度为 320px。它有什么作用呢?假设有一个简单的页面,里面有一个元素,我们没有给他设置宽度,那么它默认是 layout viewport 宽度的 100%。可以设置 layout viewport 的宽度,通过 meta 标签的 width。可以将它设置为 device-width,也就是理想视口的宽度(ideal viewport),可以通过 screen.width 来计算它。有时候 screen.width 并不是屏幕的物理像素的宽度,它代表的是屏幕的理想视口的宽度,例如,Nexus One 的物理像素的宽度是 480px,但是 Google 工程师觉得使用 480px 太宽了,于是使用它的 2/3,也就是 320px 来表示,所以它的 device-width 就是 320px。

以后可能 iPhone 手机屏的像素越来越多,但是屏幕大小不会发生变化,而我们开发完一个页面之后,它的 CSS 像素宽度是不会改变的,这个时候用 ideal viewport 来描述一块屏幕的宽度才是合适的。

meta viewport tag

<meta name="viewport" content="name=value, name=value">

  • width,layout viewport 的宽度,对于 Android WebKit 和 IE 来说,它们的最小 layout viewport 是 320px,当设置一个比 320 还小的值作为 layout viewport 的值时,这两个浏览器会将它重设为 320。
  • initial-scale,初始缩放比例,也就是 zoom factor。
  • minimum-scale,最小缩放比例。
  • maximum-scale,最大缩放比例。
  • height,layout viewport 的高度,不起作用。
  • user-scalable,是否允许用户缩放。

device-width

设备独立像素的宽度,也是 ideal viewport 的宽度。对于不同的机型,设备独立像素不同,但是对于同款机型的不同设备像素比的高清屏,它们的设备独立像素一般都是一样的。

对于 meta 标签的 width 属性,可以设置一个特殊的值,device-width,也就是将布局视口的宽度设置为理想视口的宽度。

ideal viewport

它指的是一个设备的理想像素大小,每一种设备的 ideal viewport 都不尽相同。在老式的便宜的非视网膜屏幕上面,ideal viewport 的大小就等于设备物理像素的大小。但是对于新式的高清屏,它的 ideal viewport 和老式设备还是一样的,因为它是这个设备最理想的尺寸。

对于 iPhone 4s,它的 ideal viewport 是 320x480,不管它是否是视网膜屏幕,因为 320x480 就是它的理想尺寸。

那么如何计算 ideal viewport 呢?

可以在设置 <meta name="viewport" content="width=device-width, initial-scale=1"> 的情况下,通过 document.documentElement.clientWidth 来获取。或者直接通过 screen.width 来获取 ideal viewport 的宽度,但是对于一些浏览器可能不支持。

Maximum and Minimum of layout viewport

layout viewport 的最大值可以设置为 10,000px。它的最小值可以是 ideal viewport 的 1/10,也就是缩放到最大的情况下的 visual viewport 的值,layout viewport 永远不会比最小的 visual viewport 的值小。

Maximum and Minimum zoom factor

首先,visual viewport 永远不会比 layout viewport 大,所以缩放因子的最小值就是:ideal viewport width / layout viewport width

但是对于 Android WebKit 来说,它的缩放比例因子 Minimum 最小不会小于 0.25,Maximum 最大不会超过 4。而对于 iPhone 来说,它的缩放比例因子 Minimum 最小不会小于 0.1,Maximum 最大不会超过 10。

initial-scale

当我们设置一个 meta 标签的 initial-scale 的时候,它会做两件事情:

  1. 它设置了页面的初始缩放比例。通过设备的 ideal viewport,同时它会计算出 visual viewport 的宽度。
  2. 如果我们没有设置 meta 标签的 width 值,那么它会设置 layout viewport 为 刚刚计算的 visual viewport 的值。

how to set layout viewport

当我们设置一个 meta 标签时,例如:设置在 iPhone 4s 上设置 <meta name="viewport" content="width=400, initial-scale=1">,浏览器会做以下事情:

  1. initial-scale=1 告诉浏览器设置 layout viewport 的宽度为:竖屏 320px,横屏 480px。
  2. width=400 告诉浏览器设置 layout viewport 的宽度为:竖屏和横屏都是 400px。

那么,对于浏览器来说,它会选取一个最大的值来设置为 layout viewport 的宽度,也就是在竖屏情况下,layout viewport 的宽度为:400px,而在横屏情况下,layout viewport 的宽度为:480px。

参考资料

www.quirksmode.org/mobile/view…

www.quirksmode.org/mobile/view…

www.quirksmode.org/mobile/meta…