sass-best-practices

📁 mindrally/skills 📅 Jan 25, 2026
40
总安装量
40
周安装量
#5170
全站排名
安装命令
npx skills add https://github.com/mindrally/skills --skill sass-best-practices

Agent 安装分布

claude-code 31
opencode 29
gemini-cli 28
codex 27
github-copilot 23
amp 18

Skill 文档

Sass Best Practices

You are an expert in Sass (the indented syntax), CSS architecture, and maintainable stylesheet development.

Key Principles

  • Write clean, readable Sass using the indented syntax (whitespace-sensitive)
  • Leverage Sass features to create DRY, modular stylesheets
  • Maintain consistent indentation as it defines code structure
  • Prioritize simplicity and clarity in style organization

Sass vs SCSS

Sass uses the original indented syntax:

  • No curly braces {}
  • No semicolons ;
  • Indentation defines nesting
  • File extension: .sass
// Sass (indented syntax)
.button
  display: inline-flex
  padding: 8px 16px
  background: #3498db

  &:hover
    background: darken(#3498db, 10%)
// SCSS syntax (for comparison)
.button {
  display: inline-flex;
  padding: 8px 16px;
  background: #3498db;

  &:hover {
    background: darken(#3498db, 10%);
  }
}

File Organization

Project Structure

sass/
├── abstracts/
│   ├── _variables.sass
│   ├── _functions.sass
│   ├── _mixins.sass
│   └── _placeholders.sass
├── base/
│   ├── _reset.sass
│   ├── _typography.sass
│   └── _base.sass
├── components/
│   ├── _buttons.sass
│   ├── _cards.sass
│   └── _forms.sass
├── layout/
│   ├── _header.sass
│   ├── _footer.sass
│   └── _grid.sass
├── pages/
│   └── _home.sass
├── themes/
│   └── _default.sass
├── vendors/
│   └── _normalize.sass
└── main.sass

Main Manifest

// main.sass
@use 'abstracts/variables'
@use 'abstracts/functions'
@use 'abstracts/mixins'
@use 'abstracts/placeholders'

@use 'vendors/normalize'

@use 'base/reset'
@use 'base/typography'
@use 'base/base'

@use 'layout/grid'
@use 'layout/header'
@use 'layout/footer'

@use 'components/buttons'
@use 'components/cards'
@use 'components/forms'

@use 'pages/home'

@use 'themes/default'

Variables

Naming and Organization

// _variables.sass

// Colors
$color-primary: #3498db
$color-primary-light: lighten($color-primary, 15%)
$color-primary-dark: darken($color-primary, 15%)
$color-secondary: #2ecc71
$color-text: #333333
$color-text-muted: #666666
$color-background: #ffffff
$color-border: #e0e0e0
$color-error: #e74c3c
$color-success: #27ae60
$color-warning: #f39c12

// Typography
$font-family-base: 'Helvetica Neue', Arial, sans-serif
$font-family-heading: 'Georgia', serif
$font-size-base: 1rem
$font-size-small: 0.875rem
$font-size-large: 1.25rem
$font-weight-normal: 400
$font-weight-bold: 700
$line-height-base: 1.5

// Spacing Scale
$spacing-unit: 8px
$spacing-xs: $spacing-unit * 0.5
$spacing-sm: $spacing-unit
$spacing-md: $spacing-unit * 2
$spacing-lg: $spacing-unit * 3
$spacing-xl: $spacing-unit * 4
$spacing-xxl: $spacing-unit * 6

// Breakpoints
$breakpoint-sm: 576px
$breakpoint-md: 768px
$breakpoint-lg: 992px
$breakpoint-xl: 1200px

// Z-index Scale
$z-index-dropdown: 1000
$z-index-sticky: 1020
$z-index-fixed: 1030
$z-index-modal: 1050
$z-index-tooltip: 1070

// Transitions
$transition-base: 0.3s ease
$transition-fast: 0.15s ease
$transition-slow: 0.5s ease

// Border Radius
$border-radius-sm: 2px
$border-radius-md: 4px
$border-radius-lg: 8px
$border-radius-pill: 50px

// Shadows
$shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05)
$shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1)
$shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1)

Using Maps

// Define maps for grouped values
$colors: ("primary": #3498db, "secondary": #2ecc71, "danger": #e74c3c, "warning": #f39c12, "success": #27ae60)

$breakpoints: ("sm": 576px, "md": 768px, "lg": 992px, "xl": 1200px)

// Access values
.element
  color: map-get($colors, "primary")

Mixins

Responsive Design

// _mixins.sass

=respond-to($breakpoint)
  @if map-has-key($breakpoints, $breakpoint)
    @media (min-width: map-get($breakpoints, $breakpoint))
      @content
  @else
    @warn "Unknown breakpoint: #{$breakpoint}"

// Usage
.element
  width: 100%

  +respond-to("md")
    width: 50%

  +respond-to("lg")
    width: 33.333%

Flexbox Utilities

=flex-center
  display: flex
  align-items: center
  justify-content: center

=flex-between
  display: flex
  align-items: center
  justify-content: space-between

=flex-column
  display: flex
  flex-direction: column

// Usage
.container
  +flex-center
  min-height: 100vh

Typography

=font-size($size, $line-height: null)
  font-size: $size
  @if $line-height
    line-height: $line-height

=truncate($lines: 1)
  @if $lines == 1
    white-space: nowrap
    overflow: hidden
    text-overflow: ellipsis
  @else
    display: -webkit-box
    -webkit-line-clamp: $lines
    -webkit-box-orient: vertical
    overflow: hidden

// Usage
.title
  +font-size(2rem, 1.2)

.description
  +truncate(3)

Accessibility

=visually-hidden
  position: absolute
  width: 1px
  height: 1px
  padding: 0
  margin: -1px
  overflow: hidden
  clip: rect(0, 0, 0, 0)
  white-space: nowrap
  border: 0

=focus-visible
  &:focus-visible
    outline: 2px solid $color-primary
    outline-offset: 2px

// Usage
.sr-only
  +visually-hidden

.interactive
  +focus-visible

Button Styles

=button-base
  display: inline-flex
  align-items: center
  justify-content: center
  padding: $spacing-sm $spacing-md
  border: none
  border-radius: $border-radius-md
  font-family: inherit
  font-size: $font-size-base
  font-weight: $font-weight-bold
  text-decoration: none
  cursor: pointer
  transition: all $transition-base

  &:disabled
    opacity: 0.5
    cursor: not-allowed

=button-variant($bg-color, $text-color: white)
  +button-base
  background: $bg-color
  color: $text-color

  &:hover:not(:disabled)
    background: darken($bg-color, 10%)

  &:active:not(:disabled)
    background: darken($bg-color, 15%)

// Usage
.btn-primary
  +button-variant($color-primary)

.btn-secondary
  +button-variant($color-secondary)

.btn-danger
  +button-variant($color-error)

BEM Naming Convention

// Block
.card
  background: $color-background
  border-radius: $border-radius-md
  box-shadow: $shadow-md

  // Element
  &__header
    padding: $spacing-md
    border-bottom: 1px solid $color-border

  &__title
    margin: 0
    font-size: $font-size-large
    font-weight: $font-weight-bold

  &__body
    padding: $spacing-md

  &__footer
    padding: $spacing-md
    border-top: 1px solid $color-border

  // Modifier
  &--featured
    border: 2px solid $color-primary

  &--compact
    .card__header,
    .card__body,
    .card__footer
      padding: $spacing-sm

Nesting Guidelines

Keep Nesting Shallow

// BAD: Too deep
.nav
  .nav-list
    .nav-item
      .nav-link
        .nav-icon
          // 5 levels - avoid this

// GOOD: Flat BEM structure
.nav
  display: flex

.nav__list
  display: flex
  list-style: none
  margin: 0
  padding: 0

.nav__item
  margin: 0 $spacing-sm

.nav__link
  color: $color-text
  text-decoration: none

  &:hover,
  &:focus
    color: $color-primary

  &--active
    color: $color-primary
    font-weight: $font-weight-bold

Acceptable Nesting

.component
  // Pseudo-elements
  &::before,
  &::after
    content: ''

  // States
  &:hover,
  &:focus,
  &:active
    // State styles

  // Modifiers
  &--variant
    // Modifier styles

  // Media queries
  +respond-to("md")
    // Responsive styles

Functions

// _functions.sass

// Color functions
@function tint($color, $percentage)
  @return mix(white, $color, $percentage)

@function shade($color, $percentage)
  @return mix(black, $color, $percentage)

// Unit conversion
@function px-to-rem($px, $base: 16)
  @return ($px / $base) * 1rem

@function rem-to-px($rem, $base: 16)
  @return ($rem / 1rem) * $base * 1px

// Spacing helper
@function spacing($multiplier)
  @return $spacing-unit * $multiplier

// Usage
.element
  background: tint($color-primary, 20%)
  border-color: shade($color-primary, 10%)
  font-size: px-to-rem(18)
  padding: spacing(3)

Placeholders and Extend

// Define placeholders
%clearfix
  &::after
    content: ''
    display: table
    clear: both

%list-reset
  list-style: none
  margin: 0
  padding: 0

%button-reset
  appearance: none
  background: none
  border: none
  padding: 0
  font: inherit
  cursor: pointer

// Usage
.container
  @extend %clearfix

.nav-list
  @extend %list-reset

.icon-button
  @extend %button-reset

Loops and Iteration

Generate Utility Classes

// Spacing utilities
$directions: ("": "", "t": "-top", "r": "-right", "b": "-bottom", "l": "-left")

@each $abbr, $dir in $directions
  @for $i from 0 through 8
    .m#{$abbr}-#{$i}
      margin#{$dir}: spacing($i)
    .p#{$abbr}-#{$i}
      padding#{$dir}: spacing($i)

// Color utilities
@each $name, $color in $colors
  .text-#{$name}
    color: $color
  .bg-#{$name}
    background-color: $color

Grid Generation

$grid-columns: 12

@for $i from 1 through $grid-columns
  .col-#{$i}
    width: percentage($i / $grid-columns)

// Responsive columns
@each $bp, $width in $breakpoints
  @media (min-width: $width)
    @for $i from 1 through $grid-columns
      .col-#{$bp}-#{$i}
        width: percentage($i / $grid-columns)

Conditionals

=theme-button($variant)
  @if $variant == "primary"
    background: $color-primary
    color: white
  @else if $variant == "secondary"
    background: transparent
    color: $color-primary
    border: 2px solid $color-primary
  @else if $variant == "danger"
    background: $color-error
    color: white
  @else
    background: $color-text-muted
    color: white

.btn-primary
  +theme-button("primary")

.btn-secondary
  +theme-button("secondary")

Modern Module System

Using @use and @forward

// _variables.sass
$primary: #3498db

// _mixins.sass
@use 'variables' as vars

=themed-element
  color: vars.$primary

// _index.sass (barrel file)
@forward 'variables'
@forward 'mixins'

// main.sass
@use 'abstracts'

.element
  +abstracts.themed-element

Performance Tips

  • Keep selector specificity low (prefer single class selectors)
  • Avoid !important except for utility overrides
  • Use @use instead of deprecated @import
  • Limit @extend usage across files
  • Compile without source maps in production
  • Let autoprefixer handle vendor prefixes

Code Style Guidelines

  • Use 2 spaces for indentation (critical in Sass)
  • Use single quotes for strings
  • One blank line between rule sets
  • Group related properties together
  • Comment non-obvious code
  • Use meaningful variable names
  • Keep lines under 80 characters when possible

Property Order

.element
  // Positioning
  position: relative
  top: 0
  right: 0
  z-index: 10

  // Display & Box Model
  display: flex
  width: 100%
  padding: $spacing-md
  margin: $spacing-sm 0

  // Typography
  font-family: $font-family-base
  font-size: $font-size-base
  line-height: $line-height-base
  color: $color-text

  // Visual
  background: $color-background
  border: 1px solid $color-border
  border-radius: $border-radius-md
  box-shadow: $shadow-sm

  // Animation
  transition: all $transition-base

  // Misc
  cursor: pointer