Home / Blog / SCSS Mixins: Reusable CSS Blocks with @mixin and @include
CSS Preprocessors 2026-09-23 · 10 min read

SCSS Mixins: Reusable CSS Blocks with @mixin and @include

Master SCSS mixins to create reusable CSS blocks. Learn @mixin, @include, arguments, default values, and content blocks for flexible styles.

What Are SCSS Mixins?

In plain CSS, repeating the same set of declarations across multiple selectors is inevitable — think of vendor-prefixed properties, flex centering patterns, or responsive breakpoint rules. SCSS mixins solve this by letting you define a reusable block of CSS once and include it anywhere with @include.

A mixin is defined with @mixin and called with @include. When Sass compiles your SCSS, every @include is replaced with the full CSS block from the mixin definition. The result is perfectly standard CSS — no runtime overhead.

Basic @mixin and @include Syntax

Here's the simplest possible mixin — a flex centering utility:

// Define the mixin
@mixin flex-center {
  display: flex;
  align-items: center;
  justify-content: center;
}

// Use it
.hero {
  @include flex-center;
  height: 100vh;
}

.card {
  @include flex-center;
  padding: 2rem;
}

Compiled CSS output:

.hero {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
}

.card {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2rem;
}

Mixins with Arguments

Mixins become truly powerful when they accept arguments, making them dynamic rather than static.

@mixin button($bg-color, $text-color, $padding: 0.75rem 1.5rem) {
  display: inline-block;
  background-color: $bg-color;
  color: $text-color;
  padding: $padding;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  font-weight: 600;
  transition: opacity 0.2s ease;

  &:hover {
    opacity: 0.85;
  }
}

// Include with arguments
.btn-primary {
  @include button(#3b82f6, #fff);
}

.btn-danger {
  @include button(#ef4444, #fff);
}

.btn-sm {
  @include button(#6b7280, #fff, 0.4rem 0.9rem);
}

The third argument $padding has a default value of 0.75rem 1.5rem, so you only need to pass it when you want a different size.

Default Argument Values

Default arguments make mixins flexible without requiring callers to provide every value:

@mixin shadow($color: rgba(0, 0, 0, 0.1), $blur: 10px, $spread: 0, $x: 0, $y: 4px) {
  box-shadow: $x $y $blur $spread $color;
}

.card {
  @include shadow; // Uses all defaults
}

.elevated {
  @include shadow(rgba(0, 0, 0, 0.25), 24px, -2px, 0, 8px);
}

.colored-shadow {
  @include shadow(rgba(59, 130, 246, 0.4), 20px);
}

Keyword Arguments

When a mixin has many parameters, you can pass them by name to avoid confusion about order:

@mixin position($type, $top: auto, $right: auto, $bottom: auto, $left: auto) {
  position: $type;
  top: $top;
  right: $right;
  bottom: $bottom;
  left: $left;
}

.overlay {
  @include position(fixed, $top: 0, $left: 0, $right: 0, $bottom: 0);
}

.tooltip {
  @include position(absolute, $top: -40px, $left: 50%);
}

The @content Block: Mixins That Wrap Content

The @content directive lets you pass an entire block of CSS into a mixin. This is perfect for media query mixins:

// Define breakpoint mixins
@mixin mobile {
  @media (max-width: 767px) {
    @content;
  }
}

@mixin tablet {
  @media (min-width: 768px) and (max-width: 1023px) {
    @content;
  }
}

@mixin desktop {
  @media (min-width: 1024px) {
    @content;
  }
}

// Use them
.hero-title {
  font-size: 3rem;

  @include mobile {
    font-size: 1.75rem;
  }

  @include tablet {
    font-size: 2.25rem;
  }
}

Compiled output:

.hero-title {
  font-size: 3rem;
}

@media (max-width: 767px) {
  .hero-title {
    font-size: 1.75rem;
  }
}

@media (min-width: 768px) and (max-width: 1023px) {
  .hero-title {
    font-size: 2.25rem;
  }
}

Responsive Mixin with a Breakpoint Map

A more advanced pattern uses a Sass map to drive breakpoints from a single mixin:

$breakpoints: (
  'sm':  576px,
  'md':  768px,
  'lg':  1024px,
  'xl':  1280px,
  '2xl': 1536px,
);

@mixin respond-to($bp) {
  $value: map.get($breakpoints, $bp);

  @if $value == null {
    @warn "Unknown breakpoint: #{$bp}.";
  } @else {
    @media (min-width: $value) {
      @content;
    }
  }
}

// Usage
.container {
  padding: 0 1rem;

  @include respond-to('md') {
    padding: 0 2rem;
    max-width: 1200px;
    margin: 0 auto;
  }
}

Flex Mixin for Layout

A flexible layout mixin that accepts direction and alignment:

@mixin flex(
  $direction: row,
  $justify: flex-start,
  $align: stretch,
  $wrap: nowrap,
  $gap: 0
) {
  display: flex;
  flex-direction: $direction;
  justify-content: $justify;
  align-items: $align;
  flex-wrap: $wrap;
  gap: $gap;
}

.header {
  @include flex(row, space-between, center, nowrap, 1rem);
}

.card-grid {
  @include flex(row, flex-start, stretch, wrap, 1.5rem);
}

.sidebar-menu {
  @include flex(column, flex-start, stretch, nowrap, 0.5rem);
}

Mixin vs Placeholder (%extend): When to Use Which

SCSS also has %placeholder selectors used with @extend. Understanding the difference helps you choose the right tool:

  • @mixin + @include — Copies the CSS block into each selector. Great when you need arguments or the content varies per call.
  • %placeholder + @extend — Groups selectors together in the output (more DRY output). Best for static, argument-free shared styles.
// Placeholder approach
%card-base {
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}

.product-card {
  @extend %card-base;
  padding: 1rem;
}

.profile-card {
  @extend %card-base;
  padding: 1.5rem;
}

// Compiled output — selectors are grouped:
// .product-card, .profile-card { border-radius: 8px; ... }

Real-World: Typography Mixin

A practical mixin for consistent typography across headings:

@mixin heading($size, $weight: 700, $line-height: 1.2) {
  font-size: $size;
  font-weight: $weight;
  line-height: $line-height;
  color: var(--heading-color);
  letter-spacing: -0.02em;
}

h1 { @include heading(2.5rem); }
h2 { @include heading(2rem); }
h3 { @include heading(1.5rem, 600, 1.3); }
h4 { @include heading(1.25rem, 600, 1.4); }
h5 { @include heading(1rem, 500, 1.5); }

You can inspect the compiled output of your SCSS mixins using the CSS Formatter on htmlcsseditor.com, which makes it easy to read and understand the generated CSS structure.

Mixin Best Practices

  • Keep mixins focused on a single responsibility — don't cram unrelated styles into one mixin.
  • Use default argument values for optional parameters so callers aren't burdened with boilerplate.
  • Document complex mixins with a comment block explaining parameters.
  • Avoid mixins that generate large amounts of CSS if called frequently — consider @extend for static shared styles.
  • Store all mixins in a _mixins.scss partial and import it at the top of your main file with @use 'mixins'.

Frequently Asked Questions

What is the difference between a mixin and a function in SCSS?
A mixin outputs CSS declarations and rules — it adds styles. A function computes and returns a value (number, color, string) that you use as part of a declaration. Use mixins to generate styles, and functions to calculate values.
Can a mixin call another mixin?
Yes, mixins can include other mixins. This is called mixin composition. Just make sure to import all required mixins before they are used to avoid compilation errors.
How many arguments can an SCSS mixin take?
There is no hard limit on the number of arguments. However, mixins with more than 4-5 arguments become unwieldy. Consider using a Sass map as a single argument to pass many named options cleanly.
What does @content do in a mixin?
@content is a placeholder inside a mixin that gets replaced with the CSS block passed by the caller. It allows the mixin to wrap caller-provided styles — most commonly used to create media query shorthand mixins.
Should I put mixins in a separate file?
Yes. The standard convention is to store all mixins in a _mixins.scss partial. This keeps your codebase organised and makes it easy to import with @use 'mixins' wherever mixins are needed.

Try Our Free HTML CSS Tools

Practice what you've learned with our free online tools — no installation required.

Live HTML/CSS Editor CSS Formatter CSS Minifier