13

In the Magento 2 DevDoc it says

To include a CSS file, add the <css src="<path>/<file>" media="print|<option>"/> block in <head> section in a layout file.

However it doesn't say how we can influence the order of our CSS files. And if we add CSS files this way in a custom theme which has a parent theme the result is that the files are added quite at the top of the <head> section with a lot of other CSS files below them, meaning their priority is quite low and we cannot easily override rules from the parent theme or extensions.

There were similar problems in Magento 1 and there were workarounds. Some were more clean others less.
What is the best way to order a CSS file of a custom theme at the bottom of <head> in Magento 2 - if possible complying the Magento 2 layout guidelines for custom themes?

13

Magento2 has no built-in mechanism for this so I decided to treat it as an opportunity to write my first Magento2 extension. The Quickshiftin\Assetorderer extension is now available on GitHub!

Once you have the extension installed you can specify an order attribute in your css XML tags.

<head>
  <css src="css/page/home.css" order="100"/>
</head>

You can also use the order attribute in layout XML files such as default_head_blocks.xml. Any css tags you don't specify an order for are treated as if they have an order of 1.

  • Many thanks. Your extension worked for me. But faced two issues one in di.xml and one in Quickshiftin\Assetorderer\View\Asset\File class. – Pankaj Pareek May 24 '16 at 9:27
  • Hi @PankajPareek, that's good news and bad. Any chance you can elaborate on GitHub and possibly contribute a pull request? It would be nice to make the extension useful for everyone! – quickshiftin May 24 '16 at 12:52
  • @quickshiftin This extension worked in v2.0, but not v2.1.1. However, I found out by chance that it's no longer required in v2.1.1 because when I add order="1" the file gets ordered correctly. It doesn't matter what the attribute is as long as you add an extra attribute. To make it validate, you can change it to data-order="1" and it would still work. – thdoan Oct 17 '16 at 7:19
  • order work for js file also. – Jalpesh Patel Sep 5 '17 at 6:19
  • @quickshiftin have you updated your module for the M2.2.2 – PЯINCƏ Apr 19 '18 at 10:52
7

You can add the media attribute to the css element. This will add it to the end of all the included CSS in the head.

<head>
    <css src="css/styles.css" media="all" />
</head>
  • What if I want it first? – TheBlackBenzKid Feb 21 '17 at 9:52
  • This will still load custom CSS before main magento 2 core CSS files :( – Jonathan Marzullo Oct 11 '17 at 17:15
  • As of M2.2.1 it is the only solution that worked for me. Adding 'order="X"' to the <css> node throw an error as this attribute is not allowed. – Dynomite Mar 30 '18 at 19:23
2

I answered in detail here about how magento renders css and how the ordering is happening behind the scene.

Some extra points I need to mention here is:

  1. If you want to render your custom css file after style-m.css and stlyle-l.css, then you need to define your css file like below:

    <css src="Magento_Theme:css/path/file.css" media="all" />
    
  2. If you want to load your custom css file before style-m.css and stlyle-l.css, then you need to include your css file through the layout xml file default_head_blocks.xml and add your custom css file above style-m.css and stlyle-l.css.

  3. CSS properties are finite and are well defined in the layout schema. According to the layout schema, you can use following properties in your css file.

    File: vendor/magento/framework/View/Layout/etc/head.xsd

    <xs:complexType name="linkType">
        <xs:attribute name="src" type="xs:string" use="required"/>
        <xs:attribute name="defer" type="xs:string"/>
        <xs:attribute name="ie_condition" type="xs:string"/>
        <xs:attribute name="charset" type="xs:string"/>
        <xs:attribute name="hreflang" type="xs:string"/>
        <xs:attribute name="media" type="xs:string"/>
        <xs:attribute name="rel" type="xs:string"/>
        <xs:attribute name="rev" type="xs:string"/>
        <xs:attribute name="sizes" type="xs:string"/>
        <xs:attribute name="target" type="xs:string"/>
        <xs:attribute name="type" type="xs:string"/>
        <xs:attribute name="src_type" type="xs:string"/>
    </xs:complexType>
    

    This simply means you cannot use order or any other properties along with css definition in your layout xml file. By doing so, you will get an exception which indicates schema validation fails.

1

You can make your CSS rules more or less important than the core CSS rules by adding or removing additional parent selectors.
For example, let's see a sample CSS rule in the core:

.cart.table-wrapper .item .col.item {
    padding: 20px 8px 20px 0;
}

You can make your custom rule more important by adding a parent selector, for example:

body .cart.table-wrapper .item .col.item {
    padding: 10px 8px 20px 0;
}

or

body .cart.table-wrapper .item td.col.item {
    padding: 10px 8px 20px 0;
}

You can make your custom rule less important by removing a parent selector, for example:

.item td.col.item {
    padding: 30px 8px 20px 0;
}
  • 3
    Sure and I also could simply smack down !important (but of course your approach is still better than that) or implement a vendor prefix class with LESS. Still this adds unnecessary overhead and complexity. Why prefixing hundreds or more rules when a simple order change of the CSS would do it? So I'm still looking for a good way to solve this on the Magento side... – Jey DWork Dec 24 '15 at 15:18
  • Besides when it comes to other resources than CSS positioning might get even more important as workarounds could get even uglier. – Jey DWork Dec 24 '15 at 15:21
  • 6
    That's not an answer – Ahmad Alfy Mar 17 '16 at 14:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.