CSS init
the corz.org CSS "pre-processor"

Not static, baby!

When I first started doing CSS, I quickly realised that it was full of limitations and so generated it with php, working around browser bugs, switching color scheme values with replaceable %%tokens%%, sending values with includes, modularizing repetative code and so on.

Over the years the init has picked up a few capabilities, simple mathematical expressions, minification and more, and has become a fairly powerful CSS "pre-processor" (a term that didn't even exist when I first started doing this back in 2004!).

Okay, how?

The first thing you need to do is setup your web server to handle the .css files differently. I'll give examples for Apache, because that's what most people use; but similar things are doable in most web servers (and usually with the same code!).

Simply put, we tell the web server to not spit out the files as-is, but instead pipe them through php, so it can have its wicked way with them.

In your ".htaccess" file for your css folder, add this..

<FilesMatch "\.(css|style)$">
  SetHandler application/x-httpd-php
</FilesMatch>

From now on, all files with a .css or .style extension, will be parsed by php, and treated as code.

Now for the code..

Init, innit?

Before we start spitting out individual CSS, there is some code which will be common to all the .css files. It makes sense to keep this in a single .php file, save having to code it into every one. We simply include it from the .css files.

css-init.php does the basic setup common to all the stylesheets, as well as quite a bit of magic, here it is..

<?php    /* --- ۞---> text { encoding:utf-8;bom:no;linebreaks:unix;tabs:4sp; } */
if (realpath ($_SERVER['SCRIPT_FILENAME'])       ==      realpath (__FILE__))  {
                                            die ( 
'to err is human, human!' ); }
/*
    corz.org css-init
    dynamic style sheet initialisation    v1.9.4

    The cleverest script you are reading right now!
    Seriously, I wouldn't dream of doing CSS without running it through this!

    For how-to's, notes and all that, see the accompanying text files, usually
    named "about this folder.txt" in the modules and snippets directories.

    Also here..

        <http://corz.org/engine?source=menu&section=php/corz function library/css-init>

    NOTE: If your stylesheet is *not* freely released under the creative commons
    license, you will probably want to delete that bit!

    ;o) Cor

    (c) 2004->tomorrow! cor + corz.org ;o)

*/


// I set these elsewhere, so you might want to do it here or there..

// Cache Styles?
// A global preference which user/you can override (see notes below)..
//$site_config['cache_styles'] = false;

// CSS modules + snippets paths        NOTE: YOU MUST SET THIS!
//
// Places to look for modules and snippets, as many as you like.
// They will be searched in order and the first match used.
//
// Please specify the /FULL/ path. Note: YOU MUST SET THIS!
//
$site_config['css_modules_paths'] = array();

//$site_config['css_modules_paths'][] = $site_config['full_admin_path'].'/css/modules';
//$site_config['css_modules_paths'][] = $site_config['full_admin_path'].'/css/snippets';
//$site_config['css_modules_paths'][] = $site_config['root'].'/blog/inc/themes/modules';



//*> grab color prefs, etc.
require_once $_SERVER['DOCUMENT_ROOT'].'/inc/init.php';

// everything has a name..
if (!isset($stylesheet)) {
    
$stylesheet substr(basename($_SERVER['PHP_SELF']), 0strrpos(basename($_SERVER['PHP_SELF']), "."));
}

//*> user-override minification..
if (isset($_REQUEST['deminify'])) {
    
$GLOBALS['site_config']['minify_css'] = false;
    
$dms '[de-minified output]';
} else {
    
header('X-Content-Type-Options: ?deminify to see a de-minified version.');
    
$dms ''// kinda redundant, think about it!
    
}

//*> send correct headers..
if ($site_config['cache_styles']) {
    
// use the one in your cache (NOT proxy caches, though)..
    
session_cache_limiter('private');
    
header('Content-type: text/css;X-Content-Type-Options: nosniff'true);
    
header('Cache-control: private, max-age=3600, pre-check=3600'true);
    
header('Last-Modified: ' gmdate('D, d M Y H:i:s'time() + 3600) . ' GMT'true);
    
header('Pragma: cache'true);
    
// NOTE: If you are enabling users to cache style sheets, it is wise to tag
    // ?something=<scheme-name> onto the CSS request, so they still get a fresh
    // style sheet on a scheme switch.
} else {
    
// Or grab it fresh, it's only a few Kilobytes..
    // I'll wager there's more substance in your CSS than GB's of Twittering!
    
header('Content-type: text/css');
    
header('Cache-control: no-store, no-cache, must-revalidate, max-age=0');
    
header('Expires: ' gmdate('D, d M Y H:i:s'time() + 60) . ' GMT');
}

//*> open a buffer..
ob_start();

//*> stylesheet begins..
//     if minification is disabled, users can *see* this..
echo '/*
    Generated "'
,$site_scheme['name'],'" adaptive stylesheet for '.$_SERVER['HTTP_HOST'].'

    ['
,$stylesheet,' styles]',$dms,'

    This stylesheet is freely released under the creative commons license:
    <http://creativecommons.org/licenses/by-nc-sa/1.0/>
*/'
;

//*> back to the style sheet..
return true;

// note: the configuration file for the various elements is..
// /blog/inc/themes/<your-theme>/<your-theme>.ini
// To edit styles, use http://your-site/blog/inc/scheme-edit.php

function output_CSS() {

    
//*> grab buffer into string
    //   wipe buffer, transform string, spit it out..
    
$stylesheet ob_get_contents();
    
ob_end_clean();
    
$stylesheet preg_replace_callback("/\@@([^@]+)@@/i""include_css_module"$stylesheet);
    
$stylesheet process_user_css($stylesheet);

    
//*> output minified, compressed style sheet..
    
if ($GLOBALS['site_config']['minify_css'] == true) {
        
$using_gzhandler false;
        
// I usually have this set site-wide to 16386..
        
if (!ini_set('zlib.output_compression',  4096)) { // it's good discipline to get your CSS fit into this! heh
            
$using_gzhandler ob_start("ob_gzhandler");
        }
        
ob_start('minify');
        echo 
$stylesheet;
        
ob_end_flush();
        if (
$using_gzhandler) { ob_end_flush(); }
    } else {
        echo 
$stylesheet;
    }
//if (!empty($GLOBALS['do_debug']) and $GLOBALS['do_debug'] > 0) { debug("out"); }//:debug:
}

// modules within modules..
function include_css_module($matches) {
    
ob_start();

    
$snippet false;
    
$module $matches[1];

    
//*> process sent values..
    //     set new values, override existing values..

    
if (substr($module, -11) == ')') {
        
$val_pos strrpos($module'(', -1);
        
$sent_vals substr($module$val_pos+1, -1);
        foreach (
explode(','$sent_vals) as $sent_vals) {
            
$ev_arr explode('='$sent_vals);
            
// assign value (possibly %%token%%) to site_scheme array, for use in sheet..
            
$GLOBALS['site_scheme'][$ev_arr[0]] = $ev_arr[1];
        }
        
$module substr($module0$val_pos);
    }

    if (
substr(strrchr($module"."), 1) != 'css') {
        
$module .= '.css';
    }

    
//*> include modules..
    
foreach ($GLOBALS['site_config']['css_modules_paths'] as $modules_path) {
        if (
file_exists($modules_path.'/'.$module)) {
            if (
stristr($modules_path'snippet')) {
                include 
$modules_path.'/'.$module;
                 
$snippet=true;
            } else {
                include_once 
$modules_path.'/'.$module;
            }
            break;
        }
    }
    
$inc_module ob_get_contents();
    
ob_end_clean();

    
//*> module sub-include..
    
if (!$snippet) {
        
$inc_module preg_replace_callback("/\@@([^@]+)@@/i""include_css_module"$inc_module);
    }

    
//*> process tokens..
    
$inc_module process_user_css($inc_module);
    return 
$inc_module;
}



//*> Process CSS, pluck out %%tokens%%..
//
//     transform into real scheme values (PCRE look-ahead for % values)..

function process_user_css($user_stylesheet) {
    
$user_stylesheet preg_replace_callback("/%%(((?!%%).)*)%%/i""switch_scheme_tokens"$user_stylesheet);
    return 
$user_stylesheet;
}


//*> The magical %%token%% switching..
//
function switch_scheme_tokens($matches) {

    if (
substr($matches[1], -11) !== ')') {
        if (isset(
$GLOBALS['site_scheme'][$matches[1]]) ) {
            return 
$GLOBALS['site_scheme'][$matches[1]];
        } else {
            return 
''// plain empty value
        
}

    } else { 
// Math in your CSS!

        // pluck expression out of braces..
        
$val_pos strrpos($matches[1], '(', -1);
        
$sent_val substr($matches[1], $val_pos+1, -1);    //    +4 / +4.2 / +.2 / -.5 / etc.
        
$operator $sent_val{0};                            //    + / - / etc.
        
$sent_val substr($sent_val1);                    //    4 / 4.2 / .2 / .5 / etc.

        // percentage calculation..
        
if (substr($sent_val, -1) == '%') {                    // 10%
            
$math_mode '%';                                // %
            
$sent_val substr($sent_val0, -1);            // 10
        
}

        
// get original property and value..
        
$orig_val $GLOBALS['site_scheme'][substr($matches[1], 0$val_pos)];    //    $site_scheme["top_space"] == 5rem
        
preg_match_all('/(\d|\.)|(.+)/'$orig_val$matches);
        
$orig_val implode($matches[1]);                        // 5
        
$orig_unit implode($matches[2]);                        // rem

        // do percentage..
        
if (isset($math_mode)) {
            
$sent_val = ($orig_val 100) * $sent_val;
        }

        switch (
$operator) {
            case 
'+'$new_val $orig_val $sent_val; break;
            case 
'-'$new_val $orig_val $sent_val; break;
            case 
'*'$new_val $orig_val $sent_val; break;
            case 
'/'$new_val $orig_val $sent_val; break;
            default : 
$new_val $orig_val;
        }
        return 
round($new_val3).$orig_unit;
    }
}


//*> compress CSS
//  remove all white-space and comments..
// I think this code originally came from the php manual.
function minify($css) {
    
$css preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!'''$css);
    
$css str_replace(array("\r\n""\r""\n""\t"'  ''    ''    '), ''$css);
    return 
$css;
}

?>

Welcome to corz.org!

If something isn't working, I'm probably improving it, try again in a minute. If it's still not working, please mail me!