Search code examples
htmlcsssassmixinsscss-mixins

How do I pass an HTML `data-` string attribute into a SCSS mixin via attr()?


I am trying to set up a color scheme in SCSS where I can have the following HTML:

<div class="swatch" data-bg="green">...</div>

I have a SCSS mixin defined as such:

@function color($key: 'black') {
  @return map-get($colors, $key);
}

So, if I pass it background-color: color('green'), it will look at the $colors: ( ... ) map, see 'green': #009900, and return background-color: #009900; as the CSS.

The problem comes when I try to pass the data-bg attribute value into the color() SCSS mixin, like so:

.swatch[data-bg] {
  background-color: color(attr(data-bg));
}

This doesn't work. I would expect it to parse the value as such:

color(attr(data-bg))color('green')#009900

However, SCSS won't even render that background-color line in the CSS at all.

I have a Codepen where you can see what I'm trying to go for. It's the "Brown" color swatch here: https://codepen.io/rbrum/pen/axZLxw

Any help would be greatly appreciated.


Solution

  • For anyone else who happens across this question, here is how I ended up resolving my issue.

    Instead of relying on data- attributes, I just relied on class names instead. Whenever I want an element with a certain background color, for instance, I use a class name like .bg-amber or .bg-purple. My colors are defined as such:

    $colors: (
      'black': #000000,
      'white': #FFFFFF,
      // ...
      'amber': #FFBF00,
      'purple': #800080,
      // ...
    );
    

    To make it easier to access a color, I have defined a function that calls any color by name:

    @function c($key: 'black') {
      @return map-get($colors, $key);
    }
    

    I then define a mixin that, given a color name, will apply it as the background color. I can also pass it a prefix that is used in the CSS attribute.

    @mixin bg($color-name, $prefix: '') {
      .#{$prefix}#{$color-name} {
        background-color: c($color-name);
      }
    }
    

    If I wanted to use it in a one-off situation, I would use it like so:

    @include bg('amber', 'bg-');
    

    ...which would generate the following:

    .bg-amber {
      background-color: #FFBF00;
    }
    

    Finally, I use an @each loop to do this for all of my colors:

    @each $color-name, $color-val in $colors {
      @include bg($color-name, 'bg-');
    }
    

    I can also define a "foreground" version:

    @mixin fg($color-name, $prefix: '') {
      .#{$prefix}#{$color-name} {
        color: c($color-name);
      }
    }
    

    And then I can use it in the @each loop right below the bg() usage:

    @each $color-name, $color-val in $colors {
      @include bg($color-name, 'bg-');
      @include fg($color-name, 'txt-');
    }
    

    It can also be extended for things like border colors, box shadows, and more.