# 移动 WebApp 项目开发常用技术及标准、规范和最佳实践

在项目实战开始前,我们先来学习以下三方面知识

  • 移动端与 PC 端有哪些不同 ?
  • 移动端常见的布局处理技术有哪些 ?
  • 移动设计稿的标准与规范 ?

# 1、移动端与 PC 端有哪些不同?

TIP

在上一章节,我们讲过,移动端与 PC 端有以下 4 点大的区别

  • 屏幕大小不同
  • 交互方式不同
  • 网络环境和设备性能不同
  • 兼容性不同

因为屏幕大小的不同,所以造成我们在实际的移动端布局时,不能和 PC 端一样采用固定大小来布局,而需要自适应屏幕的宽。

移动端屏幕的常见可视区大小为320-480px之间,也就意味着我们在实际开发代码时,我们的页面宽在320-480px之间。

所以移动端开发,元素的肯定不能用 px 绝对定位写死,我们得采用相对单位来做开发。

不同手机的详细配置,可点击查看详细参数 (opens new window) 👆

image-20220815134327670

image-20220815134217152

# 2、移动端常见的布局处理技术

移动端常见的 5 种布局技术如下:

  • 流体布局
  • rem 和 vw 布局
  • 响应式布局
  • Flex 弹性布局(工具)
  • Grid 网格布局(工具)

其中的流体布局、rem/vw 布局、响应式布局是可以独立实现移动端页面的开发

Flex 弹性和 Grid 网格布局,并不能独立实现移动端布局的开发,他们更像是工具,配合流体布局、rem/vw 布局、响应式布局来实现移动端页面的开发。

具体的每一种技术,我们会通过一个个单独的项目来讲解。

# 3、移动设计稿的标准与规范

TIP

在学习具体的项目开发前,我们来了解下移动开发的设计稿设计标准和规范,这样就更有利于我们后期在开发时的尺寸测量和取色。

我们以京东的移动端设计稿的标准与规范来和大家讲解

image-20220823224742226

注:

详细的规范标准,在钉钉群文件中 京东视觉规范.pdf ,或联系助理老师获取。

接下来我们学习移动 WebApp 开发布局技术中的流体布局。

# 一、流体布局

TIP

所谓的流体布局,也叫百分比%布局,本质上就是通过 %(百分比)和 怪异盒子模型结合来实现元素的相对视口缩放。

接下来我们就利用流体布局来实现以下效果图的页面开发

2022-8-15-index

# 1、搭建本项目的目录结构

TIP

  • 首先新建项目文件夹 WebApp
  • 在 WebApp 中新建 css、js、images 文件夹,分别用来存放 CSS、JS 文件和图片内容
  • 在 CSS 中新建 reset.css、global.css、index.css 文件,分别用来存放重置默认样式、全局通用样式,首页样式

reset.css 样式文件的内容

可参考博客:标签默认博客地址 (opens new window) 👆 中如下截图内容

image-20220815153351605

其它相关重要的重置样式介绍

/* 去掉点击的高亮显示效果 */
-webkit-tap-highlight-color: transparent;
/* 在移动端浏览器默认的外观在ios上加上这个属性才能给按扭和输入框自定义样式 */
-webkit-appearance: none;
/* 禁用长按页面时的弹出菜单 */
img,
a {
  -webkit-touch-callout: none;
}
/* 表单会有外轮廓 */
input {
  outline: none;
}
/* 去掉图片下面的空隙 */
vertical-align: top;

注:

建议在一开始学习时,不要引用 reset.css 文件,这样就可以在学习过程中把所有问题暴露,对于为什么要重置这个默认样式,会有更深的理解。

在实际开发中,我们直接引用 reset.css 文件就好。

进到蓝湖,打开设计稿,点击设计稿,按以下截图操作,下载所有切图,然后放到 images 文件夹,修改好名字。

image-20220816134708722

# 2、了解设计稿的整体标准和规范

TIP

设计稿采用的标准色(如下图)

颜色

字体大小、行间距、字体颜色、字体类型

  • 字体大小(12px、14px、16px)
  • 行间距为字体大小的 1.5 倍
  • 字体类型,以微软雅黑为主,数字是 Arial 类型
  • 字体颜色主要以 #101010 黑色为主

通过以上数据最后得到如下代码,添加到 global.css 文件中

font: 12px/1.5 Microsoft YaHei;
color: #101010;

具体的设计标准,每个公司都有自己的规范,在实际开发中,以公司规范为主。

# 3、新建 index.html 网页,进行首页开发

TIP

  • 在当前根目录下新建 index.html 网页
  • 做好 viewport 视口配置
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
  • 引用相关的 CSS 文件,注意引入文件的顺序
/* 重置样式 */
css代码...

/* 网站通用布局 */
css代码...

/* 通用模块 */
css代码...

/* 通用元件 */
css代码...

/* 通用响应式系统 */
css代码...
<link rel="stylesheet" href="./css/reset.css">
<link rel="stylesheet" href="./css/global.css" />
<link rel="stylesheet" href="./css/index.css" />

# 4、网站整体(html)结构划分

TIP

通过对整个设计稿页面的分析,我们可以用 html 来将整个页面划分成以下几个部分

<!-- header start -->
<header class="header"></header>
<!-- end header-->
<!-- menu start-->
<nav class="menu"></nav>
<!-- end menu -->
<!-- main start -->
<main class="main">
  <!-- cheap start-->
  <section class="cheap"></section>
  <!-- end start-->
  <!-- recommend start -->
  <section class="recommend"></section>
  <!-- end recommend -->
  <!-- product-category start -->
  <section class="product-category"></section>
  <!-- end product-category  -->
</main>
<!-- end main -->
<!-- tabbar start -->
<footer class="tabbar"></footer>
<!-- end tabbar  -->

# 5、每个版块开发

TIP

本次项目我们采用的是流体布局(%百分比 + 怪异盒子模型布局),所以整个页面中会用到的所有元素,在最开始都需要设置为怪异盒子模型 。

由于一开始,我们并不清楚,页面可能会用到那些 html 元素,所以我们一开始可以用*来处理,等页面开发完,再把*换成对应的 html 标签。

* {
  /*  怪异盒子模型 ,不过在移动端开发,我们一般会以怪异盒子模型为主 */
  box-sizing: border-box;
}

页面开发完,把*替换页面用到的 html 元素

ul,
li,
div,
p,
a,
span,
i,
input,
img {
  /* 怪异盒子模型 */
  box-sizing: border-box;
}

# 6、iOS 下 tabbar 底部留白与黑线遮挡问题

TIP

要解决 IOS 下 tabbar 底部留白问题,我们需要先了解两个概念,安全区域和刘海区

我们来看一个简单的案例,代码如下:

<style>
  html,
  body {
    margin: 0;
  }
  .tabbar {
    width: 100%;
    height: 100px;
    background-color: red;
    position: fixed;
    z-index: 222;
    bottom: 0;
  }
</style>
<body>
  <footer class="tabbar"></footer>
</body>

以上代码显示效果如下:

页面默认填宽的是安全区域的高度,并不包括刘海区

那如何让页面高度填充到刘海区呢?

  • viewport中添加viewport-fit=cover
<meta
  name="viewport"
  content="width=device-width,viewport-fit=cover,initial-scale=1.0"
/>
  • 高度填充到刘海区后,tabbar 的内容就会被底下的黑线给遮挡一小部分。

如何解决底部被黑线遮挡问题 ?

我们只需要给 tabbar 加下如下代码

方法一:

添加以下代码的元素,不能是怪异盒子模型,否则元素自身高度会减少

/* 兼容 IOS<11.2 */
padding-bottom: constant(safe-area-inset-bottom);
/* 兼容 IOS>11.2 */
padding-bottom: env(safe-area-inset-bottom);

方法二:

100px 是 tabbar 原来的高度

/* 兼容 IOS>11.2 */
height: calc(50px+ constant(safe-area-inset-bottom));
/* 兼容 IOS>11.2 */
height: calc(50px + env(safe-area-inset-bottom));

在实际开发中,我们一般是先 constant,再 env

针对其它一些机型,不支持上面两种写法的,可以选择用 CSS 的@supports

@supports not (constant(safe-area-inset-bottom)) {
  .tabbar {
    padding-bottom: 30px;
  }
}

# 7、流体布局的布局思路与缺陷

(1) 流体布局思路

  • 通过计算每个子元素占容器的比例,来平分父容器的整体大小。

  • 所有子元素宽的百分比% 加起来要等于 100%。

  • 然后通过给子元素设置对应的内边距来实现元素间的空隙。

  • 为了保证给子元素添加内边距实现空隙时,不会造成元素宽度变宽,所有元素都设为 box-sizing: border-box;

(2) 流体布局缺陷

  • 只能实现图片和容器的宽高等比缩放,没有办法实现间距,字体大小的等比缩放
  • 如果想实现对应的字体和间距在不同尺寸下,有所变化,可以与@media媒体询结合来实现微调。

# 二、移动端 rem 布局原理

TIP

在学习 rem 布局前,首先我们先来学习 rem 适配的原理

# 1、rem 实现适配的原理

TIP

假设我们现在要实现 750 * 400px 的 div,在 750px 宽的设备下,改用 rem 单位实现等比展现,那我们的 css 代码如何写呢 ?

假设此时1rem = 10px,则对应 CSS 样式如下:

div {
  /* 相当于将整个页面分成 75份  每一份大小为10px */
  width: 75rem;
  height: 40rem;
}

如果以上 CSS 代码不变(将页面分成 75 份),要实现在不同大小屏幕上能等比缩放,我们来看下,对应的 rem 要设置为多少?

设备可视宽 750px 375px 540px
1rem 大小 10px 5px 7.2px

通过上面的表格,我们知道,要计算不同设备下对应 1rem 的大小,我们需要思考将整个页面分成多少份。

然后通过公式:1rem= 设备可视宽 / 对应份数。

假设我们现在将页面分成10 份,那不同设备下1rem的大小具体如下表

设备可视宽 750px 375px 540px
1rem 大小 75px 37.5px 54px

所以我们要用 rem 来开发移动端之前,需要思考,先将页面分成多少份?然后通过以下公式

  • 1rem = 设备可视宽 / 对应份数
  • 得到不同设备下 1rem 的大小

在实际开发中,不同尺寸的手机屏幕下 1rem 的大小,是通过 js 来动态获取当前设备可视宽 / 对应份数来实现

# 2、JS 动态实现不同设备下 1rem 的大小

TIP

1rem=(html)中 font-size 的大小,则我们只需要动态修改 html 的 font-size 的大小就可以

以下 js 代码,假设将页面分成 10 份来计算 font-size 大小的

<script>
  // 页面初时化时调用
  initPage();
  function initPage() {
    // 获取html元素
    var html = document.documentElement;
    // 获取屏幕可视区宽
    var clientWidth = html.clientWidth;
    // 动态设置html的font-size大小
    html.style.fontSize = clientWidth / 10 + "px";
  }
  // 当窗口发生改变时调用
  window.onresize = initPage;
</script>

# 3、px 单位如何转换为 rem

TIP

在实际开发的时候,我们是以 750px 的设计稿为标准来开发的

  • 现在假设我将页面分成 10 份,那1rem = 750px / 10 = 75px
  • 那对应的 px 单位,转换成对应的 rem 单,计算公式:?rem = 元素对应的px单位大小 / 1rem 大小

我们来看下面这个例子,在 750px 设计稿下对应的 px 单位大小

.box {
  width: 750px;
  height: 500px;
  font-size: 20px;
  padding: 10px;
  background-color: red;
}

转换成 rem 单位, 就是用**px 单位 / 75 ** 得到

.box {
  /* 750 * 75= 10 */
  width: 10rem;
  height: 6.666rem;
  font-size: 0.2666rem;
  padding: 0.1333rem;
  background-color: red;
}

实际开发中我们并不会手动将px转换成对应rem单位,我们会用vscodepx to rem插件来实现。

# 4、px to rem 插件使用

第一步:打开 Vscode,然后搜索 px to rem 插件,具体操作如下图

image-20220823215311224

第二步:安装 px to rem 插件

image-20220823215533525

第三步:参数配置

image-20220823220214300

image-20220823220059478

第四步:查看 px to rem 转换的快捷键

image-20220823220440884

第五步:回到 html 页面,ctrl+A 选中所有 CSS 样式,然后按 Alt+Z,就会自动将 px 转成 rem 单位。

image-20220823220958169

# 5、利用 rem 实现元素宽高等比缩放

TIP

  • 将页面分成 10 份,通过 js 来实现不同视口下 1rem 的大小
  • 利用 px to rem 插件,将 px 单位转换成对应 rem 单位
  • px to rem 插件中,1rem 大小设置为 75 (以 750px 设计稿开发)
<style>
  body {
    margin: 0;
  }
  .box {
    width: 9.3333rem;
    height: 6.666rem;
    font-size: 0.2666rem;
    padding: 0.1333rem;
    background-color: red;
  }
</style>
<body>
  <div class="box"></div>
  <script>
    // 页面初时化时调用
    initPage();
    function initPage() {
      // 获取html元素
      var html = document.documentElement;
      // 获取屏幕可视区宽
      var clientWidth = html.clientWidth;
      // 动态设置html的font-size大小
      html.style.fontSize = clientWidth / 10 + "px";
    }
    // 当窗口发生改变时调用
    window.onresize = initPage;
  </script>
</body>

# 6、总结:实际开发如何用 rem 做适配

TIP

在实际开发中,我们会按以下步骤来实现开发

1、要求设计师以 750px 宽,来设计移动端的设计稿;
2、我们按正常的 750px 的设计稿,以 px 单位来开发;
3、我们会假定将页面分成对应的份数,然后求得不同份数下的 1rem 的大小;

  • 如果在 750px 设备下,将页面分成 75 份,则 html 的 font-size 大小=设备可视宽 (750) / 75 = 10px
  • 如果在 750px 设备下,将页面分成 10 份,则 html 的 font-size 大小=设备可视宽 (750) / 10 = 75px

4、将 px 单位转换为对应的 rem 单位

  • 将 px 像素转换 rem 单,公式:?rem = px值 / 1rem大小得到最对应 rem 单位值
  • 我们并不会手动一个一个去计算,而是利用 vscode 中的插件px to rem一次搞定
  • 假定将页面分成 75 份,那就把px to rem插件中对应 1rem 大小设为 10
  • 假定将页面分成 10 份,那就把px to rem插件中对应 1rem 大小设为 75
  • 最后切换到 CSS 代码,ctrl+A选中所有代码,然后Alt+Z之后,就会自动把所有px单位,转换成对应vw单位。

在实际开发中,我们是以 750px 的设计稿来开发,假定将页面分成 10 份,每 1rem = 75px

# 三、rem 布局项目实战

TIP

接下来我们就利用 rem 布局来实现以下设计稿的开发,在 rem 中我们会结合之前学会的 flex 弹性布局一起来实现。

WebApp02

# 1、搭建本项目的目录结构

TIP

  • 首先新建项目文件夹 WebApp
  • 在 WebApp 中新建 css、js、images 文件夹,分别用来存放 CSS、JS 文件和图片内容
  • 在 CSS 中新建 reset.css、global.css、index.css 文件,分别用来存放重置默认样式、全局通用样式,首页样式

reset.css 样式文件的内容

可参考博客:标签默认博客地址 (opens new window) 👆 中如下截图内容

image-20220815153351605

其它相关重要的重置样式介绍

/* 去掉点击的高亮显示效果 */
-webkit-tap-highlight-color: transparent;
/* 在移动端浏览器默认的外观在ios上加上这个属性才能给按扭和输入框自定义样式 */
-webkit-appearance: none;
/* 禁用长按页面时的弹出菜单 */
img,
a {
  -webkit-touch-callout: none;
}
/* 表单会有外轮廓 */
input {
  outline: none;
}
/* 去掉图片下面的空隙 */
vertical-align: top;

注:

建议在一开始学习时,不要引用 reset.css 文件,这样就可以在学习过程中把所有问题暴露,对于为什么要重置这个默认样式,会有更深的理解。

在实际开发中,我们直接引用 reset.css 文件就好。

进到蓝湖,打开设计稿,点击设计稿,按以下截图操作,下载所有切图,然后放到 images 文件夹,修改好名字。

image-20220815171606533

# 2、了解设计稿的整体标准与规范

2022080822222

字体大小、行间距、字体颜色、字体类型

  • 字体大小(24px、28px、32px)
  • 行间距为字体大小的 1.5 倍
  • 字体类型,以微软雅黑为主,数字是 Arial 类型
  • 字体颜色主要以 #000 黑色为主

通过以上数据最后得到如下代码,添加到 global.css 文件中

font: 24px/1.5 Microsoft YaHei;
color: #000;

具体的设计标准,每个公司都有自己的规范,在实际开发中,以公司规范为主。

# 3、新建 index.html 网页,进行首页开发

TIP

  • 在当前根目录下新建 index.html 网页
  • 做好 viewport 视口配置
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
  • 引用相关的 CSS 文件,注意引入文件的顺序
/* 重置样式 */
css代码...

/* 网站通用布局 */
css代码...

/* 通用模块 */
css代码...

/* 通用元件 */
css代码...

/* 通用响应式系统 */
css代码...
<link rel="stylesheet" href="./css/reset.css">
<link rel="stylesheet" href="./css/global.css" />
<link rel="stylesheet" href="./css/index.css" />

# 4、网站整体 html 结构划分

<!-- m-header start -->
<header class="m-header"></header>
<!-- end m-header -->
<!-- m-menu start -->
<nav class="m-menu"></nav>
<!-- end m-menu -->
<!-- m-banner start -->
<section class="m-banner"></section>
<!-- end m-banner -->
<!-- m-main start-->
<main class="m-main">
  <!-- m-nav start -->
  <nav class="m-nav"></nav>
  <!-- end m-nav -->
  <!-- m-recommend start -->
  <section class="m-recommend"></section>
  <!-- end m-recommend -->
  <!-- m-hot start -->
  <section class="m-hot"></section>
  <!-- end m-hot -->
  <!-- m-focus start -->
  <section class="m-focus"></section>
  <!-- end m-focus  -->
  <!-- view-list start -->
  <section class="view-list"></section>
  <!-- end view-list -->
</main>
<!-- footer start -->
<footer class="tabbar"></footer>
<!--end footer  -->

# 5、每个版块开发

TIP

本次项目我们采用的是 rem + Flex 弹性布局技术来实现

多行文本显示省略号

/* 超出部分隐藏 */
overflow: hidden;
/* 超出部分显示省略号 */
text-overflow: ellipsis;
/* 对象做为弹性盒子模型显示 */
display: -webkit-box;
/* 块容器 中的内容限制为指定的行数。 */
-webkit-line-clamp: 2;
/* 弹性盒子对象的子元素排列方式为竖排 */
-webkit-box-orient: vertical;

# 四、移动端 vw 项目实战

TIP

在学习 vw 项目实战前,我们现在学习下 vw 的适配原理。

# 1、vw 的适配原理

TIP

我们知道 100vw = 视口宽,相当于把整个屏幕分成了 100 份,所以不同屏幕尺寸下,1vw 的大小如下

设备可视宽(屏幕宽) 1vw 大小
750px 7.5px
680px 6.8px
480px 4.8px
375px 3.75px
  • 上面表格中,不同屏幕尺寸下 1vw 的大小,不需要我们手动或通过 js 来计算,而是浏览自动会帮我转换
  • 其实你可以理解,如果用 rem 来实现,把页面分 100 份,不同屏幕下 1rem 的大小与对应的 1vw 的大小时一样。
  • 唯 一的区别,1vw 的大小是浏览器自动转换,而 1rem 的大小,需要通过 js 获取屏幕大小 / 100 来得到。

# 2、px 如何转换成对应 vw 单位

TIP

我们同样以 750px 的设计稿为例,那 1vw = 7.5px ,则转换成对应 vw 单位,公式如下:

? vw = 元素 px 大小 / 7.5

如下代码

.box {
  width: 750px;
  height: 400px;
  background-color: skyblue;
}

转换成 vw

.box {
  /* 750 / 7.5 =100vw */
  width: 100vw;
  /* 400 / 7.5 = 53.3333 */
  height: 53.3333;
}

注:

我们不需要一个个手动将px转成vw,我们可以借助VScode的插件px to vw来实现。

px to vw的使用方法和上面讲到的px to rem是一样,唯 一的区别,就是在扩展设置时不一样

image-20220823222142164 image-20220823222421678

# 3、实际开发如何用 vw 做适配

TIP

在实际开发中,我们会按以下步骤来实现开发

1、要求设计师以 750px 宽,来设计移动端的设计稿
2、我们按正常的 750px 的设计稿,以 px 单位来开发
3、将 px 单位转换为对应的 vw 单位

  • 将 px 像素转换 vw 单位,对应公式:?vw = px值 / 7.5
  • 我们并不会手动一个一个去计算,而是利用 vscode 中的插件px to vw一次搞定
  • 在 VSCode 中安装 px to vw 软件中,然后将“扩展设置” 中 Viewport Width 值设为 750
  • 切换到 CSS 代码,ctrl+A选中所有代码,然后Alt+Z之后,就会自动把所有 px 单位,转换成对应 vw 单

# 4、项目实战

TIP

  • 我们只需将上一个项目对应的 px 代码,转换成对应的 vw 单位,就可以了。
  • 所以你会发现,vw 本质上就是 rem 的一种特殊情况(将页面分成 100 份),而不同屏屏幕尺寸下,1vw 是浏览自动计算。所以有了 vw,rem 这种方式几乎可以淘汰了。
  • 但是,vw 还存在一定的兼容问题,除此之外,我们之前开发的所有项目,都是用的 rem,如果我们需要对原项做相关修改,我们还是需要会 rem 的。所以本质上还是需要 rem,只是说淘汰是个时间问题。
  • 相关兼容型查询地址:https://caniuse.com/?search=rem (opens new window) 👆

rem 兼容,全部支持

image-20220816143422149

vw 兼容,少部分不支持

image-20220816143509802

# 5、rem+vw 混合方式

如果

公司项目不需要考虑不同浏览器兼容性(公司做 B 端业务,会指定客户使用指定浏览器来访问 WebApp),你需要在原来的代码上修改,就可以采用 rem+vw 混合的方式,修改部分,可以采用 vw 来实现,原有的 rem 方案不做更改

# 五、移动端开发常见问题

TIP

在实际项目开发中经常会遇到的常见问题 ...

# 1、图片缩放

TIP

  • 我们现在要实现下图 gif 中,第一个图片缩放效果
  • 图片的比例与填充区的比例不一样
  • 希望达到效果,图片填充满当前区块,同时等比裁剪,居中显示在当前区块中

GIF 2022-8-16 18-27-47

代码实现:

<style>
  .box {
    width: 40vw;
    height: 40vw;
    border: 2px solid red;
  }
  .box1 img {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
</style>
<body>
  <div class="box box1">
    <img src="./images/rotate3.webp" alt="" />
  </div>
</body>

处理这个问题的意义

在实际的网站上线后,数据都是从后台读取的,用户在上传图片尺寸时,并不一定会按照设计师设计的比例来上传,这样就会造成图片上传后,大小不一样。

  • 图片高度过小,会在下面留下空白,
  • 图片高度过大,会有一部分下面的内容看不到
  • 我们实际在设计一张图时,重要的内容会在中间显示,所以最理想的效果是让图片能水平垂直居中于容器中

# 2、背景图缩放

TIP

  • 当背景图片的宽高比与容器的宽高比不一样时
  • 我们希望不管容器宽高如何缩放,图片一直填充整个容器,然后水平垂直居中显示

GIF 2022-8-16 18-50-31

<style>
  body {
    margin: 0;
  }
  .box {
    width: 100vw;
    height: 31.467vw;
    /* 背景图片  不重复  水平垂直居中显示 */
    background: url(./images/banner1-@2x.png) no-repeat center;
    /* 背景图填充整个容器 */
    background-size: cover;
  }
</style>
<body>
  <div class="box"></div>
</body>

# 3、精灵图使用

TIP

  • 精灵图采用的是 2 倍图
  • 所以在处理精灵图时,我们需要通过 background-size: 50%; ,来将背景图片大小缩小一半
  • 测量尺寸时,也需要按一半的大小来测量

比如下面这种图就是一个二倍精灵图,整个图大小 401 * 123px

s_sprite

现在我们要在页面插入第二排第二个精灵图,同时实现等比缩放效果

先按正常 px 单位来实现,代码如下:

<style>
  .icon-play {
    width: 26px;
    height: 26px;
    border: 1px solid red;
    background-image: url(images/sprite.png);
    background-position: -36px -29px;
    background-size: 200px;
  }
</style>
<body>
  <div class="icon-play"></div>
</body>

最后转换成对应 vw 单位,如下:

<style>
  .icon-play {
    width: 3.467vw;
    height: 3.467vw;
    border: 0.133vw solid red;
    background-image: url(images/sprite.png);
    background-position: -4.8vw -3.867vw;
    background-size: 26.667vw;
  }
</style>
<body>
  <div class="icon-play"></div>
</body>

# 4、元素正方形缩放

TIP

元素在缩放过程中,元素的高始终等于宽,同时元素中的内容在元素中水平垂直居中

  • 利用padding-bottom:100%;来实现元素的高与元素宽一样大小,同时等比缩放
  • 利用absolute 绝对定位与transform实现子项在容器中水平垂直居中

GIF 2022-8-16 20-02-14

<style>
  .box {
    width: 200px;
  }
  .item {
    width: 100%;
    /* 通过内边距,实现元素高与宽一样大小 */
    padding-bottom: 100%;
    background-color: khaki;
    position: relative;
  }
  .content {
    width: 100px;
    height: 100px;
    background-color: skyblue;
    /* 元素水平垂直居中 */
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
  }
</style>
<body>
  <div class="box">
    <div class="item">
      <div class="content"></div>
    </div>
  </div>
</body>

把 px 单位转换成 vw

<style>
  .box {
    width: 26.667vw;
  }
  .item {
    width: 100%;
    /* 通过内边距,实现元素高与宽一样大小 */
    padding-bottom: 100%;
    background-color: khaki;
    position: relative;
  }
  .content {
    width: 13.333vw;
    height: 13.333vw;
    background-color: skyblue;
    /* 元素水平垂直居中 */
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
  }
</style>
<body>
  <div class="box">
    <div class="item">
      <div class="content"></div>
    </div>
  </div>
</body>

图片缩放总结

只要涉及到图片缩放问题,最好将图片放在一个 html 标签中,然后设置 html 标签的宽高

html 标签的宽高,就是我们希望图片等比例缩放的展示区大。

# 5、经典的 1 像素问题

TIP

在面试中,经常会问到移动端 1px 的处理问题,那到底 1px 问题,是个什么问题呢 ?

# (1)何为 1 像素问题

TIP

为了更好的理解 1 像素问题,我们从两个方面来展开讲解

  • PSD 设计稿
  • 1px 实际显示的大小

PSD 设计稿

  • 我们的设计稿是以 750px 宽来设计的,而我们实际开发时,代码是按 375px 来的。
  • 在 750px 设计稿中的 1px,按我们实际的开发代码来说,要折半,折成 0.5px 才对。
  • 但是不同手机上,不同浏览器对小数的处理是不一样的
  • 0.5px 在一些老的 IOS 和 Android 设备上不支持,他会把低于 0.5px 当成 0 来处理,>= 0.5px 当成 1px 来显示。
  • IOS 上会: 把>= 0.75px 的当作 1px 来处理 ,< 0.75 当成 0.5px 来处理 < 0.5px 当成 0 来处理
  • 而且 IOS 上,用 height: 1px 来代替 border-bottom: 1px solid red;测出的效果不同
  • 具体不同的手机上,效果不一样,具体以真机测试为主
  • 所以直接把代码折半,设置成 0.5px 显然是达不到目的。

如何解决这个问题,我们讲完下面这个问题再来解答。

1px 实际显示的大小

TIP

我们都知道 1px 在 dpr 不同时,其显示的大小不同,如下

dpr=1 dpr=2 dpr=3
image-20220816170200409 image-20220816170229231 image-20220816170351250
1px 就用一个物理像素显示 1px 就用 4 个物理像素来显示 1px 就用 9 个物理像素来显示

而在设计师眼中,他设计的 1px,就是当前设备能显示的最小方格(最细的那个线),也就是物理像素中的 1 像素。

所以在不同 dpr 下,显示的 1px 的线的宽度是下面图标出的蓝色的高度大小(1 物理像素大小)

dpr=1 dpr=2 dpr=3
image-20220816170818474 image-20220816170918766 image-20220816170956602

因此, 1px 像素问题,本质上不是问题,如果公司觉得没有必要,也就不用处理。
如果公司认为就是要用设备能显示的最细的那个小方格显示,那我们就要处理这个问题。

# (2)1px 像素解决方案

TIP

关于 1px 像素的处理方案有很多,这里我们提供一个最优的解决方案给到大家 transform+伪元素来实现

实现原理:

  • 利用伪元素来绘制 1px 的线条,然后利用定位,把线条放在对应位置
  • 利用 media 查询判断不同的设备像素比对线条进行缩放
<style>
  .box {
    height: 50px;
    margin: px auto;
    position: relative;
  }
  .border-1px::before {
    position: absolute;
    content: "";
    height: 1px;
    width: 100%;
    background-color: red;
    bottom: 0;
    /* transform: scaleY(0.5); */
    /* 变换原点 */
    transform-origin: 50% 0%;
  }
  /* dpr=2,需要缩放一半,即0.5 */
  @media only screen and (-webkit-min-device-pixel-ratio: 2) {
    .border-1px:before {
      transform: scaleY(0.5);
    }
  }
  /* dpr=3,需要缩放到1/3,即0.33 */
  @media only screen and (-webkit-min-device-pixel-ratio: 3) {
    .border-1px:before {
      transform: scaleY(0.33);
    }
  }
</style>
<body>
  <div class="box border-1px"></div>
</body>

当然,也可以通过 js 来判断 dpr,然后给元素添加对应的 Class 名字,来实现

if (window.devicePixelRatio && devicePixelRatio >= 2) {
  document.querySelector(".box").className = "border-1px";
}

你可以电脑端,打开头条的移动端,查看头条的 1px 解决方案,和我们这里讲到的是一个逻辑

image-20220816173913015

上次更新时间: 6/8/2023, 9:23:17 PM

大厂最新技术学习分享群

大厂最新技术学习分享群

微信扫一扫进群,获取资料

X