sass-best-practices

Sass (indented syntax) best practices and coding guidelines for clean, maintainable stylesheets

INSTALLATION
npx skills add https://github.com/mindrally/skills --skill sass-best-practices
Run in your project or agent environment. Adjust flags if your CLI version differs.

SKILL.md

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
BrowserAct

Let your agent run on any real-world website

Bypass CAPTCHA & anti-bot for free. Start local, scale to cloud.

Explore BrowserAct Skills →

Stop writing automation&scrapers

Install the CLI. Run your first Skill in 30 seconds. Scale when you're ready.

Start free
free · no credit card