Mixins e funções SCSS
Helpers Sass reutilizáveis com código, exemplos de uso e prévia ao vivo
O mixin responsivo mais usado do Bootstrap. Ele mantém os breakpoints centralizados e deixa o SCSS de componentes grandes muito mais fácil de ler.
@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 quando o layout precisa de um ajuste só para tablets, sem afetar telas pequenas ou 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 com make-row() e make-col-ready(), é a forma mais rápida de criar primitivas de grid próprias sobre o sistema do 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%;
}
}
Um utilitário prático quando é preciso fixar um badge, um ponto, uma alça ou um overlay exatamente no centro visual.
@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%);
}
Bom para palavras decorativas em seções hero, tipografia de pôster e rótulos com preenchimento 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 carregamento, estados de progresso, destaques em skeletons ou qualquer superfície que precise de movimento sem imagens.
@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
);
}
Um dos helpers personalizados mais fortes. A técnica de máscara o torna especialmente útil para cards premium e destaques.
@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;
}
Um dos helpers mais reutilizáveis que existem. Merece um lugar no topo de qualquer biblioteca Sass interna.
Gere uma versão personalizada com todos os parâmetros necessários em
@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;
}
Um mixin de controle deslizante reutilizável que centraliza os estilos de trilha, cursor, hover, focus e disabled e deixa cada área do produto ajustar cores e dimensões.
@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;
}
Um único mixin define o posicionamento nos eixos principal e transversal, em vez de declarações de alinhamento espalhadas pelos 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 quando a cor e a espessura do contorno dos ícones precisam ser controladas pelo componente pai, e não no markup de cada ícone.
@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;
}
Um helper prático para projetos que ainda entregam fundos rasterizados em várias resoluções.
@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;
}
Ainda útil quando você quer manter os seletores de placeholder com prefixo de fornecedor fora dos componentes de formulário.
@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 animações utilitárias, quando você quer passar vários fragmentos de animação 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 quando uma borda linear simples parece chapada demais e você quer um brilho concentrado nos cantos.
@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;
}
A variante do projeto, já usada em várias partes da UI; vale mantê-la perto dos outros helpers de superfície reutilizáveis.
@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;
}
A variante do projeto para configurar o font-face. Prática para manter um include por família de arquivos.
@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ático quando você quer listas numeradas estilizadas sem repetir o código padrão do contador em 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 os arquivos-fonte
- Padronizar os nomes
- Exportar os arquivos finais
Um helper decorativo para títulos com volume e 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);
}
O par de text3d() para caixas, útil para chips, botões e blocos de UI elevados e divertidos.
@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);
}
Pequena, mas vale documentar, porque vira parte da linguagem do design system.
@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 quando você quer espaçamentos ou tamanhos responsivos em uma faixa de largura de tela sem escrever a fórmula calc() para cada propriedade.
@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;
}
}
Ainda um dos micromixins mais copiados em bibliotecas de componentes e 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;
}
Um padrão utilitário comum, porque os seletores de barras de rolagem personalizadas são verbosos e se repetem entre aplicativos.
@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 este placeholder em rótulos ou elementos auxiliares da interface em que selecionar texto arrastando não é desejável.
%noselect {
user-select: none;
}
// Usage
.drag-label {
@extend %noselect;
}
%noselect
user-select: none
// Usage
.drag-label
@extend %noselect
.drag-label {
user-select: none;
}
Aplique um placeholder compartilhado para texto com gradiente em vez de duplicar as declarações de clip e 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;
}
Sobre a biblioteca de mixins SCSS
Explore mixins e funções Sass reutilizáveis, com código-fonte, exemplos de uso e prévia ao vivo. Copie qualquer helper para o seu projeto.
Agrupados por finalidade
Mixins e funções estão organizados em grupos lógicos — layout, tipografia, responsividade, cor, animação e outros. Encontre o helper certo na hora.
Prévias ao vivo
Veja o que cada mixin gera antes de copiar. Os painéis de prévia ao vivo mostram o resultado renderizado, para você entender o efeito visual na hora.
Código e uso
Cada item mostra a definição em SCSS junto com exemplos de uso. Copie o código do mixin ou só a linha de include — o que for melhor para o seu fluxo de trabalho.
Cópia em um clique
Copie a definição de qualquer mixin ou exemplo de uso com um único clique. Cole nos seus arquivos SCSS e comece a usar na hora, sem reescrever nada.
Perguntas frequentes
Um mixin é um bloco de código SCSS reutilizável que você define uma vez e inclui em vários seletores com @include. Mixins aceitam parâmetros, o que os torna flexíveis para gerar padrões repetitivos de CSS, como media queries, layouts com flexbox ou animações.
Um mixin gera declarações CSS e é incluído com @include. Uma função calcula e retorna um valor (como uma cor ou um número) e é chamada dentro de uma expressão. Use mixins para blocos de CSS e funções para valores calculados.
Sim. Cada mixin é independente e pode ser copiado para qualquer projeto SCSS. Alguns mixins usam variáveis — basta substituí-las pelos seus valores ou defini-las no seu arquivo de variáveis.
Os mixins duplicam o resultado em cada lugar onde são incluídos, o que pode aumentar o arquivo se usados em excesso. Para declarações compartilhadas, considere usar @extend com seletores placeholder. Mixins são ideais para padrões parametrizados que variam a cada uso.