Skip to content

Less 与响应式(一) ​

本页对应 Less 与响应式,共 7 段视频,约 43 分钟。

学习目标 ​

  • 能准确说明 vw 与 vh 的含义:vw 相对视口宽度的 1%,vh 相对视口高度的 1%,并区分二者参照对象。
  • 能结合设备宽度、高度差异说明移动端适配中优先使用 vw 而不优先使用 vh 的原因。
  • 能根据 375px 设计稿,使用“量取的 px 值 ÷ 3.75”计算对应 vw 值,并完成盒子宽高的适配设置。
  • 能使用 Less 编写样式并自动换算 vw,完成 Less 文件编译及 CSS 引入。
  • 能搭建移动端项目基础结构,创建 HTML 与 Less/CSS 文件,引入字体图标和基础样式,并说明该项目无需引入 JS 即可用 vw 完成适配。
  • 能区分“元素大小适配”和“响应式布局”,并说明响应式网页会根据设备不同呈现不同布局。

知识点 ​

先明确:vw 与 vh 是相对视口的单位 ​

为什么需要:移动端设备宽度差别很大,如果盒子宽高都写死 px,换一台设备元素大小不会跟着变,适配就要靠媒体查询反复改。vw、vh 让尺寸直接跟视口挂钩,写一次就能随屏幕变化。

怎么想:先分清参照物。vw 是 viewport width,1vw = 1/100 视口宽度;vh 是 viewport height,1vh = 1/100 视口高度。注意是“百分之一”,不是“百分之十”。转写稿里反复强调:vw 看宽,vh 看高,两者都是独立单位。

怎么做:以 iPhone 6/7/8 的 375 宽设计稿为例,1vw = 3.75px。写盒子时直接把单位换成 vw,例如:

css
.box {
  width: 50vw;
  height: 30vw;
  background-color: red;
}

浏览器切到 iPhone 6/7/8 时,宽约 50 × 3.75 = 187.5px,高约 30 × 3.75 = 112.5px;切到 Plus 等更宽设备,盒子会跟着变大,说明它已经在做适配。

易错点:不要把 1vw 说成 1% 视口宽度的“十分之一”;也不要把 vh 当成宽度单位。vw、vh 本身不负责“布局变几列”,它们只负责尺寸随视口缩放。

vw 布局:从设计稿 px 换算成 vw ​

为什么需要:设计稿标注的是 px,代码里不能继续写 px,否则尺寸被固定。必须把量到的 px 换算成 vw,才能保留适配效果。

怎么想:公式是:vw 单位的尺寸 = px 单位数值 / (1/100 视口宽度)。以 375 设计稿为准,1vw = 3.75px,所以 N vw = N × 3.75px,反推就是 px ÷ 3.75。

怎么做:转写稿中量到盒子宽 68px、高 29px。先算宽:68 ÷ 3.75 ≈ 18.133,写成 18.133vw;再算高:29 ÷ 3.75 ≈ 7.733,写成 7.733vw:

css
.box {
  width: 18.133vw;
  height: 7.733vw;
}

浏览器里看到约 67.98px、28.98px,接近 68 和 29,这是小数取舍造成的,不是写错。调试时切到 iPhone 6/7/8 看基准,再切 Plus 看是否随宽度放大。

易错点:换算分母是“1vw 对应多少 px”,不是设计稿总宽;每个尺寸都手算很累,转写稿明确说实际会配合 less 做计算,但公式必须自己会。不要把 68px 直接写成 68vw,那会大得离谱。

vh 的问题:全面屏高度变化会让盒子变形 ​

为什么需要:vh 参照视口高度,而不同设备“宽度可能一样、高度不一样”。如果宽高混用 vw 和 vh,盒子比例就会随高度变化而变形。

怎么想:转写稿用 iPhone 6/7/8 和 iPhone X 对比:宽度接近时,全面屏高度更大,vh 算出来的高度会变大;同一个盒子宽度没变、高度变了,比例就变了。笔记也明确写:vh 是 1/100 视口高度,全面屏视口高度尺寸大,混用可能导致盒子变形。

怎么做:实际适配优先用 vw,因为设备宽度通常记得住,高度不固定;宽高统一用同一种单位。转写稿的原话是:要用 vw 就都用 vw,要用 vh 就都用 vh,不要一会儿 vw 一会儿 vh。例如统一写成:

css
.box {
  width: 50vw;
  height: 30vw;
}

切到 iPhone X 时,只要宽度没变,盒子尺寸就基本不动;而把高度改成 30vh 后,高度会随全面屏高度变大。

易错点:不要误以为“宽用 vw、高用 vh”是固定搭配;它们只是两个单位。vh 不是不能用,而是全面屏场景下更容易让比例失真,所以本节建议优先 vw。

酷我音乐移动端效果图

案例目标与准备工作 ​

为什么需要:综合案例要把前面学的 VW 适配、less 计算、flex 布局串起来;没有统一入口文件,图标、样式和页面会各写各的。怎么想:转写中先拿“已完成版本”当参照,并强调切到 iPhone 678(375 宽)量尺寸,因为设计按 375 写,量出来多为整数;VW 是视口宽度 1%,375 设备下 1vw=3.75px。怎么做:新建页面,引入图标和编译后的 CSS;less 用 out 输出到 ../css/,再导入 base。易错点:不要把 VW 当“只能设宽”的单位;less 除法要加括号;本节不需要 JS,VW 本身会随视口宽度变化。

项目准备工作示意图

html
<link rel="stylesheet" href="./iconfont/iconfont.css">
<link rel="stylesheet" href="./css/index.css">
less
// out: ../css/
@import "./base";

头部布局与固定 ​

为什么需要:头部要左右分布,并且滚动时固定在顶部。怎么想:用 flex 做两端对齐;固定定位会脱标、不占位,所以后面的搜索要加 margin-top 挤下来。怎么做:header 设 position:fixed; left:0; top:0; width:100%,高度 50/@vw。易错点:固定定位盒子宽度常靠内容撑开,必须补 width:100%;搜索不加外边距会被头部盖住。

html
<header>
  <div class="left">left</div>
  <a href="#">下载APP</a>
</header>
less
body { background-color: #f9fafb; }
@vw:3.75vw;

header {
  position: fixed; left: 0; top: 0;
  display: flex; justify-content: space-between; align-items: center;
  padding: 0 (15 / @vw);
  width: 100%; height: (50 / @vw);
  background-color: #fff;
}

头部内容 ​

为什么需要:左侧是品牌图,右侧是下载按钮。怎么想:图片用背景图 contain 保持比例;按钮用圆角、黄色底、居中文字。怎么做:.left 宽 235/@vw、高 50/@vw;按钮宽 80/@vw、高 30/@vw、圆角 15/@vw。易错点:背景图不要写死 px,否则不适配;按钮行高要与高度一致。

less
header {
  .left {
    width: (235 / @vw); height: (50 / @vw);
    background-image: url(../assets/head.png);
    background-size: contain; background-repeat: no-repeat;
  }
  a {
    width: (80 / @vw); height: (30 / @vw);
    background-color: #ffe31b; border-radius: (15 / @vw);
    text-align: center; line-height: (30 / @vw); font-size: (14 / @vw);
  }
}

搜索区域 ​

为什么需要:搜索框是移动端常见入口。怎么想:外层给上下内边距,内层灰底圆角;图标和文字同色居中。怎么做:.search 加 margin-top:(50/@vw) 避开固定头部,.txt 高 32/@vw、圆角 16/@vw。易错点:不要忘记头部脱标后的占位补偿。

html
<div class="search">
  <div class="txt">
    <span class="iconfont icon-sousuo"></span>
    <span>搜索你想听的歌曲</span>
  </div>
</div>
less
.search {
  margin-top: (50 / @vw);
  padding: (10 / @vw) (15 / @vw);
  height: (52 / @vw);
  .txt {
    height: (32 / @vw); background-color: #f2f4f5;
    border-radius: (16 / @vw); text-align: center;
    line-height: (32 / @vw); color: #a1a4b3; font-size: (14 / @vw);
    .iconfont { font-size: (16 / @vw); }
  }
}

为什么需要:banner 图要铺满且不变形。怎么想:父盒固定比例,图片宽高 100%,用 object-fit:cover 裁剪覆盖。怎么做:.banner 高 108/@vw,li 宽 345/@vw,图片圆角 5/@vw。易错点:只写 width:100%;height:100% 可能压扁图片,必须配 object-fit:cover。

html
<div class="banner">
  <ul><li><a href="#"><img src="./assets/banner01.jpeg" alt=""></a></li></ul>
</div>
less
.banner {
  padding: 0 (15 / @vw); height: (108 / @vw);
  ul li {
    width: (345 / @vw); height: (108 / @vw);
    img { width: 100%; height: 100%; object-fit: cover; border-radius: (5 / @vw); }
  }
}

标题公共样式 ​

为什么需要:排行榜和推荐歌单都有“标题+更多”。怎么想:抽成 .title 公共类,flex 两端对齐。怎么做:h4 20/@vw,右侧 12/@vw 灰色。易错点:公共类不要绑死在某个模块里。

html
<div class="title">
  <h4>酷我排行榜</h4>
  <a href="#">更多<span class="iconfont icon-right"></span></a>
</div>
less
.title {
  display: flex; justify-content: space-between;
  margin-bottom: (16 / @vw); line-height: (25 / @vw);
  h4 { font-size: (20 / @vw); }
  a { font-size: (12 / @vw); color: #a1a4b3; }
}

排行榜内容 ​

为什么需要:榜单卡片是左图右文。怎么想:li 用 flex,图片固定 105/@vw,文字块纵向排列。怎么做:li 白底圆角,.txt a 设块级、灰色小字,.more 加深。易错点:a 默认行内,不设 display:block 行高会挤在一起。

html
<div class="content"><ul>
  <li>
    <div class="pic"><img src="./assets/icon_rank_hot.png" alt=""></div>
    <div class="txt">
      <a href="#" class="more">酷我热歌榜<span class="iconfont icon-right"></span></a>
      <a href="#">1.樱花树下的约定(完整版) - 旺仔小乔</a>
      <a href="#">2.就让这大雨全都落下 - 容祖儿</a>
      <a href="#">3.缺氧 - 轩姨(相信光)</a>
    </div>
  </li>
</ul></div>
less
.list {
  margin-top: (20 / @vw); padding: 0 (15 / @vw);
  li {
    display: flex; margin-bottom: (16 / @vw);
    height: (105 / @vw); background-color: #fff; border-radius: (10 / @vw);
    .pic { margin-right: (20 / @vw);
      img { width: (105 / @vw); height: (105 / @vw); border-radius: (10 / @vw); }
    }
    .txt a { display: block; font-size: (12 / @vw); color: #a1a4b3; line-height: 1.8; }
    .txt .more { font-size: (14 / @vw); color: #333;
      .iconfont { font-size: (16 / @vw); }
    }
  }
}

推荐歌单布局与内容 ​

为什么需要:歌单是两列/多列卡片。怎么想:ul 用 flex 换行,justify-content:space-between 分列;卡片图片上叠播放量。怎么做:li 宽 105/@vw,图片 100%,.cover 绝对定位左下。易错点:li 宽高要按设计稿算;cover 父级要 position:relative。

html
<div class="recommend">
  <div class="title"><h4>推荐歌单</h4><a href="#">更多<span class="iconfont icon-right"></span></a></div>
  <div class="content"><ul>
    <li><div class="pic"><img src="./assets/song01.jpeg" alt=""><div class="cover">18.2W</div></div><div class="txt">抖音嗨爆DJ!劲爆旋律萦绕双耳</div></li>
  </ul></div>
</div>
less
.recommend {
  padding: 0 (15 / @vw);
  ul { display: flex; flex-wrap: wrap; justify-content: space-between;
    li { margin-bottom: (16 / @vw); width: (105 / @vw); height: (143 / @vw); }
  }
}
.pic {
  position: relative; width: (105 / @vw); height: (105 / @vw);
  img { width: 100%; height: 100%; object-fit: cover; border-radius: (10 / @vw); }
  .cover {
    position: absolute; left: 0; bottom: 0;
    width: (70 / @vw); height: (28 / @vw);
    background-color: rgba(0,0,0,.8); border-radius: 0 (10 / @vw) 0 (10 / @vw);
    text-align: center; line-height: (28 / @vw); color: #fff; font-size: (14 / @vw);
  }
}
.txt { font-size: (14 / @vw); }

下载区域 ​

为什么需要:底部悬浮下载条要始终可见。怎么想:position:fixed 固定底部,flex 排列图标、文字、箭头。怎么做:左右定位 15/@vw,底 30/@vw,高 45/@vw,圆角 22/@vw。易错点:p 用 flex:1 占满中间;箭头用圆形灰底居中。

html
<div class="download">
  <img src="./assets/logo.png" alt="">
  <p>安装酷我音乐 发现更多好音乐</p>
  <span class="iconfont icon-right"></span>
</div>
less
.download {
  position: fixed; left: (15 / @vw); bottom: (30 / @vw);
  display: flex; align-items: center;
  padding: 0 (10 / @vw) 0 (15 / @vw);
  width: (345 / @vw); height: (45 / @vw);
  background-color: #fff; border-radius: (22 / @vw);
  img { margin-right: (10 / @vw); width: (36 / @vw); height: (36 / @vw); }
  p { flex: 1; font-size: (14 / @vw); }
  span { width: (32 / @vw); height: (32 / @vw); background-color: #f2f3f5;
    border-radius: 50%; text-align: center; line-height: (32 / @vw); font-size: (16 / @vw); }
}

调试与易错点 ​

转写里反复强调:VW 是“视口宽度的 1%”,375 设备下 1vw=3.75px;写 less 时用“量出的 px ÷ 3.75”得到 vw 数值,所以代码写 (15 / @vw)。VH 是视口高度 1%,但设备高度不统一,全面屏和非全面屏会改变比例,所以本案例优先 VW。调试时先看头部固定后搜索是否被盖住,再看 banner 图是否变形、榜单文字是否成块、歌单是否两端对齐、下载条是否固定。易错点:固定定位忘写 width:100%;图片忘 object-fit;less 除法忘括号;把 VW/VH 混着拆开用。

课件图示 ​

课件第4页:l 相对单位 l 相对视口的尺寸计算结果 l vw:viewport width

课件第5页:1. 确定设计稿对应的vw尺寸 (1/100视口宽度) Ø 查看设计稿宽度 →

课件第7页:l 思考:开发中,能不能vw和vh混用呢? Ø 不能 Ø vh是1/100视口高

代码示例 ​

示例一:vw / vh 基本使用与计算 ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <!-- 真机调试需要,否则手机会按 980px 视口渲染,vw 就不准了 -->
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>vw / vh 基本使用</title>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    /* 全部用 vw:宽高都跟着视口宽度走 */
    .box-vw {
      width: 50vw;
      height: 30vw;
      background-color: pink;
      font-size: 14vw;
    }

    /* 宽用 vw、高用 vh:换全面屏设备时盒子比例会变形 */
    .box-vh {
      width: 50vw;
      height: 30vh;
      background-color: skyblue;
      font-size: 14vw;
    }
  </style>
</head>
<body>
  <div class="box-vw">50vw × 30vw</div>
  <div class="box-vh">50vw × 30vh</div>
</body>
</html>

关键行与易错点

  • 1vw = 视口宽度的 1%,1vh = 视口高度的 1%,注意是 1%,不是 1/10。
  • 以 375 设计稿为准时:1vw = 3.75px(375 的 1%);iPhone6/7/8 高 667,1vh = 6.67px。
  • 计算公式:vw 数值 = 量的 px 值 ÷ (1/100 视口宽度),即 68px ÷ 3.75 = 18.133vw;写 less 时就是 (68 / 3.75vw)。
  • 用 vw 就自带适配,不需要媒体查询、不需要 rem + flexible.js,所以这个案例里不用引入 JS。
  • 易错点一:vw 和 vh 是两个独立的单位,不是"宽用 vw、高用 vh"的分工,用哪个就全用哪个,混着拆开用会导致盒子比例跑偏。
  • 易错点二:全面屏设备视口高度变大,用 vh 定高的盒子会被拉高变形,所以实际开发统一用 vw。

示例二:酷我音乐 —— 头部 + 搜索 + banner ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>酷我音乐 - 头部 / 搜索 / banner</title>
  <link rel="stylesheet" href="./iconfont/iconfont.css">
  <style>
    /* 对应 less 里的 @vw: 3.75vw;(以 375 设计稿为准,1vw = 3.75px) */
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    body {
      background-color: #f9fafb;
    }

    ul { list-style: none; }
    a  { text-decoration: none; }

    /* ===== 头部 ===== */
    header {
      position: fixed;
      left: 0;
      top: 0;
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 0 calc(15 / 3.75 * 1vw);   /* less: 0 (15 / @vw) */
      width: 100%;                        /* 固定定位盒子靠内容撑开,必须给 100% */
      height: calc(50 / 3.75 * 1vw);      /* less: (50 / @vw) */
      background-color: #fff;
    }

    header .left {
      width: calc(235 / 3.75 * 1vw);
      height: calc(50 / 3.75 * 1vw);
      background-image: url(./assets/head.png);
      background-size: contain;
      background-repeat: no-repeat;
    }

    header a {
      width: calc(80 / 3.75 * 1vw);
      height: calc(30 / 3.75 * 1vw);
      background-color: #ffe31b;
      border-radius: calc(15 / 3.75 * 1vw);
      text-align: center;
      line-height: calc(30 / 3.75 * 1vw);
      font-size: calc(14 / 3.75 * 1vw);
      color: #333;
    }

    /* ===== 搜索 ===== */
    .search {
      /* 头部固定定位脱标不占位,搜索区会跑到最顶部,用 margin-top 挤下来 */
      margin-top: calc(50 / 3.75 * 1vw);
      padding: calc(10 / 3.75 * 1vw) calc(15 / 3.75 * 1vw);
      height: calc(52 / 3.75 * 1vw);
    }

    .search .txt {
      height: calc(32 / 3.75 * 1vw);
      background-color: #f2f4f5;
      border-radius: calc(16 / 3.75 * 1vw);
      text-align: center;
      line-height: calc(32 / 3.75 * 1vw);
      color: #a1a4b3;
      font-size: calc(14 / 3.75 * 1vw);
    }

    .search .txt .iconfont {
      font-size: calc(16 / 3.75 * 1vw);
    }

    /* ===== banner ===== */
    .banner {
      padding: 0 calc(15 / 3.75 * 1vw);
      height: calc(108 / 3.75 * 1vw);
    }

    .banner li {
      width: calc(345 / 3.75 * 1vw);
      height: calc(108 / 3.75 * 1vw);
    }

    .banner img {
      width: 100%;
      height: 100%;
      /* 完全覆盖:图片比例和盒子不同时裁切,避免图片挤压变形 */
      object-fit: cover;
      border-radius: calc(5 / 3.75 * 1vw);
    }
  </style>
</head>
<body>
  <!-- 头部 -->
  <header>
    <div class="left">left</div>
    <a href="#">下载APP</a>
  </header>

  <!-- 搜索 -->
  <div class="search">
    <div class="txt">
      <span class="iconfont icon-sousuo"></span>
      <span>搜索你想听的歌曲</span>
    </div>
  </div>

  <!-- banner -->
  <div class="banner">
    <ul>
      <li><a href="#"><img src="./assets/banner01.jpeg" alt=""></a></li>
    </ul>
  </div>
</body>
</html>

关键行与易错点

  • 笔记里是 less:@vw: 3.75vw; 然后 (50 / @vw),编译结果就是 13.333vw。这里用 calc(50 / 3.75 * 1vw) 等价表达,不装 less 也能直接跑;写 less 时照抄 (50 / @vw) 即可。
  • header 改成固定定位后脱标不占位,搜索区会顶到最上面,所以 .search 必须补 margin-top: (50 / @vw)。
  • 固定定位的盒子宽度靠内容撑开,必须显式写 width: 100%,否则头部不会铺满。
  • padding: 0 (15 / @vw) + width: 100% 在默认盒模型下会超出视口,所以补了 box-sizing: border-box。
  • .search 高 52 = 上下 padding 10×2 + 内容 32,加了 border-box 后刚好装得下,别再重复加高。
  • banner 图片宽高都写 100%,靠 object-fit: cover 处理"图片比例 ≠ 盒子比例"的情况,不加就会挤压变形。
  • 素材(assets/ 下的图片、iconfont/ 字体图标)需按笔记的目录结构自备,路径不改就能跑。

示例三:酷我音乐 —— 排行榜列表 + 固定下载条 ​

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">
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    body {
      background-color: #f9fafb;
      /* 底部固定条会盖住内容,给 body 留出位置 */
      padding-bottom: calc(90 / 3.75 * 1vw);
    }

    ul { list-style: none; }
    a  { text-decoration: none; }

    /* ===== 标题 —— 公共样式,排行榜和推荐歌单都能复用 ===== */
    .title {
      display: flex;
      justify-content: space-between;
      margin-bottom: calc(16 / 3.75 * 1vw);
      line-height: calc(25 / 3.75 * 1vw);
    }

    .title h4 { font-size: calc(20 / 3.75 * 1vw); }

    .title a {
      font-size: calc(12 / 3.75 * 1vw);
      color: #a1a4b3;
    }

    /* ===== 排行榜 ===== */
    .list {
      margin-top: calc(20 / 3.75 * 1vw);
      padding: 0 calc(15 / 3.75 * 1vw);
    }

    .list li {
      display: flex;
      margin-bottom: calc(16 / 3.75 * 1vw);
      height: calc(105 / 3.75 * 1vw);
      background-color: #fff;
      border-radius: calc(10 / 3.75 * 1vw);
    }

    .list .pic {
      margin-right: calc(20 / 3.75 * 1vw);
    }

    .list .pic img {
      display: block;
      width: calc(105 / 3.75 * 1vw);
      height: calc(105 / 3.75 * 1vw);
      border-radius: calc(10 / 3.75 * 1vw);
    }

    .list .txt a {
      display: block;
      font-size: calc(12 / 3.75 * 1vw);
      color: #a1a4b3;
      line-height: 1.8;
    }

    .list .txt .more {
      font-size: calc(14 / 3.75 * 1vw);
      color: #333;
    }

    .list .txt .more .iconfont {
      font-size: calc(16 / 3.75 * 1vw);
    }

    /* ===== 下载条 ===== */
    .download {
      position: fixed;
      left: calc(15 / 3.75 * 1vw);
      bottom: calc(30 / 3.75 * 1vw);

      display: flex;
      align-items: center;
      padding: 0 calc(10 / 3.75 * 1vw) 0 calc(15 / 3.75 * 1vw);
      width: calc(345 / 3.75 * 1vw);
      height: calc(45 / 3.75 * 1vw);
      background-color: #fff;
      border-radius: calc(22 / 3.75 * 1vw);
    }

    .download img {
      margin-right: calc(10 / 3.75 * 1vw);
      width: calc(36 / 3.75 * 1vw);
      height: calc(36 / 3.75 * 1vw);
    }

    .download p {
      flex: 1;
      font-size: calc(14 / 3.75 * 1vw);
    }

    .download span {
      width: calc(32 / 3.75 * 1vw);
      height: calc(32 / 3.75 * 1vw);
      background-color: #f2f3f5;
      border-radius: 50%;
      text-align: center;
      line-height: calc(32 / 3.75 * 1vw);
      font-size: calc(16 / 3.75 * 1vw);
    }
  </style>
</head>
<body>
  <!-- 排行榜 -->
  <div class="list">
    <div class="title">
      <h4>酷我排行榜</h4>
      <a href="#">更多<span class="iconfont icon-right"></span></a>
    </div>

    <ul>
      <li>
        <div class="pic"><img src="./assets/icon_rank_hot.png" alt=""></div>
        <div class="txt">
          <a href="#" class="more">酷我热歌榜<span class="iconfont icon-right"></span></a>
          <a href="#">1.樱花树下的约定(完整版) - 旺仔小乔</a>
          <a href="#">2.就让这大雨全都落下 - 容祖儿</a>
          <a href="#">3.缺氧 - 轩姨(相信光)</a>
        </div>
      </li>
      <li>
        <div class="pic"><img src="./assets/icon_rank_new.png" alt=""></div>
        <div class="txt">
          <a href="#" class="more">酷我新歌榜<span class="iconfont icon-right"></span></a>
          <a href="#">1.樱花树下的约定(完整版) - 旺仔小乔</a>
          <a href="#">2.就让这大雨全都落下 - 容祖儿</a>
          <a href="#">3.缺氧 - 轩姨(相信光)</a>
        </div>
      </li>
      <li>
        <div class="pic"><img src="./assets/icon_rank_rise.png" alt=""></div>
        <div class="txt">
          <a href="#" class="more">酷我飙升榜<span class="iconfont icon-right"></span></a>
          <a href="#">1.樱花树下的约定(完整版) - 旺仔小乔</a>
          <a href="#">2.就让这大雨全都落下 - 容祖儿</a>
          <a href="#">3.缺氧 - 轩姨(相信光)</a>
        </div>
      </li>
    </ul>
  </div>

  <!-- 安装,下载 -->
  <div class="download">
    <img src="./assets/logo.png" alt="">
    <p>安装酷我音乐 发现更多好音乐</p>
    <span class="iconfont icon-right"></span>
  </div>
</body>
</html>

关键行与易错点

  • .title 是抽出来的公共标题样式,排行榜、推荐歌单都用它,改一处全站生效。
  • li 用 display: flex 让左侧封面和右侧文字并排;li 高度 105 与图片 105 一致,圆角 10 才能对上。
  • .txt a 必须写 display: block,否则多个 <a> 会挤成一行,歌单名就排不出来了。
  • 图片建议补 display: block,避免行内元素基线留白导致 105 高撑不齐。
  • .download 的 left / bottom 也用 vw 计算((15 / @vw)、(30 / @vw)),和页面其它尺寸保持同一套换算基准,不要这里用 vh。
  • 下载条是 position: fixed,会盖住页面底部内容,实际项目要给 body 补 padding-bottom(示例里已加)。
  • 下载条内部宽度:padding 15 + 图 36 + 间距 10 + 文字 + 圆钮 32 + padding 10 = 345,配 box-sizing: border-box 刚好铺满,加减一项就会溢出或留空。

常见错误 ​

  1. 现象:页面在部分手机上盒子被拉长或压扁。
    原因:宽高混用 vw 和 vh,全面屏高度变化后比例失真。
    修法:同一套适配统一用 vw,不要用 vh 控制常规盒子高度。

  2. 现象:header 固定后右侧内容没有铺满,或搜索区被顶到屏幕最上方。
    原因:固定定位盒子脱标后宽度靠内容撑开,且不占文档流。
    修法:给 header 补 width: 100%;给后续 .search 补 margin-top: (50 / @vw) 占位。

  3. 现象:Less 中写 (15 / @vw) 不生效或编译结果异常。
    原因:除法未按 Less 规则处理,或变量未定义/位置不对。
    修法:先定义 @vw: 3.75vw;,尺寸统一写成 (设计稿px / @vw),并确认 Less 已编译输出到目标 CSS。

  4. 现象:Banner 或歌单图片被拉伸变形。
    原因:图片宽高被强制设为父容器尺寸,未处理原始比例。
    修法:图片设 width: 100%; height: 100%; object-fit: cover;,父容器负责尺寸和圆角。

  5. 现象:页面引入了 index.css,但样式不生效。
    原因:只写了 index.less,没有编译生成 index.css,或 HTML 链接路径错误。
    修法:确认 Less 文件头部 // out: ../css/ 输出正确,HTML 中 link 指向编译后的 CSS。

  6. 现象:排行榜、推荐歌单中字号、圆角、间距在不同设备上不协调。
    原因:只适配了宽高,遗漏了 font-size、border-radius、line-height、padding 等尺寸。
    修法:凡设计稿量出的尺寸,统一按 (px / @vw) 转换,公共标题样式抽离复用。

练习 ​

  1. 以 375 设计稿为准,把 padding: 0 15px; height: 50px; border-radius: 15px; 改写成基于 @vw: 3.75vw; 的 Less 写法。

  2. 下面写法有问题,请改正并说明原因:

    less
    .box {
      width: (68 / @vw);
      height: 29vh;
    }
  3. 实现固定头部后,让搜索区域不被遮挡:补全 header 和 .search 中缺失的关键样式。

  4. 给推荐歌单卡片补样式:父容器 105px × 105px,图片铺满且不变形,左下角有 70px × 28px 的半透明播放量遮罩。请写出关键 Less。

  5. 检查项目准备流程:HTML 需要引入哪些文件?Less 入口文件需要做什么?为什么这个案例不需要额外引入 JS 做适配?

原视频对照 ​

#视频时长
1课程回顾02:18
2课程介绍07:29
3vw介绍06:27
4vw和vh08:27
5vw和vh使用06:05
6vw和vh布局04:46
7项目(准备)08:11

小结 ​

  1. 本案例以 375 设计稿为基准,核心变量是 @vw: 3.75vw;,所有量出的 px 尺寸都按 (px / @vw) 转换。
  2. 常规移动端适配优先统一使用 vw,不要在同一套盒子尺寸中混用 vh。
  3. 固定头部必须同时处理两件事:自身 width: 100%,后续内容补 margin-top 占位。
  4. 图片区域要同时控制父容器尺寸和 object-fit: cover,避免比例变化导致变形。
  5. 标题、字号、圆角、间距、行高都属于适配范围,不能只改宽高。
  6. Less 负责计算和复用,HTML 最终引入的是编译后的 CSS;路径和输出目录要提前确认。
  7. 公共样式如 .title 应抽离复用,排行榜、推荐歌单等模块只写差异部分。
  8. 该案例用 vw 直接完成适配,不需要额外 JS 参与尺寸换算。