Skip to content

一. 媒体查询


1. 定义

  • 媒体查询是一种提供给开发者针对不同设备需求进行定制化开发的一个接口

  • 你可以根据设备的类型(比如屏幕设备、打印机设备)或者特定的特性(比如屏幕的宽度)来修改你的页面

  • 媒体查询的使用方式主要有三种:

    • 方式一:通过@media@import使用不同的CSS规则(常用)

      css
      /* @import可以结合媒体查询一起使用 */
      @import url(./css/body_bgc.css) (max-width: 800px);
    • 方式二:使用media属性为<style>, <link>, <source>和其他HTML元素指定特定的媒体类型

      html
      <link rel="stylesheet" medie="screem amd (max-width: 800px)" href="./css/body_bgc.css">
    • 方式三:通过使用@media来使用不同的CSS规则

      css
      @media (min-width: 500px) and (max-width: 800px) {
        body {
          background-color: orange;
        }
      }
    • 方式四:使用Window.matchMedia() MediaQueryList.addListener() 方法来测试和监控媒体状态

2. 媒体类型 Media types

  • 在使用媒体查询时,你必须指定要使用的媒体类型
    • 媒体类型是可选的,并且会默认(隐式地)应用all 类型
  • 常见的媒体类型值如下:
    • all:适用于所有设备
    • print:适用于在打印预览模式下在屏幕上查看的分页材料和文档
    • screen:主要用于屏幕
    • speech:主要用于语音合成器
  • 被废弃的媒体类型:
    • CSS2.1 Media Queries 3定义了一些额外的媒体类型(tty, tv, projection, handheld, braille, embossed, 以及 aural)
    • 但是他们在Media Queries 4 中已经被废弃,并且不应该被使用
    • aural类型被替换为具有相似效果的speech

3. 媒体特性Media feature

  • 媒体特性描述了 浏览器、输出设备,或是预览环境的具体特征
    • 通常会将媒体特性描述为一个表达式

    • 每条媒体特性表达式都必须用括号括起来

      特征价值最小/最大描述
      宽度width长度是的渲染表面的宽度
      高度height长度是的渲染表面的高度
      颜色color整数是的每个颜色分量的位数
      设备比例device-aspect-ratio整数/整数是的长宽比
      设备高度device-width长度是的输出设备的高度
      设备宽度device-height长度是的输出设备的宽度
      方向orientation"portrait""landscape"屏幕方向
      分辨率resolution分辨率("dpi""dpcm""dppx"是的解析度

4. 逻辑操作符logical operators

  • 媒体查询的表达式最终会获得一个Boolean值,也就是真(true)或者假(false

    • 如果结果为真(true),那么就会生效
    • 如果结果为假(false),那么就不会生效
  • 如果有多个条件,我们可以通过逻辑操作符联合复杂的媒体查询

条件作用
and用于将多个媒体查询规则组合成单条媒体查询
not用于否定媒体查询,如果不满足这个条件则返回true,否则返回false
only仅在整个查询匹配时才用于应用样式
, (逗号)用于将多个媒体查询合并为一个规则
  • 比如下面的媒体查询,表示:屏幕宽度大于500,小于700的时候,body背景颜色为红色

    css
    @media screen and (min-width: 500px) and (max-width: 700px) {
      body {
        background-color: #f00;
      }
    }

5. 常见移动端设备

  • iPhone为例:

    image-20220501162633744
    css
    /* 
    320~375之间 font-size: 15px;
    375~414之间 font-size: 18px;
    414~480之间 font-size: 21px;
    大于480px font-size: 24px
    */
    /* @media (min-width: 320px) and (max-width: 375px) {
    .box { font-size: 15px; }
    }
    @media (min-width: 375px) and (max-width: 414px) {
    .box { font-size: 18px; }
    }
    @media (min-width: 414px) and (max-width: 480px) {
    .box { font-size: 21px; }
    }
    @media (min-width: 480px) {
    .box { font-size: 24px; }
    } */
    
    /* CSS层叠性 */
    @media (min-width: 320px) {
      .box { font-size: 15px; }
    }
    @media (min-width: 375px) {
      .box { font-size: 18px; }
    }
    @media (min-width: 414px) {
      .box { font-size: 21px; }
    }
    @media (min-width: 480px) {
      .box { font-size: 24px; }
    }
    • 这是一种简写方式,跟上面注释代码效果是一致的

二. CSS常见单位详解


  • 前面编写的CSS中,我们经常会使用px来表示一个长度(大小),比如font-size设置为18px,width设置为100px
  • px是一个长度(length)单位,事实上CSS中还有非常多的长度单位
  • 整体可以分成两类:
    • 绝对长度单位(Absolute length units
    • 相对长度单位(Relative length units

1. CSS中的绝对单位

  • 绝对单位:
    • 它们与其他任何东西都没有关系,通常被认为总是相同的大小

    • 这些值中的大多数在用于打印时比用于屏幕输出时更有用,例如,我们通常不会在屏幕上使用cm

    • 一个我们经常使用的值,就是px(像素)

      image-20220501214244920

2. CSS中的相对单位

  • 相对长度单位
    • 相对长度单位相对于其他一些东西

    • 比如父元素的字体大小,或者视图端口的大小

    • 使用相对单位的好处是,经过一些仔细的规划,您可以使文本或其他元素的大小与页面上的其他内容相对应

      image-20220501214430997

三. 深入理解pixel、DPR、PPI


1. pixel

  • 前面我们已经一直在使用px单位了,pxpixel单词的缩写,翻译为像素

  • 那么像素到底是什么呢?

    • 像素是影响显示的基本单位(比如屏幕上看到的画面、一幅图片)

    • pix是英语单词picture的常用简写,加上英语单词“元素”element,就得到pixel

    • “像素”表示“画像元素”之意,有时亦被称为pel(picture element)

      image-20220501220611860

2. 像素的不同分类

  • 但是这个100个pixel到底是多少呢?

    • 我们确实可以在屏幕上看到一个大小,但是这个大小代表的真实含义是什么呢?
    • 我们经常说一个电脑的分辨率、手机的分辨率,这跟CSS当中的像素又是什么关系呢?
  • 这里我们要深入到不同的像素概念中,来理解CSS中的pixel到底代表什么含义

  • 像素单位常见的有三种像素名称:

    • 设备像素(也称之为物理像素)
    • 设备独立像素(也称之为逻辑像素)
    • CSS像素
  • 设备像素,也叫物理像素

    • 设备像素指的是显示器上的真实像素,每个像素的大小是屏幕固有的属性,屏幕出厂以后就不会改变了
    • 我们在购买显示器或者手机的时候,提到的设备分辨率就是设备像素的大小
    • 比如iPhone X的分辨率1125x2436,指的就是设备像素
  • 设备独立像素,也叫逻辑像素

    • 如果面向开发者我们使用设备像素显示一个100px的宽度,那么在不同屏幕上显示效果会是不同的
    • 开发者针对不同的屏幕很难进行较好的适配,编写程序必须了解用户的分辨率来进行开发
    • 所以在设备像素之上,操作系统为开发者进行抽象,提供了逻辑像素的概念
    • 比如你购买了一台显示器,在操作系统上是以1920x1080设置的显示分辨率,那么无论你购买的是2k、4k的显示器,对于开发者来说,都是1920x1080的大小
    • 是操作系统帮助我们用来调节在不同物理像素设备中的显示效果保持一致的
  • CSS像素

    • CSS中我们经常使用的单位也是pixel,它在默认情况下等同于设备独立像素(也就是逻辑像素)
    • 毕竟逻辑像素才是面向我们开发者的
  • 我们可以通过JavaScript中的screen.widthscreen.height获取到电脑的逻辑分辨率:

    image-20220501221106162
  • 假如设备A的物理像素是100x100,设备A的屏幕是设置的100x100逻辑像素,A的设备像素比就是1(即1个逻辑像素在长度上对应1个物理像素),当在设备A上开发一个网页的时候,设置的100x100的图像,那么在设备A的屏幕上就是占满当前屏幕的,而当去一台300x300物理像素的设备B上显示时,如果此时设备B的逻辑像素也是100x100,设备B的像素比是3(即1个逻辑像素在长度上对应3个物理像素),设备B上比设备A显示的图像更加清晰细腻,设计稿中、开发中的像素是逻辑像素,如果图片不够清晰,在不能调整页面中显示的宽高时,就调整图片本身的尺寸(增加像素,保持偶数),如果是截图海报的这种形式,调整图片本身的尺寸,然后在截图之前放大海报的尺寸,截图后调回尺寸

3. DPR

  • DPRdevice pixel ratio

    • 2010年,iPhone4问世,不仅仅带来了移动互联网,还带来了Retina屏幕

    • Retina屏幕翻译为视网膜显示屏,可以为用户带来更好的显示

    • Retina屏幕中,一个逻辑像素在长度上对应两个物理像素,这个比例称之为设备像素比device pixel ratio

    • 我们可以通过window.devicePixelRatio获取到当前屏幕上的DPR

      image-20220501222840086

4. PPI

  • PPI每英寸像素(英语:Pixels Per Inch,缩写:PPI
    • 通常用来表示一个打印图像或者显示器上像素的密度
    • 前面我们提过1英寸=2.54厘米=96px(大概,逻辑像素),在工业领域被广泛应用

四. CSS预处理器Less Sass


1. CSS编写的痛点

  • CSS作为一种样式语言, 本身用来给HTML元素添加样式是没有问题的
  • 但是目前前端项目已经越来越复杂, 不再是简简单单的几行CSS就可以搞定的, 我们需要几千行甚至上万行的CSS来完成页面的美化工作
  • 随着代码量的增加, 必然会造成很多的编写不便:
    • 比如大量的重复代码, 虽然可以用类来勉强管理和抽取, 但是使用起来依然不方便
    • 比如无法定义变量(当然目前已经支持,但是不兼容老版本的浏览器), 如果一个值被修改, 那么需要修改大量代码, 可维护性很差; (比如主题颜色)
    • 比如没有专门的作用域和嵌套, 需要定义大量的id/class来保证选择器的准确性, 避免样式混淆
  • 所以有一种对CSS称呼是 “面向命名编程”
  • 社区为了解决CSS面临的大量问题, 出现了一系列的CSS预处理器(CSS_preprocessor)
    • CSS 预处理器是一个能让你通过预处理器自己独有的语法来生成CSS的程序
    • 市面上有很多CSS预处理器可供选择,且绝大多数CSS预处理器会增加一些原生CSS不具备的特性
    • 代码最终会转化为CSS来运行, 因为对于浏览器来说只识别CSS

2. 常见的CSS预处理器

  • 常见的预处理器有哪些呢? 目前使用较多的是三种预处理器:
  • Sass/Scss
    • 2007年诞生,最早也是最成熟的CSS预处理器,拥有ruby社区的支持,是属于Haml(一种模板系统)的一部分
    • 目前受Less影响,已经进化到了全面兼容CSSScss
  • Less
    • 2009年出现,受Sass的影响较大,但又使用CSS的语法,让大部分开发者更容易上手
    • 比起Sass来,可编程功能不够,不过优点是使用方式简单、便捷,兼容CSS,并且已经足够使用
    • 另外反过来也影响了Sass演变到了Scss的时代
    • 著名的Twitter Bootstrap就是采用Less做底层语言的,也包括ReactUI框架AntDesign
  • Stylus
    • 2010年产生,来自Node.js社区,主要用来给Node项目进行CSS预处理支持
    • 语法偏向于Python, 使用率相对于Sass/Less少很多

3. 认识Less

  • 什么是Less呢? 我们来看一下官方的介绍:

    • It's CSS, with just a little more 它是CSS,只是多了一点点东西

      image-20220502000003110
  • Less Leaner Style Sheets的缩写) 是一门CSS扩展语言,并且兼容CSS

    • Less增加了很多相比于CSS更好用的特性
    • 比如定义变量、混入、嵌套、计算等
    • Less最终需要被编译成CSS运行于浏览器中(包括部署到服务器中)

4. 编写Less代码

  • 我们可以编写如下的Less代码:

    less
    @mainColor: #fa0112;
    .box {
      color: @mainColor;
      .desc {
        font-size: 12px;
      }
      .info {
        font-size: 18px;
      }
      &:hover {
        background-color: #0f0;
      }
    }

5. Less代码的编译

  • 上述代码如何被编译成CSS代码运行呢?

  • 方式一:下载CSS环境,通过npm包管理下载less工具,使用less工具对代码进行编译

    • 因为目前我们还没有学习过Node,更没有学习过npm工具
    • 所以现阶段不推荐大家使用less本地工具来管理
    • 后续我们学习了webpack其实可以自动完成这些操作的
  • 方法二:通过VSCode插件(easy Less)来编译成CSS或者在线编译

    • https://lesscss.org/less-preview/
  • 方式三:引入CDNless编译代码,对less进行实时的处理

    • 需要在link元素中rel属性值后添加 ' /less '

      html
      <script src="https://cdn.jsdelivr.net/npm/less@4" ></script>
      <link rel="stylesheet/less" href="./less/test.less">
  • 方式四:第三种方式CDN引入,浏览器解析的时候需要先将对应资源下载到本地,会影响速度,所以将lessjs代码下载到本地,执行js代码对less进行编译

补充:

  • Less 中将 CSS 强制打包到单个文件中的技巧

  • lessimport 其它 less 文件的时候会将其合并到单个文件中。 但是当引入 css 文件时,默认不会将 css 合并进来 。 使用 inline 关键字 将 *.css 强制打包到最终的单个文件中

    less
    @import (inline) './reset.css';
    @import (inline) './common.css';
    @import (inline) './page/load.css';
    @import (inline) './page/hp.css';
    
    // 等价于上面
    @import './reset.less';
    @import './common.less';
    @import './page/load.less';
    @import './page/hp.less';

6. Less语法

  • Less语法一:Less兼容CSS

    • 可以在Less文件中编写所有的CSS代码
    • 只是将css的扩展名改成了.less结尾而已
    less
    .box {
      height: 200px;
      background-color: orange;
    }
  • Less语法二: 使用变量Variables

    • 在一个大型的网页项目中,我们CSS使用到的某几种属性值往往是特定的

    • 比如我们使用到的主题颜色值,那么每次编写类似于#f3c258格式的语法

    • 一方面是记忆不太方便,需要重新编写或者拷贝样式

    • 另一方面如果有一天主题颜色改变,我们需要修改大量的代码

    • 所以,我们可以将常见的颜色或者字体等定义为变量来使用

    • Less中使用如下的格式来定义变量

      • @变量名: 变量值;
      less
      @themeColor: #f3c258;
      @mainFontSize: 12px;
      
      .box {
        color: @themeColor;
        font-size: @mainFontSize;
      }
  • Less语法三:选择器嵌套Nesting

    • 在之前的项目中,当我们需要找到一个内层的元素时,往往需要写很多层的选择器

      less
      #main .section .news-list-info .date {
        font-size: 12px;
      }
    • Less提供了选择器的嵌套

      less
      .box {
        .title {
          color: red;
        }
        .content {
          .link {
            font-size: 20px;
            color: orange;
          }
          .keyword {
            font-size: 30px;
            color: purple;
          }
        }
      }
      
      <div class="box">
        <h1 class="title">我是标题</h1>
        <p class="content">
          我是段落内容
          <a href="#" class="link">我是超链接</a>
          <span class="keyword">keyword</span>
        </p>
      </div>
  • Less语法四:运算Operations

    • Less中,算术运算符+-*/ 可以对任何数字、颜色或变量进行运算

    • 算术运算符在加、减或比较之前会进行单位换算,计算的结果以最左侧操作数的单位类型为准

    • 如果单位换算无效或失去意义,则忽略单位

      less
      .box {
        height: 100px + 10%;
        color: #ff0000 + #00ff00;
      }
  • Less语法五:混入Mixins

    • 在原来的CSS编写过程中,多个选择器中可能会有大量相同的代码

      • 我们希望可以将这些代码进行抽取到一个独立的地方,任何选择器都可以进行复用
      • less中提供了混入(Mixins)来帮助我们完成这样的操作
    • 混入(Mixins)是一种将一组属性从一个规则集混入到另一个规则集的方法

      less
      .bordered {
        border-top: 2px solid #f00;
      }
      .box {
        height: 100px;
        .bordered()
      }
      .container {
        height: 200px;
        .bordered();
      }
    • 注意:混入在没有参数的情况下,小括号可以省略,但是不建议这样使用

    • 混入也可以传入变量

      less
      .bordered(@borderWidth: 2px) {
        border-top: @borderWidth solid #f00;
      }
      
      // 混入是可以传递参数(定义变量)的
      .box_border(@borderWidth: 5px, @borderColor: purple) {
        border: @borderWidth solid @borderColor;
      }
  • Less语法六:映射Maps

    less
    .colors() {
      primaryColor: #f00;
      secondColor: #0f0;
    }
    .box {
      color: .colors[primaryColor];
      background-color: .colors()[secondColor];
    }
    • 混入和映射结合:混入也可以当做一个自定义函数来使用

      less
      .pxToRem(@px) {
        result: (@px / @htmlFontSize) * 1rem;
      }
      .box {
        width: .pxToRem(100)[result];
        font-size: .pxToRem(10)[result];
      }
  • Less语法七:extend继承

    • mixins作用类似,用于复用代码

    • mixins相比,继承代码最终会转化成并集选择器

    • 特殊符号:& 表示当前选择器的父级(当前所处的选择器)

      less
      .borderer {
        color: red;
      }
      .box {
        &:extend(.bordered);
      }
      /* 编译后的css */
      .bordered,
      .box {
        color: red;
      }
  • Less语法八:Less内置函数

    • Less 内置了多种函数用于转换颜色、处理字符串、算术运算等

    • 内置函数手册:https://less.bootcss.com/functions/

      less
      .box {
        color: color(red); // 将red转成RGB的值
        width: convert(100px, "in"); // 单位的转行
        font-size: ceil(18.5px); // 数学函数
      }
      /* 编译后的css */
      .box {
        color: #ff0000;
        width: 1.04166667in;
        font-size: 19px;
      }
  • Less语法九:作用域Scope

    • 在查找一个变量时,首先在本地查找变量和混合(mixins

    • 如果找不到,则从“父”级作用域往上一层层找,至到找到为止

      less
      .box {
        .inner {
          font-size: @fontSize; //使用15px
        }
        @fontSize: 15px;
      }
  • Less语法十:注释Comments

    • Less中,块注释和行注释都可以使用
  • Less语法十一:导入Importing

    • 导入的方式和CSS的用法是一致的
    • 导入一个.less文件,此文件中的所有变量就可以全部使用了
    • 如果导入的文件是.less扩展名,则可以将扩展名省略掉

7. 认识Sass和Scss

  • 事实上,最初SassHaml的一部分,Haml是一种模板系统,由Ruby开发者设计和开发

  • 所以,Sass的语法使用的是类似于Ruby的语法,没有花括号,没有分号,具有严格的缩进

    scss
    $font-stack: Helvetica, sans-serif
      $primary-color: #333
    
      body
      font: 100% $font-stack
      color: $primary-color
  • 我们会发现它的语法和CSS区别很大,后来官方推出了全新的语法SCSS,意思是Sassy CSS,他是完全兼容CSS

  • 目前在前端学习SASS直接学习SCSS即可:

    • SCSS的语法也包括变量、嵌套、混入、函数、操作符、作用域等
    • 通常也包括更为强大的控制语句、更灵活的函数、插值语法等
    • 大家可以根据之前学习的less语法来学习一些SCSS语法
    • https://sass-lang.com/guide
  • 目前大家掌握Less的使用即可

五. 什么是移动端适配?


  • 移动互联网的快速发展,让人们已经越来越习惯于使用手机来完成大部分日常的事务

    • 前端我们已经学习了大量HTML、CSS的前端开发知识,并且也进行了项目实战
    • 这些知识也同样适用于移动端开发,但是如果想让一个页面真正适配于移动端,我们最好多了解一些移动端的知识
  • 移动端开发目前主要包括三类:

    • 原生App开发(iOS、Android、RN、uniapp、Flutter等)

    • 小程序开发(原生小程序、uniapp、Taro等)

    • Web页面(移动端的Web页面,可以使用浏览器或者webview浏览)

      image-20220502175323358
  • 因为目前移动端设备较多,所以我们需要对其进行一些适配

  • 这里有两个概念:

    • 自适应:根据不同的设备屏幕大小来自动调整尺寸、大小
    • 响应式:会随着屏幕的实时变动而自动调整,是一种自适应

六. 认识视口Viewport


  • 在前面我们已经简单了解过视口的概念了:
    • 在一个浏览器中,我们可以看到的区域就是视口(viewport
    • 视口当前可见的部分叫做称之为可视视口
    • 当我们在缩放浏览器比例时,布局视口不变,可视视口变小
    • 我们说过fixed就是相对于视口来进行定位的
    • PC端的页面中,我们是不需要对视口进行区分,因为我们的布局视口和视觉视口是同一个
  • 但是在移动端,不太一样,你布局的视口和你可见的视口是不太一样的
    • 这是因为移动端的网页窗口往往比较小,我们可能会希望一个大的网页在移动端可以完整的显示
    • 所以在默认情况下,移动端的布局视口是大于视觉视口的
  • 所以在移动端,我们可以将视口划分为三种情况
    • 布局视口(layout viewport
    • 视觉视口(visual layout
    • 理想视口(ideal layout
  • 这些概念的区分,事实上来自ppk,他也是对前端贡献比较大的一个人(特别是在移动端浏览器)

1. 布局视口和视觉视口

  • 布局视口(layout viewport

  • 默认情况下,一个在PC端的网页在移动端会如何显示呢?

    image-20220502175826073
    • 第一,它会默认按照宽度为980px来布局一个页面的盒子和内容
    • 第二,为了显示可以完整的显示在页面中,对整个页面进行缩小或放大
  • 我们相对于980px布局的这个视口,称之为布局视口(layout viewport

    • 布局视口的默认宽度是980px
  • 视觉视口(visual viewport

    image-20220502175948285
    • 如果默认情况下,我们按照980px显示内容,那么右侧有一部分区域就会无法显示,所以手机端浏览器会默认对页面进行缩放以显示到用户的可见区域中
    • 那么显示在可见区域的这个视口,就是视觉视口visual viewport
  • Chrome上按shift+鼠标左键可以进行缩放

2. 理想视口

  • 如果所有的网页都按照980px在移动端布局,那么最终页面都会被缩放显示

    • 事实上这种方式是不利于我们进行移动的开发的,我们希望的是设置100px,那么显示的就是100px
    • 如何做到这一点呢?通过设置理想视口(ideal viewport
  • 理想视口(ideal viewport):

    • 默认情况下的layout viewport并不适合我们进行布局

    • 我们可以layout viewport进行宽度和缩放的设置,以满足正常在一个移动端窗口的布局

    • 这个时候可以设置**meta中的viewport**

      html
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
可能的附加值描述
width一个正整数,或者字符串 device-width定义viewport的宽度
height一个正整数,或者字符串 device-height定义viewport的高度,未被任何浏览器使用
initial-scale一个0.0和10.0之间的正数定义设备宽度与viewport大小之间的缩放比例
maximum-scale一个0.0和10.0之间的正数定义缩放的最大值,必须等于minimum-scale,否则表现将不可预测
minimum-scale一个0.0和10.0之间的正数定义缩放的最小值,必须等于maximum-scale,否则表现将不可预测
user-scalableyesno默认yes,如果设置为no,将无法缩放当前页面,浏览器可忽略此规则

七. 移动端适配方案


1. 前言

  • 移动端的屏幕尺寸通常是非常繁多的,很多时候我们希望在不同的屏幕尺寸上显示不同的大小
    • 比如我们设置一个100*100的盒子
      • 375px的屏幕上显示是100 * 100
      • 320px的屏幕上显示是90+ * 90+
      • 414px的屏幕上显示是100+ * 100+
    • 其他尺寸也是类似,比如padding、margin、border、left,甚至是font-size等等
  • 这个时候,我们可能可以想到一些方案来处理尺寸:
    • 方案一:百分比设置
      • 因为不同属性的百分比值,相对的可能是不同参照物,所以百分比往往很难统一
      • 所以百分比在移动端适配中使用是非常少的
    • 方案二:rem单位 + 动态htmlfont-size
    • 方案三:vw单位
    • 方案四:flex的弹性布局

2. 适配方案 - rem + 动态html的font-size

  • rem单位是相对于html元素的font-size来设置的,那么如果我们需要在不同的屏幕下有不同的尺寸,可以动态的修改htmlfont-size尺寸

  • 比如如下案例:

    1. 设置一个盒子的宽度是2rem

    2. 设置不同的屏幕上htmlfont-size不同

      image-20220503000716916
  • 这样在开发中,我们只需要考虑两个问题:

    • 问题一:针对不同的屏幕,设置html不同的font-size
    • 问题二:将原来要设置的尺寸,转化成rem单位

注意:

  • rem方案设置的htmlfont-size,如果后代元素没有设置font-size,则会继承html的,所以一般会给body设置一个font-size,以免后代元素继承来自htmlfont-size,而导致页面尺寸混乱

3. rem的font-size尺寸

  • 方案一:媒体查询

    css
    @media screen and (min-width: 320px) {
      html { font-size: 32px; }
    }
    @media screen and (min-width: 375px) {
      html { font-size: 37.5px; }
    }
    @media screen and (min-width: 414px) {
      html { font-size: 41.4px; }
    }
    • 可以通过媒体查询来设置不同尺寸范围内的屏幕htmlfont-size尺寸
    • 缺点:
      • 需要针对不同的屏幕编写大量的媒体查询
      • 动态改变尺寸,不会实时的进行更新
  • 方案二:编写js代码

    • 如果希望实时改变屏幕尺寸时,font-size也可以实时更改,可以通过js代码

    • 方法:

      • 根据html的宽度计算出font-size的大小,并且设置到html
      • 监听页面的实时改变,并且重新设置font-size的大小到html
      js
      // 1.获取html的元素
      const htmlEl = document.documentElement
      function setRemUnit() {
        // 2.获取html的宽度(视口的宽度)
        const htmlWidth = htmlEl.clientWidth
        // 3.根据宽度计算一个html的font-size的大小
        const htmlFontSize = htmlWidth / 10
        // 4.将font-size设置到html上
        htmlEl.style.fontSize = htmlFontSize + "px"
      }
      // 保证第一次进来时, 可以设置一次font-size
      setRemUnit()
      // 当屏幕尺寸发生变化时, 实时来修改html的font-size
      window.addEventListener("resize", setRemUnit)
  • 方案三:lib-flexible等第三方库

  • 事实上,lib-flexible库做的事情是相同的,你也可以直接引入它

    js
    (function flexible (window, document) {
      var docEl = document.documentElement
      var dpr = window.devicePixelRatio || 1
    
      // adjust body font size
      function setBodyFontSize () {
        if (document.body) {
          document.body.style.fontSize = (12 * dpr) + 'px'
        }
        else {
          document.addEventListener('DOMContentLoaded', setBodyFontSize)
        }
      }
      setBodyFontSize();
    
      // set 1rem = viewWidth / 10
      function setRemUnit () {
        var rem = docEl.clientWidth / 10
        docEl.style.fontSize = rem + 'px'
      }
    
      setRemUnit()
    
      // reset rem unit on page resize
      window.addEventListener('resize', setRemUnit)
      window.addEventListener('pageshow', function (e) {
        if (e.persisted) {
          setRemUnit()
        }
      })
    
      // detect 0.5px supports
      if (dpr >= 2) {
        var fakeBody = document.createElement('body')
        var testElement = document.createElement('div')
        testElement.style.border = '.5px solid transparent'
        fakeBody.appendChild(testElement)
        docEl.appendChild(fakeBody)
        if (testElement.offsetHeight === 1) {
          docEl.classList.add('hairlines')
        }
        docEl.removeChild(fakeBody)
      }
    }(window, document))

4. rem的单位换算

  • 方案一:手动换算

    • 比如有一个在375px屏幕上,100px宽度和高度的盒子
    • 我们需要将100px转成对应的rem
    • 100/37.5=2.6667,其他也是相同的方法计算即可
  • 方案二:less混入/scss函数

    less
    /* less混入 */
    @htmlFontSize: 37.5;
    .pxToRem(@px) {
      result: (@px / @htmlFontSize) * 1rem;
    }
    
    .box {
      width: .pxToRem(100)[result];
      font-size: .pxToRem(18)[result];
    }
  • 方案三:postcss-pxtorem

    • 目前在前端的工程化开发中,我们可以借助于webpack的工具来完成自动的转化
  • 方案四:VSCode插件

    image-20220503002417328
    • px to rem 的插件,在编写时自动转化

5. 适配方案 - vw

  • flexible GitHub上已经有写过这样的一句话:

    image-20220503165837177
  • 所以它更推荐使用viewport的两个单位vw、vh

  • vw的兼容性如何呢?

    • 现在已经可以放心使用了

      image-20220503165926072

6. vw和rem的对比

  • rem事实上是作为一种过渡的方案,它利用的也是vw的思想
    • 前面不管是我们自己编写的js,还是flexible的源码
    • 都是将1rem等同于设计稿的1/10,在利用1rem计算相对于整个屏幕的尺寸大小
    • 那么我们来思考,1vw不是刚好等于屏幕的1/100吗?
    • 而且相对于rem还更加有优势
  • vw相比于rem的优势
    • 优势一:不需要去计算htmlfont-size大小,也不需要给html设置这样一个font-size
    • 优势二:不会因为设置htmlfont-size大小,而必须给body再设置一个font-size,防止继承
    • 优势三:因为不依赖font-size的尺寸,所以不用担心某些原因htmlfont-size尺寸被篡改,页面尺寸混乱
    • 优势四:vw相比于rem更加语义化,1vw刚才是1/100viewport的大小
    • 优势五:可以具备rem之前所有的优点
  • vw我们只面临一个问题,将尺寸换算成vw的单位即可
  • 所以,目前相比于vw,更加推荐大家使用vw(但是理解rem依然很重要)

7. vw的单位换算

  • 方案一:手动换算

    • 比如有一个在375px屏幕上,100px宽度和高度的盒子
    • 我们需要将100px转成对应的vw
    • 100/3.75=26.667,其他也是相同的方法计算即可
  • 方案二:less/scss函数

    less
    @vwUnit: 3.75; // 375px屏幕,1vw=3.75
    .pxToVw(@px) {
      result: (@px / @vwUnit) * 1vw;
    }
    .box {
      width: .pxToVw(100)[result];
    }
  • 方案三:postcss-px-to-viewport-8-plugin

    • rem一样,在前端的工程化开发中,我们可以借助于webpack的工具来完成自动的转化
  • 方案四:VSCode插件

    • px to vw 的插件,在编写时自动转化

      image-20220503170607955

Released under the MIT License.