Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly serve CSS

Say I for some reason want to serve my CSS through PHP (because of pre-processing, merging, etc). What do I need to do in my PHP to make this work well? Other than the most obvious:

header('content-type: text/css; charset=utf-8');

What about headers related to caching, modification times, etags, etc? Which ones should I use, why and how? How would I parse incoming headers and respond appropriately (304 Not Modified for example)?


Note: I know this can be tricky and that it would be a lot easier to just do what I want to do with the CSS before I deploy it as a regular CSS file. If I wanted to do it that way, I wouldn't have asked this question. I'm curious to how to do this properly and would like to know. What I do or could do beforehand with the CSS is irrelevant; I just want to know how to serve it properly :)

Note 2: I really would like to know how to do this properly. I feel most of the activity on this question has turned into me defending why I would want to do this, rather than getting answers on how to do this. Would very much appreciate it if someone could answer my question rather than just suggesting things like SASS. I'm sure it's awesome, and I might try it out sometime, but that's not what I'm asking about now. I want to know how to serve CSS through PHP and learn how to deal with the caching and things like that properly.

like image 251
Svish Avatar asked Feb 03 '12 13:02

Svish


People also ask

How do I serve CSS in node JS?

Css files will be stored in public folder. const http = require('http'); const path = require('path'); const express = require('express'); const bodyParser = require('body-parser'); const route = require('./routes'); const app = express(); app. use(bodyParser.


2 Answers

A commendable effort. Caching gets way too little good will. Please enjoy my short prose attempting to help you on your way.

The summary

Sending an ETag and a Last-Modified header will enable the browser to send a If-Modified-Since and a If-None-Match header back to your server on subsequent requests. You may then, when applicable, respond with a 304 Not Modified HTTP status code and an empty body, i.e. Content-Length: 0. Including a Expires header will help you to serve fresh content one day when the content has indeed changed.

The apprentice

Sounds simple enough, but it can be a bit tricky to get just right. Luckily for us all, there is really good guidance available.

Once you get it up and running, please turn to REDbot to help you smooth out any rough corners you may have left in.

The expert

For the value of the ETag, you will want to have something you can reproduce, but will still change whenever the content does. Otherwise you will not be able to tell whether the incoming value matches or not. A good candidate for a reproducible value which still changes when the content does, is an MD5 hash of the mtime of the file being served through the cache. In your case, it would probably be a sum for all the files being merged.

For Last-Modified the logical answer is the actual mtime of the file being served. Why neglect the obvious. Or for a group of files, as in your case, use the most recent mtime in the bunch.

For Expires, simply choose an appropriate TTL, or time-to-live, for the asset. Add this number to the asset's mtime, or the value you chose for Last-Modified, and you have your answer.

You may also want to include Cache-Control headers to let possible proxies on the way know how to properly serve their clients.

The scholar

For a more concrete response to your question, please refer to these questions predating yours:

  • What headers do I want to send together with a 304 response?
  • Get Browser to send both If-None-Match and If-Modified-Since
  • HTTP if-none-match and if-modified-since and 304 clarification in PHP
  • Is my implementation of HTTP Conditional Get answers in PHP is OK?
like image 69
nikc.org Avatar answered Sep 23 '22 16:09

nikc.org


The easiest way to serve CSS (or JavaScript) through PHP would be to use Assetic, a super-useful PHP asset manager similar to Django's contrib.staticfiles or Ruby's Jammit. It handles caching and cache invalidation, dynamic minification, compression, and all the "tricky bits" that were mentioned in other answers.

To understand how to write your own asset server properly, I strongly recommend you read Assetic's source code. It's very commented and readable, and you'll learn a lot about best practices regarding caching, minification, and everything else that Assetic does so well.

like image 31
Rodney Folz Avatar answered Sep 23 '22 16:09

Rodney Folz