Some ideas to organize your CSS files and autoload them in CakePHP

By Tulio Faria (tulio)
In this article, I will show some ideas in how to organize your CSS files and how to autoload them in your CakePHP project. Some of them are elegant , and others are not so elegant as they could be ...

First Idea: CSS files named whitout any link with controller names

In this method, the files names are completely different from controller names. This is not recommended, because you could lose much time searching a CSS file which is related to a specific controller.

To use this method, we will do the controller choose what CSS file will be used, so will be used a variable $CSS to store the CSS file name. For example, an Articles controller:

Controller Class:

Download code <?php 
class ArticlesController extends AppController
{
      var 
$name 'Articles';
function 
index(){

      
$this->set("CSS""articleshome");
      }
function 
read($id){
      
$this->set("CSS""readarticle");
 }
}
?>

Note that we set a variable $CSS for each method (action), and each CSS file name doesn't have any link with the method or controller name.

Now, in our default layout, inside the head tag:

View Template:

Download code
<head>
.
.
<?
if(isset($CSS)){
   echo $html->css($CSS);
}
?>
.
.
</head>

In the layout, we did a validation to know if $CSS has been set, so we only include it if this occurs.

This way is not very elegant, right?

Second Idea: CSS with the same controller name


In this method, the CSS files will have the same name of their controllers, that is, an Articles controller will have an article.css. So we will have a project a little more organized, and we will find the CSS files easier then before, because both have the same name.

Now, we don't need to do anything in controller, only in the layout.

View Template:

Download code
.
.
<head>
<?
echo $html->css($this->params["controller"]);
?>
</head>
.
.

We used $this->param to know what is the name of the controller. This array contains many useful information, like controller name, method name, and others. If you want to know more, and don't want to read api/manual, just: print_r($this->params), and see what happens.

print_r($this->params);

Third Idea: CSS file with the same name of controller, but only if CSS file exists


This method is an update from Second Idea, we will just validate if CSS file is present in server, if it is, we link it to HTML. The code for the validation is the following:

View Template:

Download code
<head>
.
.
<?
if (is_file(APP.WEBROOT_DIR.DS."css".DS.$this->params["controller"].".css")){
echo $html->css($this->params["controller"]);
}
?>
.
.
</head>
Note that to show the complete file path, we used many constants. Here is their meanings:
* APP : stores the complete path to current application. For example: c:\testCake\app\
* WEBROOT_DIR : the webroot directory name.
* DS : or Directory Separator, stores which slash we will use, depending on the OS. Backslash for windows and slash for *nix.

This method is more organized. Besides, it performs needed validations. This method is recommend when you have all style for each controller in a single CSS file.

Fourth Idea: one CSS file for each method of controller


This idea, I think it is more accurate and organized. Why? Because we will separate each CSS for one method.

Again, we will modify only the layout:

View Template:

Download code
<head>
.
.
<?
if (is_file(APP.WEBROOT_DIR.DS."css".DS.$this->params["controller"]."_".$this-params["action"].".css")){
      echo $html->css($this->params["controller"]."_".$this->params["action"]);
 }
?>
.
.
</head>

In this example, we are using the following filename ruler for CSS files: controllersname_method.css and we already are validating if the CSS file exists.

Fifth Idea: one CSS file for each method of controller, a little bit more organized


This idea is almost equal to the previous, but we won't put all CSS files in the same directory, we will separate them in foldes with the same names of controllers.
For each controller, we will have a folder like webroot/css/controllername and in this folder, we will have all CSS for each method.

View Template:

Download code
<head>
.
.
<?
if (is_file(APP.WEBROOT_DIR.DS."css".DS.$this->params["controller"].DS.$this->params["action"].".css")){
       echo $html->css($this->params["controller"]."/".$this->params["action"]);
}
?>
.
.
</head>

Note that we only change "_" for slash.
So if we have a controller called Articles and a method (action) called read, it will be linked in html, if the file /css/articles/read.css exists.

This last idea, I think it is the best.

Tulio Faria
http://www.tuliofaria.net http://www.iwtech.com.br

 

Comments 215

CakePHP Team Comments Author Comments
 

Comment

1 Global CSS

You might also want to think about global CSS if you use Cake for multiple apps. 1.2 makes it soooo easy: http://joelmoss.info/switchboard/blog/2142:Whats_new_in_CakePHP_Asset_Sharing
Posted Jan 16, 2007 by Joel Moss
 

Comment

2 Not Just for CSS

A very useful technique, and one not just limited to CSS. I can see this getting used to include controller/action specific javascript too.
Posted Jan 16, 2007 by RichardAtHome
 

Comment

3 I like it

Very handy, i've implmented this myself and added a few little bits, as Richard said, its handy for javascript too, here is my code :

View Template:


<?
    //include controller specific js automatically
    if (is_file(APP.WEBROOT_DIR.DS.'js'.DS.'inc'.DS.$this->params['controller'].DS.$this->params['controller'].'.js')){
           echo "\t".'<script type="text/javascript" src="'.$this->webroot.'js/inc/'.$this->params['controller'].DS.$this->params['controller'].'.js"></script>';
    }
    //admin js
    if (is_file(APP.WEBROOT_DIR.DS.'js'.DS.'inc'.DS.$this->params['controller'].DS.$this->params['controller'].'_admin.js') AND
                strpos($this->params['action'], 'admin_') == 0 ){
           echo "\t".'<script type="text/javascript" src="'.$this->webroot.'js/inc/'.$this->params['controller'].DS.$this->params['controller'].'_admin.js"></script>';
    }
    
    
    //include action specific js automatically
    if (is_file(APP.WEBROOT_DIR.DS.'js'.DS.'inc'.DS.$this->params['controller'].DS.$this->params['action'].'.js')){
           echo "\t".'<script type="text/javascript" src="'.$this->webroot.'js'.DS.'inc'.DS.$this->params['controller'].DS.$this->params['action'].'.js"></script>';
    }    
    ?>     
    
    <?php echo $html->css('cake.generic');?>
    
    <?
    //include controller specific css automatically
    if(is_file(APP.WEBROOT_DIR.DS.'css'.DS.'inc'.DS.$this->params['controller'].DS.$this->params['controller'].'.css')){
        echo "\t".$html->css('inc/'.$this->params['controller'].DS.$this->params['controller']);
    }
    //admin css
    if (is_file(APP.WEBROOT_DIR.DS.'css'.DS.'inc'.DS.$this->params['controller'].DS.$this->params['controller'].'_admin.css') AND 
            strpos($this->params['action'], 'admin_') == 0 ){
           echo "\t".$html->css('inc/'.$this->params['controller'].DS.$this->params['controller'].'_admin');
    }
    
    //include action specific css automatically
    if (is_file(APP.WEBROOT_DIR.DS.'css'.DS.'inc'.DS.$this->params['controller'].DS.$this->params['action'].'.css')){
           echo "\t".$html->css('inc/'.$this->params['controller'].'/'.$this->params['action']);
    }
    ?> 

I add a new directory to the /js and /css folders (/inc) to keep everything tidy. Hope you find it useful.
Posted Jun 27, 2007 by Alex McFadyen
 

Comment

4 Helper

Posted Sep 25, 2007 by Danny Ferguson
 

Comment

5 Another Idea...

If your page titles are named simply like mine, you can throw this in your default.thtml tag:

echo $html->css($this->pageTitle);
Posted Oct 15, 2007 by ted stevens
 

Comment

6 Cool

That is really great! :-D Very simple, very organized. great work! Thanks!
Posted Feb 2, 2008 by Zach Smith
 

Comment

7 A more comfortable solution

I found all these proposed solutions very interesting, but they all have an annoying thing: you MUST put in EVERY view template some code, and if you have many actions for a controller you have to edit each view.
The solution i'proposing is this:
chose your preferred method for organinzing the style sheets from the ones listed above, but
instead of putting inside the view the code for loading,
edit the AppController class, and inside the beforeRender() method put this code:

function beforeRender(){
....
if( file_exists(CSS.$this->params['controller'].'.css') ){
$this->set('controllercss_for_layout',$this->params['controller']);
}
....
}

then into your LAYOUT insert inside the section something like this:

if(isset($controllercss_for_layout))
echo $html->css($controllercss_for_layout);
?>


In this way you don't have to care about the css loading inside the views, you can do the same thing for javascripts, and extending the concept to an action specific css/js is very simple.

CakePHP is to develop FAST ..and this is avery fast way
to do it :-)
Posted May 9, 2008 by Andrea Cappalunga
 

Comment

8 great

Nicely done, good thinking!
Posted Jul 2, 2009 by Brooks