Creating a versatile SASS mixin with the ability to utilize both optional and variable parameters

Is it possible to include both optional and variable elements in a sass mixin?

I have attempted the following:

@mixin name($className,  $centered: false, $dimension...)

however, the first dimension value is wrongly assigned to $centered.

Switching the parameters order results in compilation errors:

@mixin name($className, $dimension..., $centered: false )

The error message reads:

SASSInvalid CSS after "..., $dimension...": expected ")", was ", $centered: fa..."

Given that the mixin without the optional parameter is extensively used (over 70 times), I am reluctant to modify it entirely to accommodate the new parameters. Is there a way to retain the optionality of this mixin? Or do I need to create a separate override with the new parameter?

For reference, here is the body of the mixin:

    @for $i from 1 through length($dimension){                              
        @if($centered) {
            .#{$className}Td#{$i}, .#{$className}Th#{$i}  { 
                width: nth($dimension, $i); 
                text-align:center;
            }
        }
        @else{
            .#{$className}Td#{$i}, .#{$className}Th#{$i} {width: nth($dimension, $i); }
        }
    }

EDIT with complete cooking example:

Essentially, I am defining CSS for column widths of my table more efficiently. When using the mixin like this:

@include nome("columnsName", 40%, 30%, 30%);

The output will be:

.columnsNameTd1, .columnsNameTh1{width: 40%;}

.columnsNameTd2, .columnsNameTh2{ width: 30%; }

.columnsNameTd3, .columnsNameTh3{ width: 30%;}

I am interested in finding a way to center align all columns or specific ones while keeping others left-aligned by default.

Answer №1

It is not possible to achieve what you are requesting because variable arguments (indicated by the ... syntax) must always be placed at the end. There are two solutions available, with option #2 being the recommended approach.

Solution 1 (check if the last element is a boolean):

@mixin name($className, $dimension...) {
    $last: nth($dimension, length($dimension));
    $centered: if(type-of($last) == bool, $last, false);
    $length: if(type-of($last) == bool, length($dimension) - 1, length($dimension));

    @for $i from 1 through $length {
        .#{$className}Td#{$i}, .#{$className}Th#{$i} {
            width: nth($dimension, $i);
            @if($centered) {
                text-align: center;
            }
        }
    }
}

Solution 2 (utilize the @content directive):

@mixin name($className, $dimension...) {
    @for $i from 1 through length($dimension) {
        .#{$className}Td#{$i}, .#{$className}Th#{$i} {
            width: nth($dimension, $i);
            @content;
        }
    }
}

// example of usage
@include name(rar, 10%, 20%, 30%);

@include name(rar, 10%, 20%, 30%) {
    text-align: center;
}

Answer №2

Alright, consider testing the final value in your list because it appears that sass does not accept anything beyond a list as a parameter.

@function last($list) {
  @return nth($list, length($list));
}
//This function returns the last item in a list

@mixin nome($className, $dimension...) {
    @for $i from 1 through length($dimension){
        @if(last($dimension) == true) {
            .#{$className}Td#{$i}, .#{$className}Th#{$i}  {
                width: nth($dimension, $i);
                text-align:center;
            }
        }
        @else{
            .#{$className}Td#{$i}, .#{$className}Th#{$i} {width: nth($dimension, $i); }
        }
    }
}

If you use

@include nome("className", 4%, 4%, 4%, 6%, 70%, 12%, true);
and set the last value to true, it should align your div center or achieve whatever effect you are aiming for!

Answer №3

There is a neat trick in Sass known as Arbitrary Keyword Arguments that allows for some interesting possibilities. By passing a keyword argument alongside your other variable arguments, you can then extract and manipulate it using the meta.keywords($args) function.

To better understand this concept, here is a simplified example showcasing how it can be implemented:

@use "sass:map";
@use "sass:meta";

@mixin demo($class-name, $values...) {
    $special: map.get(meta.keywords($values), special) or false;
    $i: 1;
    @each $value in $values {
        .#{$class-name}-#{$i} {
            property: $value;
            @if $special {
                additional-property: value;
            }
        }
        $i: $i + 1;
    }
}

Example outputs:

@include demo("test", 50%, 25%, 25%);
// .test-1 {property: 50%;}
// .test-2 {property: 25%;}
// .test-3 {property: 25%;}

@include demo("demo", 50%, 25%, 25%, $special: true);
// .demo-1 {property: 50%; additional-property: value;}
// .demo-2 {property: 25%; additional-property: value;}
// .demo-3 {property: 25%; additional-property: value;}

The real magic lies in how you handle the keyword argument within the mixin, like the manipulation of $special. It might seem unconventional at first glance, but it's definitely a useful technique to have in your toolkit!

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What could be causing the background image on my Jumbotron to fail to load?

Having some trouble with setting my image as the background of the Jumbotron. I've tried a few different approaches, but none seem to be working. It's not an issue with static loading because using img src directly into the Jumbotron section does ...

Incorporate a Fadein effect into the current CSS for mouseover link interaction

Is there a way to enhance my current css code for a mouseover link with a background image by adding a fade in and out effect? What's the most effective method to achieve this using jquery? .sendB { width: 100%; height: 125px; background: ...

Navigation menu automatically scrolls to the top instantaneously

Update: Apologies for the previous issues encountered with offline hosting. Upon transferring everything to the domain, the problem has been resolved. However, a lingering question remains about why the website loaded incorrectly when all files were kept i ...

Display the Bootstrap datetimepicker within a div when hovering the mouse over it

Encountering an issue with the datetimepicker functionality in Bootstrap. There is a table with a list of items, each column having an input field for searching through the data. Specifically, I need to search within a date range for the "creationDate" fie ...

Customize Tab indicator styling in Material-UI

Currently, I am attempting to customize the MUI tab by changing the indicator from a line to a background color. Through my research, I discovered that using TabIndicatorProps and setting a style of display:none eliminates the indicator completely. However ...

How to target the last child in Flexbox using CSS order property

Is there a way to correctly detect the last child after rearranging divs using flex order? Even though I have set the order in the CSS, it is still recognizing the last child based on the DOM tree. Since the items are dynamic, we can't rely on nth-chi ...

Tips for updating the content of a div with the click of another div

Is there a way to dynamically change the content of a div upon clicking on a menu item? Here is the current layout for reference: https://i.stack.imgur.com/nOnlQ.png Below is the CSS and HTML code snippet: body { background-color: #555657; ...

Bootstrap Modal closing problem

While working on a bootstrap modal, I encountered an issue where the modal contains two buttons - one for printing the content and another for closing the modal. Here is the code snippet for the modal in my aspx page: <div class="modal fade" id="myMod ...

Vue: the placeholder option in the select input is no longer visible once v-model is added

<select class="cursoruser-pointer p-2 w-full rounded-full "> <option class="rounded-full " disabled selected value="">Language to learn</option> <option class="rounded-ful ...

Differences in background-size among various browsers

Having some trouble with scaling backgrounds on different browsers. Initially designed website on Google Chrome, but background doesn't scale properly when viewed on iPhone or older versions of IE. Started with: background-size: 100% 150%; Then c ...

CSS float layout for arranging boxes of varying sizes

I am having trouble organizing this layout with CSS and using floats on the divs. The layout consists of standard sized boxes, a large box, and a tall box. Here is the link to the jsfiddle for reference. Here is the markup I am working with - <head> ...

Images with fadeIn-Out effect on a slide restrict the movement of the div

I am currently working on a project where I have a div named "background" containing 4 images (400x300px) that fade in and out in a row every x seconds. The issue I am facing is that these images are displaying on the top-left of the browser, and I am tr ...

How come my script that is dependent on the viewport does not apply classes?

I created a code to add a class to a div, but it's not working as expected. I need help troubleshooting this issue. The code works fine on codePen, but not on my WordPress website. How can I make sure the browser executes this code properly? Link to ...

How to vertically align a div inside another div

My Goal: Ensuring that the divs with "col-md-1" (the vote total and vote arrows) are vertically aligned in the center of the parent div HTML Structure: <div class="row container-fluid"> <div class="col-md-1 centered-div"> <p id ...

Tips for positioning a Div element in the center of a page with a full-page background

I am trying to center align my div containing login information on the webpage. The static values seem to work fine, but I am looking for a way to position it dynamically. Additionally, the background is only covering a strip with the height of the div... ...

Creating a Vertical Stack of Three Divs in ReactJS

Just Getting Started: As a newcomer to ReactJS and web development in general, I've put effort into researching my question without success. I acknowledge that the solution might be simpler than I think, so I apologize in advance if it turns out to b ...

Alter the design when the height of a div is adjusted

On my webpage, I have multiple divs displayed in a masonry layout. The masonry effect works smoothly, but I am facing an issue with the divs expanding in height when users leave comments. The masonry layout does not automatically adjust to accommodate the ...

Guide for reducing the size of the menu upon hovering over a link with jquery

I have a code that I'm using and I want to make the tabs in the navigation bar shrink when I hover over them, similar to how it works on apple.com. When you click on the search bar on Apple's site, the other tabs shrink. How can I implement this ...

Using CSS with absolute positioning and dynamic height

There are 4 consecutive <div> tags in absolute position, aligned using top and left. The third div tag has dynamic content, causing its height to adjust based on the text within it. However, since the top and left properties are set for all divs, th ...

Developing a vertical accordion menu with AngularJS

Looking to create a sleek vertical accordion menu using a combination of angularjs, jquery, and css. If anyone has expertise in this area, I would greatly appreciate some guidance on how to integrate these technologies seamlessly. Your assistance is much ...