# CSS3教程 - 17 视口

下面来讲解视口,以及移动端网页的适配问题。

# 17.1 像素

# 1 屏幕像素

屏幕是由一个个发光的小点构成的,这每一个小点就是一个像素。我们经常说屏幕的分辨率,例如 1920x1080 ,就表示屏幕中小点的数量,横向是1920个点,纵向是1080个点。

但是相同的分辨率,屏幕的尺寸却可能是不同的。例如24寸的显示器,分辨率是 1920*1080 ,一个手机屏幕是5.5寸的,分辨率也能达到 1920*1080 ,因为现在的手机普遍采用高清屏,也就是高清屏的像素点更小了,肉眼根本看不见像素,显示非常清晰。

所以如果有一张 200*200 像素的图片,在某些高清屏幕上,因为像素密度更大,像素点变小,显示出的图片就会变小。例如在像素密度是标准屏幕密度的两倍的屏幕上,显示出的图片看上去就像 100*100 的。

屏幕像素也可以称为物理像素。


# 2 CSS像素

我们在开发CSS时候,设置的以像素为单位的尺寸,并不是屏幕像素,而是CSS像素

在以前没有高清屏幕的时候,一个 CSS像素 等于 一个屏幕像素。但是现在因为高清屏幕的原因,一个CSS像素可能需要多个屏幕像素来显示。浏览器在显示网页的时候,需要将CSS像素转换为屏幕像素进行显示。

所以这里涉及到一个概念,就是设备像素比(DPR),在标准屏幕(DPR = 1)上,1 CSS像素 等于 1 物理像素。但是在高 DPI 屏幕(例如 Retina 屏幕,DPR = 2)上,1 CSS像素的宽度对应 2个屏幕像素的宽度,那么一个 CSS像素需要4个屏幕像素显示(宽高2*2=4)。

CSS像素也可以称为逻辑像素。

# 17.2 视口

视口(viewport)就是浏览器中用来显示网页的区域。通过查看网页的 <html> 标签的宽度,可以知道视口的大小。

默认情况下,通过移动端访问网页,视口的大小都是 980px (CSS像素),即使手机的尺寸不同,但是宽度都是 980 个CSS像素。

例如我们写一个网页如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <!--
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  -->
  <title>Document</title>
</head>
<body>
  <div class="box1">www.foooor.com</div>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
  • 就是一个普通的网页,VSCode 自动生成的,但是注意,需要将上面 viewport<meta> 去掉,这个是用来适配移动端的。

此时使用浏览器的开发者工具,使用移动端模式来查看网页,可以看到不管选择什么设备,视口宽度都是 980px:

需要注意,现在的很多网页都是针对移动端单独开发的页面,使用移动端和PC端访问是不同的页面,那么就不是这个值了。

所以说,在移动端浏览器都会将视口设置为 980 个CSS像素,以保证PC端的网页可以在移动端正常显示,如果网页的宽度超过了 980 像素,那么移动端的浏览器会自动对网页进行缩放,以保证完整显示网页的内容。

但是如果不针对移动端进行适配,通过移动端来访问网页,体验往往很差,因为屏幕太小了,显示完整的网页后,内容基本看不清,需要手动放大查看局部信息。所以大部分网站都针对移动端单独设计网页,PC端和手机端访问的是不同的网页。

通过移动端查看网页,设备像素比 = 设备屏幕宽度像素 / 980CSS像素(视口宽度) ,如果设备屏幕宽度是 1960 像素,那么设备像素比就是 2 。也就是1个CSS像素需要2个屏幕像素来显示(只说宽度方向上)。

所以我们要编写移动端页面,首先需要调整设备像素比,根据上面的公式,屏幕像素是无法调整的,只能调整视口宽度,如果降低视口宽度,那么设备像素比就变大了,一个CSS像素就需要更多的屏幕像素来显示,那么元素就会变大了。

在 HTML 中通过 <meta> 标签来设置视口的宽度。

举个栗子:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">

  <!-- 设置视口的宽度为 400 CSS像素 -->
  <meta name="viewport" content="width=400px">
  
  <title>Document</title>

  <style>
    * {
      padding: 0;
      margin: 0;
    }

    .box1 {
      width: 200px;
      height: 200px;
      background-color: skyblue;
    }
  </style>
</head>
<body>
  <div class="box1"></div>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  • 在上面设置了视口的宽度为 400 CSS像素;
  • 然后设置了 box1 的尺寸为 200 CSS 像素,那么此时box1 宽度为屏幕的一半。

显示如下:

操作的时候注意一下,保证上面显示的时候,屏幕水平和垂直都没有滚动条,如果有滚动条,通过 浏览器->显示,重置一下显示比例。


# 17.3 完美视口

好了,现在思路已经有了,要想网页在移动端显示正常,就需要调整视口的宽度,保证 CSS 像素对应合理的屏幕像素。

不同的设备,屏幕尺寸和像素是不一样的,那么视口的宽度应该设置为多少呢?

每一款移动设备在设计时,都会有一个最佳的设备像素比,一般我们只需要将像素比设置为最佳像素比,就可得到一个最佳效果。所以只需要将视口宽度设置为最佳像素比对应的视口大小,就能得到完美视口。

网页中提供了一个变量 device-width 表示设备的完美视口宽度:

<-- 将网页的视口设置为完美视口 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
1
2

device-width 代表的是 逻辑像素(CSS 像素),而不是物理像素(屏幕像素)。假设有一台设备的物理屏幕宽度是 1920 像素,DPR = 2,那么浏览器会把 device-width 设为 960 像素,这是因为设备像素比为 2,浏览器会将每 2 个物理像素映射到 1 个 CSS 像素。如果 DPR = 3,那么 device-width 将是 640 像素

所以以后写移动端的页面,需要添加上面的 <meta> 元数据标签,以实现完美视口。 initial-scale=1.0 是保证页面一开始不被缩放。

# 17.4 vw单位

在不设置网页视口宽度的时候,默认是 980 CSS像素,但是设置了完美视口以后,不同的设备视口宽度是不同的。

例如:

  • iPhone12 Pro 完美视口宽度是 390 CSS像素
  • iPhone14 Pro Max 完美视口宽度是 430 CSS像素

所以开发移动端页面,如何让网页在不同的设备上显示效果差不多,就不能直接用 px 了,因为设备的屏幕宽度是不同的。

例如 390px 在 iphone12 是全屏,在 iphone14 就短一些了,你说可以设置百分比,但是也不能所有的元素都全部使用百分比来设置吧。

# 1 vw

下面介绍一个新单位 vwvw 表示的是视口的宽度(viewport width)

  • 100vw = 整个视口的宽度
  • 1vw = 1%视口宽度

vw 是相当于视口宽度进行计算的,在移动端可以使用 vw 单位。

举个栗子:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    * {
      padding: 0;
      margin: 0;
    }

    .box1 {
      width: 20vw;
      height: 20vw;
      background-color: skyblue;
    }
  </style>
</head>
<body>
  <div class="box1"></div>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  • 上面设置 box1 的尺寸为 100vw ,这样在不同的设备上,显示效果是差不多的。

# 2 设计图宽度

上面说在移动端可以使用 vw 来定义元素的尺寸,但是设计师在给我们设计图的时候,图片是像素单位的。

如何转换为对应的 vw 值呢?

现在常见的设计图的宽度有:

  • 750px :是 375px 的两倍,iPhone 很多早期设备完美视口的宽度都是 375px
  • 1125px :是 375px 的三倍。

因为设备是高清屏幕,如果 375 像素的图片显示为 375 CSS像素,会很模糊,所以需要针对设备设计高清的图,也就是两倍三倍尺寸的图片,这样在设备像素比为2或3的设备上,显示才正常清晰。


所以如果一个设计图宽度为 750px,设计图中一个 48px × 35px 大小的元素,使用 vw 来表示,值是多少呢?

100vw = 750px,那么 1px = 0.1333...vw ,由此计算:

  • 48px = 6.4vw
  • 35px = 4.667VW

# 3 rem

设计图宽度为 750px 的情况下,通过上面的 1px = 0.1333...vw 的关系,来将 px 换算得到 vw 的值,这个操作有点麻烦。

有什么好方法吗?

在以前讲单位的时候,说过 rem 是相对于根元素的字体大小来计算的,1rem = 1个html的字体大小 ,我们可以将 html的字体大小 定义为 0.1333333333333333 ,然后使用 rem 作为元素的尺寸单位,这样岂不就可以了。

但是有一个问题,就是浏览器支持最小字体是 12 像素(0除外),不能设置一个比 12 像素还小的字体,所以 rem 的最小设置只能为 12px (0除外),所以没办法,那么只能设置 rem0.1333333333333333 的倍数,例如放大 40 倍(放大10倍不够),这样 1rem = 40px ,这样好换算一些。

举个栗子:

在一个宽度为 750px 的设计图中,有一个元素宽度为 100px,就可以设置它的宽度为 100 / 40 = 2.5rem

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    * {
      padding: 0;
      margin: 0;
    }

    html {
      font-size: 5.3333333333vw;
    }

    .box1 {
      width: 2.5rem;  /* x40,是100像素 */
      height: 2.5rem;
      background-color: skyblue;
    }
  </style>
</head>
<body>
  <div class="box1"></div>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  • 上面设置 html 的字体大小为 5.3333333333vw; ,这样 2.5rem = 2.5 * 40 = 100px。

显示如下: