前端开发必学的 Less 实用指南

6,478 阅读12分钟

前言

作为一名前端开发的同学,很多时候我们都无法避免地要去写大量的 CSS 代码,而且耗费的时间还不少,所以学习一种能够提升开发效率的 CSS 预处理器是必不可少的。社区里已经有很多介绍 CSS 预处理器的文章了,内容大多都涵盖变量、嵌套、混合、运算、继承、函数、导入等等...以个人的使用经验来看,除非工作内容涉及到 UI 组件库开发,否则日常的项目开发根本用不了多少高级属性,所以本文章会尽可能地总结一些在项目中用得比较多的功能和属性。

为什么是 Less

Less (Leaner Style Sheets 的缩写) 是一门向后兼容的 CSS 扩展语言。因为 Less 和 CSS 非常像,因此很容易学习。而且 Less 仅对 CSS 语言增加了少许方便的扩展,这就是 Less 如此易学的原因之一。

其实 LessSassStylus 等这些 CSS 预处理器的语法基本都大同小异的,没必要纠结选择哪一种预处理器,一般情况下开发团队内会要求技术栈统一,自己根据团队的实际情况进行选择即可。由于我接触过的大多数项目都是使用 Less 的,所以本文章主要会使用 Less 来编写例子。那么事不宜迟,现在就开始学习吧~ 🖐️🖐️🖐️

起步

Less 以及其它预处理本质上都是 JS 库,这些库的作用就是将预处理代码编译成标准的CSS 代码,所以预处理器给我们提供了多种使用方式。

直接引用 less.js 文件

用这种方式使用 Less 时需要注意,link 标签需要在 less.js 之前引入,并且 link 标签的 rel 属性要设置为 stylesheet/less

<head>
    <!-- 引入自己写的 less 代码 -->
    <link rel="stylesheet/less" type="text/css" href="index.less" />
    <!-- 引入 less.js 核心库 -->
    <script src="https://cdn.bootcdn.net/ajax/libs/less.js/4.1.1/less.min.js"></script>
</head>

npm 下载的方式使用

手动编译

通过 npm 全局安装

npm install less -g

-g 参数表示将 lessc 命令安装到全局环境。对于特定版本,你可以在包名称后面添加@版本号 ,例如 npm install less@2.7.1 -g

在命令行中运行以下代码,就可以将 test.less 编译为 test.css

lessc test.less test.css

由于在命令行中手动编译这种用法使用频率不高,所以这里就不做详细介绍了,有兴趣的可以去官网中查看更多的命令参数。

配合 Webpack 使用

目前大部分的公司都是使用 VueReact 等主流前端框架进行开发,所以大多数情况下我们会在 Webpack 中使用 Less

由于 Webpack 本身只能处理 js 文件,所以需要借助 less-loader 来帮忙处理 less 文件:

# 下载 less、less-loader
npm install less less-loader --save-dev
# 下载 css-loader、style-loader
npm install css-loader style-loader --save-dev

配置 webpack.config.js:

// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.less$/i, loader: [
          // 将 less 文件编译成 css 文件,注意 Webpack Loader 加载顺序从右到左
          'style-loader', 'css-loader', 'less-loader'
        ]
      }
    ]
  }
};

实际上使用像 Vue 这样的框架,官方 CLI 脚手已经帮你集成了 CSS 预处理器,无需自己手动配置Webpack 配置,在使用脚手架初始化项目时勾选上自己喜欢的预处理器就好了。

image.png

image.png

具体用法

嵌套

Less 支持以嵌套的方式去写 CSS 代码,我个人认为这是 CSS 预处理器的最大优点了。相信很多前端同学喜欢使用预处理器的主要原因也是因为它们支持嵌套的写法,因为用嵌套的方式来写 css 实在太方便了!👍 话不多说,直接上代码:

按父类嵌套子类规范来书写的 CSS

/* css 写法 */
.msg-list {
  padding: 16px 20px;
  min-height: 200px;
  max-height: 400px;
}
.msg-list .msg-item {
  height: 24px;
  line-height: 24px;
}
.msg-list .msg-item .msg-item-title {
  color: #333;
  font-size: 22px;
}
.msg-list .msg-item .msg-item-title:hover {
  font-weight: bold;
  text-decoration: underline;
}
.msg-list .msg-item .msg-item-body {
  color: #555;
  font-size: 16px;
}

使用 Less 嵌套写法:

/* less 写法 */
.msg-list {
  padding: 16px 20px;
  min-height: 200px;
  max-height: 400px;
  .msg-item {
    height: 24px;
    line-height: 24px;
    &-title {
      color: #333;
      font-size: 22px;
      &:hover {
        font-weight: bold;
        text-decoration: underline;
      }
    }
    &-body {
      color: #555;
      font-size: 16px;
    }
  }
}

以上两种写法最终得到的效果是一样的,哪一种写法更方便、更优雅,大家应该一目了然了吧。

另外,Less 嵌套还支持使用父选择器 &,例如上面代码中的 &-title&:hover 就分别表示 .msg-item-title.msg-item-title:hover,这样写起来是不是更加简单了,不需要再一层层地去写嵌套的 CSS 代码。

变量

一般用法

Less 支持像 JS 一样去声明一个变量,声明变量时需要以 @ 开头,并且需要以分号结束声明,使用的时候直接用变量名替换设置的样式值即可。

Less 代码如下:

// 声明变量
@fontSize: 16px;
@height: 24px;

// 使用变量
.msg-item {
  height: @height;
  line-height: @height;
  font-size: @fontSize;
}

编译后 CSS 代码:

.msg-item {
  height: 24px;
  line-height: 24px;
  font-size: 16px;
}

使用变量的好处是,我们可以将公共的样式值抽离出来,如果多个模块文件共用变量时,我们还可将它放在单独的文件中,然后使用 @import 导入。

比如项目中有一些比较常用的颜色值、以及文本尺寸大小值,可以这样处理:

公共文件 common.less

// 通用文本尺寸
@text-size-01: 32px; 
@text-size-02: 24px;
@text-size-03: 16px;

// 通用颜色
@title-color: #333;
@sub-text-color: #555;
@content-color: #787878;

业务模块:

@import "common.less";

.msg-item {
  &-title {
    color: @title-color;
    font-size: @text-size-01;
  }
  &-sub-title {
    color: @sub-text-color;
    font-size: @text-size-02;
  }
  &-body {
    color: @content-color;
    font-size: @text-size-03;
  }
}

插值用法

上面变量的例子都是用在 CSS 的属性值,其实变量还能够以插值的形式在选择器名称、属性名称、URL 路径以及 @import 声明中使用。 插值用法类似于 JS 模板字符串,使用时首先定义一个变量 a,然后以 @{a} 的方式去使用:

// 定义变量
@selector: banner;
@fontSize: font-size;
@imgPath: img-path;

.@{selector} { // 选择器中使用
  @{fontSize}: 16px; // 属性中使用
  font-weight: bold;
  line-height: 40px;
  margin: 0 auto;
  background-image: url("@{imgPath}/abc.png"); // URL 路径中使用
}

编译后:

.banner {
  font-size: 16px;
  font-weight: bold;
  line-height: 40px;
  margin: 0 auto;
  background-image: url("img-path/abc.png");
}

转义用法

如果一个变量是以 ~ 开头且内容是用引号包裹起来的字符串,那么在使用这个变量时会将字符串原样输出,例如:

@min768: ~"(min-width: 768px)";
.element {
  @media @min768 {
    font-size: 12px;
  }
}

编译后:

@media (min-width: 768px) {
  .element {
    font-size: 12px;
  }
}

这种用法的使用场景不多,掌握变量的一般用法以及插值用法在大部分项目中已经足够了。

混合

一般用法

使用过 Vue 做开发的同学应该都知道 Mixin 吧,Less 里面的混合跟 Vue 里面的概念差不多。混合实际上就是把一个设置了属性的选择器 a 混入到另外一个选择器 b 中,这样选择器 b 的属性就包含了 a 所有的属性。这样解释起来可能有点绕,那直接上代码吧:

// mixins 垂直水平居中
.flex-center {
  display: flex;
  justify-content: center;
  align-items: center;
}

.box-wrap {
  padding: 8px 16px;
  border: 1px solid #333;
  .flex-center();
}

.card {
  padding: 12px;
  border-radius: 4px;
  border: 1px solid #a0a0a0;
  .flex-center; // 括号可以省掉,但未来版本会被废除,最好加上
}

编译后:

// mixins 垂直水平居中
// 编译后代码会保留 .flex-center
.flex-center {
  display: flex;
  justify-content: center;
  align-items: center;
}

.box-wrap {
  padding: 8px 16px;
  border: 1px solid #333;
  display: flex;
  justify-content: center;
  align-items: center;
}

.card {
  padding: 12px;
  border-radius: 4px;
  border: 1px solid #a0a0a0;
  display: flex;
  justify-content: center;
  align-items: center;
}

上面例子中,我们先定义好 .flex-center 这个选择器的属性,然后在设置 .box-wrap.card 这两个选择器的属性时将其混入,编译之后这两个选择器的属性里就包含了 .flex-center 的所有屬性。所以,混合这种方式让我们可以轻松地将一些常用的公共样式封装出来,以达到复用的目的。

另外需要注意的是,Less 代码编译时,会把混合代码也选择渲染出来,如果不想保留混合原本的代码,定义的时候可以在它后面加上 (),例如:

.flex-center() {
  display: flex;
  justify-content: center;
  align-items: center;
}

.box-wrap {
  padding: 8px 16px;
  border: 1px solid #333;
  .flex-center();
}

编译后:

// 只保留.box-wrap,不保留.flex-center
.box-wrap {
  padding: 8px 16px;
  border: 1px solid #333;
  display: flex;
  justify-content: center;
  align-items: center;
}

嵌套用法

混合还可以嵌套使用,具体代码如下:

.box-outter() {
  border: 1px solid #e8e8e8;
  border-radius: 4px;
  .box-inner {
    padding: 8px;
  }
}

.box {
  margin: 4px;
  .box-outter();
}

编译后:

.box {
  margin: 4px;
  border: 1px solid #e8e8e8;
  border-radius: 4px;
}
.box .box-inner {
  padding: 8px;
}

带参数的用法

以上的用法都是固定的属性,其实混合还可以带参数使用,这种用法跟 JS 函数非常类似:

.size(@s) {
  width: @s;
  height: @s;
}
// 默认参数
.br(@r: 4px) {
  border-radius: @r;
}

.box {
  padding: 4px;
  .size(20px);
  .br();
}

编译后:

.box {
  padding: 4px;
  width: 20px;
  height: 20px;
  border-radius: 4px;
}

!important

在混合代码后面添加 !important,其所有的属性都会加上 !important

.text() {
  font-size: 12px;
  color: #353535;
}

.title {
  padding: 8px 12px;
  .text() !important;
}

编译后:

.title {
  padding: 8px 12px;
  font-size: 12px !important;
  color: #353535 !important;
}

常用例子🌰

最后,关于混合的用法,我这里列了一些常用的例子给大家参考:

// 垂直水平居中
.flex-center {
  display: flex;
  justify-content: center;
  align-items: center;
}

/** flex垂直布局 */
.flex-col {
  display: flex;
  flex-direction: column;
  align-items: center;
}

/** 超出文本用省略号代替 */
.ellipsis {
  white-space: nowrap;
  text-overflow: ellipsis;
  overflow: hidden;
}

/** 超出文本用省略号代替(多行) */
.ellipsis-multi-row(@row) {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: @row;
  overflow: hidden;
}

/** 背景图 */
.bg-img(@url) {
  background: url(@url) no-repeat;
  background-size: 100% 100%;
}

/** 背景颜色 */
.bg(@color: #fff) {
  background: @color;
}

/** 边框 */
.border(@color: red) {
  border: 1px solid @color;
}

/** 尺寸 */
.size(@width, @height) {
  width : @width;
  height: @height;
}

/** 正方形 */
.square(@len) {
  width : @len;
  height: @len;
}

/** 圆形 */
.circle(@dia) {
  width: @dia;
  height: @dia;
  border-radius: 100%;
}

函数与运算

Less 里面的函数与运算使用频率不是特别高,毕竟 CSS 本身就是负责页面样式的,计算这种专业的事情还是交给 JS 去做比较合适,不过这里还是可以简单说一下。

函数

Less 里面的大部分函数例如逻辑控制、字符串操作、数学计算等实际上都可以用 JS 去实现,而且操作起来更起来方便,所以个人认为没太大必要在 Less 里面去做这些东西。但是它提供了一些处理颜色、图片的函数,我觉得还是挺有意思的,我们直接用例子来看看吧:

  • 颜色相关函数:
// 假设有一个16进制的颜色值,需要取它的不透明度为50%的值,有几种做法:
// 16进制的颜色值
@color: #ea78bc;

// 做法1:去找一个可以将16进制转成rgb的网站,将其转为rgb形式后再用rgba表示
@colorRgb: rgb(234, 120, 188); // 16进制 -> rgb
@colorResult1: rgba(234, 120, 188, 0.5);

// 做法2:使用Less提供的red、green、blue函数获取rgb值,再用rgba表示
@colorResult2: rgba(red(@color), green(@color), blue(@color), 0.5);

// 做法3:使用fade、fadeout函数直接处理
@colorResult3: fade(@color, 50%); // 设置颜色的不透明度
@colorResult4: fadeout(@color, 50%); // 增加颜色的不透明度

以上代码编译之后,@colorResult1~4 得到的结果是一样的。

  • 图片相关函数:
// 返回图片宽高
@imgSize: image-size("image.jpg"); // output: 100px 100px

// 返回图片宽
@imgWidth: image-width("image.jpg"); // output: 100px

// 返回图片高
@imgHeight: image-height("image.jpg"); // output: 100px

// 返回图片的base64数据
@imgUrl: data-uri('./image.jpg'); // output: url('data:image/jpeg;base64,bm90IGFjdHVhbGx5IGEganBlZyBmaWxlCg==')

.box-wrap {
  width: @imgWidth;
  height: @imgHeight;
  background-image: @imgUrl;
  background-size: @imageSize;
}

上面例子中,当图片尺寸不确定且需要根据图片的尺寸来设置元素的样式时,获取图片尺寸相关的函数就可以派上用场了。另外,将一些比较小的图片转化为base64数据格式,以行内的方式使用图片,这样可以减少资源请求次数,起到性能优化的效果。

运算

算术运算符 +-*/ 可以对任何数字、颜色或变量进行运算。如果可能的话,算术运算符在加、减或比较之前会进行单位换算。计算的结果以最左侧操作数的单位类型为准。如果单位换算无效或失去意义,则忽略单位。无效的单位换算例如:px 到 cm 或 rad 到 % 的转换。

上面这段话是官网上的描述,但是看起来不是很容易理解,让我们再看看它的例子吧:

// 所有操作数被转换成相同的单位
@conversion-1: 5cm + 10mm; // 结果是 6cm 
@conversion-2: 2 - 3cm - 5mm; // 结果是 -1.5cm 

// conversion is impossible 
@incompatible-units: 2 + 5px - 3cm; // 结果是 4px 

// example with variables 
@base: 5%;
@filler: @base * 2; // 结果是 10% 
@other: @base + @filler; // 结果是 15%

例子看起来不是很难理解,但是同学们在使用的时候可能要注意一下单位换算,因为一不小心单位可能就被整没了。但以我的经验来看,绝大多数项目里应该都不会这样使用,也不敢这么用,反正我是没用过。😂

导入与注释

导入

有时候并不是所有的变量、混合代码都在同一个文件里,这个时候需要使用 @import 将其它文件导入。导入之后,该文件的所有变量、混合都可以被使用,如果导入的文件是 Less 文件可以省略后缀名:

@import "common"; // common.less
@import "reset.css";

注释

Less 里面的注释跟 JS 注释基本一样:

// 这是一句行注释 
@color: white;

/* 
 * 这是一个 
 * Less块注释
 */
@fontSize: 12px;

总结

以上就是本人在项目开发中使用 Less 的经验总结,希望能够对你有所帮助,看完之后觉得还不错的同学帮忙点个赞👍再走吧~ ❤️