Less And UI Framework

Concepts

Separate Stylesheets

Magento 2 LESS compilation works differently to most platforms in that it generates two CSS output files instead of one.

1
2
<link rel="stylesheet" type="text/css" media="all" href="http://example.com/static/version1573393649/frontend/Magento/luma/en_US/css/styles-m.css" />
<link rel="stylesheet" type="text/css" media="screen and (min-width: 768px)" href="http://example.com/static/version1573393649/frontend/Magento/luma/en_US/css/styles-l.css" />

Note the media attribute on the link element for styles-l. This means that all devices will load styles-m (mobile) and only devices that have a minimum horizontal resolution of 768 pixels will load styles-l.

It is important to be aware of this as it is important that this optimisation is taken advantage of as much possible. Magento by default works in a mobile first approach when creating stylesheets and this should be adopted when working with Magento 2.

Practices

It is strongly advised that styling changes (in modules and themes) conform to the standard Magento 2 style rules.

https://devdocs.magento.com/guides/v2.3/coding-standards/code-standard-less.html

Whilst not explicitly stated in the guidelines, it is clear that Magento 2 use the BEM methodology when writing stylesheets. Here is an example of BEM being used in Magento 2.

There are different flavours of BEM (block element modifier) in the wild.

More information Bem documentation Preprocessors and BEM

Tooling

Magento 2 uses Grunt by default when working in a development environment, it allows for much faster iterations when making changes To use Grunt, you must have Node and NPM installed in your development environment and all project dependencies installed.

Before this you'll need to install bzip2

1
2
sudo bash
yum install bzip2

Before Grunt will work, you will need to install and configure it for your theme

Commands

Grunt has a number of commands available to use, unfortunately at the time of writing Magento have not listed all the available commands and sufficient documentation.

All commands listed are prefixed with grunt <command-name>. Where available, the official Magento 2 description is used, different usage variants are comma separated. To see a full list of available Grunt commands, use grunt -h.

Command Usage Description Notes
clean clean Removes the theme related static files in the pub/static and var directories. This will remove all files related to the themes and is not useful on it's own
exec exec,
exec:<theme_name>
Republishes symlinks to the source files to the pub/static/frontend/ directory. Use grunt exec: to republish symlinks for a specific theme. This will create the symlinks required for less compilation to work, if you have created a new LESS file you will need to re-run this or it will not be compiled. Extra files such as fonts and images will not be published.
less less,
less:<theme_name>
Compiles CSS files using the symlinks published in the pub/static/frontend/ directory. Use grunt less: to use the symlinks published for a specific theme. Performs a single LESS compilation
watch watch,
watch:<theme_name>
Tracks the changes in the source files, recompiles .css files, and reloads the page in the browser. When first run, it does not compile CSS until a change is detected. Browsers will not update automatically if you use a container for development such as LXC or Docker
refresh refresh,
refresh:<theme_name>
Is a combination of clean and exec, this will ensure your symlinks are present for LESS compilation.

It is important to note that when you republish your theme symlinks that you will be missing fonts, images and other assets required for your theme. To get around this, static-content deploy can be used with some extra flags to ensure the content is available.

The following is a simple bash script that can be used instead of exec and refresh when developing your theme.

1
2
3
grunt refresh:mytheme;
php bin/magento setup:static-content:deploy --no-less --no-css -j 4 en_GB en_US -a frontend;
php bin/magento setup:static-content:deploy -a adminhtml en_GB en_US

This snippet will run the refresh command for mytheme and then re-deploy static content for non CSS/LESS changes. All fonts, images or other assets should then remain and be visible when developing the theme.

Common Rules

As mentioned before, Magento 2 splits all rules between a large and mobile stylesheet (styles-m and styles-l). The large stylesheet is only loaded by the Browser if the device being used meets the minimum horizontal resolution.

When writing rules, it is important to try and distinguish which rules can be applied to both mobile and large devices. This is important because we can optimise the LESS compilation to only include the styles necessary for mobile devices and leave the remaining rules in the large spreadsheet. This reduces the download size of the mobile spreadsheet to only include the required styles and as a result - improves download time of the stylesheet and rendering time.

When rules can be applied to both types of devices, you need to wrap the rules with media-common.

1
2
3
4
5
& when (@media-common = true)
{
    // Rules that are shared (common) between mobile and desktop
    // ...
}

This forces the rules inside the statement to only be placed in styles-m which will be loaded by both desktop and mobile.

Media Query Breakpoints

Breakpoints (media queries) are used in CSS to declare styling rules that are specific to different devices or contexts. For example to target mobile, tablet and desktop devices independently.

Magento 2 expands upon this by placing the contents of media queries into either the styles-m or styles-l stylesheets depending on their conditions.

For examples, rules declared to only apply to screen widges in excess of 768px will be places in styles-l and not styles-m. This is done by the use of Mixin Guards.

To use Magento's breakpoint system you need to use the .media-width mixin.

1
2
3
4
5
6
//
//  Medium Desktop
//  _____________________________________________
.media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) {
    // Rules specific to devices larger than 768px horizontally will apply from here
}

The @extremum parameter is either min or max strings followed by the desired targeted breakpoint @break.

When specifying the breakpoint, it is important to only use the predefined breakpoints. The breakpoints are defined in lib/web/css/source/lib/variables/_responsive.less

Note that this is a core file and should not be edited and it is also strongly discouraged to override the breakpoints unless absolutely necessary. Any changes to the LESS files within lib are liable to be overwritten when Magento is updated to a newer version.