Mixins y funciones SCSS
Helpers Sass reutilizables con su código, ejemplos de uso y vista previa en vivo
El mixin responsive más usado de Bootstrap. Mantiene los breakpoints centralizados y hace que el SCSS de los componentes grandes sea mucho más fácil de leer.
@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);
}
}
Útil cuando un diseño necesita un ajuste solo para tablets sin afectar a las pantallas pequeñas ni a las grandes.
@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;
}
}
Junto con make-row() y make-col-ready(), es la forma más rápida de crear tus propias primitivas de cuadrícula sobre el sistema de Bootstrap.
@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%;
}
}
Una utilidad práctica cuando necesitas fijar una insignia, un punto, un control o una superposición en el centro visual real.
@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%);
}
Ideal para palabras decorativas en secciones hero, tipografía de póster y etiquetas con relleno transparente.
@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;
}
Útil para barras de carga, estados de progreso, acentos en skeletons o cualquier superficie que necesite movimiento sin imágenes.
@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
);
}
Uno de los helpers personalizados más potentes. Gracias al enmascarado, resulta especialmente útil para tarjetas premium y avisos destacados.
@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;
}
Uno de los helpers más reutilizables. Debería estar entre los primeros de cualquier biblioteca Sass interna.
Genera una versión personalizada con todos los parámetros necesarios:
@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;
// preferred(vw) = (min-size - slope * min-screen) + slope * 100vw
$slope: math.div($max-size - $min-size, $max-screen - $min-screen);
$intercept-rem: math.div($min-size - $slope * $min-screen, 16px) * 1rem;
$slope-vw: $slope * 100 * 1vw;
@return clamp(#{$min-size-rem}, calc(#{$intercept-rem} + #{$slope-vw}), #{$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
// preferred(vw) = (min-size - slope * min-screen) + slope * 100vw
$slope: math.div($max-size - $min-size, $max-screen - $min-screen)
$intercept-rem: math.div($min-size - $slope * $min-screen, 16px) * 1rem
$slope-vw: $slope * 100 * 1vw
@return clamp(#{$min-size-rem}, calc(#{$intercept-rem} + #{$slope-vw}), #{$max-size-rem})
// Usage
.headline
font-size: to-clamp(28px, 72px)
margin-bottom: to-rem(24px)
.headline {
font-size: clamp(1.75rem, calc(1.0825rem + 2.85vw), 4.5rem);
margin-bottom: 1.5rem;
}
Un mixin de slider reutilizable que centraliza los estilos de la pista, el control, hover, focus y disabled, y deja que cada área del producto ajuste colores y dimensiones.
@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;
}
Usa un solo mixin para definir a la vez la posición en el eje principal y en el transversal, en lugar de repartir declaraciones de alineación por los componentes.
@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;
}
Útil cuando el color y el grosor del trazo de los iconos deben controlarse desde el componente padre y no en el marcado de cada icono.
@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;
}
Un helper práctico para proyectos que todavía sirven fondos rasterizados en varias resoluciones.
@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;
}
Sigue siendo útil cuando quieres mantener los selectores de placeholder con prefijo fuera de los componentes de formulario.
@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);
}
Útil para conjuntos de animaciones utilitarias cuando quieres pasar varios fragmentos de animación como argumentos.
@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;
}
Útil cuando un borde lineal simple se ve demasiado plano y quieres un brillo concentrado en las esquinas.
@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;
}
La variante del proyecto que ya se usa en distintas partes de la interfaz; conviene tenerla junto a los demás helpers de superficies reutilizables.
@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;
}
La variante propia del proyecto para configurar font-face. Práctica para tener un include por cada familia de archivos.
@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;
}
Práctico cuando quieres listas numeradas con estilo sin repetir el código repetitivo del contador en cada componente.
@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) ". ";
}
- Reunir los archivos fuente
- Unificar los nombres
- Exportar los recursos finales
Un helper decorativo para títulos con volumen y textos de marca estilizados.
@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);
}
El complemento de text3d() para cajas: útil para chips, botones y bloques de interfaz elevados con un toque divertido.
@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);
}
Diminuta, pero vale la pena documentarla porque pasa a formar parte del lenguaje del sistema de diseño.
@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;
}
Útil cuando quieres espaciados o tamaños responsive en un rango de viewport sin escribir la fórmula calc() para cada propiedad.
@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;
}
}
Sigue siendo uno de los micromixins más copiados en bibliotecas de componentes y paneles de control.
@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;
}
Un patrón utilitario habitual, porque los selectores de barras de desplazamiento personalizadas son engorrosos y se repiten en todas las aplicaciones.
@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;
}
Usa este placeholder en etiquetas o elementos auxiliares de la interfaz donde no conviene que se pueda seleccionar texto arrastrando.
%noselect {
user-select: none;
}
// Usage
.drag-label {
@extend %noselect;
}
%noselect
user-select: none
// Usage
.drag-label
@extend %noselect
.drag-label {
user-select: none;
}
Aplica un único placeholder compartido para el texto con relleno degradado en lugar de duplicar las declaraciones de clip y fill.
%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;
}
Acerca de la biblioteca de mixins SCSS
Explora mixins y funciones Sass reutilizables con su código fuente, ejemplos de uso y vista previa en vivo. Copia cualquier helper en tu proyecto.
Agrupados por propósito
Los mixins y las funciones están organizados en grupos lógicos: maquetación, tipografía, responsive, color, animación y más. Encuentra al instante el helper que necesitas.
Vista previa en vivo
Mira qué genera cada mixin antes de copiarlo. Los paneles de vista previa en vivo muestran el resultado renderizado, así entiendes el efecto visual al instante.
Código y uso
Cada entrada muestra la definición SCSS junto con ejemplos de uso. Copia el código del mixin o solo la línea include, lo que mejor encaje en tu flujo de trabajo.
Copia en un clic
Copia la definición de cualquier mixin o su ejemplo de uso con un solo clic. Pégalo en tus archivos SCSS y empieza a usarlo enseguida, sin reescribir nada.
Preguntas frecuentes
Un mixin es un bloque de código SCSS reutilizable que defines una vez e incluyes en varios selectores con @include. Los mixins pueden recibir parámetros, lo que los hace flexibles para generar patrones CSS repetitivos como media queries, diseños con flexbox o animaciones.
Un mixin genera declaraciones CSS y se incluye con @include. Una función calcula y devuelve un valor (como un color o un número) y se llama dentro de una expresión. Usa mixins para bloques de CSS y funciones para valores calculados.
Sí. Cada mixin es autónomo y se puede copiar en cualquier proyecto SCSS. Algunos mixins pueden hacer referencia a variables: basta con sustituirlas por tus propios valores o definirlas en tu archivo de variables.
Los mixins duplican su salida allí donde se incluyen, lo que puede aumentar el tamaño del archivo si se abusa de ellos. Para declaraciones compartidas, plantéate usar @extend con selectores placeholder. Los mixins funcionan mejor para patrones paramétricos que cambian en cada uso.