Sitethief Sitethief - 4 years ago 163
Sass (Sass) Question

SASS mixin with dynamic argument list does not work with only one argument

I wrote the following mixin to dynamicly create two classes used for a title and subtitle. I wanted to be able to add arrays of arguments to the classes. But I only got it working if I have multiple values in the arrays, not with only one. I suspect its not treated as an array.

@mixin argument ($key, $value) {
#{$key}: $value;
}

// dynamic mixin that creates two seperate classes for a header title and subtitle
@mixin header-titles($name, $title-size, $title-color, $sub-size, $sub-color, $title-extra: false, $sub-extra: false) {

.#{$name}-title {
@include font($bold-font, 900, $title-size, $title-color)
@if $title-extra {
@each $t-extra in $title-extra{
@include argument(nth($t-extra,1),nth($t-extra,2));
}
}
}

.#{$name}-subtitle {
@include font($bold-font, 900, $sub-size, $sub-color)
@if $sub-extra {
@each $s-extra in $sub-extra {
@include argument(nth($s-extra,1),nth($s-extra,2));
}
}
}
}


It works if you call it like this in SASS and run
mix.sass('homepage.scss');
for it using gulp watch and laravel elixir.

@include header-titles(
'fubar',
$fubar-title-font-size,
$fubar-title-text-color,
$fubar-sub-title-font-size,
$fubar-sub-title-text-color,
((margin, 50px 0 0 0),(padding, 50px 0 0 0)),((margin, 50px 0 0 0),(padding, 50px 0 0 0))
)


But not if called like this

@include header-titles(
'fubar',
$fubar-title-font-size,
$fubar-title-text-color,
$fubar-sub-title-font-size,
$fubar-sub-title-text-color,
((margin, 50px 0 0 0)),((margin, 50px 0 0 0))
)


Then I get the following error:

Error: index out of bounds for `nth($list, $n)`
on line 86 of resources/assets/sass/_mixins.scss
>> @include argument(nth($t-extra,1),nth($t-extra,2));
------------------------------------------^

at options.error ({obfuscated projectdirname}\node_modules\node-sass\lib\index.js:286:26)
status: 1,
file: '{obfuscated projectdirname}/resources/assets/sass/_mixins.scss',
line: 86,
column: 51,
message: 'resources\\assets\\sass\\_mixins.scss\nError: index out of bounds for `nth($list, $n)`\n on line 86 of resources/assets/sass/_mixins.scss\n>> @include argument(nth($t-extra,1),nth($t-extra,2));\n ------------------------------------------^\n',
formatted: 'Error: index out of bounds for `nth($list, $n)`\n on line 86 of resources/assets/sass/_mixins.scss\n>> @include argument(nth($t-extra,1),nth($t-extra,2));\n ------------------------------------------^\n',
messageFormatted: 'resources\\assets\\sass\\_mixins.scss\nError: index out of bounds for `nth($list, $n)`\n on line 86 of resources/assets/sass/_mixins.scss\n>> @include argument(nth($t-extra,1),nth($t-extra,2));\n ------------------------------------------^\n',
messageOriginal: 'index out of bounds for `nth($list, $n)`',
relativePath: 'resources\\assets\\sass\\_mixins.scss',
name: 'Error',
stack: 'Error: resources\\assets\\sass\\_mixins.scss\nError: index out of bounds for `nth($list, $n)`\n on line 86 of resources/assets/sass/_mixins.scss\n>> @include argument(nth($t-extra,1),nth($t-extra,2));\n ------------------------------------------^\n\n at options.error ({obfuscated projectdirname}\\exroot\\node_modules\\node-sass\\lib\\index.js:286:26)',
showStack: false,
showProperties: true,
plugin: 'gulp-sass' }
{ Error: resources\assets\sass\_mixins.scss
Error: index out of bounds for `nth($list, $n)`
on line 86 of resources/assets/sass/_mixins.scss
>> @include argument(nth($t-extra,1),nth($t-extra,2));
------------------------------------------^

at options.error ({obfuscated projectdirname}\node_modules\node-sass\lib\index.js:286:26)
status: 1,
file: '{obfuscated projectdirname}/resources/assets/sass/_mixins.scss',
line: 86,
column: 51,
message: 'resources\\assets\\sass\\_mixins.scss\nError: index out of bounds for `nth($list, $n)`\n on line 86 of resources/assets/sass/_mixins.scss\n>> @include argument(nth($t-extra,1),nth($t-extra,2));\n ------------------------------------------^\n',
formatted: 'Error: index out of bounds for `nth($list, $n)`\n on line 86 of resources/assets/sass/_mixins.scss\n>> @include argument(nth($t-extra,1),nth($t-extra,2));\n ------------------------------------------^\n',
messageFormatted: 'resources\\assets\\sass\\_mixins.scss\nError: index out of bounds for `nth($list, $n)`\n on line 86 of resources/assets/sass/_mixins.scss\n>> @include argument(nth($t-extra,1),nth($t-extra,2));\n ------------------------------------------^\n',
messageOriginal: 'index out of bounds for `nth($list, $n)`',
relativePath: 'resources\\assets\\sass\\_mixins.scss',
name: 'Error',
stack: 'Error: resources\\assets\\sass\\_mixins.scss\nError: index out of bounds for `nth($list, $n)`\n on line 86 of resources/assets/sass/_mixins.scss\n>> @include argument(nth($t-extra,1),nth($t-extra,2));\n ------------------------------------------^\n\n at options.error ({obfuscated projectdirname}\\node_modules\\node-sass\\lib\\index.js:286:26)',
showStack: false,
showProperties: true,
plugin: 'gulp-sass' }


My google-fu abandoned me when trying to find out what this error means.

My question: what did I do wrong here? Is there maybe a better way to do this?

Sorry for the long code blocks...

Answer Source

It is a known problem/behavior with respect to single element lists. As mentioned in this GitHub thread you can add an extra comma at the end to make Sass treat it as a list. This method works from Sass v3.3.0 onwards. (Tested at sassmeister.com with v3.4.21.)

@include header-titles(
    'fubar',
    $fubar-title-font-size,
    $fubar-title-text-color,
    $fubar-sub-title-font-size,
    $fubar-sub-title-text-color,
    ((margin, 50px 0 0 0),),((margin, 50px 0 0 0),)
)

When it is sent without that extra comma, it seems like the Sass compiler treats it as $title-extra is a list with two values where the first one is margin and the second one is 50px 0 0 0. The behavior is similar for the $sub-extra list also. This is what happens at sassmeister.com when I tried to output the individual values within the @each loop. Since the 1st value of $title-extra itself is just margin, the compiler is failing at the below line (within first iteration of @each loop) because there is no second value to pick using the nth.

/* $t-extra in 1st iteration is only margin and so nth($t-extra,2) reports error */
@include argument(nth($t-extra,1),nth($t-extra,2)); 
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download