Pragmatically Splitting ASP.NET StyleBundles for IE

Lets start with a disclaimer: I am a front-end guy. I *heart-emoji* HTML and CSS. I know my way around javascript. But I am not a programmer. My knowledge of ASP.NET/C# is minimal. So the following will probably be bloody obvious for people who are C#-gurus, but here we go anyway.

Another disclaimer: this is gonna be about technical webstuffs. Feel free to ignore the rest if that is not your cup of tea.

This week at work, I ran across a classic: Internet Explorer 9’s 4095-selector issue. If a stylesheet has more than 4095 selectors, it will ignore the rest. With all of Bootstrap and a bunch of stuff that still needs to be weeded out, we went a bit over that, and, hey presto, IE9 was børked.

(Over the past 12 months, IE9 and earlier still accounted for roughly 3.5% or 750k visitors. The last few months there’s a sharp decline, but there is still enough of a business case for a webshop to support at least IE9. Besides, a website should work in every browser. That does not mean that it should look exactly the same in every browser or even that it should have exactly the same bells and whistles — that’s where madness lies — but within reason, it should just work.)

The solution was easy: split the file in two.

This is how our StyleBundle was constructed:

bundles.Add(new StyleBundle("~/bundles/css")
    .Include("~/assets/vendor/bootstrap/css/bootstrap.css")
    .Include("~/assets/vendor/foo/bar.css")
    .Include("~/assets/css/fonts.css")
    .Include("~/assets/css/base.css")
    .Include("~/assets/css/grid.css")
    .Include("~/assets/css/header.css")
    .Include("~/assets/css/footer.css")
);

There are more files, but you get the idea. The logical split was to separate the vendor-styles from our own. So initially, I made two bundles:

bundles.Add(new StyleBundle("~/bundles/css-vendor")
    .Include("~/assets/vendor/bootstrap/css/bootstrap.css")
    .Include("~/assets/vendor/foo/bar.css")
);
bundles.Add(new StyleBundle("~/bundles/css-own")
    .Include("~/assets/css/fonts.css")
    .Include("~/assets/css/base.css")
    .Include("~/assets/css/grid.css")
    .Include("~/assets/css/header.css")
    .Include("~/assets/css/footer.css")
);

This, of course, works, but isn’t ideal. People who use an up-to-date browser will now have to download two files instead of one. Then I figured that there should be a way to combine those two bundles without having duplicate GLOFs. There is: StyleBundle’s Include-method apparently takes an Array as argument. So, after a bit of rejigging:

string[] vendorStyles = new string[] {
    "~/assets/vendor/bootstrap/css/bootstrap.css",
    "~/assets/vendor/foo/bar.css",
};

string[] ourOwnFancyStyleFiles = new string[] {
    "~/assets/css/fonts.css",
    "~/assets/css/base.css",
    "~/assets/css/grid.css",
    "~/assets/css/header.css",
    "~/assets/css/footer.css",
};

bundles.Add(new StyleBundle("~/bundles/css-vendor")
    .Include(vendorStyles)
);

bundles.Add(new StyleBundle("~/bundles/css-own")
    .Include(ourOwnFancyStyleFiles)
);

bundles.Add(new StyleBundle("~/bundles/css")
    .Include(vendorStyles)
    .Include(ourOwnFancyStyleFiles)    
);

Now, I had three bundles to the page: two for IE9, the combined one for the rest. Adding them to the page was only a matter of rigging up some Conditional Comments.

<!--[if lte IE 9]>
    @Styles.Render("~/bundles/css-vendor")
    @Styles.Render("~/bundles/css-own")   
<![endif]-->
<!--[if gte IE 10]>-->
    @Styles.Render("~/bundles/css")
<!--<![endif]-->

So. There it is: a two stylesheets for IE9 and below, a single one for everybody else, with no duplicate GLOFs. And the realisation that I don’t have any syntax highlighting set up here.

I know there are a lot of legitimate questions about this approach — “Why don’t you use Grunt/Gulp/build tooling?”, “Do you really need that much CSS?”, “Why Bootstrap?”, “But HTTP/2 changes everything!” — and believe me, I know. I know. We’re getting there. I started here less than six months ago, and we’re making progress. But Stallman reigns supreme when you do web development in the world of eCommerce: the site has to keep working, and the time or resources to completely overhaul everything usually aren’t there. So you do what you can, while you can. Baby steps will get you there too, eventually.