Search code examples
lessmixins

LESS mixin: How to loop through passed in arguments


I usually write SASS, but for a particular project I have to use LESS.

How do I achieve something like the below using less? Using sass the mixin can be called like @include align(hcenter top) to position an element horizontally in the middle and to the top.

@mixin align($styles) {
  position: absolute;
  content: '';
  display: block;

  @each $style in $styles {

      @if ($style == center) {
          margin-left: auto;
          margin-right: auto;
          margin-top: auto;
          margin-bottom: auto;
          left: 0;
          right: 0;
          top: 0;
          bottom: 0;
      }
      @if ($style == hcenter) {
          margin-left: auto;
          margin-right: auto;
          left: 0;
          right: 0;
      }
      @if ($style == vcenter) {
          margin-top: auto;
          margin-bottom: auto;
          top: 0;
          bottom: 0;
      }
      @if ($style == top) {
          top: 0;
      }
      @if ($style == bottom) {
          bottom: 0;
      }
      @if ($style == right) {
          right: 0;
      }
      @if ($style == left) {
          left: 0;
      }

    }

}

Solution

  • See Mixin Arguments, List Functions and Loops.

    With a thing like "for" the snippet can be converted to something like:

    @import "loops/for";
    
    #usage {
        .align(hcenter, top, bottom, etc);
    }
    
    .align(@styles...) {
        position: absolute;
        content:  '';
        display:  block;
    
        .for(@styles); .-each(@style) {
            & when (@style = center) {
                margin-left:   auto;
                margin-right:  auto;
                margin-top:    auto;
                margin-bottom: auto;
                left:   0;
                right:  0;
                top:    0;
                bottom: 0;
            }
            & when (@style = hcenter) {
                margin-left:   auto;
                margin-right:  auto;
                left:   0;
                right:  0;
            }
            & when (@style = vcenter) {
                margin-top:    auto;
                margin-bottom: auto;
                top:    0;
                bottom: 0;
            }
            & when (@style = top) {
                top:    0;
            }
            & when (@style = bottom) {
                bottom: 0;
            }
            & when (@style = right) {
                right:  0;
            }
            & when (@style = left) {
                left:   0;
            }
        }
    }
    

    ---

    Actually above code can be optimized to more compact:

    .align(@styles...) {
        position: absolute;
        content:  '';
        display:  block;
    
        .center(@pos) {
            margin-@{pos}: auto;
            @{pos}: 0;
        }
    
        .for(@styles);
            .-each(center)  {.-each(hcenter); .-each(vcenter)}
            .-each(hcenter) {.center(left); .center(right)}
            .-each(vcenter) {.center(top); .center(bottom)}
            .-each(@style)  when (default()) {@{style}: 0}
    }
    

    Though this way it may look more confusing for one not too familiar with Less.