Skip to content

移动端适配与 rem(四) ​

本页对应 移动端适配与 rem,共 7 段视频,约 1 小时 8 分。

学习目标 ​

  1. 能够使用 @import 在 LESS 文件中导入基础样式文件,并说明导入 .less 文件时可省略后缀。
  2. 能够使用 out: 注释配置 LESS 文件的导出路径和文件名,并设置 VS Code 默认导出路径,将 LESS 编译为指定目录下的 CSS。
  3. 能够按项目规范创建 less、css、images、js 等目录,并在 HTML 中正确引入字体图标、编译后的 CSS 和适配脚本。
  4. 能够定义 LESS 变量表示 375 设计稿下的基准值,并用变量替换重复的 37.5rem 换算写法。
  5. 能够使用 Flex 布局完成头部左中右三栏及 banner 区域的结构与样式,并实现文字、图片、间距和颜色的适配。
  6. 能够完成文本列表区域的边框、内边距、垂直居中、图片与文字间距等样式,并在不同移动端设备上验证适配效果。

知识点 ​

先看整体与准备工作 ​

极速问诊设计稿

做这个综合案例前,先明确目标:把设计稿拆成“头部、banner、问诊类型列表”三块,再逐块用 flex 布局实现。为什么需要先准备目录?因为页面要引入字体图标、公共样式、适配脚本和图片素材,目录乱了后面路径很容易错。怎么想:先按“html、css、less、js、assets、iconfont”分文件夹;怎么做:HTML 里先引入图标样式、页面样式和 flexible.js,less 里用 @import 引入公共基础样式。转写稿里特别强调:@import 后写路径和分号,路径是 less 文件时可省略 .less 后缀;导出路径写在 less 第一行 // out: ../css/,公共基础文件若不想导出 CSS,可写 // out: false。易错点:@import 不是 @important,末尾要有分号;如果没设置默认导出路径,就要自己在文件第一行写 // out: ../css/。

项目目录结构

html
<link rel="stylesheet" href="./iconfont/iconfont.css">
<link rel="stylesheet" href="./css/index.css">

<body>
  ......
  <script src="./js/flexible.js"></script>
</body>
less
// out: ../css/

@import "./base";

头部布局 ​

为什么先做头部?它是页面最上面的固定结构,包含返回、标题、问诊记录三块,适合先练“大盒子 + flex 横排”。怎么想:把头部当成一个 header 大盒子,左右用 space-between 分开,垂直方向用 line-height 与高度一致做居中。怎么做:高度按设计稿 44px 换算成 rem,左右内边距 15px,也统一除以 @rootSize。转写稿里调试时先加粉色背景看盒子范围,确认高度、左右间距没问题后再删掉背景色。易错点:高度写成固定 44px 就不会适配;padding: 0 (15 / @rootSize) 要记得括号;line-height 与 height 一致才能让文字垂直居中。

html
<!-- 头部 -->
<header>1</header>
less
// 头部
header {
  display: flex;
  justify-content: space-between;
  padding: 0 (15 / @rootSize);
  height: (44 / @rootSize);
  background-color: pink;
  line-height: (44 / @rootSize);
}

头部内容 ​

为什么要把返回、标题、记录分成三个元素?因为它们在 flex 主轴上有左中右关系,单独控制字体大小和颜色更方便。怎么想:左边用 a.back 包字体图标,中间用 h3,右边用 a.note;字体图标大小 22,标题 17,记录文字 15 且用绿色 #2CB5A5。怎么做:结构写好后,分别给 .icon-left、h3、.note 设置字号和颜色。转写稿里调试发现 .icon-left 的字号被 .iconfont 的默认样式覆盖,原因是同类选择器后写或权重相同;解决时可写 header .icon-left 或 .iconfont.icon-left 提高权重。易错点:不要写成 header .icon-left h3 这类错误层级;.note 的颜色要写在 a 上;图标大小不要漏写。

html
<a href="#" class="back"><span class="iconfont icon-left"></span></a>
<h3>极速问诊</h3>
<a href="#" class="note">问诊记录</a>
less
.icon-left {
  font-size: (22 / @rootSize);
}

h3 {
  font-size: (17 / @rootSize);
}

.note {
  font-size: (15 / @rootSize);
  color: #2CB5A5;
}

为什么 banner 要单独成块?它由入口图和一句提示文字组成,和头部、列表的间距不同。怎么想:外层 .banner 控制上下外边距和文字居中;图片固定宽高;文字里的“20s”用 span 单独变绿。怎么做:margin-top: 30、margin-bottom: 34,图片 240×206、下边距 18,p 字号 16,span 颜色 #16C2A3。转写稿里调试时先给盒子加背景看间距,再通过 text-align: center 让图片和文字整体居中。易错点:图片宽高不要只写宽度;span 要写在 p 内部并用 p span 选中;上下 margin 合并时看起来间距不对,要检查相邻盒子。

html
<!-- banner -->
<div class="banner">
  <img src="./assets/entry.png" alt="">
  <p><span>20s</span> 快速匹配专业医生</p>
</div>
less
// banner
.banner {
  margin-top: (30 / @rootSize);
  margin-bottom: (34 / @rootSize);
  text-align: center;
  img {
    margin-bottom: (18 / @rootSize);
    width: (240 / @rootSize);
    height: (206 / @rootSize);
  }

  p {
    font-size: (16 / @rootSize);
    span {
      color: #16C2A3;
    }
  }
}

问诊类型布局 ​

为什么列表外层要加 .type?因为列表整体左右有 15px 内边距,每个 li 之间还有 15px 下边距。怎么想:ul 里放多个 li,每个 li 是带边框的卡片;卡片内部用 a 做 flex 横排,让图片、文字、右箭头一行排列。怎么做:li 设高度 78、边框 1px、圆角 4;a 也设高度 78 并 align-items: center,实现内容垂直居中。转写稿里提到 1px 边框不要再除以 @rootSize,因为最小线条通常就是 1px。易错点:li 和 a 的高度要配合;padding 写在 li 上时注意边框是否被撑开;margin-bottom 不要漏。

html
<!-- 问诊类型 -->
<div class="type">
  <ul>
    <li>
      <a href="#">
        <div class="pic">1</div>
        <div class="txt">2</div>
        <span class="iconfont icon-right"></span>
      </a>
    </li>
    <li>2</li>
  </ul>
</div>
less
// 问诊类型
.type {
  padding: 0 (15 / @rootSize);
  li {
    margin-bottom: (15 / @rootSize);
    padding: 0 (15 / @rootSize);
    height: (78 / @rootSize);
    border: 1px solid #EDEDED;
    border-radius: (4 / @rootSize);
    a {
      display: flex;
      align-items: center;
      // 内容在78里面垂直居中
      height: (78 / @rootSize);
    }
  }
}

问诊类型内容 ​

为什么文字区要加 flex: 1?因为一行里图片固定 40×40,右侧图标固定大小,中间文字要自动占满剩余空间。怎么想:图片给 margin-right: 14,.txt 用 flex: 1,标题 16、行高 24,描述 13 且灰色 #848484,右箭头 16。怎么做:结构上按“图片、文字、箭头”三块写,样式上分别控制。转写稿里调试时发现标题和描述挤在一起,就给 h4 加行高;箭头不靠右时,检查 .txt 是否真的 flex: 1。易错点:.txt 不写 flex: 1 时箭头不会贴右;h4 默认外边距可能影响布局,可在 base 里清除;图标选择器不要误写成标签选择器。

html
<div class="pic">
  <img src="./assets/type01.png" alt="">
</div>
<div class="txt">
  <h4>三甲图文问诊</h4>
  <p>三甲主治及以上级别医生</p>
</div>
<span class="iconfont icon-right"></span>
less
img {
  margin-right: (14 / @rootSize);
  width: (40 / @rootSize);
  height: (40 / @rootSize);
}
.txt {
  flex:1;
  h4 {
    font-size: (16 / @rootSize);
    color: #3C3E42;
    line-height: (24 / @rootSize);
  }
  p {
    font-size: (13 / @rootSize);
    color: #848484;
  }
}
.iconfont {
  font-size: (16 / @rootSize);
}

课件图示 ​

课件第36页:案例 项目 – 极速问诊 u 项目目录 u 设计稿

代码示例 ​

  1. HTML 结构
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>极速问诊</title>
  <link rel="stylesheet" href="./iconfont/iconfont.css">
  <link rel="stylesheet" href="./css/index.css">
</head>
<body>
  <!-- 头部 -->
  <header>
    <a href="#" class="back"><span class="iconfont icon-left"></span></a>
    <h3>极速问诊</h3>
    <a href="#" class="note">问诊记录</a>
  </header>

  <!-- banner -->
  <div class="banner">
    <img src="./assets/entry.png" alt="">
    <p><span>20s</span> 快速匹配专业医生</p>
  </div>

  <!-- 问诊类型 -->
  <div class="type">
    <ul>
      <li>
        <a href="#">
          <div class="pic">
            <img src="./assets/type01.png" alt="">
          </div>
          <div class="txt">
            <h4>三甲图文问诊</h4>
            <p>三甲主治及以上级别医生</p>
          </div>
          <span class="iconfont icon-right"></span>
        </a>
      </li>
    </ul>
  </div>

  <script src="./js/flexible.js"></script>
</body>
</html>

要点:头部使用 header 包住左、中、右三块内容;iconfont 引入后使用 icon-left、icon-right 字体图标;banner 中 span 单独包住 20s 方便单独设色;问诊类型按“ul > li > a”组织,pic、txt、iconfont 对应左中右三块。易错点:iconfont.css、css/index.css、flexible.js 和图片资源路径要与项目目录一致;第二项问诊类型可复制第一项结构后替换图片和文字。

  1. LESS 样式
less
// out: ../css/

@import "./base";

@rootSize: 37.5rem;

// 头部
header {
  display: flex;
  justify-content: space-between;
  padding: 0 (15 / @rootSize);
  height: (44 / @rootSize);
  background-color: pink;
  line-height: (44 / @rootSize);

  .icon-left {
    font-size: (22 / @rootSize);
  }

  h3 {
    font-size: (17 / @rootSize);
  }

  .note {
    font-size: (15 / @rootSize);
    color: #2CB5A5;
  }
}

// banner
.banner {
  margin-top: (30 / @rootSize);
  margin-bottom: (34 / @rootSize);
  text-align: center;

  img {
    margin-bottom: (18 / @rootSize);
    width: (240 / @rootSize);
    height: (206 / @rootSize);
  }

  p {
    font-size: (16 / @rootSize);

    span {
      color: #16C2A3;
    }
  }
}

// 问诊类型
.type {
  padding: 0 (15 / @rootSize);

  li {
    margin-bottom: (15 / @rootSize);
    padding: 0 (15 / @rootSize);
    height: (78 / @rootSize);
    border: 1px solid #EDEDED;
    border-radius: (4 / @rootSize);

    a {
      display: flex;
      align-items: center;
      height: (78 / @rootSize);

      img {
        margin-right: (14 / @rootSize);
        width: (40 / @rootSize);
        height: (40 / @rootSize);
      }

      .txt {
        flex: 1;

        h4 {
          font-size: (16 / @rootSize);
          color: #3C3E42;
          line-height: (24 / @rootSize);
        }

        p {
          font-size: (13 / @rootSize);
          color: #848484;
        }
      }

      .iconfont {
        font-size: (16 / @rootSize);
      }
    }
  }
}

要点:@rootSize: 37.5rem; 用于 375 设计稿换算,所有需要适配的尺寸写成 (数值 / @rootSize);头部用 display:flex; justify-content:space-between; 实现左中右分布;问诊类型卡片中 a 设为 flex 并用 align-items:center; 让内容在 78 高度内垂直居中;.txt { flex:1; } 让中间文字区域占满剩余宽度。易错点:LESS 除法要加括号;1px 边框通常不参与 rem 换算;h3 要写在 header 下,不要误写成图标内部的 h3。

  1. LESS 导入与导出
less
// out: ../css/

@import "./base";

@rootSize: 37.5rem;

要点:第一行 // out: ../css/ 控制该 LESS 编译后导出到上一级 css 文件夹;@import "./base"; 用于把基础公共样式导入当前 LESS,避免重复写清除默认样式等代码;@rootSize: 37.5rem; 定义换算基准,后续尺寸统一除它。易错点:@import 后面要有引号和分号;导出注释一般放第一行;如果 base.less 只是被导入、不需要单独导出 CSS,可按转写稿思路使用禁止导出配置。

常见错误 ​

  1. 现象:修改 less 后页面样式不变,css 目录也没有新文件 → 原因:// out: 注释不在第一行、路径写错,或文件未保存 → 修法:检查首行 // out: ../css/,保存 less,确认对应 css 已生成到目标目录。
  2. 现象:页面基础样式全部丢失 → 原因:index.less 未导入 base.less,或 @import 路径/分号写错 → 修法:补 @import "./base";,保存后检查生成的 css 是否包含基础样式。
  3. 现象:字体图标显示为方块或不显示 → 原因:HTML 未引入 iconfont.css,或类名写成 icon-left 却漏了 iconfont → 修法:确认 link 引入正确,使用 class="iconfont icon-left" 这类完整类名。
  4. 现象:头部左中右三块没有分开,或左右贴边 → 原因:header 未设 display:flex,或 justify-content:space-between、左右 padding 写错 → 修法:header 设 flex 与 space-between,左右 padding 用 (15 / @rootSize)。
  5. 现象:尺寸明显过大/过小,换设备后不协调 → 原因:把设计稿 px 直接写成 rem,或漏引 flexible.js,或未统一除以根字号 → 修法:确认 flexible.js 已引入,尺寸统一用 (设计稿px / @rootSize),并抽成变量替换。
  6. 现象:问诊类型右侧箭头紧贴文字,文字区没有撑开 → 原因:.txt 未设置 flex:1,或 a 未设 flex/高度 → 修法:给 .txt{flex:1},给 a{display:flex;align-items:center;height:(78 / @rootSize)}。
  7. 现象:给标题设置字号不生效 → 原因:标签选择器权重低于 .iconfont 等类选择器,被覆盖 → 修法:用父级限定提高权重,如 header h3 或 .type .txt h4。
  8. 现象:移动端边框被算成 0.x px 后几乎看不见 → 原因:把 1px 边框也按根字号换算 → 修法:边框保留 1px solid #EDEDED,不要参与 rem 细算。

练习 ​

  1. 新建 less/index.less,完成 base.less 导入与导出到 ../css/ 的配置,保存后检查 css 文件生成位置和内容。
  2. 完成头部三栏布局:返回图标、标题“极速问诊”、问诊记录;要求高度 44/37.5rem,左右内边距 15/37.5rem,三块两端对齐。
  3. 完成 banner 区域:图片宽 240/37.5rem、高 206/37.5rem,图文整体居中,“20s”单独高亮。
  4. 完成问诊类型列表:每个 li 高 78/37.5rem、边框 1px、圆角 4/37.5rem;a 垂直居中,.txt 占满剩余空间,右侧箭头靠右。
  5. 将 37.5 抽成 less 变量并替换头部、banner、问诊类型中的换算;分别用 iPhone 6/7/8 与 iPad 宽度检查字号、间距、图片是否稳定。

原视频对照 ​

#视频时长
1less导入08:05
2less导出13:41
3项目准备07:30
4项目(头部)14:47
5变量01:15
6项目(banner)07:24
7项目(完成)15:33

小结 ​

  1. 本案例的核心是移动端适配与页面拆分,不是新的布局体系。
  2. less 工程化要先保证导入、导出链路正确,再进入页面样式编写。
  3. 尺寸换算应统一走根字号变量,避免页面中散落魔法数。
  4. 头部、banner、问诊类型都适合“大盒包小块”,再逐块调间距、字号、颜色。
  5. 1px 边框按设计稿保留,不参与 rem 细算。
  6. 综合案例中选择器权重问题比单个属性问题更常见,父级限定是低成本修法。
  7. 验收适配时要同时看不同设备宽度下的字号、间距、图片和文字稳定性。
  8. 先结构后样式、先大盒后内容,能明显减少返工。