Single CSS file vs multiple CSS files in an MVC application
1 Aug 2011, 8:11PM
Read the previous blog post first if you haven't already.
So I've been at my new job for about 3 weeks now. Its a new site I'm working on and so I'm lucky to be using .NET, MVC 3 and I think I migrated the first View to Razor (we're currently in the process of migrating). After this site (the Perihelion, which I wrote in my two weeks off before starting my new job) its my first MVC site I've worked on.
So first up, I'm loving working in a MVC project, its so much cleaner than ASP.NET forms sites. I'm also loving the Razor syntax, its clean, minimal and less obtrusive than the <% %> tags embedded everywhere. As I mentioned I migrated the first View across to Razor and it raised some questions (the mind often gets distracted when it should be working).
What I was thinking was where should I put the CSS?
First the site has one massive site wide stylesheet. This is fine, its large (3000 lines or so) but its downloaded once (or at least not that often) and its cached so then no more stylesheet downloads for any page on the site for a while (until the CSS file date changes and the browser in all its wisdom decides to check for a newer version). Ok so far the good points, the bad is that its a mess to read (you can't tell what styles apply to the current page easily) its a mess to maintain (you will tend to add new styles to "fix" any issues rather than refactor as you should) and it will therefore deteriorate much faster than, say, a shared site stylesheet and individual files per page for styles only on that page.
So one shared stylesheet and individual files per page sounds good then you say? Well its easier to read, understand and therefore modify and maintain, but it means that first hit on every page requires loading of a new (different) stylesheet. Its just another connection to the server and thats something we're trying to reduce. So thats really where most people sit, one stylesheet per site (or maybe two if you have distinct areas in the site), or individual ones per page type (template).
So MVC offers something new over ASP.NET forms. You can define a section in the master template (e.g. a "Head" section) and then individual Views can add content to this. This means the view itself can include links to CSS or JS files OR have inline styles place there that are specific to that View. When I say inline styles I mean within <style></style> tags, not inline on HTML.
This means you now have a third option of having one shared stylesheet for the site + inline styles per page. This removes the extra connection but makes your page slightly larger (on every request as pages in general are cached less often than CSS files). But we're heading in the right direction, this is tidier and easier to maintain than the other two options so far.
So we're really determined that for maintainability we want separate styles per View and one (or two) shared stylesheets for the whole site. Its now just a question of how best we can achieve this.
The idea is to take the best from both worlds. Why not have individual stylesheets per view but only link to one site-wide CSS file? We could achieve this by linking to a CSS controller which built the single file on demand (with some caching of course) from all the individual files. This would require...
- All pages include the following link
<link type="text/css" rel="stylesheet" href="/CSS/Site.css">
- For each View create a separate stylesheet with the same View name (just different .css extension) in the same location as the View.
- We create an MVC route for "/CSS/Site.css" that points to a controller. This controller will find all CSS files in the Views folder, combine them into one CSS file with comments acting as visual separators to indicate file beginings. We would then either keep this file in memory (for quick retrieval) or write to disk.
And done. The benefits of a single stylesheet that is cached site wide combined with the maintainability of individual files.
- Build the CSS file as a build task rather than on first request (so it doesn't slow down first access to a site). This may be important for sites that get large numbers of hits.
- Parse and either format or compress the CSS as you combine it. Compress for size optimisation or format for readability (e.g. for debugging or if you are like me and like tidy CSS).
Ok so you get the idea, all quite easy, just a little work. Obviously there would still be some improvements you could make, e.g. having stylesheets in with your View files will polute the folder view (think if you also had JS files here, one per View you are trippling the number of files there). You may keep all stylesheets in a separate folder and mirror the View folders but then you face the issue of finding the right one to open from your View for easy editing (maybe a VS plugin to allow quick access to it).
Also you can have inline styles, you could parse the Views themselves and extract the styles to put in a stylesheet (needs some further thinking how this would work, e.g. you'd want to remove the style from the View after building the master stylesheet).
Finally because you are reading the CSS and re-writing to a single file you can also parse it. This means you can add variables and nested CSS support and remove it on the final CSS build. Nice and clean and tidy!
So I haven't talked much about compression, minifying files, or the style you write your CSS in (e.g. I prefer a single style all on one line). Lots of other places cover these things so they are important as well. Also you can apply similar logic to JS files. A lot of JS files I see contain code to link events up to elements on other pages, this shouldn't really be the case!
Ok, enough writing, time to blob. I had an interesting discussion with my workmate this afternoon about Bots spamming Forms on sites and how to block them without using a CAPTCHA. I may write about that next...