20

I want to dynamically create mixins in SASS, named after each item in the list, but it doesn't seem to work.

I tried this but I get an error:

$event-icons: fair, concert, art-show, conference, dance-show, film, party, festival, theatre, launch
@each $event-icon in $event-icons
  @mixin event-icon-#{$event-icon}
    background-position: -($event-icon-width * $i) 0

Error:

Invalid CSS after "": expected expression (e.g. 1px, bold), was "#{$event-icon}"

Is this usage not supported by SASS? I couldn't find anything in the manual about it.

John Slegers
  • 45,213
  • 22
  • 199
  • 169
Cristian
  • 5,877
  • 6
  • 46
  • 55

3 Answers3

28

Variable interpolation in @mixins does not appear to be supported currently.

The SASS documentation calls this #{} interpolation and describes it like this:

Interpolation: #{}

You can also use SassScript variables in selectors and property names using #{} interpolation syntax:

$name: foo;
$attr: border;
p.#{$name} {
  #{$attr}-color: blue;
}

Per the documentation, interpolation of variable names only appears to be supported for selectors and property names, and not for @mixins. If you'd like that feature, you may want to file an Issue for it, although this one may already be tracking what you're describing.

Edit: Are you sure you need to use a @mixin to accomplish the kind of styling you're talking about? Could you just use a selector with interpolation? For example, would this work:

$event-icons: fair, concert, art-show, conference, dance-show, film, party, festival, theatre, launch
@for $i from 1 to length($event-icons)
  $event-icon: nth($event-icons, $i)
  .event-icon-#{$event-icon}
    background-position: -($event-icon-width * $i) 0
Community
  • 1
  • 1
Stuart M
  • 11,458
  • 6
  • 45
  • 59
  • I actually ended up using a selector, but that doesn't work for all situations. I want to be independent of selectors and have mixins that could easily be used other places, also with pseudo-selectors like :hover on links (which wrap the icon). – Cristian Apr 04 '13 at 14:28
  • It is better to use `through` in the for-loop declaration in this case. Otherwise, the last element (`launch`) won't be counted. – Matt McCarthy Jul 26 '20 at 18:44
20

As of this moment (March 30th, 2014), Chris Eppstein still refuses to implement dynamic mixins. See issue 857 and issue 626 on Github.

I've been trying to convince Chris that this feature is quite essential for Sass to unleash its true power... and I'm not the only one there.

If you agree that this is an important feature, please go to issue 857 and issue 626 and address this problem yourself. The more of us provide a use case for this feature, the more likely we'll be able to convince Chris and/or one of the other lead developers.


UPDATE: In 2016, Eppstein did end up implementing this feature due to the number of requests for it. However, today (mid 2018), these changes still haven't been merged into the main branch and thus remain unavailable in the sass release. See issue 2057.

John Slegers
  • 45,213
  • 22
  • 199
  • 169
  • 7
    +1 As I said in the thread, it's a good feature -- I actually need it at work. As soon as the Sass feature freeze is over we'll be able to work on it. I don't know why you're trying to lobby for a feature that we've already agreed is a fine idea. Instead, maybe work on a pull request so it gets done sooner? – chriseppstein May 08 '15 at 21:15
  • @chriseppstein I'm not very fluent in Ruby, I'm afraid. I'm more of a PHP/MySQL, HTML/CSS/JS & XML/Json kind of guy. Anyway, you'll notice that this answer was posted on March 30th, 2014. Back then, you were still véry reluctant to add this feature. I'm glad you changed your mind. Maybe my lobbying paid off in the end?!? ;-) – John Slegers May 08 '15 at 21:36
  • Actually you are correct. I have not yet been convinced that dynamic definition of mixins is a good idea. However the issue you linked to was about including a mixin using a dynamic name. Which I am for. The OP's problem is solved better by accepting an argument to a single mixin instead of defining a unique mixin for each icon. – chriseppstein May 08 '15 at 22:39
  • @chriseppstein : It would be nice to both define and include a mixin, analogous to dynamically defining and extending placeholders (which is a feature I love). Still, I agree that defining them dynamically is not really an essential feature. Including them dynamically is a far more essential feature IMO (see eg. https://github.com/sass/sass/issues/857#issuecomment-39013579). – John Slegers May 08 '15 at 23:17
9

The best solution is to implement a single mixin that takes an argument.

$event-icons: fair, concert, art-show, conference, dance-show, film, party, festival, theatre, launch
@mixin event-icon($name)
  @if not index($event-icons, $name)
    @error "#{$name} is not an event icon."
  background-position: -($event-icon-width * $i) 0
chriseppstein
  • 10,453
  • 1
  • 25
  • 17