Passing Rulesets To Mixins In Less CSS

Recently, I've been making a concerted effort to actually learn more about Less CSS - the CSS preprocessor. As I was reading through the documentation, I came across the ability to pass rulesets to mixins where they could be evaluated. I was having trouble wrapping my head around the concept, so I thought I would play around. My first thought was to try and treat the ruleset like a block in Ruby that could be used to iterate over a list of items.

NOTE: I am not sure if I am using the term "block" correctly; I am not a Ruby developer - don't tase me, bro.

Given a list of elements, I wanted to see if I could generate a CSS class for each item in the list. Furthermore, I wanted to see if I could generate AngularJS-inspired iteration variables like @first, @last, and @mid. In the end, this actually ended up being a really cool challenge because it touched on a number of Less CSS features:

To do this, I created a mixin, .list-loop, which takes a list and a ruleset. It then iterates over the loop [recursively] and "invokes" the ruleset for each item in the list. During the iteration, I'm making the @{it} variable point to the current item in the iteration. This value is then being used, inside the ruleset (thanks to scoping), to dynamically generate class names and properties in the resultant CSS.

// I loop over the given list and apply the given ruleset on each iteration. During

// the iteration, the loop context provides several variables:

// --

// @it - the current item of iteration.

// @index - the current iteration index.

// @length - the length of the list being iterated.

// @first - is true on the first iteration of the loop.

// @last - is true on the last iteration of the loop.

// @mid - is true when the iteration is neither first nor last.

// --

.list-loop( @list ; @ruleset ) {

@length: length( @list ) ;

// Initiate the loop.

.looper( 1 ) ;

// I am the recursive portion of the loop.

.looper( @index ) when ( @index <= @length ) {

// Set the current value of the iteration.

@it: extract( @list, @index ) ;

// Set values that the rules can used for context.

// --

// NOTE: This is using JavaScript since LESS doesn't seem to allow me to set

// the result of an equality check.

@first: `( @{index} == 1 )` ;

@last: `( @{index} == @{length} )` ;

@mid: `! ( @{first} || @{last} )` ;

// Invoke the given ruleset.

// --

// CAUTION: All variables defined in this set of mixins will be made

// available to the scope of the ruleset when it is evaluated.

@ruleset();

// Call recursively for next iteration.

.looper( @index + 1 ) ;

}

}

// ---------------------------------------------------------- //

// ---------------------------------------------------------- //

// When looping over the list, @{it} contains the current item in the iteration.

// The ruleset will then be "invoked" for each value of @{it}.

.list-loop(

alpha, beta, theta, omega ;

{

span.@{it} {

background-position: ( ( @index - 1 ) * 50px ) 0px ;

content: "@{it} is the awesome" ;

& when ( @first ) {

border-top: 0px ;

}

& when ( @last ) {

border-bottom: 0px ;

}

}

}

);

As you can see, I'm using variable interpolation to generate the class names and the "content" property. When we compile the above Less CSS, we get the following CSS output:

span.alpha {

background-position: 0px 0px;

content: "alpha is the awesome";

border-top: 0px ;

}

span.beta {

background-position: 50px 0px;

content: "beta is the awesome";

}

span.theta {

background-position: 100px 0px;

content: "theta is the awesome";

}

span.omega {

background-position: 150px 0px;

content: "omega is the awesome";

border-bottom: 0px ;

}

While I was able to the @first and @last variables to dynamically add CSS properties, I'm not sure it really makes any sense in this context; but, like I said, I'm just trying to learn more about the Less CSS preprocessor. Since Less CSS tries really hard to look like normal CSS, the syntax is a bit ... odd; but, it seems to be pretty powerful.

Reader Comments

Note: In the video, I stated that I thought the mixin variables were available in the ruleset since the ruleset was running in the context of the mixin. I think that was incorrect. According to the docs, any variables defined in the mixin are simply available in the calling context:

> All variables defined in a mixin are visible and can be used in caller's scope (unless the caller defines its own variable with the same name).

I believe *this* is why the @first, @last, and so-on, are available in the ruleset. But, I am not 100% sure.

I really appreciate that! I've been using LESS fairly "lightly" for the last 2 years. By lightly, I mean that I've basically been using the nesting capabilities and some Bootstrap mixins. That said, even that usage has been a **game changer**. CSS preprocessing is just awesome! And you can tell that it's so awesome because it's taken me 2 years of light use before I even felt the real desire to dig deeper. Even the simple stuff makes such a huge difference.

Grunt is one of the things I gotta check out as well; and Gulp. I hear great stuff about that. The whole "build" ecosystem is relatively new. I only really got into Less because there are apps that do it for you (ie, LiveReload, Less.app, CodeKit, etc).

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments

Live in the Now

Oops!

Name:

Email:

( I keep this private )

Website:

Comment:

Subscribe to comments.

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please
do not post unrelated questions or
large chunks of code. And, above all, please be nice to each other - we're trying to
have a good conversation here.