Philip L Philip L - 1 month ago 21
Sass (Sass) Question

@each with an @include mixin

I have a dropdown of 30 fonts where I'd like the font of the dropdown to also display the Google Font (for visual representation, of course!) example text.

I have the HTML with the ID's, for example:

font-oswald-light
,
font-oswald-reg
,
font-oswald-bold
.

Using the @each directive, I wanted to do something like this:

@each $font-name, $font-mixin in (lato, Lato-Light),
(open_sans, Open_Sans-Light),
(oswald, Oswald-Light),
(raleway, Raleway-Light),
(roboto, Roboto-Light),
(source_sans_pro, Source_Sans_Pro-Light),
(ubuntu, Ubuntu-Light) {
#font-#{$font-name}-light {
@include #{$font-mixin};
}
}


create the font-family:

@import url('https://fonts.googleapis.com/css?family=......)

@mixin Lato-Light {
font-family: 'Lato', sans-serif;
font-weight: 300;
font-style: normal;
}

@mixin Lato-Reg {
font-family: 'Lato', sans-serif;
font-weight: 400;
font-style: normal;
}

@mixin Lato-Bold {
font-family: 'Lato', sans-serif;
font-weight: 700;
font-style: normal;
}


However, the @each does not like the
@include
inside to display the font-family. I'm not using any libraries (bourbon, compass, etc) to create the font-face().

My question is: what would be a way to dynamically create the @each font-ID list so it doesn't error out when trying to @include the families?

Answer
#font-#{$font-name}-light {
  @include #{$font-mixin};
}

First of all, this code can't work. Interpolation does not work this way in Sass. Sass expects an identifier after the @include keyword and when it comes across this code, it evaluates $font-mixin to the value represented by the variable and that's all it is, a value. Sass will not interpret that value as an identifier

Secondly you don't need to create a mixin for every single font. That approach is not flexible and even less maintainable.

I suggest one using one mixin that will loop through a fonts map to dynamically generate the css you want.

$fonts-list:(
  lato-light: ("Lato", sans-serif) 300 normal,
  lato-reg: ("Lato", sans-serif) 400 normal,
  lato-bold: ("Lato", sans-serif) 700 normal,
  oswald-light: ("Oswald", sans-serif) 200 normal,
  oswald-reg: ("Oswald", sans-serif) 400 normal
);


@mixin fonts($family, $weight, $style) {
  font-family: $family;
  font-weight: $weight;
  font-style: $style;
}

@each $font, $attributes in $fonts-list {
  #font-#{$font} {
    @include fonts(nth($attributes, 1), nth($attributes, 2), nth($attributes, 3));
  }
}

The compiled CSS looks like this

#font-lato-light {
  font-family: "Lato", sans-serif;
  font-weight: 300;
  font-style: normal;
}

#font-lato-reg {
  font-family: "Lato", sans-serif;
  font-weight: 400;
  font-style: normal;
}

#font-lato-bold {
  font-family: "Lato", sans-serif;
  font-weight: 700;
  font-style: normal;
}

#font-oswald-light {
  font-family: "Oswald", sans-serif;
  font-weight: 200;
  font-style: normal;
}

#font-oswald-reg {
  font-family: "Oswald", sans-serif;
  font-weight: 400;
  font-style: normal;
}

You can decide to have multiple font maps to store fonts based on variations i.e $fonts-light, which stores all the light variations of the fonts, $fonts-reg, which stores all the regular variations of the fonts... And then you could loop through each of them the same way. It all depends on the structure you prefer. I hope this helps