CSS 预处理器 - Less
章节介绍
Less(Leaner Style Sheets)是一种动态样式语言,是 CSS 的扩展,它使 CSS 更具可维护性、主题性和可扩展性。Less 与 Sass 类似,提供了许多高级特性,如变量、混合、嵌套、继承等,但语法更加简洁,学习曲线相对较平缓。本章节将详细介绍 Less 的核心特性和使用方法,帮助你掌握这个简洁高效的 CSS 开发工具。
核心知识点讲解
1. Less 的安装和使用
安装 Less
Less 可以通过多种方式安装,最常用的是通过 npm 安装:
# 全局安装
npm install -g less
# 项目本地安装
npm install --save-dev less基本使用
Less 文件的扩展名为 .less。
# 编译单个文件
lessc input.less output.css
# 编译并压缩
lessc --compress input.less output.min.css
# 监视文件变化并自动编译(需要使用第三方工具如 gulp 或 webpack)在浏览器中使用
Less 也可以在浏览器中直接使用,但仅建议用于开发环境:
<link rel="stylesheet/less" type="text/css" href="styles.less" />
<script src="https://cdn.jsdelivr.net/npm/less@4/dist/less.min.js"></script>2. 变量
变量是 Less 最基本的特性之一,它允许你存储和重用值。
变量定义和使用
// 定义变量
@primary-color: #3498db;
@font-size: 16px;
@spacing: 10px;
// 使用变量
body {
font-size: @font-size;
color: @primary-color;
}
.container {
margin: @spacing;
padding: @spacing;
}变量作用域
Less 变量有全局作用域和局部作用域:
// 全局变量
@color: red;
.container {
// 局部变量,只在 .container 内部有效
@color: blue;
color: @color; // 输出 blue
}
.text {
color: @color; // 输出 red
}变量插值
变量插值允许你在选择器、属性名和字符串中使用变量:
@prefix: btn;
.@{prefix} {
display: inline-block;
padding: 10px 20px;
}
.@{prefix}-primary {
background-color: #3498db;
color: white;
}变量计算
Less 允许你对变量进行计算:
@base-font-size: 16px;
@text-lg: @base-font-size * 1.5;
@text-sm: @base-font-size * 0.8;
.text-lg {
font-size: @text-lg;
}
.text-sm {
font-size: @text-sm;
}3. 嵌套
嵌套是 Less 的另一个核心特性,它允许你在选择器内部嵌套其他选择器,反映 HTML 的层次结构。
基本嵌套
nav {
ul {
list-style: none;
margin: 0;
padding: 0;
}
li {
display: inline-block;
margin-right: 10px;
}
a {
text-decoration: none;
color: #333;
&:hover {
color: #3498db;
}
}
}父选择器引用
使用 & 可以引用父选择器:
.btn {
display: inline-block;
padding: 10px 20px;
border: none;
border-radius: 4px;
&:hover {
opacity: 0.8;
}
&:active {
transform: translateY(1px);
}
&-primary {
background-color: #3498db;
color: white;
}
&-secondary {
background-color: #2ecc71;
color: white;
}
}嵌套媒体查询
Less 允许你在选择器内部嵌套媒体查询:
.container {
width: 960px;
margin: 0 auto;
@media (max-width: 768px) {
width: 100%;
padding: 0 10px;
}
@media (max-width: 480px) {
padding: 0 5px;
}
}4. 混合(Mixins)
混合是 Less 中最强大的特性之一,它允许你创建可重用的样式块。
基本混合
// 定义混合
.flex-center {
display: flex;
justify-content: center;
align-items: center;
}
// 使用混合
.container {
.flex-center;
height: 400px;
}
.card {
.flex-center;
flex-direction: column;
}带参数的混合
// 定义带参数的混合
.button(@bg-color, @text-color: white, @padding: 10px 20px) {
display: inline-block;
padding: @padding;
background-color: @bg-color;
color: @text-color;
border: none;
border-radius: 4px;
cursor: pointer;
&:hover {
opacity: 0.8;
}
}
// 使用带参数的混合
.btn-primary {
.button(#3498db);
}
.btn-secondary {
.button(#2ecc71, white, 8px 16px);
}带默认值的混合
// 定义带默认值的混合
.box-shadow(@shadow: 0 2px 4px rgba(0, 0, 0, 0.1)) {
-webkit-box-shadow: @shadow;
-moz-box-shadow: @shadow;
box-shadow: @shadow;
}
// 使用带默认值的混合
.card {
.box-shadow;
}
.card-hover {
.box-shadow(0 4px 8px rgba(0, 0, 0, 0.2));
}不带输出的混合
在混合名前添加 () 可以创建一个不会被编译到 CSS 中的混合:
// 定义不带输出的混合
.button() {
display: inline-block;
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
}
// 使用混合
.btn-primary {
.button;
background-color: #3498db;
color: white;
}
.btn-secondary {
.button;
background-color: #2ecc71;
color: white;
}5. 继承
继承允许你从一个选择器继承样式到另一个选择器,减少代码冗余。
基本继承
// 基础样式
.btn {
display: inline-block;
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
}
// 继承基础样式
.btn-primary {
&:extend(.btn);
background-color: #3498db;
color: white;
}
.btn-secondary {
&:extend(.btn);
background-color: #2ecc71;
color: white;
}继承多个选择器
// 基础样式
.btn {
display: inline-block;
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
}
.btn-hover {
&:hover {
opacity: 0.8;
}
}
// 继承多个选择器
.btn-primary {
&:extend(.btn, .btn-hover);
background-color: #3498db;
color: white;
}6. 操作符
Less 提供了各种操作符,如算术操作符、比较操作符、逻辑操作符等,可以在样式中进行计算。
算术操作符
@base-font-size: 16px;
@container-width: 960px;
@column-count: 3;
body {
font-size: @base-font-size;
}
.container {
width: @container-width;
margin: 0 auto;
}
.column {
width: @container-width / @column-count;
float: left;
margin-right: 20px;
&:last-child {
margin-right: 0;
}
}
.text-lg {
font-size: @base-font-size * 1.5;
}
.text-sm {
font-size: @base-font-size * 0.8;
}颜色操作
@primary-color: #3498db;
.btn {
background-color: @primary-color;
&:hover {
// 使颜色变暗 10%
background-color: darken(@primary-color, 10%);
}
&:active {
// 使颜色变亮 5%
background-color: lighten(@primary-color, 5%);
}
}
// 其他颜色函数
@color: #3498db;
// 调整饱和度
saturate(@color, 10%);
// 降低饱和度
desaturate(@color, 10%);
// 调整透明度
fade(@color, 50%); // 50% 透明度
// 混合颜色
mix(@color, #fff, 50%);7. 函数
Less 提供了许多内置函数,同时也允许你定义自己的函数。
内置函数
// 字符串函数
@string: "Hello, Less!";
// 转换为大写
@upper: e(%("@{string}".toUpperCase()));
// 数字函数
@number: 10.5;
// 取整
round(@number);
// 向上取整
ceil(@number);
// 向下取整
floor(@number);
// 列表函数
@list: 1, 2, 3, 4, 5;
// 获取列表长度
length(@list);
// 获取列表中的元素
extract(@list, 2);
// 颜色函数
@color: #3498db;
// 获取颜色的红色通道
red(@color);
// 获取颜色的绿色通道
green(@color);
// 获取颜色的蓝色通道
blue(@color);
// 获取颜色的 alpha 通道
alpha(@color);自定义函数
Less 没有直接的自定义函数语法,但你可以使用混合来模拟函数:
// 定义一个模拟函数的混合
.calculate-width(@container-width, @column-count, @gutter, @result) {
@result: (@container-width - (@gutter * (@column-count - 1))) / @column-count;
}
// 使用混合
.container {
width: 960px;
margin: 0 auto;
}
.column {
.calculate-width(960px, 3, 20px, @width);
width: @width;
float: left;
margin-right: 20px;
&:last-child {
margin-right: 0;
}
}8. 导入
Less 的导入功能允许你将样式拆分成多个文件,提高代码的可维护性。
导入文件
// 导入变量
@import 'variables.less';
// 导入混合
@import 'mixins.less';
// 导入基础样式
@import 'base.less';
// 导入组件样式
@import 'components/buttons.less';
@import 'components/cards.less';
@import 'components/forms.less';
// 导入布局样式
@import 'layouts/header.less';
@import 'layouts/footer.less';
@import 'layouts/grid.less';导入选项
Less 提供了多种导入选项:
// 导入为参考,不输出导入的样式
@import (reference) 'variables.less';
// 导入为内联,不处理导入文件中的 Less 语法
@import (inline) 'reset.css';
// 强制导入为 Less 文件
@import (less) 'style.css';
// 强制导入为 CSS 文件
@import (css) 'style.less';
// 导入一次,即使多次导入也只处理一次
@import (once) 'variables.less';
// 总是导入,即使多次导入也每次都处理
@import (multiple) 'variables.less';9. 条件语句
Less 提供了条件语句,允许你根据条件生成不同的样式。
@if 指令
@theme: dark;
body {
@if @theme == dark {
background-color: #333;
color: white;
} @else if @theme == light {
background-color: #fff;
color: #333;
} @else {
background-color: #f5f5f5;
color: #333;
}
}带条件的混合
// 定义带条件的混合
.button(@bg-color, @text-color: white) {
display: inline-block;
padding: 10px 20px;
background-color: @bg-color;
color: @text-color;
border: none;
border-radius: 4px;
cursor: pointer;
@if (lightness(@bg-color) > 50%) {
// 亮色背景,使用深色文本
color: #333;
} @else {
// 暗色背景,使用浅色文本
color: white;
}
}
// 使用混合
.btn-primary {
.button(#3498db);
}
.btn-light {
.button(#ecf0f1);
}10. 循环
Less 提供了循环功能,允许你生成重复的样式。
递归混合实现循环
// 定义递归混合
.generate-columns(@n, @i: 1) when (@i <= @n) {
.col-@{i} {
width: (@i / @n) * 100%;
}
.generate-columns(@n, (@i + 1));
}
// 使用混合生成列类
.generate-columns(4);
// 输出
.col-1 {
width: 25%;
}
.col-2 {
width: 50%;
}
.col-3 {
width: 75%;
}
.col-4 {
width: 100%;
}生成间距工具类
// 定义间距变量
@spacings: 5px, 10px, 15px, 20px, 30px;
// 定义生成间距类的混合
.generate-spacing-classes(@spacings) {
.loop(@spacings, 1);
.loop(@list, @index) when (extract(@list, @index) != null) {
@spacing: extract(@list, @index);
.m-@{index} {
margin: @spacing;
}
.p-@{index} {
padding: @spacing;
}
.loop(@list, (@index + 1));
}
}
// 使用混合生成间距类
.generate-spacing-classes(@spacings);
// 输出
.m-1 {
margin: 5px;
}
.p-1 {
padding: 5px;
}
.m-2 {
margin: 10px;
}
.p-2 {
padding: 10px;
}
// ... 以此类推实用案例分析
案例一:使用 Less 变量管理颜色方案
场景描述
需要管理一个网站的颜色方案,确保颜色的一致性和可维护性。
实现代码
// variables.less
// 颜色变量
@colors: {
primary: #3498db;
secondary: #2ecc71;
danger: #e74c3c;
warning: #f39c12;
success: #27ae60;
dark: #333;
light: #f5f5f5;
gray: #999;
white: #fff;
};
// 获取颜色值的混合
.color(@key) {
color: @colors[@key];
}
.bg-color(@key) {
background-color: @colors[@key];
}
.border-color(@key) {
border-color: @colors[@key];
}
// mixins.less
// 按钮混合
.button(@color-key, @padding: 10px 20px) {
display: inline-block;
padding: @padding;
.bg-color(@color-key);
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
&:hover {
opacity: 0.8;
}
}
// buttons.less
// 导入变量和混合
@import 'variables.less';
@import 'mixins.less';
// 按钮样式
.btn {
display: inline-block;
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
&:hover {
opacity: 0.8;
}
}
.btn-primary {
.button(primary);
}
.btn-secondary {
.button(secondary);
}
.btn-danger {
.button(danger);
}代码解析
- 颜色变量管理:使用对象存储所有颜色值,便于统一管理
- 颜色混合:创建
.color()、.bg-color()等混合,方便使用颜色值 - 按钮混合:创建带参数的混合,根据颜色键生成不同样式的按钮
- 按钮样式:使用混合生成不同类型的按钮样式
案例二:使用 Less 创建响应式网格系统
场景描述
需要创建一个响应式网格系统,支持不同屏幕尺寸下的布局调整。
实现代码
// variables.less
// 网格变量
@grid-columns: 12;
@grid-gutter: 20px;
// 断点变量
@breakpoints: {
xs: 0;
sm: 576px;
md: 768px;
lg: 992px;
xl: 1200px;
};
// 获取断点值的混合
.breakpoint(@key) {
@media (min-width: @breakpoints[@key]) {
@content;
}
}
// mixins.less
// 网格列混合
.col(@columns, @total-columns: @grid-columns) {
width: (@columns / @total-columns) * 100%;
}
// grid.less
// 导入变量和混合
@import 'variables.less';
@import 'mixins.less';
// 容器样式
.container {
width: 100%;
padding-left: @grid-gutter / 2;
padding-right: @grid-gutter / 2;
margin-left: auto;
margin-right: auto;
.breakpoint(sm) {
max-width: 540px;
}
.breakpoint(md) {
max-width: 720px;
}
.breakpoint(lg) {
max-width: 960px;
}
.breakpoint(xl) {
max-width: 1140px;
}
}
// 行样式
.row {
display: flex;
flex-wrap: wrap;
margin-left: -@grid-gutter / 2;
margin-right: -@grid-gutter / 2;
}
// 列样式
.col {
position: relative;
width: 100%;
padding-left: @grid-gutter / 2;
padding-right: @grid-gutter / 2;
}
// 生成列类
.generate-columns(@n, @i: 1) when (@i <= @n) {
.col-@{i} {
.col(@i);
}
.breakpoint(sm) {
.col-sm-@{i} {
.col(@i);
}
}
.breakpoint(md) {
.col-md-@{i} {
.col(@i);
}
}
.breakpoint(lg) {
.col-lg-@{i} {
.col(@i);
}
}
.breakpoint(xl) {
.col-xl-@{i} {
.col(@i);
}
}
.generate-columns(@n, (@i + 1));
}
// 使用混合生成列类
.generate-columns(@grid-columns);代码解析
- 网格变量:定义网格列数、间距和断点
- 断点混合:创建
.breakpoint()混合,生成媒体查询 - 网格列混合:创建
.col()混合,计算列宽 - 容器样式:定义不同断点下的容器最大宽度
- 行和列样式:定义行和列的基本样式
- 生成列类:使用递归混合生成不同断点下的列类
案例三:使用 Less 管理字体和排版
场景描述
需要管理网站的字体和排版系统,确保字体大小、行高、字重等的一致性。
实现代码
// variables.less
// 字体变量
@fonts: {
primary: 'Arial, sans-serif';
secondary: 'Georgia, serif';
monospace: 'Courier New, monospace';
};
// 字体大小变量
@font-sizes: {
xs: 12px;
sm: 14px;
base: 16px;
md: 18px;
lg: 20px;
xl: 24px;
xxl: 30px;
xxxl: 36px;
};
// 行高变量
@line-heights: {
tight: 1.2;
normal: 1.5;
loose: 1.8;
};
// 字重变量
@font-weights: {
light: 300;
normal: 400;
medium: 500;
semibold: 600;
bold: 700;
};
// 获取字体值的混合
.font(@key) {
font-family: @fonts[@key];
}
.font-size(@key) {
font-size: @font-sizes[@key];
}
.line-height(@key) {
line-height: @line-heights[@key];
}
.font-weight(@key) {
font-weight: @font-weights[@key];
}
// mixins.less
// 排版混合
.typography(@size, @weight: normal, @line-height: normal) {
.font-size(@size);
.font-weight(@weight);
.line-height(@line-height);
}
// typography.less
// 导入变量和混合
@import 'variables.less';
@import 'mixins.less';
// 基础排版
body {
.font(primary);
.typography(base);
color: #333;
}
// 标题样式
h1 {
.typography(xxxl, bold, tight);
margin-bottom: @font-sizes[md];
}
h2 {
.typography(xxl, semibold, tight);
margin-bottom: @font-sizes[sm];
}
h3 {
.typography(xl, semibold, tight);
margin-bottom: @font-sizes[sm];
}
h4 {
.typography(lg, medium, normal);
margin-bottom: @font-sizes[xs];
}
h5 {
.typography(md, medium, normal);
margin-bottom: @font-sizes[xs];
}
h6 {
.typography(base, medium, normal);
margin-bottom: @font-sizes[xs];
}
// 文本样式
.text-xs {
.typography(xs);
}
.text-sm {
.typography(sm);
}
.text-base {
.typography(base);
}
.text-lg {
.typography(lg);
}
.text-xl {
.typography(xl);
}
// 字重样式
.font-light {
.font-weight(light);
}
.font-normal {
.font-weight(normal);
}
.font-medium {
.font-weight(medium);
}
.font-semibold {
.font-weight(semibold);
}
.font-bold {
.font-weight(bold);
}代码解析
- 字体变量:使用对象存储字体、字体大小、行高和字重
- 字体混合:创建混合从对象中获取字体相关值
- 排版混合:创建
.typography()混合,根据参数设置字体样式 - 基础排版:设置 body 的基础字体样式
- 标题样式:使用混合设置不同级别标题的样式
- 文本样式:创建不同字体大小的文本类
- 字重样式:创建不同字重的文本类
Less 项目结构最佳实践
推荐的项目结构
less/
├── variables.less // 变量定义
├── mixins.less // 混合定义
├── reset.less // 重置样式
├── base.less // 基础样式
├── components/ // 组件样式
│ ├── buttons.less // 按钮组件
│ ├── cards.less // 卡片组件
│ ├── forms.less // 表单组件
│ ├── navigation.less // 导航组件
│ └── modals.less // 模态框组件
├── layouts/ // 布局样式
│ ├── header.less // 头部布局
│ ├── footer.less // 页脚布局
│ ├── grid.less // 网格布局
│ └── sidebar.less // 侧边栏布局
├── pages/ // 页面特定样式
│ ├── home.less // 首页样式
│ ├── about.less // 关于页样式
│ └── contact.less // 联系页样式
├── utils/ // 工具类
│ ├── typography.less // 排版工具类
│ ├── spacing.less // 间距工具类
│ ├── colors.less // 颜色工具类
│ └── flex.less // Flexbox 工具类
└── style.less // 主文件,导入所有部分文件导入顺序
- 变量和混合:这些是基础,其他样式会依赖它们
- 重置和基础样式:重置浏览器默认样式,设置全局基础样式
- 组件样式:可重用组件的样式
- 布局样式:页面布局相关的样式
- 页面特定样式:特定页面的样式
- 工具类:通用的工具类
代码示例:完整的 Less 项目示例
// style.less
// 导入变量和混合
@import 'variables.less';
@import 'mixins.less';
// 导入重置和基础样式
@import 'reset.less';
@import 'base.less';
// 导入组件样式
@import 'components/buttons.less';
@import 'components/cards.less';
@import 'components/forms.less';
@import 'components/navigation.less';
// 导入布局样式
@import 'layouts/header.less';
@import 'layouts/footer.less';
@import 'layouts/grid.less';
// 导入页面特定样式
@import 'pages/home.less';
@import 'pages/about.less';
@import 'pages/contact.less';
// 导入工具类
@import 'utils/typography.less';
@import 'utils/spacing.less';
@import 'utils/colors.less';
@import 'utils/flex.less';
// variables.less
// 颜色变量
@colors: {
primary: #3498db;
secondary: #2ecc71;
danger: #e74c3c;
warning: #f39c12;
success: #27ae60;
dark: #333;
light: #f5f5f5;
gray: #999;
white: #fff;
};
// 字体变量
@fonts: {
primary: 'Arial, sans-serif';
secondary: 'Georgia, serif';
};
// 字体大小变量
@font-sizes: {
xs: 12px;
sm: 14px;
base: 16px;
md: 18px;
lg: 20px;
xl: 24px;
};
// 间距变量
@spacing: {
xs: 5px;
sm: 10px;
md: 15px;
lg: 20px;
xl: 30px;
xxl: 40px;
};
// mixins.less
// 按钮混合
.button(@bg-color, @text-color: white, @padding: 10px 20px) {
display: inline-block;
padding: @padding;
background-color: @bg-color;
color: @text-color;
border: none;
border-radius: 4px;
cursor: pointer;
&:hover {
opacity: 0.8;
}
}
// 响应式混合
.responsive(@breakpoint) {
@media (min-width: @breakpoint) {
@content;
}
}
// base.less
// 基础样式
body {
font-family: @fonts[primary];
font-size: @font-sizes[base];
line-height: 1.5;
color: @colors[dark];
background-color: @colors[light];
}
// 链接样式
a {
color: @colors[primary];
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
// 标题样式
h1, h2, h3, h4, h5, h6 {
margin-top: 0;
margin-bottom: @spacing[md];
font-weight: bold;
}
h1 {
font-size: @font-sizes[xl];
}
h2 {
font-size: @font-sizes[lg];
}
h3 {
font-size: @font-sizes[md];
}
// components/buttons.less
// 按钮样式
.btn {
display: inline-block;
padding: @spacing[sm] @spacing[lg];
border: none;
border-radius: 4px;
cursor: pointer;
font-size: @font-sizes[base];
font-weight: bold;
text-align: center;
text-decoration: none;
&:hover {
opacity: 0.8;
}
&:active {
transform: translateY(1px);
}
}
.btn-primary {
.button(@colors[primary]);
}
.btn-secondary {
.button(@colors[secondary]);
}
.btn-danger {
.button(@colors[danger]);
}
// utils/spacing.less
// 间距工具类
.generate-spacing-classes(@spacings) {
.loop(@spacings, 1);
.loop(@list, @index) when (extract(@list, @index) != null) {
@spacing: extract(@list, @index);
@name: e(%("@{index}"));
.m-@{name} {
margin: @spacing;
}
.mt-@{name} {
margin-top: @spacing;
}
.mb-@{name} {
margin-bottom: @spacing;
}
.ml-@{name} {
margin-left: @spacing;
}
.mr-@{name} {
margin-right: @spacing;
}
.p-@{name} {
padding: @spacing;
}
.pt-@{name} {
padding-top: @spacing;
}
.pb-@{name} {
padding-bottom: @spacing;
}
.pl-@{name} {
padding-left: @spacing;
}
.pr-@{name} {
padding-right: @spacing;
}
.loop(@list, (@index + 1));
}
}
// 使用混合生成间距类
.generate-spacing-classes(@spacing[xs], @spacing[sm], @spacing[md], @spacing[lg], @spacing[xl]);章节总结
本章节详细介绍了 Less 预处理器的核心特性和使用方法,包括:
- 变量:存储和重用值,支持对象和计算
- 嵌套:反映 HTML 的层次结构,支持嵌套媒体查询
- 混合:创建可重用的样式块,支持参数和默认值
- 继承:从一个选择器继承样式到另一个选择器
- 操作符:在样式中进行计算,支持算术和颜色操作
- 函数:使用内置函数处理值
- 导入:将样式拆分成多个文件,支持多种导入选项
- 条件语句:根据条件生成不同的样式
- 循环:生成重复的样式
- 项目结构:推荐的 Less 项目结构和导入顺序
通过本章节的学习,你应该能够:
- 安装和使用 Less 预处理器
- 掌握 Less 的核心特性,如变量、嵌套、混合、继承等
- 使用 Less 创建可维护、可重用的样式代码
- 设计合理的 Less 项目结构
- 应用 Less 最佳实践,提高 CSS 开发效率
Less 是一个简洁高效的 CSS 预处理器,它可以大大提高你的开发效率和代码质量。通过合理使用 Less 的特性,你可以编写更加简洁、可维护、可扩展的 CSS 代码,为项目的成功做出贡献。与 Sass 相比,Less 的语法更加接近 CSS,学习曲线相对较平缓,适合初学者入门。