Less 插件 #

Less 插件系统允许你扩展 Less 的功能,添加自定义函数、后处理器和访问器等。

使用插件 #

命令行使用 #

bash
# 安装插件
npm install less-plugin-autoprefix --save-dev

# 使用插件
lessc styles.less styles.css --autoprefix="last 2 versions"

Node.js API 使用 #

javascript
const less = require('less');
const LessPluginAutoPrefix = require('less-plugin-autoprefix');

const options = {
  plugins: [
    new LessPluginAutoPrefix({
      browsers: ['last 2 versions']
    })
  ]
};

less.render(lessInput, options)
  .then(output => {
    console.log(output.css);
  });

编程方式使用 #

javascript
const less = require('less');

less.render(lessInput, {
  plugins: [
    {
      install: function(less, pluginManager) {
        // 插件安装逻辑
      }
    }
  ]
});

常用插件 #

less-plugin-autoprefix #

自动添加浏览器前缀:

bash
npm install less-plugin-autoprefix --save-dev
bash
lessc styles.less styles.css --autoprefix="last 2 versions, ie 11"

输入:

less
.box {
  display: flex;
  transition: all 0.3s;
}

输出:

css
.box {
  display: -webkit-flex;
  display: -ms-flexbox;
  display: flex;
  -webkit-transition: all 0.3s;
  transition: all 0.3s;
}

less-plugin-clean-css #

压缩 CSS 输出:

bash
npm install less-plugin-clean-css --save-dev
bash
lessc styles.less styles.css --clean-css

less-plugin-glob #

支持 glob 模式导入:

bash
npm install less-plugin-glob --save-dev
less
@import "components/**/*.less";

postcss-less-plugin #

使用 PostCSS 处理 Less:

bash
npm install postcss postcss-less --save-dev

插件类型 #

函数插件 #

添加自定义函数:

javascript
const less = require('less');

const myFunctions = {
  'double': function(n) {
    return new less.tree.Dimension(n.value * 2, n.unit);
  },
  'rem': function(px) {
    return new less.tree.Dimension(px.value / 16, 'rem');
  }
};

less.render(lessInput, {
  functions: myFunctions
});

使用:

less
.box {
  width: double(50px);  // 100px
  margin: rem(32px);    // 2rem
}

访问器插件 #

访问 AST 节点:

javascript
const less = require('less');

const visitorPlugin = {
  install: function(less, pluginManager) {
    const Visitor = less.visitors.Visitor;
    
    function MyVisitor() {
      this._visitor = new Visitor(this);
    }
    
    MyVisitor.prototype = {
      run: function(root) {
        return this._visitor.visit(root);
      },
      visitRule: function(ruleNode, visitArgs) {
        // 处理规则节点
        console.log('Found rule:', ruleNode.name);
        return ruleNode;
      }
    };
    
    pluginManager.addVisitor(new MyVisitor());
  }
};

less.render(lessInput, {
  plugins: [visitorPlugin]
});

后处理器插件 #

在 CSS 输出前处理:

javascript
const less = require('less');

const postProcessorPlugin = {
  install: function(less, pluginManager) {
    function PostProcessor() {
      this.process = function(css) {
        // 添加版权注释
        return '/* Copyright 2024 */\n' + css;
      };
    }
    
    pluginManager.addPostProcessor(new PostProcessor());
  }
};

less.render(lessInput, {
  plugins: [postProcessorPlugin]
});

预处理器插件 #

在 Less 解析前处理:

javascript
const less = require('less');

const preProcessorPlugin = {
  install: function(less, pluginManager) {
    function PreProcessor() {
      this.process = function(src, extra) {
        // 添加全局变量
        return '@version: "1.0.0";\n' + src;
      };
    }
    
    pluginManager.addPreProcessor(new PreProcessor());
  }
};

less.render(lessInput, {
  plugins: [preProcessorPlugin]
});

开发自定义插件 #

完整插件示例 #

javascript
const less = require('less');

class MyPlugin {
  constructor(options) {
    this.options = options || {};
    this.minVersion = [3, 0, 0];
  }
  
  install(less, pluginManager, functions) {
    // 添加自定义函数
    functions.add('px-to-rem', (px, base = 16) => {
      return new less.tree.Dimension(px.value / base, 'rem');
    });
    
    functions.add('contrast-color', (color) => {
      const r = color.rgb[0];
      const g = color.rgb[1];
      const b = color.rgb[2];
      const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
      return luminance > 0.5 
        ? new less.tree.Color([0, 0, 0]) 
        : new less.tree.Color([255, 255, 255]);
    });
    
    // 添加后处理器
    pluginManager.addPostProcessor({
      process: (css) => {
        if (this.options.banner) {
          return `/* ${this.options.banner} */\n${css}`;
        }
        return css;
      }
    });
  }
}

// 使用插件
less.render(lessInput, {
  plugins: [new MyPlugin({ banner: 'My Project' })]
});

自定义颜色函数 #

javascript
const less = require('less');

const colorFunctions = {
  'tint': function(color, weight) {
    const w = weight.value / 100;
    const rgb = color.rgb.map(c => Math.round(c + (255 - c) * w));
    return new less.tree.Color(rgb);
  },
  'shade': function(color, weight) {
    const w = weight.value / 100;
    const rgb = color.rgb.map(c => Math.round(c * (1 - w)));
    return new less.tree.Color(rgb);
  }
};

less.render(lessInput, {
  functions: colorFunctions
});

使用:

less
@primary: #007bff;

.lighter {
  background: tint(@primary, 20%);
}

.darker {
  background: shade(@primary, 20%);
}

自定义数学函数 #

javascript
const less = require('less');

const mathFunctions = {
  'sqrt': function(n) {
    return new less.tree.Dimension(Math.sqrt(n.value), n.unit);
  },
  'pow': function(base, exp) {
    return new less.tree.Dimension(Math.pow(base.value, exp.value), base.unit);
  },
  'clamp': function(value, min, max) {
    const v = value.value;
    const minVal = min.value;
    const maxVal = max.value;
    return new less.tree.Dimension(Math.max(minVal, Math.min(maxVal, v)), value.unit);
  }
};

less.render(lessInput, {
  functions: mathFunctions
});

使用:

less
.box {
  width: sqrt(100px);        // 10px
  height: pow(2px, 3);       // 8px
  opacity: clamp(1.5, 0, 1); // 1
}

Webpack 集成 #

javascript
// webpack.config.js
const LessPluginAutoPrefix = require('less-plugin-autoprefix');

module.exports = {
  module: {
    rules: [
      {
        test: /\.less$/,
        use: [
          'style-loader',
          'css-loader',
          {
            loader: 'less-loader',
            options: {
              lessOptions: {
                plugins: [
                  new LessPluginAutoPrefix({
                    browsers: ['last 2 versions']
                  })
                ]
              }
            }
          }
        ]
      }
    ]
  }
};

Vite 集成 #

javascript
// vite.config.js
const LessPluginAutoPrefix = require('less-plugin-autoprefix');

export default {
  css: {
    preprocessorOptions: {
      less: {
        plugins: [
          new LessPluginAutoPrefix({
            browsers: ['last 2 versions']
          })
        ]
      }
    }
  }
};

Gulp 集成 #

javascript
// gulpfile.js
const gulp = require('gulp');
const less = require('gulp-less');
const LessPluginAutoPrefix = require('less-plugin-autoprefix');
const LessPluginCleanCSS = require('less-plugin-clean-css');

const autoprefix = new LessPluginAutoPrefix({ browsers: ['last 2 versions'] });
const cleanCSS = new LessPluginCleanCSS({ advanced: true });

gulp.task('less', function() {
  return gulp.src('./src/**/*.less')
    .pipe(less({
      plugins: [autoprefix, cleanCSS]
    }))
    .pipe(gulp.dest('./dist'));
});

最佳实践 #

插件顺序 #

javascript
// 正确顺序
plugins: [
  preProcessor,    // 1. 预处理
  functions,       // 2. 自定义函数
  autoprefixer,    // 3. 自动前缀
  cleanCSS         // 4. 压缩
]

错误处理 #

javascript
functions.add('safe-divide', function(a, b) {
  if (b.value === 0) {
    throw { message: 'Division by zero' };
  }
  return new less.tree.Dimension(a.value / b.value, a.unit);
});

类型检查 #

javascript
functions.add('process', function(value) {
  if (value.type === 'Dimension') {
    // 处理数值
  } else if (value.type === 'Color') {
    // 处理颜色
  } else if (value.type === 'Quoted') {
    // 处理字符串
  }
});

下一步 #

现在你已经掌握了插件,接下来学习 最佳实践 来优化你的 Less 项目!

最后更新:2026-03-28