Skip to content
On this page

Sass 工具与资源

Sass生态系统提供了丰富的工具和资源,帮助开发者提高工作效率、优化代码质量和简化开发流程。本章将详细介绍Sass开发中常用的工具和资源。

开发工具

编辑器和IDE插件

Visual Studio Code插件

json
// 推荐的VS Code扩展
{
  "recommendations": [
    "bradlc.vscode-tailwindcss",    // Tailwind CSS智能提示
    "csstools.postcss",             // PostCSS支持
    "ms-vscode.vscode-scss",        // SCSS语言支持
    "stylelint.vscode-stylelint",   // Stylelint集成
    "formulahendry.auto-rename-tag", // 自动重命名标签
    "esbenp.prettier-vscode",       // 代码格式化
    "gruntfuggly.todo-tree",        // TODO标记树
    "aaron-bond.better-comments"    // 改进注释高亮
  ]
}

WebStorm/IntelliJ IDEA配置

xml
<!-- WebStorm Sass配置 -->
<!-- Settings > Languages & Frameworks > Stylesheets > Sass/SCSS -->
<config>
  <!-- Sass可执行文件路径 -->
  <sass-compiler>
    <executable-path>/path/to/sass</executable-path>
    <watchers>
      <watch-scss>true</watch-scss>
      <watch-sass>true</watch-sass>
    </watchers>
  </sass-compiler>
  
  <!-- 自动导入 -->
  <auto-imports>
    <import-abstracts>true</import-abstracts>
    <resolve-partials>true</resolve-partials>
  </auto-imports>
</config>

命令行工具

Sass命令行工具

bash
# 基本编译命令
sass input.scss output.css

# 监听文件变化
sass --watch input.scss output.css

# 监听整个目录
sass --watch scss:css

# 压缩输出
sass --style compressed input.scss output.css

# 生成源映射
sass --sourcemap input.scss output.css

# 使用自定义配置文件
sass --load-path=node_modules input.scss output.css

# 更多选项
sass --help

高级命令行用法

bash
# 条件编译
sass --style=compressed --no-source-map --quiet scss/main.scss css/main.min.css

# 多文件编译
sass scss/:css/ --style=expanded

# 带错误处理的编译
sass scss/main.scss css/main.css 2>&1 | tee sass-build.log

# 持续集成中的用法
sass --no-source-map --style=compressed --quiet-deps scss/main.scss dist/main.css

构建工具集成

Webpack配置

javascript
// webpack.config.js
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');

module.exports = {
  entry: './src/js/main.js', // 如果有JS入口
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'js/[name].[contenthash].js'
  },
  module: {
    rules: [
      {
        test: /\.(sa|sc|c)ss$/,
        use: [
          // 开发环境使用style-loader,生产环境使用MiniCssExtractPlugin
          process.env.NODE_ENV !== 'production' 
            ? 'style-loader' 
            : MiniCssExtractPlugin.loader,
          {
            loader: 'css-loader',
            options: {
              importLoaders: 2, // 在css-loader前执行的loader数量
              sourceMap: true
            }
          },
          {
            loader: 'postcss-loader', // 可选,用于自动添加浏览器前缀
            options: {
              sourceMap: true,
              postcssOptions: {
                plugins: [
                  ['autoprefixer', {}]
                ]
              }
            }
          },
          {
            loader: 'sass-loader',
            options: {
              implementation: require('sass'),
              sourceMap: true,
              sassOptions: {
                includePaths: [
                  path.resolve(__dirname, 'node_modules'),
                  path.resolve(__dirname, 'src/scss')
                ],
                outputStyle: process.env.NODE_ENV === 'production' ? 'compressed' : 'expanded'
              }
            }
          }
        ]
      }
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/[name].[contenthash].css',
      chunkFilename: 'css/[id].[contenthash].css'
    })
  ],
  optimization: {
    minimizer: [
      new CssMinimizerPlugin({
        test: /\.css$/g,
        parallel: true, // 使用多进程并行运行来提高构建速度
      })
    ],
    splitChunks: {
      cacheGroups: {
        styles: {
          name: 'styles',
          type: 'css/mini-extract',
          chunks: 'all',
          enforce: true,
        }
      }
    }
  }
};

Vite配置

javascript
// vite.config.js
import { defineConfig } from 'vite';
import { resolve } from 'path';

export default defineConfig({
  css: {
    preprocessorOptions: {
      scss: {
        additionalData: `
          @use "@/styles/abstracts/variables" as *;
          @use "@/styles/abstracts/mixins" as *;
        `,
        includePaths: [
          resolve(__dirname, 'src/styles'),
          resolve(__dirname, 'node_modules')
        ]
      }
    },
    modules: {
      localsConvention: 'camelCase' // CSS Modules配置
    }
  },
  resolve: {
    alias: {
      '@': resolve(__dirname, 'src'),
      '@styles': resolve(__dirname, 'src/styles')
    }
  }
});

Gulp构建

javascript
// gulpfile.js
const gulp = require('gulp');
const sass = require('gulp-sass')(require('sass'));
const sourcemaps = require('gulp-sourcemaps');
const autoprefixer = require('gulp-autoprefixer');
const cleanCSS = require('gulp-clean-css');
const rename = require('gulp-rename');
const gulpif = require('gulp-if');
const browserSync = require('browser-sync').create();

// 环境变量
const isProduction = process.env.NODE_ENV === 'production';

// Sass编译任务
gulp.task('sass', function() {
  return gulp.src('src/scss/**/*.scss')
    .pipe(gulpif(!isProduction, sourcemaps.init()))
    .pipe(sass({
      outputStyle: isProduction ? 'compressed' : 'expanded',
      includePaths: ['node_modules', 'src/scss'],
      sourceComments: !isProduction,
      errLogToConsole: true
    }).on('error', sass.logError))
    .pipe(autoprefixer({
      cascade: false,
      grid: 'autoplace'
    }))
    .pipe(gulpif(isProduction, cleanCSS()))
    .pipe(gulpif(!isProduction, sourcemaps.write('.')))
    .pipe(gulp.dest('dist/css'))
    .pipe(browserSync.stream());
});

// 监听任务
gulp.task('watch', function() {
  browserSync.init({
    server: {
      baseDir: './'
    }
  });
  
  gulp.watch('src/scss/**/*.scss', gulp.series('sass'));
  gulp.watch('*.html').on('change', browserSync.reload);
});

// 默认任务
gulp.task('default', gulp.series('sass', 'watch'));

代码质量工具

Stylelint配置

json
// .stylelintrc.json
{
  "extends": [
    "stylelint-config-standard-scss",
    "stylelint-config-recess-order"
  ],
  "plugins": [
    "stylelint-scss",
    "stylelint-order",
    "stylelint-prettier"
  ],
  "rules": {
    "at-rule-no-unknown": null,
    "scss/at-rule-no-unknown": true,
    "scss/dollar-variable-pattern": "^[a-z]+([a-z0-9-]+[a-z0-9]+)?$",
    "scss/percent-placeholder-pattern": "^[a-z]+([a-z0-9-]+[a-z0-9]+)?$",
    "scss/selector-nest-combinators": "always",
    "scss/selector-no-redundant-nesting-selector": true,
    "scss/at-extend-no-missing-placeholder": true,
    "scss/double-slash-comment-whitespace-inside": "always",
    "order/properties-order": [
      [
        "position",
        "top",
        "right",
        "bottom",
        "left",
        "z-index",
        "display",
        "vertical-align",
        "flex",
        "flex-grow",
        "flex-shrink",
        "flex-basis",
        "flex-direction",
        "flex-wrap",
        "flex-flow",
        "justify-content",
        "align-items",
        "align-content",
        "align-self",
        "order",
        "grid",
        "grid-area",
        "grid-template",
        "grid-template-areas",
        "grid-template-rows",
        "grid-template-columns",
        "grid-row",
        "grid-row-start",
        "grid-row-end",
        "grid-column",
        "grid-column-start",
        "grid-column-end",
        "grid-auto-rows",
        "grid-auto-columns",
        "grid-auto-flow",
        "grid-gap",
        "grid-row-gap",
        "grid-column-gap",
        "gap",
        "row-gap",
        "column-gap",
        "margin",
        "margin-top",
        "margin-right",
        "margin-bottom",
        "margin-left",
        "margin-block",
        "margin-block-start",
        "margin-block-end",
        "margin-inline",
        "margin-inline-start",
        "margin-inline-end",
        "padding",
        "padding-top",
        "padding-right",
        "padding-bottom",
        "padding-left",
        "padding-block",
        "padding-block-start",
        "padding-block-end",
        "padding-inline",
        "padding-inline-start",
        "padding-inline-end",
        "float",
        "clear",
        "object-fit",
        "overflow",
        "overflow-x",
        "overflow-y",
        "overflow-scrolling",
        "clip",
        "clip-path",
        "width",
        "min-width",
        "max-width",
        "height",
        "min-height",
        "max-height",
        "inline-size",
        "min-inline-size",
        "max-inline-size",
        "block-size",
        "min-block-size",
        "max-block-size",
        "box-sizing",
        "writing-mode",
        "resize",
        "zoom",
        "outline",
        "outline-width",
        "outline-style",
        "outline-color",
        "outline-offset",
        "border",
        "border-color",
        "border-style",
        "border-width",
        "border-top",
        "border-top-color",
        "border-top-style",
        "border-top-width",
        "border-right",
        "border-right-color",
        "border-right-style",
        "border-right-width",
        "border-bottom",
        "border-bottom-color",
        "border-bottom-style",
        "border-bottom-width",
        "border-left",
        "border-left-color",
        "border-left-style",
        "border-left-width",
        "border-radius",
        "border-top-left-radius",
        "border-top-right-radius",
        "border-bottom-right-radius",
        "border-bottom-left-radius",
        "border-start-start-radius",
        "border-start-end-radius",
        "border-end-start-radius",
        "border-end-end-radius",
        "border-image",
        "border-image-source",
        "border-image-slice",
        "border-image-width",
        "border-image-outset",
        "border-image-repeat",
        "border-collapse",
        "border-spacing",
        "background",
        "background-color",
        "background-image",
        "background-attachment",
        "background-repeat",
        "background-position",
        "background-position-x",
        "background-position-y",
        "background-clip",
        "background-origin",
        "background-size",
        "background-blend-mode",
        "color",
        "font",
        "font-family",
        "font-size",
        "font-style",
        "font-weight",
        "font-variant",
        "font-size-adjust",
        "font-stretch",
        "font-effect",
        "font-emphasize",
        "font-emphasize-position",
        "font-emphasize-style",
        "font-smooth",
        "line-height",
        "text-align",
        "text-align-last",
        "vertical-align",
        "text-overflow",
        "text-transform",
        "text-decoration",
        "text-decoration-color",
        "text-decoration-line",
        "text-decoration-style",
        "text-shadow",
        "text-fill-color",
        "text-stroke",
        "text-stroke-width",
        "text-stroke-color",
        "letter-spacing",
        "word-spacing",
        "white-space",
        "caption-side",
        "tab-size",
        "hyphens",
        "overflow-wrap",
        "word-wrap",
        "word-break",
        "quotes",
        "counter-reset",
        "counter-increment",
        "list-style",
        "list-style-position",
        "list-style-type",
        "list-style-image",
        "table-layout",
        "empty-cells",
        "caption-side",
        "display",
        "visibility",
        "unicode-bidi",
        "direction",
        "columns",
        "column-span",
        "column-width",
        "column-count",
        "column-fill",
        "column-gap",
        "column-rule",
        "column-rule-width",
        "column-rule-style",
        "column-rule-color",
        "break-before",
        "break-inside",
        "break-after",
        "page-break-before",
        "page-break-inside",
        "page-break-after",
        "orphans",
        "widows",
        "zoom",
        "fill",
        "fill-rule",
        "clip-rule",
        "stroke"
      ],
      {
        "unspecified": "bottom",
        "empty-lines-between-override-groups": 1
      }
    ]
  }
}

Prettier配置

json
// .prettierrc
{
  "semi": true,
  "trailingComma": "es5",
  "singleQuote": true,
  "printWidth": 80,
  "tabWidth": 2,
  "useTabs": false,
  "bracketSpacing": true,
  "arrowParens": "avoid",
  "endOfLine": "lf",
  "overrides": [
    {
      "files": "*.scss",
      "options": {
        "parser": "scss"
      }
    },
    {
      "files": "*.sass", 
      "options": {
        "parser": "sass"
      }
    }
  ]
}

在线工具和资源

在线Sass编辑器

html
<!-- 推荐的在线Sass工具 -->
<ul>
  <li><a href="https://sass.js.org/">Sass.js</a> - 在线Sass编译器</li>
  <li><a href="https://www.sassmeister.com/">SassMeister</a> - Sass在线编辑器</li>
  <li><a href="https://codepen.io/">CodePen</a> - 支持Sass的在线代码编辑器</li>
  <li><a href="https://jsfiddle.net/">JSFiddle</a> - 在线测试工具,支持Sass</li>
</ul>

颜色工具

scss
// 颜色管理工具和资源
/*
1. Coolors (https://coolors.co/)
   - 快速生成配色方案

2. Adobe Color (https://color.adobe.com/)
   - 专业的配色工具

3. Material Palette (https://www.materialpalette.com/)
   - Material Design配色

4. Color Hunt (https://colorhunt.co/)
   - 流行的配色方案

5. CSS Gradient (https://cssgradient.io/)
   - 渐变生成器
*/

Sass框架和库

Bootstrap Sass

scss
// Bootstrap with Sass
// package.json
{
  "dependencies": {
    "bootstrap": "^5.3.0"
  }
}

// main.scss
// 导入Bootstrap的Sass文件
@import "~bootstrap/scss/bootstrap";

// 或者按需导入
@import "~bootstrap/scss/functions";
@import "~bootstrap/scss/variables";
@import "~bootstrap/scss/mixins";

// 自定义变量
$primary: #007bff;
$secondary: #6c757d;

// 导入组件
@import "~bootstrap/scss/buttons";
@import "~bootstrap/scss/forms";

Foundation for Sites

scss
// Foundation框架
// package.json
{
  "dependencies": {
    "foundation-sites": "^6.7.0"
  }
}

// main.scss
@import 'foundation';

// 启用特定组件
@include foundation-global-styles;
@include foundation-grid;
@include foundation-typography;
@include foundation-button;
@include foundation-forms;

Bulma

scss
// Bulma框架
// package.json
{
  "dependencies": {
    "bulma": "^0.9.4"
  }
}

// main.scss
// 自定义变量
$primary: #007bff;
$info: #17a2b8;
$success: #28a745;

// 导入Bulma
@import "~bulma/bulma.sass";

实用Sass库

Sass MQ (媒体查询库)

scss
// _mq.scss - 媒体查询工具库
$mq-breakpoints: (
  mobile:  320px,
  tablet:  768px,
  desktop: 1024px,
  wide:    1200px
);

@mixin mq($from: null, $until: null, $and: null) {
  $media-query: '';

  @if $from {
    $media-query: '#{$media-query} and (min-width: #{map-get($mq-breakpoints, $from)})';
  }

  @if $until {
    $media-query: '#{$media-query} and (max-width: #{map-get($mq-breakpoints, $until) - 1px})';
  }

  @if $and {
    $media-query: '#{$media-query} and #{$and}';
  }

  // Remove unnecessary ' and ' at the beginning
  @if str-slice($media-query, 1, 5) == ' and ' {
    $media-query: str-slice($media-query, 6);
  }

  @media #{$media-query} {
    @content;
  }
}

// 使用示例
.element {
  font-size: 1rem;
  
  @include mq($from: tablet) {
    font-size: 1.2rem;
  }
  
  @include mq($from: desktop) {
    font-size: 1.5rem;
  }
}

Sass Flexbox Grid

scss
// _flexbox-grid.scss - Flexbox网格系统
$grid-columns: 12;
$grid-gutter: 30px;

%grid-container {
  width: 100%;
  padding-right: $grid-gutter / 2;
  padding-left: $grid-gutter / 2;
  margin-right: auto;
  margin-left: auto;
}

%grid-row {
  display: flex;
  flex-wrap: wrap;
  margin-right: -($grid-gutter / 2);
  margin-left: -($grid-gutter / 2);
}

%grid-col {
  position: relative;
  width: 100%;
  padding-right: $grid-gutter / 2;
  padding-left: $grid-gutter / 2;
}

@for $i from 1 through $grid-columns {
  %col-#{$i} {
    flex: 0 0 percentage($i / $grid-columns);
    max-width: percentage($i / $grid-columns);
  }
}

性能优化工具

PurgeCSS (CSS清理工具)

javascript
// purgecss.config.js
module.exports = {
  content: [
    './src/**/*.html',
    './src/**/*.js',
    './src/**/*.jsx', 
    './src/**/*.ts',
    './src/**/*.tsx',
    './src/**/*.vue',
    './src/**/*.svelte'
  ],
  css: [
    './dist/css/main.css'
  ],
  extractors: [
    {
      extractor: content => {
        // 自定义提取器
        return content.match(/[\w-/:]+(?<!:)/g) || [];
      },
      extensions: ['html', 'js', 'jsx', 'ts', 'tsx', 'vue', 'svelte']
    }
  ],
  variables: true,
  safelist: [
    // 保持某些类不被删除
    'active',
    'show',
    'hide',
    /^alert-/,
    /^btn-/,
    /^col-/
  ]
};

代码分析工具

json
// .stylelintignore
# 忽略特定文件
dist/
node_modules/
vendor/
*.min.css
javascript
// 分析CSS复杂度的工具配置
// package.json
{
  "scripts": {
    "analyze:css": "css-analyzer dist/css/main.css",
    "bundle-size": "webpack-bundle-analyzer --mode static dist/stats.json",
    "lint:css": "stylelint 'src/**/*.scss'",
    "format:css": "prettier --write 'src/**/*.scss'"
  }
}

学习资源

官方文档和教程

markdown
## 官方资源
- [Sass官网](https://sass-lang.com/)
- [Sass指南](https://sass-lang.com/guide)
- [Sass文档](https://sass-lang.com/documentation)

## 学习平台
- [Sass Bites](https://sassbites.com/) - Sass教程
- [CSS-Tricks Sass指南](https://css-tricks.com/snippets/sass/)
- [Scotch.io Sass教程](https://scotch.io/tutorials/getting-started-with-sass)

## 社区资源
- [Sass Guidelines](https://sass-guidelin.es/) - Sass最佳实践
- [Hugo Giraudel的Sass资源](https://hugogiraudel.com/)
- [Sass Summit](https://sasssummit.com/) - Sass会议资源

代码规范和样式指南

scss
// .scss-lint.yml 或 .stylelintignore
# 推荐的Sass代码规范
# 基于Sass Guidelines (https://sass-guidelin.es/)

# 变量命名规范
# 使用连字符分隔,语义化命名
$primary-color: #007bff;
$border-radius-sm: 2px;

# 混合宏命名规范
# 动词开头,描述性命名
@mixin center-element { }
@mixin responsive-grid { }

# 选择器命名规范
# BEM方法论或类似规范
.component { }
.component__element { }
.component--modifier { }

这些工具和资源将帮助您更高效地使用Sass,提高代码质量和开发效率。