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%;
  }
}
6/12
6/12
3/12
3/12

Uno de los pocos helpers de accesibilidad que toda biblioteca de componentes debería tener a mano.

@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;
}

La etiqueta para lectores de pantalla sigue siendo accesible mientras la interfaz visible muestra solo el icono.

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;
}
CONTORNO

Ú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;
}
Borde de tarjeta premium

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: Generador de clamp()

@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;
}
Título fluido

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;
}
Filtro Ordenar Exportar Compartir

Ú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;
}
Fondo listo para Retina

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;
}
Estado en vivo

Ú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;
}
Borde de tarjeta premium

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;
}
Unos estilos de barra de desplazamiento reutilizables hacen que los paneles largos se lean con comodidad. Unos estilos de barra de desplazamiento reutilizables hacen que los paneles largos se lean con comodidad. Unos estilos de barra de desplazamiento reutilizables hacen que los paneles largos se lean con comodidad. Unos estilos de barra de desplazamiento reutilizables hacen que los paneles largos se lean con comodidad. Unos estilos de barra de desplazamiento reutilizables hacen que los paneles largos se lean con comodidad. Unos estilos de barra de desplazamiento reutilizables hacen que los paneles largos se lean con comodidad. Unos estilos de barra de desplazamiento reutilizables hacen que los paneles largos se lean con comodidad. Unos estilos de barra de desplazamiento reutilizables hacen que los paneles largos se lean con comodidad.

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;
}
Aa
Título de prueba de la fuente

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) ". ";
}
  1. Reunir los archivos fuente
  2. Unificar los nombres
  3. 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);
}
JINERO

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);
}
Chip con volumen

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;
}
Título fluido

Ú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;
  }
}
Vista previa del espaciado fluido

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;
}
Este es un título de tarjeta muy largo que debería cortarse limpiamente con puntos suspensivos

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;
}
Unos estilos de barra de desplazamiento reutilizables hacen que los paneles largos se lean con comodidad. Unos estilos de barra de desplazamiento reutilizables hacen que los paneles largos se lean con comodidad. Unos estilos de barra de desplazamiento reutilizables hacen que los paneles largos se lean con comodidad. Unos estilos de barra de desplazamiento reutilizables hacen que los paneles largos se lean con comodidad. Unos estilos de barra de desplazamiento reutilizables hacen que los paneles largos se lean con comodidad. Unos estilos de barra de desplazamiento reutilizables hacen que los paneles largos se lean con comodidad. Unos estilos de barra de desplazamiento reutilizables hacen que los paneles largos se lean con comodidad. Unos estilos de barra de desplazamiento reutilizables hacen que los paneles largos se lean con comodidad.

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;
}
Este texto no se puede seleccionar

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;
}
Texto degradado

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.