So after reading my post about hickups with the infinite theme inheritance feature in Magento 1.9 you decide to give it a try. You want to use the rwd/default theme as a base and just add some new fancy CSS, so that the site is in accordance with your corporate design. But then you realise that your CSS file is rendered as the first CSS file, so that all your changes are overridden by the CSS files of the parent theme. Why is this the case? How can you solve this? Read on.
So we put our child theme under rwd/mychild and define an etc/theme.xml where we define the parent theme as well as a layout update file:
<?xml version="1.0"?> <theme> <parent>rwd/default</parent> <layout> <updates> <mychild_default> <file>mychild/default.xml</file> </mychild_default> </updates> </layout> </theme>
In the mychild/default.xml, we simply add a new CSS file:
<?xml version="1.0"?> <layout version="0.1.0"> <default> <reference name="head"> <action method="addItem"> <type>skin_css</type> <name>css/mychild.css</name> </action> </reference> </default> </layout>
So where is the CSS file now rendered? We would of course like it to be the last CSS file which is included, because we want to change the parent theme’s CSS. But you know what happens? It is rendered as the first CSS file. Hence, all our changes are overridden by the parent’s CSS files, because they are loaded after our child CSS file. CSS’s !important for the win. Not a good solution. So what the heck is happening here? Analysing how rwd/default adds the CSS files, something catched my eyes. They use CSS conditional comments to include their stylesheets. For instance:
<action method="addItem"> <type>skin_css</type> <name>css/madisonisland.css</name> <params/> <if><![CDATA[<!--[if (gte IE 9) | (IEMobile)]><!-->]]></if> </action>
So could this be the reason? Let us give it a try in our mychild/layout/mychild/default.xml:
<?xml version="1.0"?> <layout version="0.1.0"> <default> <reference name="head"> <action method="addItem"> <type>skin_css</type> <name>css/mychild.css</name> <params/> <if><![CDATA[<!--[if (gte IE 9) | (IEMobile)]><!-->]]></if> </action> </reference> </default> </layout>
Guess what happens? Yes, indeed, our CSS file is now loaded at the very last position. But we want that our CSS file is loaded in every browser, even in older IEs. We do not want to use any condition. Well, then we can use this little workaround here:
<action method="addItem"> <type>skin_css</type> <name>css/mychild.css</name> <params/> <if><![CDATA[<!--><!-->]]></if> </action>
Our CSS file is now included after all parent CSS files like this:
<!--><!--> <link rel="stylesheet" type="text/css" href="http://magento190.local/skin/frontend/rwd/mychild/css/mychild.css" media="all" /> <!--<![endif]-->
It has some empty conditional comments around it, but that should not be a problem. „Normal“ browsers will ignore them anyway and older IEs should include the file, because we did not define any condition. Problem solved.
So why does this happen? The crucial point is line 177 of Mage_Page_Block_Html_Head:
$lines[$if][$item['type']][$params][$item['name']] = $item['name'];
Here, the skin CSS files are grouped by their if condition. If our CSS file does not have any if condition, it comes into the first group with an empty if. This group is also rendered first. Whereas the rwd/default CSS files come into another group which is rendered at a later point. With our workaround with an empty if condition, our CSS file comes into yet another group which is then rendered at the last point.
4 Gedanken zu „Magento 1.9 Infinite Theme Inheritance: Child CSS Not Rendered Last“
Danke sehr. Das hat mir wirklich geholfen Magento besser zu verstehen.
(I used google translate so I hope my meaning comes through)
Wouldn’t every other modification in the child’s `mychild/default.xml` file also load before the parent’s layout file?
No. The layout XML file is indeed processed after the parent’s layout files. The reason why the parent’s CSS is rendered later are just the conditional comments.