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%;
}
}
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;
}
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;
}
This is one of the most reusable helpers you already have. It should sit near the top of any internal Sass library.
@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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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) ". ";
}
- Collect source files
- Normalize naming
- 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);
}
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);
}
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;
}
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;
}
}
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;
}
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;
}
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;
}
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;
}
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.