Object-oriented LESS mixins
I’ve been using LESS for a few years now, and even with large swathes of time using SCSS, I still prefer LESS's simplified-and-yet-still-supremely-powerful design.
Throughout my experience with it, I’ve come up with a workflow that I thought was interesting to share that involves using LESS mixins a little bit like regular OOP classes.
Object orientation and class inheritance
Inspired by some recent ES6 class-based components I’ve been recently developing, I wanted to approach my LESS styles for building component styles with a similar object-oriented and extended mindset.
Using LESS’s features like Parametric Mixins, Mixins as Functions, and Passing Rulesets to Mixins (aka Detached Rulesets) I’ve come up with a methodology which borrows from object-oriented programming, only for LESS/CSS styles.
CSS already has a wide range of object-oriented programming concepts banded about (see OOCSS, Atomic Design/CSS, SMACSS and BEM, or this blog post on a site called Club Mate (mmm, yum) which explains the TL;DR of them all), but with using LESS I can also define and attach nested mixins and variables which I can import and use in other class definitions, or extend at various points (often in JS these are referred to as callbacks, but in less they're "detached rulesets") to add/customise more styles.
There’s potential I may have over-complicated something which doesn’t necessarily need to be, but I feel there’s some worth in my reusable and extensible LESS implementation for managing components’ multiple visual properties, states and the like from a template, which can then be customised and configured per related component or even per component instance.
One real-world example I’ve come up with in my ES6 JS component building (and how I came to this LESS workflow) is defining a Toggleable component and a Modal component. The Toggleable component controls if/when a component is visible, and the Modal component extends/inherits this behavior.
In ES6 JS it’s simple to make the extension of behaviour:
That effectively allows me to have all the toggleable properties and methods automatically assigned to the Modal. I like this because it allows me to compose new components with a mixture of various other “primitive” component properties and behaviours. My personal implementation is kind of inspired by my work with Ember and how they use mixins, and same with the Stamp spec. It’s all part of the good fight to keep one’s code DRY.
After the JS behaviours were implemented, the next issue to solve was on the styles side. I didn't want to just control visual state with embedded styles, since the functionality was simple enough to do via styles (and in the case of CSS animations/transitions, necessary anyway). While traditional front-end dev might be something like:
I wanted something with a little more heavy duty to use in the styles — to compose CSS classes from a combination of multiple components, like mixins/stamps — rather than combining the two component classes on the element in the HTML. The declarative multiple class assignment is great for simple things, but when you deal with responsive sites with ever shifting styles and functionality, the extra declared classes in the HTML can quickly become a liability.
With the above example, two classes isn’t really a problem, but if there were another component with more than two, and perhaps significant differences between a mobile and computer visuals/behaviours, managing the classes in the HTML can have its limitation.
Also when developing sites with third-party vendor front-end code, having their opinions significantly affect my own code and techniques really irks me a bit (I’m looking at you WordPress and WooCommerce), so this composable method means I can ship components with default styles whereby developers can customise and integrate more inline with their own hierarchy and class naming opinions and approaches.
I took the object-oriented approach and wanted to import a class into my LESS file to then control and extend specific parameters about the component’s visual state. For the Modal being hidden, I need it to be more than just display: none, and even on other Toggleable instances, when something is shown it might need to be display: block or display: inline-block, depending on the use case.
Using parametric mixins with LESS is the cool thing to do when building composable and extensible classes. You can define default values and also nest other mixins within, effectively namespacing and/or defining related methods within the mixin class.
LESS’s power with lazy loaded variables and block scoping helps too. Mixins can effectively be used as closures, but borrowing variable values as defaults defined further up the file. Using detached rulesets lets to import or set more styles. It’s like cut-and-paste collage! Super fun.
Here’s an example of how I might construct and structure my composable Toggleable mixin class:
Let me break down the above mixin class into some digestible pieces.
1. Mixin class definition and namespacing
Namespacing the composable mixin class with something like .ui-lvl99-toggleable is just my own personal convention (I usually use the ui prefix to denote classes which modify an element, but you do as you like). There’s the @ns parameter which enables me to configure the generated classes whenever I invoke this mixin.
Here’s some examples of how this mixin class could then be used within other class definitions:
2. Compile any variables using the namespace
Any extra parameters I have on my mixin will affect how the mixin and its related variables and states are initialised:
The variables at the top are initialised with the namespace variable, which means when I import the mixin class, those variables are preset and available for me to do anything with.
3. Nested class and state mixins
I then define the various states of my component using these generated variables (and any other parameters to customise base styles/behaviours), which I define as nested mixins with a detached ruleset parameter, so they can be invoked and extended in any other class definitions on a per-use basis.
The difference between the class and state mixins is that the class mixin assigns the visual properties like any other regular class, and the state mixin assigns that class mixin with any other modifications, such as using parent & selectors to ensure that class is assigned to the component.
Using the nested method .-toggleable-init-default means I can preset what the general component defaults will be and when I import the mixin class I can choose to apply the defaults, or I could use all the other preset nested variables and mixins to configure the styles for each state, or build extra styles. In the Toggleable’s case, it will assign the show and hide classes using the nested state mixins:
When broken down, it seems pretty basic and simple, really. I like the power of importing mixins into the scope so that one can generate and configure any variables and related classes/states. In real-world practice, my Toggleable component actually has a lot more to do with transitions, so it needs states controlling when the component is transitioning via showing and closing states, which are just extra class/state mixins that are also initialised in the .-toggleable-init-default mixin.
The power I gain is when I combine and extend with other component mixin classes, similar to the JS ES6 class inheritance… almost. I essentially import the inherited mixin classes into the new component mixin class definition. The modal mixin class might look something like this:
As you can see it is basic, since it only inherits the .ui-lvl99-toggleable defaults, but creating a specific default init nested mixin I can customise how the modal class initialises. In this case, it’s only loading the basic toggleable states, but should I need something more specific, it could be something like this:
So when using the above Modal mixin class, I could initialise a new modal CSS class in LESS which inherits the Toggleable variables/states like so:
Want to see the code in action? See a working example of the above on Codepen
In my experiments with LESS I’ve managed to build a workflow for mixin class inheritance. There are some minor drawbacks, but I’ve found with building sites with lots of components that share similar styles/behaviours, using this composable format with namespaced and nested mixins, variables and detached rulesets has given me some great control to initialise components with a boilerplate of styles, and given me various points in which I can construct and build “frankenstein” versions with ease.