I’ve been coding websites for a long time but even I was a little puzzled when I came across a Hacker News comment where the commenter described their own makeshift CMS that involves using your own file system. The most interesting part to me was when the person said they add CSS to pages on their personal projects by means of HTTP headers.
I had heard of this technique before and the person does say in the comment that this doesn’t work in every browser. But I decided to do some research to figure out how one might do this and why this would be easier than just dropping in one or more
<link> elements in the HTML.
I’m sure many of you who have been developing sites for some time now are familiar with this. But I thought I’d write it up for those looking for a quick solution. This should especially be helpful because this apparently isn’t the easiest topic to search for since the terms “HTTP” and “header” are quite common in web development (and due to the fact that Google search has sucked for many years now).
Adding Headers via .htaccess
Before getting to the actual solution, let’s take a brief look at how to add HTTP headers in general. You can put a line like the following in your website’s (or directory’s) .htaccess file (assuming you’re on an Apache server):
Header add Header-Name "parameter=value"
This uses Apache’s
Header directive. The part inside the quotes is a parameter/value pair that works as the value for that specific header.
To demonstrate, I’ll do the following, which creates a custom header:
Header add Funky-Music "getdownand=boogie"
This is just a header that I made up. You can also add any valid HTTP header, assuming you use the correct syntax. You also have the option to use the
set argument instead of
add, which will overwrite the header if it already exists. There are other arguments you can use, described in the aforementioned apache.org doc.
I’ve set up a demo directory and I’ve added an .htaccess file to that directory, along with a basic HTML file called index.html. When you load up that page in your browser, you can see the headers that the server responds with by viewing the Network tab in the browser’s developer tools:
In Firefox it looks like this:
In both cases you can see the custom header that I added. You can also see any other headers that are added by default.
That’s a fairly basic summary of adding HTTP headers, including adding custom headers. For a more thorough discussion of the topic, check out this post by Jeff Starr.
Adding CSS via HTTP Headers
Now that you have a basic idea of how to add HTTP headers, let’s take a look at how to add a stylesheet via the same method. The W3C’s HTML4 spec has some info on how to do this, however it notes:
This section only applies to user agents conforming to versions of HTTP that define a Link header field. Note that HTTP 1.1 as defined by [RFC2616] does not include a Link header field.
According to my testing, the only current desktop browser that supports this feature is Firefox. The only mobile browser that I could find that supports this is Opera Mini (tested on iPad). This leads me to believe that pre-WebKit Opera supported the feature.
Nonetheless, to add CSS using an HTTP header, you can put the following line in your .htaccess file:
Header add Link "<style.css>;rel=stylesheet;media=all"
The syntax is the same as that for the custom header I added previously, and basically the same syntax as when adding any HTTP headers, custom or not.
In this case, I’m using
Link as the name of the header. This is what tells a supporting browser that I want to add a
<link> element to my page. The value for the header consists of:
- The URL of the stylesheet inside angle brackets
- Attribute/value pairs separated by semi-colons
The quotes around the full value are optional if the value doesn’t contain spaces. If it does, then the quotes are mandatory for correct parsing.
So the above header would be equivalent to adding the following to the HTML:
<link rel="stylesheet" href="style.css" media="all">
href value can of course be relative or absolute. And, as you probably figured out, this isn’t just for CSS but for anything that can be added using HTML’s
I’ve set up another demo page that adds some CSS using the
Link header. As mentioned, you’ll have to view it in Firefox to see it work. View the HTTP headers in the Network tab of the developer tools, and you’ll see the stylesheet included:
Try viewing source on the page itself. You’ll see there’s no CSS file in the source, but the styles are there if you inspect each element. The header will be visible in the Network tab of any browser, but the CSS will only work in Firefox or another browser that supports the
Link HTTP header.
Status of the
Link HTTP Header
From what I can see, the
Link header is not a deprecated or obsolete feature, it’s just not well supported. It’s confusing to try to figure out if this is still considered a valid web feature, but here’s what I’ve uncovered:
- MDN has an article on it and doesn’t indicate that it’s obsolete (though the browser support section is missing).
LinkHeader is described in the IETF’s RFC 8288, which I believe is the latest proposed standard for “Web Linking”.
- As the HTML4 spec mentions, the last version of the HTTP 1.1 spec doesn’t include it, whereas the HTTP2 spec seems to mention the
Linkheader in passing.
Why Add CSS Via HTTP Headers?
With so little browser support, it’s hard to justify any use for this other than novelty. As the user on Hacker News said, personal projects can be fun because you can do whatever you want, including using a feature that apparently more than 90% of your users won’t see.
I suppose if you have a lot of HTML pages and you’re not using any kind of back-end scripting or includes, then maybe the best solution is using the
Link header. But the fact that it’s so poorly supported doesn’t make it very attractive, personal project or not.
At this point, the only thing I can think of that could justify use for this in production is as a way to include some Firefox-only CSS, which Eric Meyer mentions as a possibility in an old post on this subject. But it’s not guaranteed to always only work in Firefox, so that’s still a problem.
Do with this what you like, but it’s extremely unlikely that this will have any use in a real project. I just thought it would be fun to mess around with it and write it up.