EthicsComputerCourses
Join training +91 90532 10052

Interpolation

Sass · Lesson 7 of 26 Beginner 5 min read Updated

A variable can normally go only where a CSS value goes. But sometimes you want a value inside a selector (.btn-primary), a property name (margin-left), a URL or a custom property. Interpolation is the tool for this: wrap any Sass expression in #{ } and Sass inserts its result as text, right there.

In this lesson you will use interpolation in selectors, property names, media queries, URLs, strings and custom properties, and learn when you do not need it.

The #{} syntax

#{expression} evaluates the expression and pastes the result into the surrounding code. The expression can be a variable, maths, or a function call:

SCSSTry it yourself
$prefix: "ec";
$side: "left";
$img: "hero";

.#{$prefix}-btn {
  padding: 1rem;
}

.box {
  margin-#{$side}: 2rem;
  border-#{$side}-width: 3px;
}

.hero {
  background-image: url("/img/#{$img}@2x.webp");
}

.gate::after {
  content: "Gate #{1 + 2}";
}
Output
.ec-btn {
  padding: 1rem;
}

.box {
  margin-left: 2rem;
  border-left-width: 3px;
}

.hero {
  background-image: url("/img/hero@2x.webp");
}

.gate::after {
  content: "Gate 3";
}
  • In the selector, .#{$prefix}-btn became .ec-btn. Notice that the quotes around "ec" disappeared: interpolation removes the quotes from quoted strings, which is what you want in a selector.
  • In the property names, #{$side} built margin-left and border-left-width.
  • Inside the quoted URL and the content string, the values were inserted into the text, and 1 + 2 was calculated first.

Generating classes in a loop

Interpolation becomes powerful together with loops. One @each rule can write a whole set of classes. Here is a set of colour classes for a Kerala tourism site's tags:

SCSSTry it yourself
$tags: (backwaters: #0e7490, hills: #15803d, beaches: #d97706, temples: #b91c1c);

@each $name, $color in $tags {
  .tag-#{$name} {
    background: $color;
    color: white;
  }
}
Output
.tag-backwaters {
  background: #0e7490;
  color: white;
}

.tag-hills {
  background: #15803d;
  color: white;
}

.tag-beaches {
  background: #d97706;
  color: white;
}

.tag-temples {
  background: #b91c1c;
  color: white;
}

Here is the result on a page:

HTMLTry it yourself
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Tag colours</title>
  <style>
    body { font-family: system-ui, sans-serif; padding: 1rem; }
    span { display: inline-block; padding: 0.25rem 0.75rem; border-radius: 999px; margin: 0.25rem; }
    /* compiled from the SCSS above */
    .tag-backwaters { background: #0e7490; color: white; }
    .tag-hills { background: #15803d; color: white; }
    .tag-beaches { background: #d97706; color: white; }
    .tag-temples { background: #b91c1c; color: white; }
  </style>
</head>
<body>
  <h1>Explore Kerala</h1>
  <span class="tag-backwaters">Backwaters</span>
  <span class="tag-hills">Hills</span>
  <span class="tag-beaches">Beaches</span>
  <span class="tag-temples">Temples</span>
</body>
</html>

Add a fifth entry to the map and Sass writes a fifth class. You will learn loops fully in Control Flow.

Custom properties and comments

Two places need interpolation even though they look like normal values:

  • CSS custom properties (--name: value). Sass copies their values as plain text, so --brand: $brand; would output the text $brand. Write --brand: #{$brand};.
  • Loud comments (/* */). Write /* Built for #{$client} */ to stamp a value into a comment.
SCSSTry it yourself
$brand: #cc6699;
$space: 8px;
$client: "Rohtak Sweets";

/* Theme for #{$client} */
:root {
  --brand: #{$brand};
  --space-2: #{$space * 2};
  --wrong: $brand;
}
Output
/* Theme for Rohtak Sweets */
:root {
  --brand: #cc6699;
  --space-2: 16px;
  --wrong: $brand;
}

--wrong shows the bug: the browser receives the meaningless text $brand. --space-2 shows that the expression inside #{ } is calculated first.

When you do not need interpolation

Beginners often wrap everything in #{ }. In normal values it is unnecessary, and it can hurt, because interpolation always produces an unquoted string, not a number. You cannot do maths with the result:

SCSSTry it yourself
$size: 16px;

.ok {
  font-size: $size * 1.25;
}

.not-needed {
  font-size: #{$size};
}

.broken {
  font-size: #{$size} * 1.25;
}
Output
Undefined operation "16px * 1.25".
   ╷
12 │   font-size: #{$size} * 1.25;
   │              ^^^^^^^^^^^^^^^
   ╵
  - 12:14  root stylesheet

The whole file failed because of .broken: #{$size} turned the number into the unquoted text 16px, and Sass cannot multiply text by a number, so it stops with "Undefined operation". Delete the .broken rule and run again: .ok calculates 20px, and .not-needed works but adds nothing.

Also, you do not need interpolation in media queries or in calc() any more. Current Dart Sass understands variables there directly: @media (width >= $tablet) and calc(100% - $sidebar) both work. You will still see @media (min-width: #{$tablet}) and calc(100% - #{$sidebar}) in older code; they produce the same result.

Common mistakes

  • --brand: $brand; outputs the literal text. Custom properties always need #{$brand}.
  • Interpolating and then doing maths. #{$size} * 2 multiplies text by a number, which is an error. Do the maths inside, #{$size * 2}, or better, skip interpolation.
  • Interpolating whole selectors from user data. Keep generated selectors simple (letters, digits, hyphens) so the output stays valid CSS.
  • Using interpolation everywhere. Only use it where a plain variable cannot go: selectors, property names, strings, custom properties and comments.

Key points

  • #{expression} evaluates the expression and inserts the result as text.
  • Use it in selectors (.btn-#{$name}), property names (margin-#{$side}), URLs, strings, loud comments and custom property values.
  • Interpolation removes quotes from quoted strings and always returns an unquoted string, so you cannot do maths on its result.
  • Plain variables work in normal values, media queries and calc() without interpolation.
  • Loops plus interpolation generate families of classes from a map.

Exercise

A Lucknow coaching centre needs spacing helper classes. Using a map (1: 0.25rem, 2: 0.5rem, 3: 1rem) and a list of sides top, bottom, generate classes like .mt-1 (margin-top: 0.25rem) and .mb-3 (margin-bottom: 1rem). Hint: nest one @each inside another and use string.slice($side, 1, 1) from sass:string to get the first letter of the side.

Show solution
SCSS
@use "sass:string";

$space: (1: 0.25rem, 2: 0.5rem, 3: 1rem);
$sides: top, bottom;

@each $side in $sides {
  @each $step, $size in $space {
    .m#{string.slice($side, 1, 1)}-#{$step} {
      margin-#{$side}: $size;
    }
  }
}

The outer loop picks a side, the inner loop a size. Interpolation builds both the class name (.mt-1) and the property name (margin-top), giving six classes in total.

Quick Quiz

1. What does .icon-#{$name} compile to when $name: "star"?

2. Why does --brand: $brand; not work?

3. What happens with width: #{$size} * 2; when $size: 10px?

4. Where is interpolation needed?

Learn Sass with a mentor

Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.

  • Project-based learning
  • Mentor code reviews
  • Free counselling call