Skip to content

移动端布局

媒介查询

css
html {
  font-size: 10px;
}
@media screen and (min-width: 321px) and (max-width: 375px) {
  html {
    font-size: 11px;
  }
}
@media screen and (min-width: 376px) and (max-width: 414px) {
  html {
    font-size: 12px;
  }
}
@media screen and (min-width: 415px) and (max-width: 639px) {
  html {
    font-size: 15px;
  }
}
@media screen and (min-width: 640px) and (max-width: 719px) {
  html {
    font-size: 20px;
  }
}
@media screen and (min-width: 720px) and (max-width: 749px) {
  html {
    font-size: 22.5px;
  }
}
@media screen and (min-width: 750px) and (max-width: 799px) {
  html {
    font-size: 23.5px;
  }
}
@media screen and (min-width: 800px) {
  html {
    font-size: 25px;
  }
}
html {
  font-size: 10px;
}
@media screen and (min-width: 321px) and (max-width: 375px) {
  html {
    font-size: 11px;
  }
}
@media screen and (min-width: 376px) and (max-width: 414px) {
  html {
    font-size: 12px;
  }
}
@media screen and (min-width: 415px) and (max-width: 639px) {
  html {
    font-size: 15px;
  }
}
@media screen and (min-width: 640px) and (max-width: 719px) {
  html {
    font-size: 20px;
  }
}
@media screen and (min-width: 720px) and (max-width: 749px) {
  html {
    font-size: 22.5px;
  }
}
@media screen and (min-width: 750px) and (max-width: 799px) {
  html {
    font-size: 23.5px;
  }
}
@media screen and (min-width: 800px) {
  html {
    font-size: 25px;
  }
}
  • 1).item 类在所有设备下的 width 都是 3.4rem,但在不同分辨率下的实际像素是不一样的,所以在有些分辨率下,width 的界面效果不一定合适,有可能太宽,有可能太窄,这时候就要对 width 进行调整,那么就需要针对.item 写媒介查询的代码,为该分辨率重新设计一个 rem 值。然而,这里有 7 种媒介查询的情况,css 又有很多跟尺寸相关的属性,哪个属性在哪个分辨率范围不合适都是不定的,最后会导致要写很多的媒介查询才能适配所有设备,而且在写的时候 rem 都得根据某个分辨率 html 的 font-size 去算,这个计算可不见得每次都那么容易,比如 40px / 23.5px,这个 rem 值口算不出来吧!由此可见这其中的麻烦有多少。
  • (2)以上代码中给出的 7 个范围下的 font-size 不一定是合适的,这 7 个范围也不一定合适,实际有可能不需要这么多,所以找出这些个范围,以及每个范围最合适的 font-size 也很麻烦
  • (3)设计稿都是以分辨率来标明尺寸的,前端在根据设计稿里各个元素的像素尺寸转换为 rem 时,该以哪个 font-size 为准呢?这需要去写才能知道

名词

屏幕尺寸:屏幕对角线的长度

屏幕像素密度:屏幕密度是指一个设备表面上存在的像素数量,它通常以每英寸有多少像素来计算(PPI)。

屏幕分辨率:横纵向上物理像素的个数(物理像素)

物理像素(physical pixel)或设备像素(device pixel):物理像素又被称为设备像素,它是显示设备中一个最微小的物理部件。每个像素可以根据操作系统设置自己的颜色和亮度透明度,通过控制每个像素点的颜色,使屏幕显示出不同的图像,屏幕从工厂出来那天起,它上面的物理像素点就固定不变了,单位 pt。

设备独立像素(density-independent pixel):设备独立像素也称为密度无关像素,可以认为是计算机坐标系统中的一个点,这个点代表一个可以由程序使用的虚拟像素(比如说 CSS 像素),然后由相关系统转换为物理像素。

css 像素或者逻辑像素或者设备无关像素(device-independent pixel):CSS 像素又称为逻辑像素或者与设备无关的像素(device-independent pixel),简称 DIPs,是 web 开发者使用的最小单位,也就是我们经常写的 width=多少 px 中的 px

设备像素比(device pixel ratio):设备像素比 = 物理像素 / 设备独立像素

分辨率又分为【物理分辨率】和【逻辑分辨率】,值得注意的是实际工作中设计师常常给的是物理分辨率,程序中用到的是逻辑分辨率,但是都称为分辨率,容易混淆。 【物理分辨率】是硬件所支持的分辨率,【逻辑分辨率】是软件可以达到的分辨率。 【像素倍率 dpr】物理分辨率和逻辑分辨率的商,即常说的几倍屏。

位图像素

一个位图像素是栅格图像(如:png, jpg, gif 等)最小的数据单元。每一个位图像素都包含着一些自身的显示信息(如:显示位置,颜色值,透明度等)。

理论上,1 个位图像素对应于 1 个物理像素,图片才能得到完美清晰的展示

img

如上图:对于 dpr=2 的 retina 屏幕而言,1 个位图像素对应于 4 个物理像素,由于单个位图像素不可以再进一步分割,所以只能就近取色,从而导致图片模糊(注意上述的几个颜色值)。

所以,对于图片高清问题,比较好的方案就是两倍图片(@2x)。

如:200×300(css pixel)img 标签,就需要提供 400×600 的图片

关于设计稿为什么要使用二倍图、三倍图

理论上一个位图像素对应一个物理像素,图片才能完美显示!设计稿是按 px 单位设计的,为了应对高分辨率显示屏(设备像素比 dpi = 2 或者 3 等)的高像素密度==>同等 px 大小拥有 dpi 倍的物理像素点,我们将设计稿增大 dpi 倍,一般是 2 被或者 3 倍,这样设计稿缩放到屏幕时的分辨率就和屏幕本身的分辨率一致了(实际中设计稿总像素数要大于或者等于屏幕分辨率就可以),图片就可以完美显示了,

img

上图中, Retina 为高清设备屏幕,它的一个 css 像素对应 了 4 个物理像素

在 Javascript 中,可以通过 window.devicePixelRatio获取到当前设备的 dpr。

在 css 中,可以通过 -webkit-device-pixel-ratio-webkit-min-device-pixel-ratio-webkit-max-device-pixel-ratio进行媒体查询,对不同 dpr 的设备,做一些样式适配。

或者使用 resolution | min-resolution | max-resolution 这些比较新的标准方式

缩放比 scale

缩放比:scale = 1/dpr

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

整个网页在设备内显示时的页面宽度就会等于设备逻辑像素大小,也就是 device-width。这个 device-width 的计算公式为:设备的物理分辨率/(devicePixelRatio * scale),在 scale 为 1 的情况下,device-width = 设备的物理分辨率/devicePixelRatio 。这就是 initial-scale 的意义

视窗 viewport

简单的理解,viewport 是严格等于浏览器的窗口。在桌面浏览器中,viewport 就是浏览器窗口的宽度高度。但在移动端设备上就有点复杂。

移动端的 viewport 太窄,为了能更好为 CSS 布局服务,所以提供了两个 viewport:虚拟的 visualviewport 和布局的 layoutviewport。

viewport 的内容比较深,推荐阅读PPK 写的文章,以及中文翻译

视窗缩放 viewport scale

在开发移动端页面,我们可以设置meta标签的 viewport scale 来对视窗的大小进行缩放定义

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

rem

rem 原理

等比缩放

rem 单位

rem就是相对于根元素<html>font-size来做计算

网易

设备屏幕尺寸为逻辑像素,即:document.documentElement.clientWidth

稿=稿=稿稿html=1rem=稿px

100?

为了方便计算

1rem=(设备屏幕尺寸/设计稿尺寸)*100

那么设计稿上的尺寸,除以 100 就行了

问题:

  • 1).item 类在所有设备下的 width 都是 3.4rem,但在不同分辨率下的实际像素是不一样的,所以在有些分辨率下,width 的界面效果不一定合适,有可能太宽,有可能太窄,这时候就要对 width 进行调整,那么就需要针对.item 写媒介查询的代码,为该分辨率重新设计一个 rem 值。然而,这里有 7 种媒介查询的情况,css 又有很多跟尺寸相关的属性,哪个属性在哪个分辨率范围不合适都是不定的,最后会导致要写很多的媒介查询才能适配所有设备,而且在写的时候 rem 都得根据某个分辨率 html 的 font-size 去算,这个计算可不见得每次都那么容易,比如 40px / 23.5px,这个 rem 值口算不出来吧!由此可见这其中的麻烦有多少。
  • (2)以上代码中给出的 7 个范围下的 font-size 不一定是合适的,这 7 个范围也不一定合适,实际有可能不需要这么多,所以找出这些个范围,以及每个范围最合适的 font-size 也很麻烦
  • (3)设计稿都是以分辨率来标明尺寸的,前端在根据设计稿里各个元素的像素尺寸转换为 rem 时,该以哪个 font-size 为准呢?这需要去写才能知道

example

iphone6 的分辨率写着375*667,指的是逻辑分辨率;750*1334则是它的物理分辨率,dpr=2。

设备逻辑像素 device-width = 设备物理像素 /(devicePixelRatio scale) 设备物理像素: iphone6 = 750px 设备逻辑像素: iphone6 = 750/(2 1) = 375px document.documentElement.clientWidth === 设备逻辑像素 body-width(rem 为单位) = 设计稿宽度/100 = 640 / 100 = 6.4 rem 【取 100,主要为了容易计算】 html font-size(px 为单位) = device-width / body-width = 320 / 6.4 = 50 px

javascript
document.documentElement.style.fontSize =
  document.documentElement.clientWidth / 6.4 + 'px'
document.documentElement.style.fontSize =
  document.documentElement.clientWidth / 6.4 + 'px'
如果设计稿基于iphone6,横向分辨率为750,body的width为750 / 100 = 7.5rem
如果设计稿基于iphone4/5,横向分辨率为640,body的width为640 / 100 = 6.4rem
如果设计稿基于iphone6,横向分辨率为750,body的width为750 / 100 = 7.5rem
如果设计稿基于iphone4/5,横向分辨率为640,body的width为640 / 100 = 6.4rem
html
<meta
  name="viewport"
  content="initial-scale=1,maximum-scale=1, minimum-scale=1"
/>
<meta
  name="viewport"
  content="initial-scale=1,maximum-scale=1, minimum-scale=1"
/>

当 deviceWidth 大于设计稿的横向分辨率时,html 的 font-size 始终等于横向分辨率/body 元素宽

var deviceWidth = document.documentElement.clientWidth;
if(deviceWidth > 640) deviceWidth = 640;
document.documentElement.style.fontSize = deviceWidth / 6.4 + 'px';
var deviceWidth = document.documentElement.clientWidth;
if(deviceWidth > 640) deviceWidth = 640;
document.documentElement.style.fontSize = deviceWidth / 6.4 + 'px';

淘宝

device-width = 设备的物理分辨率/devicePixelRatio/scale

js
var scale = 1 / devicePixelRatio
document
  .querySelector('meta[name="viewport"]')
  .setAttribute(
    'content',
    'initial-scale=' +
      scale +
      ', maximum-scale=' +
      scale +
      ', minimum-scale=' +
      scale +
      ', user-scalable=no'
  )
var scale = 1 / devicePixelRatio
document
  .querySelector('meta[name="viewport"]')
  .setAttribute(
    'content',
    'initial-scale=' +
      scale +
      ', maximum-scale=' +
      scale +
      ', minimum-scale=' +
      scale +
      ', user-scalable=no'
  )
document.documentElement.style.fontSize = document.documentElement.clientWidth / 10 + 'px';
document.documentElement.style.fontSize = document.documentElement.clientWidth / 10 + 'px';

布局的时候,各元素的 css 尺寸=设计稿标注尺寸/设计稿横向分辨率/10

解析

假设 IPhone6,dpr=2,逻辑像素为 375px,实际屋里像素为 750px;设计稿为 750px,设计稿上有一个 150px 的元素

此时 document.documentElement.clientWidth=375,

设置 scale 后,scale = 1 / devicePixelRatio=0.5,

此时 document.documentElement.clientWidth=750,

页面实际会两倍缩放。但页面宽度为 750,那么此时设计稿的宽度=设备的宽度了。页面上元素的宽度,也就是设计稿上的宽度。只不过我们需要将 px 换成 rem.

我们先假设 1rem=750px。即根元素的 font-size 为 750px,那么设计稿宽 750px,为 1rem,设计稿上 150px 的元素应该为多少 rem 呢?

1rem750px=?150px

我们可以求得。150px 就应该对应 0.2rem。

针对 750 设计稿我们就得到一个公式

rem=稿px750

由此方法,我就可以算出 750px 设计稿上,多有元素尺寸 px 应该是多少 rem 了。

设备像素大小是不能改变的,但设计稿的大小是可以改变的,如果设计稿不是 750px,而是 1000px,或者 640px 呢,以 1000px 设计稿为例,如何 1000px 设计稿 放到 750px 的屏幕上?

不同尺寸的设计稿肯定是等比例放大或缩小的。

即设计稿宽度从 750 到 1000 放大了多少,那么 750 设计稿上 150 的元素,到 1000 设计稿上就应该放大多少,得到以下公式

7501000=750稿1000稿

这里把 1000 的设计稿变为 750 的设计稿,也就是当我知道了 1000 设计稿元素尺寸,我要知道它在 750 设计稿上的尺寸是多少。即

750稿=7501000稿1000

我们前面已经推出了 750 设计稿 rem 的计算公式,

rem=7501000稿1000750=1000稿1000

由此我们也就得到了一个不管多大设计稿,求 rem 的通用公式

rem==稿稿

10?

10 可以是 5,可以是 20,10 只是一个系数,便于算出来的值不会太大,也不会太小,

计算麻烦?

借助 css 处理器

less
//定义一个变量和一个mixin
@baseFontSize: 75; //基于视觉稿横屏尺寸/10得出的基准font-size
.px2rem(@name, @px) {
  @{name}: @px / @baseFontSize * 1rem;
}
//使用示例:
.container {
  .px2rem(height, 240);
}
//less翻译结果:
.container {
  height: 3.2rem;
}
//定义一个变量和一个mixin
@baseFontSize: 75; //基于视觉稿横屏尺寸/10得出的基准font-size
.px2rem(@name, @px) {
  @{name}: @px / @baseFontSize * 1rem;
}
//使用示例:
.container {
  .px2rem(height, 240);
}
//less翻译结果:
.container {
  height: 3.2rem;
}

比较

共同点:

  • 都能适配所有的手机设备,对于 pad,网易与淘宝都会跳转到 pc 页面,不再使用触屏版的页面
  • 都需要动态设置 html 的 font-size
  • 布局时各元素的尺寸值都是根据设计稿标注的尺寸计算出来,由于 html 的 font-size 是动态调整的,所以能够做到不同分辨率下页面布局呈现等比变化
  • 容器元素的 font-size 都不用 rem,需要额外地对 font-size 做媒介查询
  • 都能应用于尺寸不同的设计稿,只要按以上总结的方法去用就可以了

不同点

  • 淘宝的设计稿是基于 750 的横向分辨率,网易的设计稿是基于 640 的横向分辨率,还要强调的是,虽然设计稿不同,但是最终的结果是一致的,设计稿的尺寸一个公司设计人员的工作标准,每个公司不一样而已
  • 淘宝还需要动态设置 viewport 的 scale,网易不用

VM

window.innerWidth/window.innerHeight

  • vw : 1vw 等于视窗宽度的 1%
  • vh : 1vh 等于视窗高度的 1%
  • vmin : 选取 vw 和 vh 中最小的那个
  • vmax : 选取 vw 和 vh 中最大的那个

img

目前出视觉设计稿,我们都是使用750px宽度的,从上面的原理来看,那么100vw = 750px,即1vw = 7.5px

width: 369px;就应该为 width: 49.2vw;

  • 使用vw来实现页面的适配,并且通过 PostCSS 的插件postcss-px-to-viewportpx转换成vw。这样的好处是,我们在撸码的时候,不需要进行任何的计算,你只需要根据设计图写px单位
  • 为了更好的实现长宽比,特别是针对于imgvedioiframe元素,通过 PostCSS 插件postcss-aspect-ratio-mini来实现,在实际使用中,只需要把对应的宽和高写进去即可
  • 为了解决1px的问题,使用 PostCSS 插件postcss-write-svg,自动生成border-image或者background-image的图片

不足:

  • 比如当容器使用vw单位,margin采用px单位时,很容易造成整体宽度超过100vw,从而影响布局效果。对于类似这样的现象,我们可以采用相关的技术进行规避。比如将margin换成padding,并且配合box-sizing。只不过这不是最佳方案,随着将来浏览器或者应用自身的 Webview 对calc()函数的支持之后,碰到vwpx混合使用的时候,可以结合calc()函数一起使用,这样就可以完美的解决。

  • 他除了在手机端上有较好的浏览效果之外,其他宽屏设备会占满全屏幕,浏览起来就觉得很大,, 使用 clamp()

  • 而且 vw 还不能像 rem 那种方案,让其在 PC 端(宽屏)之下水平居中 ????

  • 另外一点,px转换成vw单位,多少还会存在一定的像素差,毕竟很多时候无法完全整除