# 响应式布局

## 前言

随着移动设备的普及和网络技术的发展，如何让网站或应用在各种设备和屏幕尺寸上都能呈现出良好的用户体验，这个问题变得尤为重要。这就是响应式布局的目标，它通过使用一系列技术来创建可以适应各种屏幕尺寸的网站和应用。

响应式布局并非没有挑战，需要确保内容在所有设备上都可以正常访问，且在大屏幕上并非总是能够保持小屏幕上的效果。另外，响应式图片和视频，以及跨浏览器兼容性也是我们需要关注的问题。

响应式网站有以下特点：

- 同时适配平板+PC+手机等多终端
- 标签导航在接近手持终端设备时改变为经典的抽屉式导航

- 网站的布局会根据视口来调整模块的大小和位置

优点：

- 面对不同分辨率设备灵活性强；

- 能够快捷解决多设备显示适用问题。

缺点：

- 效率较低，兼容各设备工作量大；
- 代码较为累赘，加载时间会加长；
- 在一定程度上改变了网站原有的布局结构，会出现用户混淆的情况



## 核心概念

首先，我们来谈谈响应式布局的核心概念。响应式布局是一种设计和开发应对不断变化的用户行为和设备环境的方法。这种环境包括设备的屏幕大小、操作系统、浏览器、输入方式等。在实践中，响应式布局常常涉及到包括弹性网格和布局、图片、CSS媒体查询等元素的使用。

那么，如何实现响应式布局呢？

一个基本的响应式布局方案通常包含三个核心技术：**媒体查询、弹性网格布局和可变图片**。

1. **媒体查询**：媒体查询是CSS3的一部分，它允许内容根据设备的某些特性，如视口宽度、屏幕分辨率等来呈现。通过使用媒体查询，我们可以为不同的视口大小编写特定的CSS规则。
2. **弹性网格布局**：弹性网格布局是通过相对单位（如百分比），而不是固定的像素单位来定义布局的一种方式。这使得布局可以适应不同的屏幕大小。
3. **可变图片**：可变图片的意思是图片的大小可以根据屏幕尺寸的变化而变化。这意味着我们可以为不同的设备和屏幕尺寸提供适当大小的图片，从而优化性能和用户体验。



## 技术方案

接下来，让我们看一些具体的响应式布局技术。

### 媒体查询

最常见的响应式布局实现方式就是媒体查询，CSS3中的媒体查询可以让我们针对不同的媒体类型定义的不同的样式，当重置浏览器窗口大小的过程中，页面也会根据浏览器的宽度和高度重新渲染页面。

| Minimum width | CSS                                  |
| ------------- | ------------------------------------ |
| 640px         | `@media (min-width: 640px) { ... }`  |
| 768px         | `@media (min-width: 768px) { ... }`  |
| 1024px        | `@media (min-width: 1024px) { ... }` |
| 1280px        | `@media (min-width: 1280px) { ... }` |
| 1536px        | `@media (min-width: 1536px) { ... }` |

上面的断点，把常见的屏幕划分开来。

首先需要设置`viewport`:

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

> - width=device-width: 自适应手机屏幕的尺寸宽度
> - maximum-scale: 缩放比例的最大值
> - minimum-scale: 缩放比例的最小值
> - inital-scale: 缩放的初始化
> - user-scalable: 用户的可以缩放的操作
>
> 通过设置`width=device-width, initial-scale=1`，我们可以让视口的宽度等于设备的宽度，并且禁止用户进行缩放，从而确保网站在移动设备上以正确的大小显示

使用`@media`关键字：

```css
/* pc width > 1100px */
html{ font-size: 100%;}
body {
    background-color: yellow;
    font-size: 1.5rem;
}
/* ipad pro */
@media screen and (max-width: 1024px) {
    body {
      background-color: #FF00FF;
      font-size: 1.4rem;
    }
}
/* ipad */
@media screen and (max-width: 768px) {
    body {
      background-color: green;
      font-size: 1.3rem;
    }
}
/* iphone6 7 8 plus */
@media screen and (max-width: 414px) {
    body {
      background-color: blue;
      font-size: 1.25rem;
    }
}
/* iphoneX */
@media screen and (max-width: 375px) and (-webkit-device-pixel-ratio: 3) {
    body {
      background-color: #0FF000;
      font-size: 1.125rem;
    }
}
/* iphone6 7 8 */
@media screen and (max-width: 375px) and (-webkit-device-pixel-ratio: 2) {
    body {
      background-color: #0FF000;
      font-size: 1rem;
    }
}
/* iphone5 */
@media screen and (max-width: 320px) {
    body {
      background-color: #0FF000;
      font-size: 0.75rem;
    }
}
```



### rem布局

`REM`是`CSS3`新增的单位，并且移动端的支持度很高Android2.x+、ios5+都支持。`rem`单位都是相对于根元素html的`font-size`来决定大小的,根元素的`font-size`相当于提供了一个基准，当页面的size发生变化时，只需要改变`font-size`的值，那么以`rem`为固定单位的元素的大小也会发生响应的变化。 因此，如果通过`rem`来实现响应式的布局，只需要根据视图容器的大小，动态的改变`font-size`即可（而`em`是相对于父元素的）。



**rem响应式的布局思想：**

- 一般不要给元素设置具体的宽度，但是对于一些小图标可以设定具体宽度值

- 高度值可以设置固定值，设计稿有多大，我们就严格有多大

- 所有设置的固定值都用`rem`做单位（首先在HTML总设置一个基准值：`px`和`rem`的对应比例，然后在效果图上获取`px`值，布局的时候转化为`rem`值)

- js获取真实屏幕的宽度，让其除以设计稿的宽度，算出比例，把之前的基准值按照比例进行重新的设定，这样项目就可以在移动端自适应了

  

**缺点：**

在响应式布局中，必须通过js来动态控制根元素`font-size`的大小，也就是说css样式和js代码有一定的耦合性，且必须将改变`font-size`的代码放在`css`样式之前

```javascript
function refreshRem() {
    var docEl = doc.documentElement;
    var width = docEl.getBoundingClientRect().width;
    var rem = width / 1920;
    docEl.style.fontSize = rem + 'px';
    flexible.rem = win.rem = rem;
}
win.addEventListener('resize', refreshRem);
```

`REM`布局也是目前多屏幕适配的最佳方式。默认情况下我们html标签的`font-size`为`16px`，我们利用媒体查询，设置在不同设备下的字体大小。



### 视口单位

![image-20230519150930249](https://static.www.toimc.com/blog/picgo/2023/05/19/image-20230519150930249-8e2d52.webp)

类似百分比方案，单位是vw（视口宽度），它们可以帮助我们创建真正的流畅布局。1vw等于视口宽度的1%，这使得元素的大小可以根据视口的宽度动态变化，借助`calc`函数，可以实现单位上的换算。

CSS3中引入了一个新的单位`vw/vh`，与视图窗口有关，`vw`表示相对于视图窗口的宽度，`vh`表示相对于视图窗口高度，除了`vw`和`vh`外，还有`vmin`和`vmax`两个相关的单位。

各个单位具体的含义如下：

| 单位 | 含义                                                      |
| ---- | --------------------------------------------------------- |
| vw   | 相对于视窗的宽度，1vw 等于视口宽度的1%，即视窗宽度是100vw |
| vh   | 相对于视窗的高度，1vh 等于视口高度的1%，即视窗高度是100vh |
| vmin | vw和vh中的较小值                                          |
| vmax | vw和vh中的较大值                                          |

用视口单位度量，视口宽度为`100vw`，高度为`100vh`（左侧为竖屏情况，右侧为横屏情况）。例如，在桌面端浏览器视口尺寸为`650px`，那么 1vw = 650 * 1% = 6.5px（这是一个理论值，如果浏览器不支持`0.5px`，那么实际渲染结果可能是`7px`）。

与百分比方案的对比：

| 单位  | 含义                                                         |
| ----- | ------------------------------------------------------------ |
| %     | 大部分相对于祖先元素，也有相对于自身的情况比如（border-radius、translate等) |
| vw/vh | 相对于视窗的尺寸                                             |

具体做法：

```scss
//iPhone 6尺寸作为设计稿基准
$vm_base: 375; 
@function vw($px) {
    @return ($px / 375) * 100vw;
}
```

