CSS 预处理器互转
Less / Sass / SCSS / Stylus · 命令行编译指引 · 浏览器内编译
Less↔CSS/Sass/SCSS/Stylus
Less / Sass / SCSS / Stylus · 命令行编译指引 · 浏览器内编译
浏览器内可用 less.js 直接编译 Less:
· 变量:Less @var / Sass $var / Stylus var(无前缀)
· 嵌套:都支持 · Stylus 可省略 {} ;
· Mixin:Less .mixin() / SCSS @include mixin
· 导入:Less @import "x.less" / SCSS @use "x"(新)
· 推荐:新项目用 SCSS(Dart Sass 是事实标准,Vite 原生集成)
了解工具定位 · 使用场景 · 对比优势
将 Less 或 Sass/SCSS 代码实时编译为 CSS,支持在 Less、Sass、SCSS、Stylus 四种预处理器之间互相转换。前端开发者调试样式、迁移旧项目、对比不同语法差异时使用。粘贴代码即可编译,全部在浏览器本地完成,代码不上传服务器。
前端团队接手一个使用 Sass 编写的旧项目,但新团队标准是 Less。手动转换数百个 .scss 文件耗时且易错。使用本工具,直接粘贴 Sass/SCSS 代码,一键编译为 Less 语法,保留变量、嵌套、mixin 等核心结构,将迁移时间从数天压缩到数小时。
CSS 预处理器中深层嵌套(如 5 层以上)生成的最终 CSS 选择器冗长且难以调试。前端开发者编写 Less 嵌套时,可实时预览编译后的 CSS 输出,快速发现因嵌套过深导致的特异性冲突或冗余选择器,优化代码可维护性。
设计系统团队同时维护 Less 和 Stylus 两套样式源文件,成员习惯不同。使用本工具将 Stylus 代码转为 Less,确保设计 Token(颜色、间距、字体)在两种预处理器中完全一致,避免因语法差异导致的样式偏差,提升协作效率。
产品经理给出一个用 SCSS 写的样式原型,前端开发者需要快速将其转为项目使用的 Less 语法。不必手动重写变量名和运算逻辑,直接粘贴 SCSS 代码,本工具自动转换,几分钟内即可将原型集成到 Less 项目中,加速迭代周期。
| 维度 | 本工具 | 竞品 A(CodePen) | 传统方法(本地环境) |
|---|---|---|---|
| 数据隐私 | 纯浏览器编译,代码不上传服务器 | 代码上传至 CodePen 服务器 | 代码完全在本地,不涉及网络传输 |
| 处理速度 | 1 秒内完成单文件编译 | 取决于网络延迟和服务器负载,通常 1-3 秒 | 取决于本地硬件和项目规模,大型项目首次编译可能需数秒 |
| 离线可用 | 完全离线可用 | 必须联网 | 完全离线可用 |
| 环境配置 | 零配置,打开即用 | 需注册账号,但无需本地安装 | 需安装 Node.js、npm、Less/Sass CLI 等,配置复杂 |
| 文件导入 | 仅支持单文件或粘贴代码 | 支持导入外部 CSS 库和 JS 库 | 支持 @import 本地文件、使用 Webpack 等模块打包器 |
| 适用场景 | 快速测试代码片段、学习语法差异 | 在线演示、原型设计、团队协作 | 正式项目开发、大型工程、需要完整构建流程 |
| 输出格式 | Less ↔ CSS / Sass / SCSS / Stylus | 仅显示 CSS 编译结果 | 可自定义输出格式、压缩、Source Map 等 |
上手步骤 · 输入输出 · 避坑提示
| 输入 | 输出 | 说明 |
|---|---|---|
| .box { color: red; } | .box { color: red; } | 典型常规场景:基础 Less 变量编译 |
| @primary: #333; .header { color: @primary; } | .header { color: #333; } | 常见用法:变量替换编译 |
| .mixin(@color) { color: @color; } .foo { .mixin(blue); } | .foo { color: blue; } | 典型场景:带参数 Mixin 编译 |
| /* 空文件 */ | 边界 case:空输入直接输出空字符串 | |
| .box { color: red; } | .box { color: red; } | 边界 case:纯 CSS 输入(无 Less 语法)原样输出 |
| @var: 10px; .box { width: @var + 5; } | .box { width: 15px; } | 易错 case:Less 运算需加单位,否则报错 |
| .box { color: red; } | .box { color: red; } | 易错 case:用户误将 Sass 语法($var)当 Less 输入 |
$my-variable: 10px; .box { width: $my_variable; }$my-variable: 10px; .box { width: $my-variable; }Sass 视连字符和下划线为同一字符($my-variable 与 $my_variable 等价),但 SCSS 编译器不会报错,易造成混淆
.my-mixin;.my-mixin();Less 中无参 mixin 调用必须带括号(.my-mixin()),否则会被当作普通类选择器,不会展开 mixin 内容
.btn { & .icon { color: red; } }.btn { .icon { color: red; } }& 代表父选择器本身,.btn & .icon 会生成 .btn .icon,与不加 & 结果相同;错误使用 & 会生成 .btn.btn .icon
.box
color red
font-size 14px.box
color red
font-size 14pxStylus 依赖缩进层级,子属性必须与父属性同级缩进;多缩进会被视为嵌套,导致编译失败或意外结构
@import 'variables.less';@import (reference) 'variables.less';Less 默认 @import 会输出文件所有内容;若只需变量/混入,加 (reference) 可只引用不输出,避免重复样式
%my-placeholder { color: red; } .box { @extend %my-placeholder; }%my-placeholder { color: red; } .box { @extend %my-placeholder; }%placeholder 本身不会生成 CSS,仅用于 @extend;若直接写 .my-placeholder 则会输出空类,浪费体积
width: 100px / 2;width: (100px / 2);Less 3.0+ 中除法必须用括号包裹,否则会被当作 CSS 原生除法(不计算),编译后仍是 100px / 2
.a { color: red; } .b { @extend .a; } .c { @extend .b; }使用 @mixin 或 %placeholder 替代链式 @extend@extend 会复制选择器到所有引用处,链式继承会使选择器组合指数增长,最终 CSS 体积膨胀
公式推导 · 流程图解 · 依据出处
Less/Sass 编译本质是 AST 转换:T(CSS) → CSS,其中 T 为 Less/Sass 解析器实现的语法树变换函数
T — Less/Sass 编译器实现的变换函数CSS — 输入的 Less/Sass/SCSS/Stylus 源码CSS — 输出的标准 CSS 代码输入 Less 源码:@primary-color: #3498db; .btn { color: @primary-color; }。编译器 T 解析变量 @primary-color,替换为 #3498db,输出 CSS:.btn { color: #3498db; }。
适用于 Less、Sass、SCSS、Stylus 四种预处理器语法。不适用于 PostCSS 插件或纯 CSS 文件(无变量/嵌套等预处理特性)。基于 W3C CSS 规范及各预处理器官方解析器实现。
3 种主流语言 · 复制即用
import subprocess
import tempfile
import os
# 使用 lessc 编译 Less → CSS
less_code = """
@color: #4D926F;
#header {
color: @color;
}
"""
with tempfile.NamedTemporaryFile(suffix='.less', mode='w', delete=False) as f:
f.write(less_code)
input_path = f.name
output_path = input_path.replace('.less', '.css')
try:
subprocess.run(['lessc', input_path, output_path], check=True, capture_output=True)
with open(output_path) as f:
print(f.read()) # #header { color: #4D926F; }
finally:
os.unlink(input_path)
if os.path.exists(output_path):
os.unlink(output_path)package main
import (
"fmt"
"os"
"os/exec"
"path/filepath"
)
func main() {
// 使用 sass 命令行工具编译 SCSS → CSS
scss := `
$font-stack: Helvetica, sans-serif;
$primary-color: #333;
body {
font: 100% $font-stack;
color: $primary-color;
}`
dir, _ := os.MkdirTemp("", "sass")
defer os.RemoveAll(dir)
src := filepath.Join(dir, "style.scss")
os.WriteFile(src, []byte(scss), 0644)
cmd := exec.Command("sass", src, filepath.Join(dir, "style.css"))
if err := cmd.Run(); err != nil {
panic(err)
}
out, _ := os.ReadFile(filepath.Join(dir, "style.css"))
fmt.Println(string(out))
// body { font: 100% Helvetica, sans-serif; color: #333; }
}const less = require('less');
// 使用 less.js 在 Node.js 中直接编译
const input = `
@width: 10px;
@height: @width + 10px;
#header {
width: @width;
height: @height;
}`;
less.render(input)
.then(output => {
console.log(output.css);
// #header { width: 10px; height: 20px; }
})
.catch(err => console.error(err));8 个高频疑问
「时间 / 数字开发」下的其他工具