Static and dynamic CSS combined
Some of you have probably heard “dynamic CSS”. It originates from a need to serve different CSS at different times, to different people, or on different pages. You do this by first generating the CSS on the server and then sending it off to the users requesting it. There are problems though, since the CSS gets regenerated each time you lose the advantage of caching. You could send HTTP headers so that the file gets cached anyway, but then it’s no longer dynamic right? This article presents a way to both have dynamic CSS that changes on each request, and make sure the user loads it from cache when it can.
How dynamic CSS works
Sometimes you want to send a different set of CSS rules depending on what page you are on. An example could be if your site was module based. Depending on what page you surf to you might get a calendar, some list of latest news or a small box showing the weather in, say, Stockholm.
The functionallity is not too hard to build with some server side language, but what about the CSS? Is it really necessary to load the calendar’s CSS on the news page, where the calendar is hidden? The same thing applies for each of the modules you have on your site; that list of news has certain CSS rules tied to it that isn’t needed on the gallery page. You get the point. So how do we solve this? We could do it my generating it on the fly (I’m using PHP here, but any other language would work):
PHP source:
<?php
// This line makes sure the browser handles
// the file as CSS and not PHP.
header('Content-Type: text/css');
if ($module['calendar'] == true) {
echo '
.calendar { width: 300px; }
.calendar table { background: pink;}
...
';
}
if ($module['newslist'] == true) {
echo '
.newslist { list-style: none; }
.newslist li { display: inline; }
...
';
}
[and so on every new module added]
?>
Generated file:
.calendar { width: 300px; }
.calendar table { background: pink; }
...
.newslist { list-style: none; }
.newslist li { display: inline; }
...
You save this file as “dynamic_stylesheet.php” and link it like you would if it was a static CSS file. Everything works fine and all the dynamic CSS makes the file sent to the user quite small. Both you and your users are all happy. The site starts growing.
Problems with dynamic CSS
After a while you start getting reports of the site getting slow. After some research you find that it’s in fact the dynamic CSS that does it. The file has gotten quite big and regenerating it each time is a lot of work. So you read up on caching and find that all that’s needed is a few lines at the top of your dynamic CSS file:
header('Cache-control: must-revalidate');
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 3600) . ' GMT');
This makes the browser load the file from cache for one hour instead of requesting it again. Problem solved! Right? Well, this means that you won’t get a regenerated file if you visit a new page on the site. The browser will load the style from cache instead and your users will get an unstyled calendar (or any other module) for an hour. Pretty annoying if you ask me.
Say we solve the problem above and get the page to only get cached on a per page basis. There’s still something that feels like a bit of a waste: we require the user to download the entire page again if just one of the modules changes. Say the user moves from the news list to checking out a certain news item. They will probably look pretty much the same, it’s just that the news list’s CSS won’t be needed on the news item page. We would need some way of only telling the browser to only cache parts of the files and make the loading of those parts dynamic.
@import to the rescue
Caching only fragments of your style is certainly doable in a lot of ways. The easiest I have found is using CSS’s own @import command. You simply change the example above to:
<?php
// This line makes sure the browser handles
// the file as CSS and not PHP.
header('Content-Type: text/css');
if ($module['calendar'] == true) {
echo '
@import "calendar.css";
';
}
else if ($module['newslist'] == true) {
echo '
@import "newslist.css";
';
}
[and so on every new module added]
?>
Generated file:
@import "calendar.css";
@import "newslist.css";
This makes the individual CSS files get cached by the browser (just like directly linking a CSS file would) while still allowing each page to dynamically add the style blocks it needs. A simple solution to a hard problem, just the kind of solutions I like best. What do you think?
Fredrik Wärnsberg ( 16 Jul 2006 )
I’m not sure since I havent tested this at all, but would only echoing one line (@import) really be that much faster than echoing out all rules to the css-file, or am I missing something here?
Emil Stenström ( 16 Jul 2006 )
@Fredrik Wärnsberg: compare echoing out 1000 lines of CSS each time versus echoing out 20 lines where each line references a static CSS file.
For small sites this wouldn\’t matter, for bigger I think it would.
r21vp ( 16 Jul 2006 )
I guess it would be even easier to use style tag in document header instead (containing generated @import references). This way we can save one webserver request.
Fredrik Wärnsberg ( 17 Jul 2006 )
@Emil then perhaps readfile() would be an even better option? I’m not positive though - some testing might be in place.
Plod On Planet Opera ( 17 Jul 2006 )
links for 2006-07-17…
JamJar: 源自Adobe的Flex2.0应用[视频]老天!俄国人是这样喝伏特加的!太牛B了!!![url=http://www.makezine.com/blog/archiv ……
Phill Sparks ( 17 Jul 2006 )
@Fredrik: The point is to allow the browser to cache as much css as possible but at the same time only load the css that’s needed. If you were to output all of the css onto the page, or into a single file then you run into caching or updating problems (pick the worse of two evils). Whereas outputting a list of @imports, each referencing a cachable file, solves both of these problems and only adds a small amount of extra load.
Emil Stenström ( 17 Jul 2006 )
@r21vp: Yes, that would probably be a bit faster. Feels a bit dirty to include 10 lines of imports though, but I guess that could work.
ozgur alaz ( 17 Jul 2006 )
Great article is worth to be homepage of digg. The story has dugg now, please add your diggs:
http://digg.com/programming/Static_and_dynamic_CSS_combined
davidbisset.com » Static and dynamic CSS combined ( 18 Jul 2006 )
[...] “This article presents a way to both have dynamic CSS that changes on each request, and make sure the user loads it from cache when it can.” [...]
SitePoint Blogs » Jul 17, 2006 News Wire ( 18 Jul 2006 )
[...] Static and dynamic CSS combined With version 4 browsers nearly a dim memory, we can start putting the CSS @import command to good use. One problem it can neatly solve is giving cacheability to dynamic CSS. (tags: css php) [...]
Johan ( 18 Jul 2006 )
how about using the link tag (alternate stylesheets) to import the different stylesheets
Emil Stenström ( 19 Jul 2006 )
@Johan: that works for a few “modules” but as soon as you get over 5 diffent it starts to feel strange. Feels a little better handling it in the CSS file altogether in my opinion.
Juan Calderón - Desarrollo Web » Combinando CSS estático y dinámico ( 19 Jul 2006 )
[...] Friendly Bit » Static and dynamic CSS combined [...]
project.47 - Portfolio & Personal Website » Blog Archive » Combinao de CSS esttico e dinmico ( 20 Jul 2006 )
[...] Encontrei um artigo (em ingls) no Friendly Bit ensinando como fazer essa dinamicidade do CSS, abrindo, somente, quando pertinente. Trata-se de um script PHP simples e funcional. [...]
Static and dynamic CSS combined · Style Grind ( 20 Jul 2006 )
[...] Check out the code from Friendly Bit. [...]
Johan ( 22 Jul 2006 )
How about combining both:
imported stylesheets and linked stylesheets. Eg:
linked stylesheet module 1:
import CSS module 1.1
import CSS module 1.2
Recursos de fin de semana (II) ( 23 Jul 2006 )
[...] Combinando CSS dinámico y estático. [...]
Lillicotch.com » Blog Archive » Static and dynamic CSS combined ( 1 Aug 2006 )
[...] More… Posted in Web Information | [...]
How to structure large CSS files - Friendly Bit ( 26 Nov 2006 )
[...] [Update: Another part structuring your CSS is making sure you don’t load too much. I wrote an article previously about combining static and dynamic CSS.] [...]
Web Clippings (Geekcraft) 2/17/2007 » Continuous Learning ( 17 Feb 2007 )
[...] Static and dynamic CSS combined - Friendly Bit Describing how to utilize PHP to generate unique CSS for a given user. Article focuses on both the generation approach as well as the client-side caching technique. [...]
Dave Hallam ( 21 Mar 2007 )
I have a php script for family history site which I am rebuilding. I have 4 families (grandparents). The script has a template with css. I am looking to have each family pages a different color (switched) in the background via PHP. Each family has the php code ending in tree=01 or tree=02 etc, could you give me advice how to do this please?
many thanks,
Dave
SolucioPC - Blog » Blog Archive » Crear hojas de estilo dinámicas con php ( 25 Jun 2007 )
[...] http://friendlybit.com/css/static-and-dynamic-css-combined/ [...]
Static and dynamic CSS combined at 1222north ( 23 Jun 2008 )
[...] Friendly Bit [...]