Skip to content

Less 语法(Day19 3/3) ​

本页对应 Day19_PC项目&Less,共 5 段视频,约 59 分钟。

学习目标 ​

  • 能够使用 @import 导入 .less 与 .css 文件,并通过编译结果说明二者在内容合并与原样输出上的差异。
  • 能够编写 Less 嵌套规则,正确生成后代、子元素、相邻兄弟、通用兄弟选择器,并使用 & 生成交集选择器、伪类和伪元素。
  • 能够将混合与嵌套结合使用,编写并调用带嵌套结构的混合(如清除浮动),并说明混合内变量与混合在常见开发场景中的使用方式。
  • 能够使用 +、-、*、/ 进行 Less 运算,正确使用括号处理除法,并说明运算结果的单位选择规则。
  • 能够使用 percentage()、mod()、lighten()、darken() 等 Less 函数完成百分比计算、取余和颜色亮度调整,并验证编译结果。

知识点 ​

Less 导入:先理解 CSS @import 与 Less @import 的差异 ​

为什么需要:项目里常把变量、重置样式、混合拆成多个文件,如果每个页面都手工复制,维护成本高。怎么想:先看 CSS 本身也支持 @import,再看 Less 导入 .less 文件时会把内容合并进最终 CSS。怎么做:课堂先写 index.css 导入 reset.css 做对照,再新建 index.less:

less
@import "reset.css";
@import "variables.less";

导入 Less 文件时可省略 .less,Less 会自动补扩展名:

less
@import "variables";

实际结构常是:variables.less 放变量,reset.less 放重置样式,index.less 作为入口文件统一导入,只编译 index.less,其他零碎 Less 文件不单独编译。易错点:导入 .css 时,Less 会把 @import 原样编译到 CSS 中;导入 .less 时,才会把目标文件内容拿过来合并。被导入的模块文件扩展名应是 .less,否则不会按 Less 内容合并。

Less 嵌套:层级选择器、& 与媒体查询 ​

为什么需要:CSS 里写 .container .item .active 容易重复写父级,结构深时难找。怎么想:Less 允许在选择器内部继续写子选择器,编译时生成层级选择器。怎么做:

less
.container {
  .item {
    color: red;
    > .active { color: blue; }
    + .content { color: green; }
    ~ div { background: #900; }
  }
}

它会编译出后代、子代 >、相邻 +、兄弟 ~ 等结构。& 用来取消层级、做交集或拼伪类:

less
.item {
  &.active { color: red; }
  &:hover { color: blue; }
  &::after { content: ""; }
}

媒体查询也可嵌在选择器里,编译后会自动补上选择器:

less
.container {
  width: 100%;
  @media (min-width: 768px) {
    width: 80%;
  }
}

易错点:不加 & 时,.item { :hover {} } 会变成后代选择器;加了 & 才是 .item:hover。媒体查询嵌套只是写法简化,浏览器最终认识的仍是普通媒体查询结构。

混合与嵌套结合:作用域、变量提升与清除浮动 ​

为什么需要:混合像“自定义函数”,可复用一段样式;嵌套让混合内部也能写层级。怎么想:先定义混合,再在选择器中调用;混合内变量和内部混合的使用范围要实测。怎么做:

less
.center-books(@w: 500px) {
  width: @w;
  &:after {
    display: block;
    clear: both;
  }
}

.wrapper {
  .center-books();
}

课堂还演示了清除浮动混合:

less
.clearfix() {
  &:after {
    display: block;
    clear: both;
  }
}

易错点:转写稿中先以为混合内变量外部不能用,后来发现是变量名写错;当前规则下变量可提升,不必过度纠结复杂作用域。混合内再定义混合时,若外层没有调用父混合,内部混合不能直接用;调用父混合后才可用。实际开发按“变量单独文件、混合单独文件、入口统一导入”的规范写,基本不受这些边界影响。

Less 运算符:加减乘除、单位与括号 ​

为什么需要:宽度、间距常需计算,如一行 6 个元素。怎么想:Less 支持 + - * /,但单位规则和除法写法要验证。怎么做:

less
.box {
  width: 10 + 10px;      // 20px
  height: 80% + 10%;     // 90%
  margin: (100px / 2);   // 50px
  padding: mod(100px, 6);// 4px
}

两个操作数都有单位时,结果取第一个操作数的单位;只有一个有单位时用该单位;都没有单位则结果无单位。相同属性相同值会被合并。易错点:除法必须用小括号包起来,否则斜杠会被当成属性值的一部分,因为 background、font、border-radius 等 CSS 值里本来就有斜杠。% 不支持取余运算,要用 mod() 函数。

Less 函数:百分比、取余与颜色明暗 ​

为什么需要:有些计算用运算符不方便,Less 自带函数可做纯计算。怎么想:函数很多,不必全记,掌握常用几个即可。怎么做:

less
.col {
  width: percentage(1 / 6); // 约 16.666%
  margin: mod(100px, 6);    // 4px
  background: lighten(#900, 10%);
  color: darken(#900, 20%);
}

percentage() 会自动拼百分号;mod() 补足取余;lighten()、darken() 调整颜色明暗。易错点:Less 函数不是自定义混合,不生成样式,主要用于计算;大量数学、三角函数和颜色函数实际写样式很少用,不要为了记函数而记函数,按需查文档即可。

课堂画面 ​

课堂画面 1

课堂画面 2

课堂画面 3

课堂画面 4

课堂画面 5

代码示例 ​

示例一:Less 导入(入口文件 + 变量文件 + 重置样式) ​

文件结构

demo/
├── index.html
├── index.less        ← 入口文件(只编译它)
├── variables.less    ← 变量文件(不单独编译)
└── reset.less        ← 重置样式表(不单独编译)

index.html

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>Less 导入</title>
  <!-- 注意:rel 必须是 stylesheet/less -->
  <link rel="stylesheet/less" href="./index.less">
  <script src="https://cdn.jsdelivr.net/npm/less@4"></script>
</head>
<body>
  <h1>导入</h1>
  <p>这是一段文字</p>
</body>
</html>

variables.less

less
@master-red: #f00;
@base-font: 16px;

reset.less

less
* {
  margin: 0;
  padding: 0;
}

index.less(入口文件)

less
// 导入 .less 文件:扩展名可以省略
@import "./reset";
@import "./variables";

h1 {
  color: @master-red;
}

p {
  font-size: @base-font;
}

关键行与易错点

  • @import "./reset"; 省略 .less 后 Less 会自动补上,等价于 @import "./reset.less";。
  • 导入 .less 与导入 .css 结果完全不同:导入 .less 时,被导入文件的内容会被合并进来,最终产物里只有一份 CSS;导入 .css(如 @import "theme.css";)时,Less 会原样输出这条 @import 语句,内容不会被合并——所以拆分的零碎文件扩展名必须是 .less。
  • 拆分后只需要编译 index.less 这一个入口文件,reset.less、variables.less 不需要单独编译出同名 CSS。
  • 浏览器端用 less.js 编译 @import 会发起额外请求,file:// 打开会跨域失败,必须用本地 http 服务(如 VSCode Live Server)打开。

示例二:嵌套、& 符号与媒体查询嵌套 ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>Less 嵌套</title>
  <style type="text/less">
    @master-red: #f00;

    .container {
      width: 600px;
      margin: 0 auto;

      .item {
        line-height: 40px;
        font-size: 14px;

        /* & 取消层级:生成 .container .item.active */
        &.active {
          color: @master-red;
        }
        /* 生成 .container .item:hover */
        &:hover {
          background-color: #eee;
        }
        /* 伪元素紧跟:.container .item::after */
        &::after {
          content: " →";
          color: #999;
        }
        /* 子元素选择器 */
        > .title {
          font-weight: bold;
        }
        /* 相邻兄弟选择器 */
        + .item {
          border-top: 1px solid #ccc;
        }
        /* 通用兄弟选择器 */
        ~ .desc {
          color: #666;
        }
      }

      /* 媒体查询嵌套:不用再重复写 .container 选择器 */
      @media (min-width: 768px) {
        width: 750px;
      }
    }
  </style>
  <script src="https://cdn.jsdelivr.net/npm/less@4"></script>
</head>
<body>
  <div class="container">
    <div class="item active"><span class="title">标题一</span></div>
    <div class="item">标题二</div>
    <div class="desc">描述文字</div>
  </div>
</body>
</html>

关键行与易错点

  • 嵌套默认生成后代选择器(带空格):.container .item;写 > .title、+ .item、~ .desc 时 Less 会保留这些组合符,生成 .container .item > .title 等层级结构选择器。
  • & 的作用是取消层级、拼接成同一层:&.active → .item.active(交集选择器,中间无空格);&:hover → .item:hover;&::after → .item::after。
  • 最容易错:写成 .active { }(不加 &)会变成后代选择器 .item .active,与 &.active 的效果完全不同。
  • 媒体查询写在选择器内部时,Less 会自动把当前选择器包进 @media 里,编译成浏览器认识的 @media (min-width: 768px) { .container { width: 750px; } },省去重复写选择器的麻烦。

示例三:混合、运算符与内置函数 ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>Less 混合 / 运算 / 函数</title>
  <style type="text/less">
    @master-red: #f00;

    /* 混合:清除浮动,内部用 & 接伪元素 */
    .clearfix() {
      &::after {
        display: block;
        clear: both;
        content: "";
      }
    }

    .wrapper {
      .clearfix();               /* 带括号调用,不输出 .clearfix 本身 */
      border: 1px solid #ccc;

      .box {
        float: left;
        width: 100px;
        height: 50px;
        background-color: @master-red;
      }
    }

    .calc {
      width: 10 + 10px;          /* 20px   只有一个带单位,取该单位 */
      height: 56px + 10;         /* 66px   同上 */
      margin-left: 1em + 78px;   /* 79em   都带单位,取前一个的单位 */
      padding-left: (100px / 2); /* 50px   除法必须加括号 */
      padding-top: mod(100px, 6);/* 4px    取余用 mod() 函数 */
    }

    .fn {
      width: percentage((1 / 6));            /* 16.66666667% */
      background-color: lighten(#900, 10%);  /* #cc0000  调亮 */
      color: darken(#900, 20%);              /* #330000  调暗 */
    }
  </style>
  <script src="https://cdn.jsdelivr.net/npm/less@4"></script>
</head>
<body>
  <div class="wrapper"><div class="box">box</div></div>
  <div class="calc">calc</div>
  <div class="fn">fn</div>
</body>
</html>

关键行与易错点

  • .clearfix() 定义时带括号是混合,调用 .clearfix(); 只把内容拷进 .wrapper;若定义时不带括号写成 .clearfix { },它就是一个普通类,编译后会额外输出一份 .clearfix 样式。
  • 混合里写 &::after,调用时 & 会替换成调用者(.wrapper),生成 .wrapper::after;如果写成 ::after 而不加 &,会变成后代选择器 .wrapper ::after,清除浮动就失效了。
  • 运算单位规则:两个操作数只有一个带单位→ 用那个单位;都带单位→ 用前一个的单位(1em + 78px = 79em,没有谁优先级更高,只看先后)。
  • 除法必须加小括号 (100px / 2),否则 Less 会把 / 当成属性值的一部分原样输出——因为 CSS 本身在 background、font、border-radius 等复合属性里就用斜杠做分隔,Less 无法区分。
  • Less 不支持 % 取余运算,要用 mod(100px, 6) 函数。
  • percentage((1/6)) 内层除法也要括号;lighten() / darken() 的第二个参数是百分比,直接调亮/调暗颜色,省去自己算色值。

常见错误 ​

  1. 现象:在 Less 中写 @import "reset.css";,期望把 CSS 内容合并进来,结果编译后仍是导入语句。
    原因:导入 .css 文件时按 CSS 导入原样保留,不会像 Less 模块一样内联。
    修法:需要内联和参与 Less 编译时改为 .less 文件;确实要保留 CSS 导入语义时再使用 .css。

  2. 现象:嵌套里写 .item { :hover { ... } },生成的是后代选择器,不是元素自身 hover。
    原因:缺少 &,嵌套默认按层级/后代关系拼接。
    修法:伪类、伪元素、属性选择器、交集选择器需要紧贴时写成 &:hover、&::after、&.active。

  3. 现象:width: 100px / 2; 没有计算出结果,斜杠被原样保留。
    原因:CSS 属性值中斜杠有合法语义,Less 新版不会无条件把 / 当除法。
    修法:除法用括号明确计算,如 width: (100px / 2);;同时提前统一单位。

  4. 现象:在混合外部直接使用混合内部定义的变量或嵌套混合,报错或结果不符合预期。
    原因:混合存在作用域和调用上下文影响,不能按全局变量随意依赖。
    修法:变量集中放到独立 variables.less 并由入口导入;混合内部变量只在调用上下文内使用,不依赖提升规则。

  5. 现象:媒体查询嵌套后,@media 内部又重复写选择器,或误以为浏览器直接识别 Less 写法。
    原因:媒体查询嵌套应围绕外层选择器组织,最终由 Less 编译成浏览器可识别的重复选择器结构。
    修法:把 @media 嵌入目标选择器内部,内部直接写属性;检查编译产物是否符合预期。

  6. 现象:把 Less 函数当混合用,期望函数生成一组样式;或用 % 做取余。
    原因:函数主要用于计算,不负责生成样式;% 在 CSS 中有百分比语义,Less 不提供 % 取余运算。
    修法:样式复用使用混合,计算使用函数;取余用 mod(),百分比计算用 percentage()。

练习 ​

  1. 现有 variables.less 定义品牌色,index.less 作为入口文件。请写出合理的导入与编译组织方式,并说明哪些文件需要单独编译、哪些不需要。

  2. 改写下面结构,使 hover 只作用于 li 自身、> a 只作用于直接子元素、& + & 表示相邻同级项,并写出你认为会生成的关键选择器:

    less
    .nav &#123;
      li &#123;
        /* 在此补充 */
      &#125;
    &#125;
  3. 判断并修正下列写法中的运算问题,说明原因:

    less
    .box &#123;
      width: 100px / 2;
      height: (80% + 10em);
      margin: 100px % 6;
    &#125;
  4. 将下面传统媒体查询改写成 Less 嵌套写法,要求选择器不重复书写:

    css
    .container &#123; width: 100%; &#125;
    @media (min-width: 768px) &#123;
      .container &#123; width: 750px; &#125;
    &#125;
    @media (min-width: 992px) &#123;
      .container &#123; width: 970px; &#125;
    &#125;
  5. 场景题:mixins.less 中定义 clearfix(),内部包含 &::after。在 .wrapper 中调用该混合后,请说明生成的选择器结构;如果去掉 &,结构会怎样变化?

原视频对照 ​

#视频时长
1Less导入16:08
2Less嵌套15:54
3混合和嵌套的结合10:14
4Less运算符08:19
5Less函数08:52

小结 ​

  1. Less 导入的关键不是“能不能导入”,而是区分 Less 模块内联与 CSS 导入保留,入口文件负责统一编译。
  2. 嵌套用于表达结构,& 用于取消层级或拼接;二者混用时优先检查最终选择器是否符合预期。
  3. 媒体查询嵌套应减少选择器重复,但必须以编译产物可读、可维护为准。
  4. 混合负责样式复用,函数负责计算,不要把两者职责混在一起。
  5. 运算符的高频风险在单位与除法:单位提前统一,除法用括号明确表达。
  6. 变量、混合应集中管理并按模块拆分,不依赖作用域提升这类边缘行为。
  7. 函数按需掌握常用项即可,颜色函数和数学函数不必追求记全。
  8. 工程化视角下只编译入口文件,其他 Less 模块作为可组合、可维护的源码模块存在。