SCSS Mixins & Functions

SCSS Mixins & Functions

Reusable Sass helpers with code definitions, usage examples, and live previews

Bootstrap's most-used responsive mixin. It keeps breakpoints centralized and makes large component SCSS much easier to scan.

@mixin media-breakpoint-up($name, $breakpoints: $grid-breakpoints) {
  $min: breakpoint-min($name, $breakpoints);

  @if $min {
    @media (min-width: $min) {
      @content;
    }
  } @else {
    @content;
  }
}

// Usage
.card-grid {
  display: grid;
  gap: 16px;
  grid-template-columns: 1fr;

  @include media-breakpoint-up(lg) {
    grid-template-columns: repeat(3, 1fr);
  }
}
@mixin media-breakpoint-up($name, $breakpoints: $grid-breakpoints)
  $min: breakpoint-min($name, $breakpoints)

  @if $min
    @media (min-width: $min)
      @content
  @else
    @content

// Usage
.card-grid
  display: grid
  gap: 16px
  grid-template-columns: 1fr

  +media-breakpoint-up(lg)
    grid-template-columns: repeat(3, 1fr)
// Equivalent output
.card-grid {
  display: grid;
  gap: 16px;
  grid-template-columns: 1fr;
}

@media (min-width: 992px) {
  .card-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

Useful when a layout needs a tablet-only correction without affecting small or large screens.

@mixin media-breakpoint-between($lower, $upper, $breakpoints: $grid-breakpoints) {
  $min: breakpoint-min($lower, $breakpoints);
  $max: breakpoint-max($upper, $breakpoints);

  @media (min-width: $min) and (max-width: $max) {
    @content;
  }
}

// Usage
.toolbar {
  @include media-breakpoint-between(md, lg) {
    gap: 8px;
    flex-wrap: wrap;
  }
}
@mixin media-breakpoint-between($lower, $upper, $breakpoints: $grid-breakpoints)
  $min: breakpoint-min($lower, $breakpoints)
  $max: breakpoint-max($upper, $breakpoints)

  @media (min-width: $min) and (max-width: $max)
    @content

// Usage
.toolbar
  +media-breakpoint-between(md, lg)
    gap: 8px
    flex-wrap: wrap
@media (min-width: 768px) and (max-width: 991.98px) {
  .toolbar {
    gap: 8px;
    flex-wrap: wrap;
  }
}

Paired with make-row() and make-col-ready(), this is the quickest way to create custom grid primitives on top of Bootstrap's system.

@mixin make-col($size: false, $columns: $grid-columns) {
  @if $size {
    flex: 0 0 auto;
    width: percentage(divide($size, $columns));
  } @else {
    flex: 1 1 0;
    max-width: 100%;
  }
}

// Usage
.feature-row {
  @include make-row();
}

.feature-card {
  @include make-col-ready();
  @include make-col(6);

  @include media-breakpoint-up(xl) {
    @include make-col(3);
  }
}
@mixin make-col($size: false, $columns: $grid-columns)
  @if $size
    flex: 0 0 auto
    width: percentage(divide($size, $columns))
  @else
    flex: 1 1 0
    max-width: 100%

// Usage
.feature-row
  +make-row()

.feature-card
  +make-col-ready()
  +make-col(6)

  +media-breakpoint-up(xl)
    +make-col(3)
.feature-row {
  display: flex;
  flex-wrap: wrap;
  margin-inline: -12px;
}

.feature-card {
  width: 50%;
  padding-inline: 12px;
}

@media (min-width: 1200px) {
  .feature-card {
    width: 25%;
  }
}
6/12
6/12
3/12
3/12

One of the few accessibility helpers every component library should keep around.

@mixin visually-hidden() {
  width: 1px !important;
  height: 1px !important;
  padding: 0 !important;
  margin: -1px !important;
  overflow: hidden !important;
  clip: rect(0, 0, 0, 0) !important;
  white-space: nowrap !important;
  border: 0 !important;
}

// Usage
.icon-button__label {
  @include visually-hidden();
}
@mixin visually-hidden()
  width: 1px !important
  height: 1px !important
  padding: 0 !important
  margin: -1px !important
  overflow: hidden !important
  clip: rect(0, 0, 0, 0) !important
  white-space: nowrap !important
  border: 0 !important

// Usage
.icon-button__label
  +visually-hidden()
.icon-button__label {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

Screen-reader label stays accessible while the visible UI remains icon-only.

A practical utility when you need a badge, dot, handle, or overlay element pinned to the real visual center.

@mixin centerer($horizontal: true, $vertical: true) {
  position: absolute;

  @if ($horizontal and $vertical) {
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
  }
}

// Usage
.badge-dot {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: $accent;

  @include centerer;
}
@mixin centerer($horizontal: true, $vertical: true)
  position: absolute

  @if ($horizontal and $vertical)
    top: 50%
    left: 50%
    transform: translate(-50%, -50%)

// Usage
.badge-dot
  width: 18px
  height: 18px
  border-radius: 50%
  background: $accent
  +centerer
.badge-dot {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

Good for decorative hero words, poster typography, and labels where fill should remain transparent.

@mixin text-outline($color: black, $stroke: 1px) {
  color: transparent;
  -webkit-text-stroke-width: $stroke;
  -webkit-text-stroke-color: $color;
}

// Usage
.hero-word {
  font-size: 72px;
  font-weight: 700;

  @include text-outline(#111827, 1.5px);
}
@mixin text-outline($color: black, $stroke: 1px)
  color: transparent
  -webkit-text-stroke-width: $stroke
  -webkit-text-stroke-color: $color

// Usage
.hero-word
  font-size: 72px
  font-weight: 700
  +text-outline(#111827, 1.5px)
.hero-word {
  font-size: 72px;
  font-weight: 700;
  color: transparent;
  -webkit-text-stroke: 1.5px #111827;
}
STROKE

Useful for loader bars, progress states, skeleton accents, or any surface that needs motion without images.

@mixin stripes($opacity, $color, $size: 25px, $deg: -135deg) {
  background-size: $size $size;
  background-image: linear-gradient($deg, rgba($color, $opacity) 25%, transparent 25%, transparent 50%, rgba($color, $opacity) 50%, rgba($color, $opacity) 75%, transparent 75%, transparent);
}

// Usage
.loader-track {
  @include stripes(.22, #2563eb, 20px, -45deg);
}
@mixin stripes($opacity, $color, $size: 25px, $deg: -135deg)
  background-size: $size $size
  background-image: linear-gradient($deg, rgba($color, $opacity) 25%, transparent 25%, transparent 50%, rgba($color, $opacity) 50%, rgba($color, $opacity) 75%, transparent 75%, transparent)

// Usage
.loader-track
  +stripes(.22, #2563eb, 20px, -45deg)
.loader-track {
  background-size: 20px 20px;
  background-image: linear-gradient(
    -45deg,
    rgba(37, 99, 235, .22) 25%,
    transparent 25%,
    transparent 50%,
    rgba(37, 99, 235, .22) 50%,
    rgba(37, 99, 235, .22) 75%,
    transparent 75%,
    transparent
  );
}

One of your stronger custom helpers. The masking approach makes it especially useful for premium cards and callouts.

@mixin border-gradient($color1: #fff, $color2: #fff, $deg: 45deg, $border: 1px) {
  background: linear-gradient($deg, $color1, $color2) border-box;
  -webkit-mask: linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  border: $border solid transparent;
}

// Usage
.promo-card {
  border-radius: 16px;
  @include border-gradient(#22c55e, #0ea5e9, 135deg, 1px);
}
@mixin border-gradient($color1: #fff, $color2: #fff, $deg: 45deg, $border: 1px)
  background: linear-gradient($deg, $color1, $color2) border-box
  -webkit-mask: linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0)
  -webkit-mask-composite: xor
  mask-composite: exclude
  border: $border solid transparent

// Usage
.promo-card
  border-radius: 16px
  +border-gradient(#22c55e, #0ea5e9, 135deg, 1px)
.promo-card {
  border: 1px solid transparent;
  border-radius: 16px;
  background:
    linear-gradient(135deg, #22c55e, #0ea5e9) border-box;
  -webkit-mask:
    linear-gradient(#fff 0 0) padding-box,
    linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
}
Premium card border

This is one of the most reusable helpers you already have. It should sit near the top of any internal Sass library.

Generate a custom version with all required parameters in Clamp Generator

@function to-clamp($min-size, $max-size, $min-screen: 375px, $max-screen: 1920px) {
  $min-size-rem: math.div($min-size, 16px) * 1rem;
  $max-size-rem: math.div($max-size, 16px) * 1rem;
  $vw-coefficient: math.div($max-size - $min-size, $max-screen - $min-screen) * 100vw;
  @return clamp(#{$min-size-rem}, calc(#{$min-size-rem} + #{$vw-coefficient}), #{$max-size-rem});
}

// Usage
.headline {
  font-size: to-clamp(28px, 72px);
  margin-bottom: to-rem(24px);
}
@function to-clamp($min-size, $max-size, $min-screen: 375px, $max-screen: 1920px)
  $min-size-rem: math.div($min-size, 16px) * 1rem
  $max-size-rem: math.div($max-size, 16px) * 1rem
  $vw-coefficient: math.div($max-size - $min-size, $max-screen - $min-screen) * 100vw
  @return clamp(#{$min-size-rem}, calc(#{$min-size-rem} + #{$vw-coefficient}), #{$max-size-rem})

// Usage
.headline
  font-size: to-clamp(28px, 72px)
  margin-bottom: to-rem(24px)
.headline {
  font-size: clamp(1.75rem, calc(1.75rem + 2.84vw), 4.5rem);
  margin-bottom: 1.5rem;
}
Fluid headline

A reusable slider mixin that centralizes track, thumb, hover, focus, and disabled styling while letting each product area tune colors and dimensions.

@mixin c-range-styles(
  $track-height: 4px,
  $track-color: $dark-200,
  $thumb-size: 14px,
  $thumb-color: $primary,
  $thumb-border-width: 0,
  $thumb-border-color: transparent,
  $thumb-shadow: none,
  $hover-scale: 1.15,
  $focus-shadow: 0 2px 6px rgba(0, 0, 0, 0.18)
) {
  appearance: none;
  background: transparent;
  cursor: pointer;

  &::-webkit-slider-runnable-track {
    height: $track-height;
    background: $track-color;
    border-radius: 999px;
  }

  &::-webkit-slider-thumb {
    appearance: none;
    width: $thumb-size;
    height: $thumb-size;
    margin-top: math.div($track-height - $thumb-size, 2);
    border-radius: 50%;
    background: $thumb-color;
    border: $thumb-border-width solid $thumb-border-color;
    box-shadow: $thumb-shadow;
  }
}

// Usage
.c-range {
  @include c-range-styles(
    $track-height: 6px,
    $track-color: #dbe3ef,
    $thumb-size: 18px,
    $thumb-color: #111827
  );
}
@mixin c-range-styles(
  $track-height: 4px,
  $track-color: $dark-200,
  $thumb-size: 14px,
  $thumb-color: $primary,
  $thumb-border-width: 0,
  $thumb-border-color: transparent,
  $thumb-shadow: none,
  $hover-scale: 1.15,
  $focus-shadow: 0 2px 6px rgba(0, 0, 0, 0.18)
)
  appearance: none
  background: transparent
  cursor: pointer

  &::-webkit-slider-runnable-track
    height: $track-height
    background: $track-color
    border-radius: 999px

  &::-webkit-slider-thumb
    appearance: none
    width: $thumb-size
    height: $thumb-size
    margin-top: math.div($track-height - $thumb-size, 2)
    border-radius: 50%
    background: $thumb-color
    border: $thumb-border-width solid $thumb-border-color
    box-shadow: $thumb-shadow

// Usage
.c-range
  +c-range-styles(
    $track-height: 6px,
    $track-color: #dbe3ef,
    $thumb-size: 18px,
    $thumb-color: #111827
  )
.c-range {
  appearance: none;
  background: transparent;
}

.c-range::-webkit-slider-runnable-track {
  height: 6px;
  border-radius: 999px;
  background: #dbe3ef;
}

.c-range::-webkit-slider-thumb {
  width: 18px;
  height: 18px;
  margin-top: -6px;
  border-radius: 50%;
  background: #111827;
}

Use one mixin to define cross-axis and main-axis positioning together instead of scattering alignment declarations through components.

@mixin flex-align($align: center, $justify: center) {
  align-items: $align;
  justify-content: $justify;
}
// $align: flex-start | center | flex-end | stretch | baseline
// $justify: flex-start | center | flex-end | space-between | space-around | space-evenly

// Usage
.toolbar {
  display: flex;
  @include flex-align(center, space-between);
}
@mixin flex-align($align: center, $justify: center)
  align-items: $align
  justify-content: $justify
// $align: flex-start | center | flex-end | stretch | baseline
// $justify: flex-start | center | flex-end | space-between | space-around | space-evenly

// Usage
.toolbar
  display: flex
  +flex-align(center, space-between)
.toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
Filter Sort Export Share

Useful when icon color and stroke weight need to be controlled from the parent component rather than per-icon markup.

@mixin svg($color, $width) {
  svg {
    path,
    line,
    polyline {
      stroke: $color;
      stroke-width: $width;
    }

    path {
      fill: transparent;
    }
  }
}

// Usage
.icon-wrap {
  @include svg(#111827, 1.5px);
}
@mixin svg($color, $width)
  svg
    path,
    line,
    polyline
      stroke: $color
      stroke-width: $width

    path
      fill: transparent

// Usage
.icon-wrap
  +svg(#111827, 1.5px)
.icon-wrap svg path,
.icon-wrap svg line,
.icon-wrap svg polyline {
  stroke: #111827;
  stroke-width: 1.5px;
}

A practical asset helper for projects that still ship raster backgrounds in multiple resolutions.

@mixin background-image($img, $type: png, $x: 0, $y: 0, $repeat: no-repeat) {
  background-image: url("../images/#{$img}.#{$type}");
  background-image: image-set(
    url("../images/#{$img}.#{$type}") 1x,
    url("../images/#{$img}@2x.#{$type}") 2x,
    url("../images/#{$img}@3x.#{$type}") 3x
  );
  background-repeat: #{$repeat};
  background-position: #{$x}px #{$y}px;
}

// Usage
.hero {
  @include background-image("noise", png, 0, 0, repeat);
}
@mixin background-image($img, $type: png, $x: 0, $y: 0, $repeat: no-repeat)
  background-image: url("../images/#{$img}.#{$type}")
  background-image: image-set(url("../images/#{$img}.#{$type}") 1x, url("../images/#{$img}@2x.#{$type}") 2x, url("../images/#{$img}@3x.#{$type}") 3x)
  background-repeat: #{$repeat}
  background-position: #{$x}px #{$y}px

// Usage
.hero
  +background-image("noise", png, 0, 0, repeat)
.hero {
  background-image: url("../images/noise.png");
  background-repeat: repeat;
  background-position: 0 0;
}
Retina-ready background surface

Still useful when you want to keep vendor placeholder selectors out of form components.

@mixin placeholder {
  &::-webkit-input-placeholder { @content; }
  &:-moz-placeholder { @content; }
  &::-moz-placeholder { @content; }
  &:-ms-input-placeholder { @content; }
}

// Usage
.input {
  @include placeholder {
    color: rgba($text, .45);
  }
}
@mixin placeholder
  &::-webkit-input-placeholder
    @content
  &:-moz-placeholder
    @content
  &::-moz-placeholder
    @content
  &:-ms-input-placeholder
    @content

// Usage
.input
  +placeholder
    color: rgba($text, .45)
.input::placeholder {
  color: rgba(17, 24, 39, .45);
}

Useful for utility animation stacks when you want to pass several animation fragments as arguments.

@mixin anim($animate...) {
  $max: length($animate);
  $animations: "";
  @for $i from 1 through $max {
    $animations: #{$animations + nth($animate, $i)};
  }
  animation: $animations;
}

// Usage
.pulse-chip {
  @include anim(fade-in .25s ease, float 2s linear infinite);
}
@mixin anim($animate...)
  $max: length($animate)
  $animations: ""
  @for $i from 1 through $max
    $animations: #{$animations + nth($animate, $i)}
  animation: $animations

// Usage
.pulse-chip
  +anim(fade-in .25s ease, float 2s linear infinite)
.pulse-chip {
  animation: fade-in .25s ease, float 2s linear infinite;
}
Live status

Useful when a plain linear border feels too flat and you want corner-focused glow treatment.

@mixin border-radial-gradient($color1: #fff, $color2: #fff, $percent: 25%) {
  background: radial-gradient(circle at 0% 0%, $color1 0%, $color2 $percent) border-box, radial-gradient(circle at 100% 100%, $color1 0%, $color2 $percent) border-box;
  -webkit-mask: linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  border: 1px solid transparent;
}

@mixin border-radial-gradient-x2($color1: #fff, $color2: #fff, $percent: 25%) {
  background: radial-gradient(circle at 0% 0%, $color1 0%, $color2 $percent) border-box, radial-gradient(circle at 100% 0%, $color1 0%, $color2 $percent) border-box, radial-gradient(circle at 0% 100%, $color1 0%, $color2 $percent) border-box, radial-gradient(circle at 100% 100%, $color1 0%, $color2 $percent) border-box;
  border: 1px solid transparent;
}

// Usage
.panel {
  @include border-radial-gradient-x2(#7c3aed, #06b6d4, 32%);
}
@mixin border-radial-gradient($color1: #fff, $color2: #fff, $percent: 25%)
  background: radial-gradient(circle at 0% 0%, $color1 0%, $color2 $percent) border-box, radial-gradient(circle at 100% 100%, $color1 0%, $color2 $percent) border-box
  -webkit-mask: linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0)
  -webkit-mask-composite: xor
  border: 1px solid transparent

@mixin border-radial-gradient-x2($color1: #fff, $color2: #fff, $percent: 25%)
  background: radial-gradient(circle at 0% 0%, $color1 0%, $color2 $percent) border-box, radial-gradient(circle at 100% 0%, $color1 0%, $color2 $percent) border-box, radial-gradient(circle at 0% 100%, $color1 0%, $color2 $percent) border-box, radial-gradient(circle at 100% 100%, $color1 0%, $color2 $percent) border-box
  border: 1px solid transparent

// Usage
.panel
  +border-radial-gradient-x2(#7c3aed, #06b6d4, 32%)
.panel {
  border: 1px solid transparent;
  background: radial-gradient(circle at 0% 0%, #7c3aed 0%, #06b6d4 32%) border-box;
}
Premium card border

The in-project variant already used across UI pieces; good to keep near your other reusable surface helpers.

@mixin scrollbars($size, $foreground-color, $background-color: mix($foreground-color, white, 50%)) {
  &::-webkit-scrollbar { width: $size; height: $size; }
  &::-webkit-scrollbar-thumb { background: $foreground-color; }
  &::-webkit-scrollbar-track { background: $background-color; }
}

// Usage
.panel {
  @include scrollbars(10px, #111827, #e5e7eb);
}
@mixin scrollbars($size, $foreground-color, $background-color: mix($foreground-color, white, 50%))
  &::-webkit-scrollbar
    width: $size
    height: $size
  &::-webkit-scrollbar-thumb
    background: $foreground-color
  &::-webkit-scrollbar-track
    background: $background-color

// Usage
.panel
  +scrollbars(10px, #111827, #e5e7eb)
.panel::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}

.panel::-webkit-scrollbar-thumb {
  background: #111827;
}

.panel::-webkit-scrollbar-track {
  background: #e5e7eb;
}
Reusable scrollbar styling keeps long panels readable. Reusable scrollbar styling keeps long panels readable. Reusable scrollbar styling keeps long panels readable. Reusable scrollbar styling keeps long panels readable. Reusable scrollbar styling keeps long panels readable. Reusable scrollbar styling keeps long panels readable. Reusable scrollbar styling keeps long panels readable. Reusable scrollbar styling keeps long panels readable.

The project-specific variant of font-face setup. Good for keeping one include per file family.

@mixin font($fname, $fstyle, $fweight, $furl, $fstrech: normal) {
  @font-face {
    font-family: $fname;
    font-style: $fstyle;
    font-weight: $fweight;
    font-stretch: $fstrech;
    src: url($furl) format("woff2");
    font-display: swap;
  }
}

// Usage
@include font("Manrope", normal, 500, "/fonts/manrope-500.woff2");
@mixin font($fname, $fstyle, $fweight, $furl, $fstrech: normal)
  @font-face
    font-family: $fname
    font-style: $fstyle
    font-weight: $fweight
    font-stretch: $fstrech
    src: url($furl) format("woff2")
    font-display: swap

// Usage
+font("Manrope", normal, 500, "/fonts/manrope-500.woff2")
@font-face {
  font-family: "Manrope";
  font-style: normal;
  font-weight: 500;
  src: url("/fonts/manrope-500.woff2") format("woff2");
  font-display: swap;
}
Aa
Font preview headline

Handy when you want styled numbered lists without repeating the counter boilerplate in every component.

@mixin counter($var, $sep) {
  counter-reset: list + $var;
  > li {
    &:before {
      content: counter(list + $var) $sep;
      counter-increment: list + $var;
    }
  }
}

// Usage
.steps {
  @include counter(step, ". ");
}
@mixin counter($var, $sep)
  counter-reset: list + $var
  > li
    &:before
      content: counter(list + $var) $sep
      counter-increment: list + $var

// Usage
.steps
  +counter(step, ". ")
.steps {
  counter-reset: step;
}

.steps > li::before {
  counter-increment: step;
  content: counter(step) ". ";
}
  1. Collect source files
  2. Normalize naming
  3. Export final assets

A decorative helper for dimensional headings and stylized brand text.

@mixin text3d($primary, $depth: 5, $shadowsteps: 5, $shadowincrementer: 3px, $shadowopacity: 0.4, $primaryshadowcolour: #000, $lighting: $LIGHTING_CEIL) {
  $predefinedShadows: (
    0 0 5px rgba($primaryshadowcolour, 0.05),
    0 -1px 3px rgba($primaryshadowcolour, 0.2),
    0 3px 5px rgba($primaryshadowcolour, 0.2)
  );
  $value: ();

  @for $i from 1 through $depth {
    $num: $i + px;
    $num1: $i * 1.3 + px;
    $hueadjust: $i * 0.2;

    @if ($lighting == $LIGHTING_FLOOR) {
      $hueadjust: ($i * 2 - $depth - 5) * 1%;
    } @else if ($lighting == $LIGHTING_CEIL) {
      $hueadjust: -($i * 2 + $depth - 10) * 1%;
    } @else if ($lighting == $LIGHTING_FLAT) {
      $hueadjust: -$depth * 1%;
    }

    $colour: adjust-color($primary, $lightness: $hueadjust);
    $theShadow: $num1 $num 1px $colour;
    $value: append($value, $theShadow, comma);
  }

  @for $i from 1 through $shadowsteps {
    @if ($i >= length($predefinedShadows)) {
      $dist: $i * $shadowincrementer;
      $value: append($value, 0 $dist $dist rgba($primaryshadowcolour, $shadowopacity));
    } @else {
      $value: append($value, nth($predefinedShadows, $i));
    }
  }

  text-shadow: $value;
}

// Usage
.logo-mark {
  @include text3d(#f97316, 6, 4, 3px, .18);
}
@mixin text3d($primary, $depth: 5, $shadowsteps: 5, $shadowincrementer: 3px, $shadowopacity: 0.4, $primaryshadowcolour: #000, $lighting: $LIGHTING_CEIL)
  $predefinedShadows: (0 0 5px rgba($primaryshadowcolour, 0.05), 0 -1px 3px rgba($primaryshadowcolour, 0.2), 0 3px 5px rgba($primaryshadowcolour, 0.2))
  $value: ()

  @for $i from 1 through $depth
    $num: $i + px
    $num1: $i * 1.3 + px
    $hueadjust: $i * 0.2

    @if ($lighting == $LIGHTING_FLOOR)
      $hueadjust: ($i * 2 - $depth - 5) * 1%
    @else if ($lighting == $LIGHTING_CEIL)
      $hueadjust: -($i * 2 + $depth - 10) * 1%
    @else if ($lighting == $LIGHTING_FLAT)
      $hueadjust: -$depth * 1%

    $colour: adjust-color($primary, $lightness: $hueadjust)
    $theShadow: $num1 $num 1px $colour
    $value: append($value, $theShadow, comma)

  @for $i from 1 through $shadowsteps
    @if ($i >= length($predefinedShadows))
      $dist: $i * $shadowincrementer
      $value: append($value, 0 $dist $dist rgba($primaryshadowcolour, $shadowopacity))
    @else
      $value: append($value, nth($predefinedShadows, $i))

  text-shadow: $value

// Usage
.logo-mark
  +text3d(#f97316, 6, 4, 3px, .18)
.logo-mark {
  text-shadow: 1px 1px 0 #f59e0b, 2px 2px 0 #ea580c, 0 8px 16px rgba(0,0,0,.12);
}
JINERO

The box companion to text3d(), useful for chips, buttons, and playful elevated UI blocks.

@mixin box3d($primary, $depth: 5, $shadowsteps: 5, $shadowincrementer: 3px, $shadowopacity: 0.4, $primaryshadowcolour: #000, $lighting: $LIGHTING_CEIL) {
  $predefinedShadows: (
    0 0 5px rgba($primaryshadowcolour, 0.05),
    0 -1px 3px rgba($primaryshadowcolour, 0.2),
    0 3px 5px rgba($primaryshadowcolour, 0.2)
  );
  $value: ();

  @for $i from 1 through $depth {
    $num: $i + px;
    $num1: $i * 1.5 + px;
    $hueadjust: $i * 0.2;

    @if ($lighting == $LIGHTING_FLOOR) {
      $hueadjust: ($i * 2 - $depth - 5) * 1%;
    } @else if ($lighting == $LIGHTING_CEIL) {
      $hueadjust: -($i * 2 + $depth - 10) * 1%;
    } @else if ($lighting == $LIGHTING_FLAT) {
      $hueadjust: -$depth * 1%;
    }

    $colour: adjust-color($primary, $lightness: $hueadjust);
    $theShadow: $num1 $num 1px $colour;
    $value: append($value, $theShadow, comma);
  }

  @for $i from 1 through $shadowsteps {
    @if ($i >= length($predefinedShadows)) {
      $dist: $i * $shadowincrementer;
      $value: append($value, 0 $dist $dist rgba($primaryshadowcolour, $shadowopacity));
    } @else {
      $value: append($value, nth($predefinedShadows, $i));
    }
  }

  box-shadow: $value;
}

// Usage
.chip {
  @include box3d(#8b5cf6, 5, 3, 3px, .16);
}
@mixin box3d($primary, $depth: 5, $shadowsteps: 5, $shadowincrementer: 3px, $shadowopacity: 0.4, $primaryshadowcolour: #000, $lighting: $LIGHTING_CEIL)
  $predefinedShadows: (0 0 5px rgba($primaryshadowcolour, 0.05), 0 -1px 3px rgba($primaryshadowcolour, 0.2), 0 3px 5px rgba($primaryshadowcolour, 0.2))
  $value: ()

  @for $i from 1 through $depth
    $num: $i + px
    $num1: $i * 1.5 + px
    $hueadjust: $i * 0.2

    @if ($lighting == $LIGHTING_FLOOR)
      $hueadjust: ($i * 2 - $depth - 5) * 1%
    @else if ($lighting == $LIGHTING_CEIL)
      $hueadjust: -($i * 2 + $depth - 10) * 1%
    @else if ($lighting == $LIGHTING_FLAT)
      $hueadjust: -$depth * 1%

    $colour: adjust-color($primary, $lightness: $hueadjust)
    $theShadow: $num1 $num 1px $colour
    $value: append($value, $theShadow, comma)

  @for $i from 1 through $shadowsteps
    @if ($i >= length($predefinedShadows))
      $dist: $i * $shadowincrementer
      $value: append($value, 0 $dist $dist rgba($primaryshadowcolour, $shadowopacity))
    @else
      $value: append($value, nth($predefinedShadows, $i))

  box-shadow: $value

// Usage
.chip
  +box3d(#8b5cf6, 5, 3, 3px, .16)
.chip {
  box-shadow: 1px 1px 0 #a78bfa, 2px 2px 0 #8b5cf6, 0 10px 18px rgba(0,0,0,.12);
}
Depth chip

Tiny, but worth documenting because it becomes part of the design-system language.

@function to-rem($pixels) {
  @return math.div($pixels, 16px) * 1rem;
}

// Usage
.card {
  padding: to-rem(24px);
}
@function to-rem($pixels)
  @return math.div($pixels, 16px) * 1rem

// Usage
.card
  padding: to-rem(24px)
.card {
  padding: 1.5rem;
}
Fluid headline

Useful when you want responsive spacing or sizing across a viewport range without writing the calc() formula for every property.

@function stripUnit($value) {
  @return $value / ($value * 0 + 1);
}

@mixin fluid(
  $min-value,
  $max-value,
  $min-vw,
  $max-vw,
  $properties...
) {
  @each $property in $properties {
    #{$property}: $min-value;
  }

  @media only screen and (min-width: #{$min-vw}) {
    @each $property in $properties {
      #{$property}: calc(#{$min-value} + #{stripUnit($max-value - $min-value)} * (100vw - #{$min-vw}) / #{stripUnit($max-vw - $min-vw)});
    }
  }

  @media only screen and (min-width: #{$max-vw}) {
    @each $property in $properties {
      #{$property}: $max-value;
    }
  }
}

// Usage
.example {
  @include fluid(20px, 40px, 320px, 1200px, padding-top, margin-bottom);
}
@function stripUnit($value)
  @return $value / ($value * 0 + 1)

@mixin fluid(
  $min-value,
  $max-value,
  $min-vw,
  $max-vw,
  $properties...
)
  @each $property in $properties
    #{$property}: $min-value

  @media only screen and (min-width: #{$min-vw})
    @each $property in $properties
      #{$property}: calc(#{$min-value} + #{stripUnit($max-value - $min-value)} * (100vw - #{$min-vw}) / #{stripUnit($max-vw - $min-vw)})

  @media only screen and (min-width: #{$max-vw})
    @each $property in $properties
      #{$property}: $max-value

// Usage
.example
  +fluid(20px, 40px, 320px, 1200px, padding-top, margin-bottom)
.example {
  padding-top: 20px;
  margin-bottom: 20px;
}

@media only screen and (min-width: 320px) {
  .example {
    padding-top: calc(20px + 20 * (100vw - 320px) / 880);
    margin-bottom: calc(20px + 20 * (100vw - 320px) / 880);
  }
}

@media only screen and (min-width: 1200px) {
  .example {
    padding-top: 40px;
    margin-bottom: 40px;
  }
}
Fluid spacing preview

Still one of the most copied micro-mixins in component libraries and dashboards.

@mixin ellipsis($width: 100%) {
  display: inline-block;
  max-width: $width;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

// Usage
.card-title {
  @include ellipsis(240px);
}
@mixin ellipsis($width: 100%)
  display: inline-block
  max-width: $width
  overflow: hidden
  text-overflow: ellipsis
  white-space: nowrap

// Usage
.card-title
  +ellipsis(240px)
.card-title {
  display: inline-block;
  max-width: 240px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
This is a very long card title that should truncate neatly with an ellipsis

A common utility pattern because custom scrollbar selectors are noisy and repeated across apps.

@mixin scrollbars($size, $thumb, $track: rgba($thumb, .2)) {
  &::-webkit-scrollbar {
    width: $size;
    height: $size;
  }

  &::-webkit-scrollbar-thumb {
    background: $thumb;
  }

  &::-webkit-scrollbar-track {
    background: $track;
  }
}

// Usage
.panel {
  @include scrollbars(10px, #111827, #e5e7eb);
}
@mixin scrollbars($size, $thumb, $track: rgba($thumb, .2))
  &::-webkit-scrollbar
    width: $size
    height: $size

  &::-webkit-scrollbar-thumb
    background: $thumb

  &::-webkit-scrollbar-track
    background: $track

// Usage
.panel
  +scrollbars(10px, #111827, #e5e7eb)
.panel::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}

.panel::-webkit-scrollbar-thumb {
  background: #111827;
}

.panel::-webkit-scrollbar-track {
  background: #e5e7eb;
}
Reusable scrollbar styling keeps long panels readable. Reusable scrollbar styling keeps long panels readable. Reusable scrollbar styling keeps long panels readable. Reusable scrollbar styling keeps long panels readable. Reusable scrollbar styling keeps long panels readable. Reusable scrollbar styling keeps long panels readable. Reusable scrollbar styling keeps long panels readable. Reusable scrollbar styling keeps long panels readable.

Use this placeholder for labels or helper UI where dragging to select text is undesirable.

%noselect {
  user-select: none;
}

// Usage
.drag-label {
  @extend %noselect;
}
%noselect
  user-select: none

// Usage
.drag-label
  @extend %noselect
.drag-label {
  user-select: none;
}
This text cannot be selected

Apply one shared placeholder for gradient-filled text instead of duplicating clip and fill declarations.

%text-gradient {
  background-clip: text;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
}

// Usage
.brand-word {
  @extend %text-gradient;
  background-image: linear-gradient(135deg, #0ea5e9, #8b5cf6);
}
%text-gradient
  background-clip: text
  -webkit-background-clip: text
  -webkit-text-fill-color: transparent

// Usage
.brand-word
  @extend %text-gradient
  background-image: linear-gradient(135deg, #0ea5e9, #8b5cf6)
.brand-word {
  background-image: linear-gradient(135deg, #0ea5e9, #8b5cf6);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
}
Gradient text

About the SCSS Mixins Library

Browse reusable Sass mixins and functions with source code, usage examples, and live previews. Copy any helper into your project.

Grouped by Purpose

Mixins and functions are organized into logical groups — layout, typography, responsive, color, animation, and more. Find the right helper instantly.

Live Previews

See what each mixin produces before copying it. Live preview panels show the rendered output so you understand the visual result immediately.

Code & Usage

Every entry shows the SCSS definition alongside usage examples. Copy the mixin source or just the include statement — whatever your workflow needs.

One-Click Copy

Copy any mixin definition or usage snippet with a single click. Paste it into your SCSS files and start using it right away without manual rewriting.

Frequently Asked Questions

A mixin is a reusable block of SCSS code that you define once and include in multiple selectors using @include. Mixins can accept parameters, making them flexible for generating repetitive CSS patterns like media queries, flexbox layouts, or animations.

A mixin outputs CSS declarations and is included with @include. A function computes and returns a value (like a color or number) and is called inline. Use mixins for blocks of CSS; use functions for computed values.

Yes. Each mixin is self-contained and can be copied into any SCSS project. Some mixins may reference variables — just replace those with your own values or define them in your variables file.

Mixins duplicate their output wherever they are included, which can increase file size if overused. For shared declarations, consider using @extend with placeholder selectors instead. Mixins are best for parametric patterns that vary per usage.