# 移动端适配和零散知识汇总

# 移动端适配🤩

乍一看,移动端适配看起来就很高级的鸭子🦆,实则确实,我们知道,如果的前端,不再仅仅只是谢谢 pc 端的网页呀这些枯燥无味的事情了,取而代之的是越来越花里胡哨(贼难🥺)的东西。话不多说,进入我们今天的正题:移动端适配。

# 前置技术支持💡

# 像素

像素是指由图像的小方格组成的,这些小方块都有一个明确的位置和被分配的色彩数值,小方格颜色和位置就决定该图像所呈现出来的样子。

图片、电子屏幕(手机、电脑)就是由无数个具有特定颜色和特定位置的小方块拼接而成。

像素可以作为图片或电子屏幕的最小组成单位。

# 分辨率

分辨率指含有的像素数。

iPhone XS Max 的分辨率分别为 2688 x 1242。这表示手机分别在垂直和水平上所具有的像素点数。

一张图片的分辨率为 800 x 400。这表示图片分别在垂直和水平上所具有的像素点数为 800 和 400。

# 移动端调试方法

  • 模拟器调试

    Chrome DevTools (谷歌浏览器) 的移动端模拟

img

  • 真机测试(检测 bug 用的多)

    搭建本地 web 服务器,手机和服务器在同一个局域网内,通过手机去访问服务器

  1. 首先先确定自己当前所在局域网的 ipv4

​ Windows:ipconfig

img

​ MacOS/Linux: ifconfig

img

  1. 然后在手机浏览器中输入正确的 ip 地址(或加端口号)即可访问
  • 使用 ip 或域名直接访问(几乎用不到)

    这里就不过多介绍了,感兴趣的同学可以去看看各大网站的移动端网站

# 视口(重点)⭐️⭐️

视口(Viewport) 是移动 Web 开发中一个非常重要的概念,最早是由苹果公司在推出 iPhone 手机时发明的,其目的是为了让 iPhone 的小屏幕尽可能完整显示整个网页。通过设置视口,不管网页原始的分辨率尺寸有多大,都能将其缩小显示在手机浏览器上,这样保证网页在手机上看起来更像在桌面浏览器中的样子。在苹果公司引入视口的概念后,大多数的移动开发者也都认同了这个做法。

简单来说, 视口就是浏览器显示页面内容的屏幕区域 。在移动端浏览器中,存在着三种视口,即 布局视口(layout viewport)、视觉视口(visual viewport)和理想视口(ideal viewport) ,下面分别进行详细讲解。

# 布局视口(layout viewport)

布局视口是指网页的宽度,一般移动端浏览器都默认设置了布局视口的宽度。根据设备不同,布局视口的默认宽度有可能是 768px、980px 或 1024px…… 等,所以 PC 上的网页大多都能在手机上呈现,只不过元素看上去很大,一般默认可以通过手动缩放网页,但是这个宽度并不适合在手机屏幕中展示。移动端浏览器之所以采用这样的默认设置,是为了解决早期的 PC 端页面在手机上显示的问题。

img

在上图中,当移动端浏览器展示在 PC 端网页内容时,由于移动端设备屏幕比较小,不能像 PC 端浏览器那样完美的展示网页,这正是布局视口存在的问题。这样的网页在手机浏览器中会出现左右滚动条,用户需要左右滑动才能查看完整的一行内容。

(题外话:这个 demo 的话一般比较难找哈,我相信在大家没有了解过这些东西之前写出来的页面很有可能就是有左右滚动条的哦。哈哈哈)

当我们以百分比来指定一个元素的大小时,它的计算值是由这个元素的包含块计算而来的。当这个元素是最顶级的元素时,它就是基于布局视口来计算的。

所以,布局视口是网页布局的基准窗口,在 PC 浏览器上,布局视口就等于当前浏览器的窗口大小(不包括 borders 、margins、滚动条)。

在移动端,布局视口被赋予一个默认值,大部分为 980px,这保证 PC 的网页可以在手机浏览器上呈现,但是非常小,用户可以手动对网页进行放大。

我们可以通过调用 document.documentElement.clientWidth / clientHeight 来获取布局视口大小

[

](https://blog.csdn.net/abraham_ly/article/details/111454724)

img

img

# 视觉视口(visual viewport)

视觉视口是指用户正在看到的网站的一个区域,这个区域的宽度等同于移动设备的浏览器窗口的宽度。下图演示了什么是视觉视口。

img

** 注意:** 当我们在手机中缩放网页的时候,操作的是视觉视口,而布局视口仍然保存原来的宽度。

# img

# 理想视口(ideal viewport)

理想视口是指对设备来讲最理想的视口尺寸。采用理想视口的方式,可以使网页在移动端浏览器上获得最理想的浏览和阅读的宽度。下图演示了什么使理想视口。

img

在上图中可以看出,在理想视口的情况下,布局视口的大小和屏幕宽度是一致的,这样就不需要左右滚动页面了。在实际开发中,为了实现理想视口,需要给移动端页面添加 meta 标签配置视口,通知浏览器进行处理。

当页面缩放比例为 100% 时,1 单位的 CSS 的 pixel 是严格相等于 1 单位的设备 pixel,即 CSS 像素 = 设备独立像素,理想视口 = 视觉视口。

我们可以通过设置 Meta viewport 来实现。

Meta viewport

我们可以借助 <meta> 元素的 viewport 来帮助我们设置视口、缩放等,从而让移动端得到更好的展示效果。

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
Value可能值描述
width正整数或 device-widthpixels (像素)为单位, 定义布局视口的宽度。
initial-scale0.0 - 10.0定义页面初始缩放比率。
minimum-scale0.0 - 10.0定义缩放的最小值;必须小于或等于 maximum-scale 的值。
maximum-scale0.0 - 10.0定义缩放的最大值;必须大于或等于 minimum-scale 的值。
user-scalableyes / no如果设置为 no ,用户将不能放大或缩小网页。默认值为 yes。

为了在移动端让页面获得更好的显示效果,我们必须让布局视口、视觉视口都尽可能等于理想视口。

device-width 就等于理想视口的宽度,所以设置 width=device-width 就相当于让布局视口等于理想视口。

# 多倍图(重点)

# 物理像素

物理像素:即设备像素,而物理像素点是屏幕显示的最颗粒,在同一设备上,它的物理像素和物理像素点是固定的。这是厂商在出厂时就设置好的,即一个设备的分辨率时固定的。比如 iphone6 的物理像素是 750px * 1334px。

img

# 逻辑像素

** 逻辑像素:** 即 css 像素,是视口中的一个小方格,所以 css 样式代码中使用的是逻辑像素。假如在一个设备中,物理像素和逻辑像素相同,将不会产生任何问题。但是在 iphone4 中,物理像素是 640px * 960px,而逻辑像素为 320px * 480px,因此需要使用大约 4 个物理像素来显示一个 css 像素 (逻辑像素)。因为 iphone 的屏幕是 Retina 屏幕,也就是说将 4 个物理像素点(宽 2 个,高两个,合计 4 个)压缩到一个 css 像素中,来达到高清的效果。

# Retina (视网膜屏幕)

所谓 “Retina” 是一种显示技术,可以将更多的像素点压缩至一块屏幕里,从而达到更高的分辨率并提高屏幕显示的细腻程度。由苹果公司发明。最初该技术是用于苹果的 iPhone4 上。其屏幕分辨率为 960×640(每英寸像素数 326ppi)。这种分辨率在正常观看距离下足以使人肉眼无法分辨其中的单独像素。也被称为视网膜显示屏。

对于一张 50px * 50px 的图片,在手机或 Retina 屏中打开,按照刚才的物理像素比会放大倍数,这样会造成图片模糊。

# 物理像素比

物理像素比是指:物理像素与逻辑像素之间的比例。当像素比为 1:1 时,使用一个物理像素显示一个逻辑像素,当像素比为 2:1 时,使用 4 个物理像素显示一个逻辑像素。

img

那么我们如何知道设备的物理像素比呢?总不能自己在那算吧,不用着急,js 已经在 window 对象中为我们封装好了一个属性:var a = window.devicePixelRatio;,我们可以通过这个属性来获取设备的物理像素比。

# 倍图的作用

在实际开发中,我们大多数情况下会使用到 2 倍图和 3 倍图来操作 background-size 属性,来解决精灵图(雪碧图)或背景图片模糊的问题。

在实际开发中,我们从视觉小姐姐!!🤩 那拿到的设计图通常都是 640px 或 750px 的设计图,所以为了解决设备中背景图模糊的问题,我们可以把更多的像素点压缩至一块屏幕,或者说压缩到一个逻辑像素 (css 像素) 内,从而达到更高的分辨率并提高屏幕显示的细腻程度。

# 背景缩放 background-size

介绍: background-size 属性指定背景图片的大小

语法: background-size: length | percentage | cover | contain;

单位:px (像素) 或 %(百分比)

注意:如果想要图片在盒子内全部覆盖显示,则使用 100% 即可

描述
length设置背景图片高度和宽度。第一个值设置宽度,第二个值设置的高度。如果只给出一个值,第二个是设置为 auto (自动)
percentage将计算相对于背景定位区域的百分比。第一个值设置宽度,第二个值设置的高度。如果只给出一个值,第二个是设置为 "auto (自动)"
cover此时会保持图像的纵横比并将图像缩放成将完全覆盖背景定位区域的最小大小。
contain此时会保持图像的纵横比并将图像缩放成将适合背景定位区域的最大大小。

# 移动端适配方案

# 1. rem 布局

/* 设置 html 元素的字体大小为 16px,即 1rem = 16px */
html {
    font-size: 16px;
}
/* 设置 box 元素宽 160px,10rem = 160px */
.box {
    width: 10rem; /* 160px */
}

修改 HTML 元素的字体大小可以成比例的调整以 rem 为单位的属性,通过这一个特性,我们可以实现将视窗按一定比例划分为一份一份的,当页面内元素刚好分完所有的份数,页面内容即充满整个视窗且无横向滚动条。

以宽度 750 像素的设计稿为例,有两个元素,一个元素占 550 个像素,另一个占 750 个像素:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        *{
            padding: 0;
            margin: 0;
        }
        .w-550px {
            width: 550rem;
            height: 100px;
            background-color: rgb(209, 255, 240);
        }
        .full {
            width: 750rem;
            height: 100px;
            background-color: rgb(195, 200, 199);
        }
    </style>
</head>
<body>
    <div class="w-550px"></div>
    <div class="full"></div>
    <script>
        function setRem() {
            // 当前页面宽度相对于 750 宽的缩放比例,可根据自己需要修改
            const scale = document.documentElement.clientWidth / 750;
            document.documentElement.style.fontSize = scale + 'px';
        }
        setRem();
        window.onresize = setRem;
    </script>
</body>
</html>

页面伸缩,网页布局也会进行伸缩。运行结果如下:

img

目前,除了 IE8 及更早版本外,所有浏览器均已支持 rem。

# 总结

优点:rem 布局能很好的实现在不同尺寸的屏幕横向填满屏幕,且在不同屏幕元素大小比例一致

缺点:在大屏设备(Pad)上,元素尺寸会很大,页面显示更少的内容。

针对大屏改进方案:

  1. 限制 rem 的最大值,
  2. 通过媒体查询,限制内容最大宽度,如:腾讯网荔枝 FM

在移动端浏览器 rem 方案是解决移动端适配的主流方案,这套方案的另一个名字叫做 flexible 方案,通过动态设置 rem 实现在不同尺寸的设备上界面展示效果一致。

lib-flexible 库里有这样一段话:

由于 viewport 单位得到众多浏览器的兼容,lib-flexible 这个过渡方案已经可以放弃使用,不管是现在的版本还是以前的版本,都存有一定的问题。建议大家开始使用 viewport 来替代此方。

可知,rem 方案的目的是解决 viewport 不兼容的问题,但是我个人认为,rem 的目的提供一种比例单位,不仅可以解决移动端适配问题,也还有其他的用处。

# 2. vw/vh 布局

vw/vh 方案与 rem 方案类似,都是将页面分成一份一份的,只不过 vw/vh 是将页面分为 100 份,1vw = device-width/100

# 总结

优点:vw、vh 布局能良好的实现在不同尺寸的屏幕横向填满屏幕,使用 postcss-px-to-viewport 能很好的帮我们进行单位转换

缺点:

  • 无法修改 vw/vh 的值,在大屏设备(Pad)中元素会放大,且无法通过 js 干预
  • 兼容性 - 大多数浏览器都支持、ie11 不支持 少数低版本手机系统 ios8、android4.4 以下不支持

# 3. 百分比布局

在 css 中,我们可以使用百分比来实现布局,但是需要特定宽度时,这个百分比的计算对开发者来说并不友好,且元素百分比参考的对象为父元素,元素嵌套较深时会有问题。

案例:设计稿为 750*1136,我们需要一个宽度为 200px 的盒子

.box {
  /* w = 200 / (750/100) = 26.66667 */
  /* 可知,计算复杂,且会存在误差 */
  width: 26.6%;
}

扩展: 子元素的 width 和 height 百分比参考对象是父元素的 width 和 height,margin、padding 的参考对象为父元素的 width,border-radius、background-size、transform: translate()、transform-origin 的参考对象为自身宽高

# 4. 响应式布局

通过媒体查询,可以针对不同的屏幕进行单独设置,但是针对所有的屏幕尺寸做适配显然是不合理的,但是可以用来处理极端情况(例如 IPad 大屏设备)或做简单的适配(隐藏元素或改变元素位置)

CSS3 @media 查询属性详解

媒体查询案例:

body {
  background-color: yellow;
}
/* 针对大屏产品 ipad pro */
@media screen and (min-width: 1024px) {
    body {
      background-color: blue;
    }
}

# 5. px 为主,搭配 vw/vh、媒体查询与 flex 进行布局

先查看一下当前各大网站移动端适配的结果:

小屏幕自适应,限制最大宽度:腾讯网荔枝 FM

布局高度固定,宽度自适应:淘宝网百度网易

移动端适配的宗旨是:让拥有不同屏幕大小的终端设备拥有一致的 UI 界面,让拥有更大屏幕的终端展示更多的内容, 那么布局高度固定、宽度自适应的方案针对文本较多的网页(百度网易)是更好的,针对大屏幕,腾讯网荔枝 FM 的做法是限制最大宽度来让大屏有更好的体验。

我们从页面编写的角度出发,页面中更多的是文本和布局,关于文本,我们应该使用 px 作为单位,来实现在大屏设备显示更多的内容,而不是更大的文本;关于布局,我们可以使用 flex 实现弹性布局,当实现特定宽高元素时,可以适当的使用 vw/vh,当特定的值使用 vw/vh 计算复杂或存在误差时,也可以使用 rem

# 适配流程

  1. 编写 <meta> 标签设置 viewport 的内容 width=device-width,让网页宽度等于视窗宽度

  2. 在 css 中使用 px

  3. 在适当的场景使用 flex 布局,或者配合 vw 进行自适应

  4. 在跨设备类型的时候(pc <-> 手机 <-> 平板)使用媒体查询

  5. 在跨设备类型如果交互差异太大的情况,考虑分开项目开发

# 零散知识汇总之乱七八糟

# 1.Node 的简单使用

大家可能或多或少都接触甚至使用 node,其实我是不想给大家讲这个东西的,但担心讲的东西太少,时间不够,所以来水个时间。

首先大家听到的最多就是 node 可以用来写后端,可以让前端成为全栈爷,实则不然,这只是他众多模块的比较重要的一块 - http 模块。的确,他可以让我们像后端一样去写接口,但我们今天不讲🤪🤪🤪。今天我们主要来讲一下什么是 node 和他的一些简单使用。

上官网:

img

node 的简单学习

大家是不是看的迷迷糊糊,这很正常,因为学长当时也是这样。

在学长看来,node 是对 es 标准的一个实现,是 js 跑起来的一个引擎。

通过 Node 可以使 js 代码在服务器端执行

  • Node 仅仅对 ES 标准进行了实现,所以在 Node 中不包含 DOM 和 BOM
  • Node 中可以使用所有的内建对象
    String Number Boolean Math Date RegExp Function Object Array
    而 BOM 和 DOM 都不能使用
    但是可以使用 console 也可以使用定时器(setTimeout () setInterval ())

大家都知道,你们一般去跑 js 代码都是在控制台去进行输出或着把 js 代码放在 html 里面让浏览器去解析。

这会不会觉得很浪费时间。我就想打印一个 1,你却让我如此劳累,实在辛苦。

那我们有什么方法可以直接去执行 js 代码呢。这个时候 node 就站出来了说我来!!!

node index.js
// 我帮你执行一下这个 js 代码哈,不用谢我。

那万一我执行代码想传参呢,没问题,直接写

node index.js nirvana age=18 idol="钰姐"

那我们怎么知道我们参数传没传成功呢,其实所有的参数都存在 process.argv 里面。我们可以试着打印一下看看结果。

argv:[
   "node":node的系统路径,
   "index.js":运行javascri文件的路径
   ...[参数]
    e.g:
    "Nirvana",
    "age=18"
]

img

我们发现这其实是个数组,那我们是不是就可以对他进行各种花式操作

process.argv[2];
process.argv[3];
你也可以:
process.argv.foreach()

这就是 node 的一个简单使用。

# 2.Node 中的一些注意事项

img

img

但在 node 中我们去直接打印 this 我们会发现是一个空对象。这是为什么呢,其实 node 在执行时和我们的浏览器还是有区别的。毕竟二者不是同一个东西嘛,不必大惊小怪的。

下面的东西大家暂时只用做一个了解。

global 是一个全局对象,事实上前端我们提到的 process,console,setTimeout 等都要放在其中

img

他其实就跟我们的 window 对象很像,但也有区别,这也就是为什么同是打印 this,输出的结果不同的原因

var name ="Nirvana"
console.log(name)//Nirvana
console.log(global.name)//undefined
因为在浏览器中,是没有模块的概念,但是在node中会有模块化的思想,每一个文件都是一个模块,
他不会轻易将变量放在global上面的

# 3.npm

img

npm node package manager,通常称为 node 包管理器。npm 不需要单独安装。在安装 Node 的时候,会连带一起安装。

node 包就是封装了特定功能的模块,有人将一些经常使用的、成熟的功能封装成 node 包并将其放在了 npm 上。通过 npm 我们可以免费使用其他人做好的模块,只需下载后引入即可。当然你也可以自己造轮子为社区做贡献 hhh。

# 4.call 和 apply

大家都知道,我们的对象中的 this 时指向本身,而函数的 this 指向他的调用者,那如果有一天,我们别的对象也想让函数的 this 指向他,那我们应该怎么办呢🤔🤔。

这个时候我们的 call 和 apply 方式就出现啦。

老规矩,上 mdn!

img

function idol(){
    console.log("我的idol:",this.idol)
}
// 害,可我想粉钰姐咋办
let me ={
    idol:"钰姐"
}
idol.call(me)
// 我的 idol:钰姐

这就是 call 的简单操作,对于 apply 的话其实也大同小异。大家可以去查阅 MDN 进行更多的学习。

(小声哔哔:主要是水的时间差不多了,可以下班了)

# 作业:

  1. 既然大家都有自己的学长学姐,那大家就手写一个 call 和 apply 吧。(我相信这个对大家来说不难的吧🤪)
//call 的模拟实现
Function.prototype.myCall = function(){
   
}
//apply 的模拟实现
Function.prototype.myApply = function(){
   
}
  1. 嗯,偶像不能多,更不能重复啦,那我们就再实现一个数组的去重吧!!!!
//es5
//es6

大家可能会觉得奇怪

移动端适配的作业怎么奇奇怪怪的,没有办法,学长也不想的,总不能让大家去做一个移动端页面吧,这不得累死大家。所以呢学长只能名正言顺的摸鱼了。(傲娇🥳🥳)

更新于 阅读次数