主题
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 区域
为什么需要: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 混着拆开用。
课件图示



代码示例
示例一: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刚好铺满,加减一项就会溢出或留空。
常见错误
现象:页面在部分手机上盒子被拉长或压扁。
原因:宽高混用vw和vh,全面屏高度变化后比例失真。
修法:同一套适配统一用vw,不要用vh控制常规盒子高度。现象:
header固定后右侧内容没有铺满,或搜索区被顶到屏幕最上方。
原因:固定定位盒子脱标后宽度靠内容撑开,且不占文档流。
修法:给header补width: 100%;给后续.search补margin-top: (50 / @vw)占位。现象:Less 中写
(15 / @vw)不生效或编译结果异常。
原因:除法未按 Less 规则处理,或变量未定义/位置不对。
修法:先定义@vw: 3.75vw;,尺寸统一写成(设计稿px / @vw),并确认 Less 已编译输出到目标 CSS。现象:Banner 或歌单图片被拉伸变形。
原因:图片宽高被强制设为父容器尺寸,未处理原始比例。
修法:图片设width: 100%; height: 100%; object-fit: cover;,父容器负责尺寸和圆角。现象:页面引入了
index.css,但样式不生效。
原因:只写了index.less,没有编译生成index.css,或 HTML 链接路径错误。
修法:确认 Less 文件头部// out: ../css/输出正确,HTML 中link指向编译后的 CSS。现象:排行榜、推荐歌单中字号、圆角、间距在不同设备上不协调。
原因:只适配了宽高,遗漏了font-size、border-radius、line-height、padding等尺寸。
修法:凡设计稿量出的尺寸,统一按(px / @vw)转换,公共标题样式抽离复用。
练习
以 375 设计稿为准,把
padding: 0 15px; height: 50px; border-radius: 15px;改写成基于@vw: 3.75vw;的 Less 写法。下面写法有问题,请改正并说明原因:
less.box { width: (68 / @vw); height: 29vh; }实现固定头部后,让搜索区域不被遮挡:补全
header和.search中缺失的关键样式。给推荐歌单卡片补样式:父容器
105px × 105px,图片铺满且不变形,左下角有70px × 28px的半透明播放量遮罩。请写出关键 Less。检查项目准备流程:HTML 需要引入哪些文件?Less 入口文件需要做什么?为什么这个案例不需要额外引入 JS 做适配?
原视频对照
| # | 视频 | 时长 |
|---|---|---|
| 1 | 课程回顾 | 02:18 |
| 2 | 课程介绍 | 07:29 |
| 3 | vw介绍 | 06:27 |
| 4 | vw和vh | 08:27 |
| 5 | vw和vh使用 | 06:05 |
| 6 | vw和vh布局 | 04:46 |
| 7 | 项目(准备) | 08:11 |
小结
- 本案例以 375 设计稿为基准,核心变量是
@vw: 3.75vw;,所有量出的 px 尺寸都按(px / @vw)转换。 - 常规移动端适配优先统一使用
vw,不要在同一套盒子尺寸中混用vh。 - 固定头部必须同时处理两件事:自身
width: 100%,后续内容补margin-top占位。 - 图片区域要同时控制父容器尺寸和
object-fit: cover,避免比例变化导致变形。 - 标题、字号、圆角、间距、行高都属于适配范围,不能只改宽高。
- Less 负责计算和复用,HTML 最终引入的是编译后的 CSS;路径和输出目录要提前确认。
- 公共样式如
.title应抽离复用,排行榜、推荐歌单等模块只写差异部分。 - 该案例用
vw直接完成适配,不需要额外 JS 参与尺寸换算。