PR for the order of merged stylesheets issue #24


#1

Also see issue #24

I’m putting together a PR for a feature to allow the merged CSS stylesheets to be placed somewhere other than the top of the <head> block. The problem with the current implementation (merged CSS goes at the top) is that if you use something like Bootstrap than any Bootstrap CSS overrides you might have (which are in the merged CSS bundle) get clobbered when Bootstrap is loaded. The fix seems straight-forward enough (just swap the load order) but I need to resolve exactly what this feature looks like. There are 3 competing options:

  1. Move the CSS bundle to the end of the head. PROS: Solves the general problem, trivial to implement. CONS: Are there any cases where this will break existing apps?

  2. Use a “component” tag such as <cssbundleatbottom> as a flag to put the CSS bundle at the bottom. If not present, CSS bundle goes at the top. PROS: maintains backward compatibility, relatively easy to implement, can be placed anywhere in the head CONS: Less flexible than option 3.

  3. Use <link rel="stylesheet" href="meteor_merged_css" /> to indicate where in the head to place the CSS bundle. Could instead use a “component” tag such as <putcsshere>. If not present, then place it at the top to be compatible. PROS: Completely flexible for all use cases, maintains backward compatibility. CONS: Somewhat complex to implement, I don’t actually see a use case for this much flexibility as opposed to option 2, but someone might.

I have working (but ugly) versions of all 3 options already coded. If you have a preference or any other suggestions, please leave a comment here or on issue #24. If there isn’t a consensus by Feb 10th, I’m going to go with option 3 since it is the most flexible.


#2

Hm. I personally think that if loading order of CSS files matters, your CSS code is messed up. It is the purpose of the “cascading” part in CSS that you can override your styles as needed, your styles just have to be specific enough.

The simplest solution to achieve this is to add a style class to your <html> tag like this:

<html class="my-awesome-app">

You can now override any Bootstrap style easily by prepending it with .my-awesome-app, e.g.:

.my-awesome-app .btn-primary {
   background-color: magenta;
}

A second approach is to use the SASS version of Bootstrap which allows you to customize Bootstrap via variables.

In my own apps, I am using a combination of the two approaches and am very happy with this solution.

Another benefit of the “class-on-html-tag” approach is that it can be applied to user use-cases, too. For instance, I am defining additional classes depending on the environment the app runs in. If the app runs on iOS, I add the ios class, no Android android is added etc. This is very helpful if you want to design your Cordova apps according to the OS-specific style-guides.


#3

I would have to agree with @waldgeist here. CSS that depends on the order of loading has a high likelihood of breaking in the future unexpectedly. We should do our best to avoid the action at a distance bogeyman. I think a better solution is to use selector specificity instead of order of rules/files for overriding styles.

Having said that, over at the github issue several people more experienced than me seem to have an opposing view. So take my comment with a grain of salt.

But props for aiming to get feedback prior to the PR. Very nice to see such process.


#4

@waldgeist, @vooteles, To imply that CSS load order doesn’t or shouldn’t matter is simply incorrect. It’s part of the CSS specification. See Section 6 of this W3C document entitled Order of Appearance. And, yes, you can overcome the load order by adding additional selector specificity, but that clutters up the CSS with extra selectors that could be avoided if the Meteor load order is changed. What I’m interested in most, is there a use case where changing the order of the CSS bundle from first to last will break existing code. If the developer has already worked around the issue by adding selectors, moving the bundle to the end shouldn’t break anything. But is there a case where the existing order matters and would break if the order is reversed? I’m looking for a reason to not simply implement case 1 (which involves moving 4 lines of code from the top to the bottom of the template). Otherwise, options 2 and 3 would suit your viewpoint since if you don’t modify your code everything remains the same.

And @vooteles, thanks for the props. You learn to respect process after 40 years of industry experience because so many companies have either no process or a broken process.


#5

On my very personal opinion, I like the third approach where I can change the order of CSS directly like if I was in a regular HTML environment:


<link rel="stylesheet" href="meteor_merged_css" />

Why would we get distant from what is the standard for all applications ? Let’s minimize the overhead when using Meteor


#6

I’ve opened a new issue to discuss implementing <meteor-bundled-js> to allow the JS scripts to be moved into the head. If you have any interest in this feature please head over here and chime in. I’m not going to implement this, and the powers-that-be won’t merge the PR, unless there is actually some interest in the feature.


#7

I’ve created this PR to add <meteor-bundled-css>. It allows you to move the bundled CSS around in the head. If not present then the current behavior (at the top) is used. Multiple instances are first seen wins and the other instances are ignored and removed. The code and tests are done, so head over here if you want to check it out or grab it and test.