Magento 2 – How to Override LESS in Custom Theme

lessmagento2theme

I've spent the better part of this week trying to find a clear guide on how to properly create a custom theme and extend exist LESS/CSS without having to copy the entire magento-blank theme.

The official documentation gives basics on overriding variables, but that has limited uses. Existing guides, like Sonassi's for example, appear to based on a beta release of Magento 2.

Coming from Magento 1, there was a bit of a learning curve figuring out how LESS works, and how Magento collects all the files into CSS. It took me a while to dig through pieces of guides and get a clear answer of which files to modify and when and I thought I would share what I found so future users (and future me) could have get a quick start on using LESS in Magento 2.

Best Answer

Note 1: This will always assume you are extending magento-blank.

Note 2: <theme-dir> is app/design/frontend/Vendor/theme/

The basics: Changing Base Variables

(for tl;dr, skip to conclusion)

Most guides I found only cover this step in theming with LESS, so I will try to keep this short. Magento 2 has a base set of Variables that define commonly used aspects of a theme. Colors, fonts, style of page titles, and so on are defined in these variables.

In <magento-root>/lib/web/css/source/lib/variables/ you will find a number of intuitively named LESS files. In each of these you can find values assigned to variables for many of the common elements in Magento 2.

To change any of these variables, simply create a file in <theme-dir>/web/css/source/_theme.less. Example:

@newPrimary: #1980fe;
@primary__color: @newPrimary;


@link__color: @newPrimary;
@link__visited__color: lighten(@link__color, 10%);

Technically, you can put any CSS or LESS in here, and it will successfully apply to your site (but don't do this). I will explain how this works in a moment.

Adding new CSS file

You can add new CSS to the head of all your template pages.

Create <theme-dir>/Magento_Theme/layout/default_head_blocks.xml:

<?xml version="1.0"?>
    <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
        <head>
            <css src="css/myStyle.css" />
        </head>
    </page>

And then you create a file with your new CSS or LESS:

<theme-dir>/web/css/myStyle.less. You can write LESS or CSS here.

Overriding Existing Styles

I found that Magento 2 LESS is not easily superseded by simply adding a new CSS file. And this is where I began to get lost, and I will explain how Magento 2 finds its LESS files.

By default, Magento 2 will includes (and ultimately falls back to) these files:

<Magento_Blank_theme_dir>/web/css/styles-m.less //Mobile Styles
<Magento_Blank_theme_dir>/web/css/styles-l.less //Desktop enhancements
<Magento_Blank_theme_dir>/web/css/print.less //Print Styles

These files include (import) other LESS files, which often include even more LESS files. And this is where other guides became unhelpful to me and I will explain what I found, as best I could.

The source/lib Magic

In styles-m.less, there is the line: @import 'source/lib/_responsive.less';. You'll notice that there is no source/lib directory in the magento-blank theme. It's evident that Magento 2 styles ultimately fall back to <magento-root>/lib/web/css/. It's there you find source/lib/_responsive.less.

The variables you use in _theme.less are available because of a source/lib file imported in the magento-blank theme. Note: _theme.less is an empty file in the default themes. Continue reading to learn why this is important to note.

"Automatically included" LESS files

A few guides I found insisted that you can create <theme-dir>/web/css/_styles.less because Magento automatically looks for, and includes, that file. I found this to be bad advice.

If you create <theme-dir>/web/css/_styles.less, your site will break. theme-frontend-blank/web/css/styles-m.less imports _styles.less, which in turn imports 3 more .less files, which each import even more .less files.

If you create a _styles.less, you are overriding it. By overriding _styles.less, you are overriding all the files it imports, and all the files those files import, and so on.

Note about _theme.less: This file is empty in default themes, and therefore is safe to simply create and start adding to if you are basing your theme on a default. However, if you are extending a theme that already extends a default, chances are _theme.less is already used. Creating that again will override it.

The magical @magento_import

In styles-m.less you will see a couple of commented out lines:

//@magento_import 'source/_module.less'; // Theme modules
//@magento_import 'source/_widgets.less'; // Theme widgets

These lines not actually commented out! Magento 2 has special handling for lines that start with //@magento_import. These lines can only be included in files at <theme-dir>/web/css.

The lines above instruct Magento 2 to include any file within the theme that follows the given pattern. So the above lines will automatically include:

'<theme-dir>/Magento_Catalog/web/css/source/_widgets.less';
'<theme-dir>/Magento_Catalog/web/css/source/_module.less';

'<theme-dir>/Magento_Cms/web/css/source/_widgets.less';
'<theme-dir>/Magento_Cms/web/css/source/_module.less';

'<theme-dir>/Magento_Reports/web/css/source/_widgets.less';
'<theme-dir>/Magento_Reports/web/css/source/_module.less';
...and so on

Adding files names _widgets.less and _module.less will be automatically found and included, even if its a new module or a module that doesn't already have that file.

Be aware that Magento-Blank includes those files for most Modules, and if you want to use this method, you will need to copy-paste the originals (unless you're doing a complete re-write).

Conclusion

(Read: don't use _styles.less).

When you're looking to change the CSS of an element, you want to do the best you can to find what file that style is defined in. Sometimes all you need to do is change a variable in _theme.less. Most times, I suspect, you will simply need to copy-paste the _module.less or _widgets.less into your theme and make the changes.

If you've created a new module, or have new HTML elements, you may need to create a LESS file and have it separately included in the <head> of every page.

In complicated cases, you may need to create a new @import or @magento_import. You want to find the lowest child that makes sense for what you're doing, so you're not copy-pasting a bunch of unnecessary files or adding confusing @import lines that appear to lead nowhere.