A New Way To Manage My Css

Hey,

I don’t know how this is with you guys, but for me CSS is always trouble. First I start with a nice split up of files like:

design.css

layout.css

yii.css

fonts.css

I do a lot of inline comments and try to keep things together. But after a while it becomes a mess. For big projects, my CSS files end up from 500 line to even more. Maybe for you this is no problem, but what I like about the MVC is small files up to 100 lines max. Most of the time only 20 lines or less. It keep things clear for me. Also because every model and controller and views has there own directory and files.

So why not do this for CSS I thought after a new mess up disaster.

So now I got in my themes directory:

css

–design

----top.css

----content.css

----top_menu.css

----main_menu.css

----side_menu.css

----footer.css

–layout

----general.css

----content.css

----tables.css

----footer.css

----sidebar.css

–modules

----blog

------admin

--------admin.css

------blogger

--------admin.css

----user

------admin

--------admin.css

------user

--------profile.css

–yii

----cdetailview.css

----cgridview.css

----clinkpager.css

etc. etc.

This is just an example. But the bottom line is I’ve got a lot of very small CSS files now. When I have to look for something, I now exactly where to look and don’t have to scroll trough hundred of CSS lines.

But of course you don’t want to include them one by one. So I added a little Component that combines and minifies all these files into one CSS file:

protected/components/CssMin.php




class CssMin extends CApplicationComponent

{

	public $minAllFilename = 'all.min.css';

	public $path;	

		

	// Create minimized css file from all css files in given directory.	

	public function minimize()

	{

		$buffer = "";	

			

		$dir = new RecursiveDirectoryIterator($this->path);

		$ite = new RecursiveIteratorIterator($dir);

		$files = new RegexIterator($ite,'/^.+\.css$/i',RegexIterator::GET_MATCH);

		foreach($files as $file) 

		{

			if(basename($file[0]) != $this->minAllFilename)

			{

				$buffer .= file_get_contents($file[0]);	

			}			

		}

		

		// Minimize.

		$buffer = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $buffer);

		// Remove space after colons

		$buffer = str_replace(': ', ':', $buffer);

		// Remove whitespace

		$buffer = str_replace(array("\r\n", "\r", "\n", "\t", '  ', '    ', '    '), '', $buffer);		

		

		// Write minimized css file.

		$outputFile = $this->path.$this->minAllFilename;

		$fwrite = fopen($outputFile,"w");

		fwrite($fwrite, $buffer);

		fclose($fwrite);		

		

		return true;

	}			

			

}



The performance seems to be no issue. I expected it to consume a lot of time, but it’s just a few milliseconds. But it would be stupid to do this for every request in production environment, so in my main layout view I’ve got:




		if(DEV_MODE)

		{

			Yii::app()->cssmin->path = Yii::app()->theme->basePath.'/css/';

			Yii::app()->cssmin->minimize();			

		}

		

		Yii::app()->clientScript->registerCssFile(Yii::app()->baseUrl.'/css/reset.css');

		Yii::app()->clientScript->registerCssFile(Yii::app()->theme->baseUrl.'/css/'.Yii::app()->cssmin->minAllFilename);



You can see that I include the reset.css file from my main css directory and that it’s not in the css directory of my theme. Because you have to call the reset.css first else it would mess up things. Of course I can also modify my CssMin class to grab certain files first and put the reset.css also into the theme css directory.

For me this works. Never have to search trough lines and lines of CSS saves me a lot of stress :D. What do you think about this? Is it a good approach, could I improve some things?

Thanks for reading.

Just for understanding: You split the big css file in many small css files. Every css-file is for an own view. If someone call your website, you create the big css file again, or not?

But what happens if you have the css file A and css file B. Both define the class ‘test’, file A with background-color:#000; file B with background-color:#fff;. Or you defined a css-style for an object with id ‘tester’ and both views (A and B ) have an object ‘tester’.

I think, the splitting is a good idea but if you want to debug a css-error, you will go crazy.

If there’s a big file, you got the possibility to find the error quickly, but not with many small files.

An other solution could be that you publish the small css-file for a view if the view-file is called. You can modify the Controller-Class to overwrite the function beforeRender. If a small css-file for the view exists, publish them, else not.

Thanks Riff for thinking along with me.

Indeed in dev mode the big CSS file is created on every request. In production mode, the big CSS file is not created again, just have to upload it once.

Indeed there are some drawbacks, but in my situation this is no problem.

Double classes for example are a problem. The last one will be applied. But I never use double classes. I have some main classes that are used site/theme wide and some special classes for a module. Like ‘.blog-selectable-image’ for example. I also try to use some good ideas from: http://smacss.com/.

Also there are no CSS files for all my views, only if they need some special markup that can’t be applied in my main CSS files.