Now, why would you want this? Hacking on files outside your theme directory is bad practice. It complicates maintenance and you end up with bugs that are hard to track. Another reason is that adding tons of styles into your "style.css" file can eventually make it unwieldy and error prone.
There are two approaches to overriding styles sheets outside the theme directory. One is to automatically load a modified version with drupal_add_css() and setting a 'theme' parameter so the cascading order overrides them. ("Theme" styles always print out after "module" styles.) The other is to manipulate the PHPTemplate variable $css
directly so it depends entirely on your modified version.
The following code should be inside your template.php file and rename MYTHEME to the name of your theme.
First approach:
The function:
/**
* Used to detect styles outside the theme folder and attach a modified version.
*/
function MYTHEME_attach_module_styles($css) {
foreach ($css as $media => $types) {
foreach ($types['module'] as $file => $preprocess) {
// modified version detected here. basename() returns the file name.
if (file_exists($attach = path_to_theme() .'/styles/mod-'. basename($file))) {
// Use theme for easy overriding through CSS cascade.
drupal_add_css($attach, 'theme', $media, $preprocess);
}
}
}
}
Where it's called:
/**
* Overridden only to add stylesheets before drupal_get_css gets called
* from phptemplate_page. This minimizes preprocessed style sheets.
*/
function MYTHEME_page($content, $show_blocks = TRUE) {
// Conditionally attach modified module styles.
MYTHEME_attach_module_styles(drupal_add_css());
return phptemplate_page($content, $show_blocks);
}
What's going on here? MYTHEME_page()
overrides phptemplate_page()
. This isn't necessary but phptemplate_page() calls drupal_get_css()
which renders all the preprocessed style sheets. Adding to the styles array before it will make it more efficient. Afterwards, phptemplate_page() is called directly so it can go through and render the page.
The styles array is returned from drupal_add_css()
. That's fed into MYTHEME_attach_module_styles()
which scans through all the style sheets for the page. When a style sheet prepended with "mod-" within the "styles" folder matches the module style it will pick it up overriding all the rulesets is inside mod-MODULE.css. Prepending it differentiates from the original style, nice for debugging. Remember to use the exact same selector from the original style or something more specific. If the css selector inside the original style is more specific, CSS cascading won't take effect. This makes it very easy to manage separate module styles specific to your theme.
Second approach:
The function:
/**
* Replace 'module' styles when an override exists in "styles/" directory in
* the theme folder. It can also be disabled by appending ".disabled" to the
* style name. Style order is maintained.
*/
function MYTHEME_override_css($css) {
$css_override = array();
foreach ($css as $media => $types) {
// Focus on module styles.
foreach ($types['module'] as $file => $preprocess) {
// override detected here. basename() returns the file name.
if (file_exists($override = path_to_theme() .'/styles/'. basename($file))) {
$css_override[$media]['module'][$override] = $preprocess;
}
// Appending ".disabled" to the style disables it. Useful if
// you want to manage the styles from the theme style.
elseif (!file_exists($override .'.disabled')) {
$css_override[$media]['module'][$file] = $preprocess;
}
}
// Append theme styles.
if (!empty($types['theme'])) {
$css_override[$media]['theme'] = $types['theme'];
}
}
if (!empty($css_override)) {
$css = $css_override;
}
return $css;
}
Where it's called:
function _phptemplate_variables($hook, $vars) {
if ($hook == 'page') {
$vars['css'] = MYTHEME_override_css($vars['css']);
$vars['styles'] = drupal_get_css($vars['css']);
}
return $vars;
}
With this approach, if the module style is detected within the "styles" folder. It will completely omit the original style sheet and include the themes version. This does mean more maintenance and more preprocessed styles. You can also completely disable styles sheets and that can get complicated trying to manage them also but it's presented here to show you the possibilities. The first approach is recommended.
After the function is setup, all you need to do is copy the modified styles into your "styles" directory. It will be pretty much automated from there.
Two things to watch out for in both approaches:
- Images included with the style sheet will break. You must re-link them or you'll get a bunch of 'file not found' errors in you logs.
- Style sheets outside the theme sharing the same name may interfere with each other. This usually isn't a problem but it's something to watch out for.
Comments
Or use a CSS file uploaded with CCK
I have a Content Type with the option to add a CSS file. With this CSS file editors have the option to override styling for a specific node.
To add this CSS file to the HEAD of the page I use this piece of code in my template.php:
Baris Wanschers (@BarisW)
Drupal specialist
Is this Theme Snippets applicable on D6
If not can someone help and add D6 code? Thanks
Contact me for drupal projects in English, German, Italian, Drupal Hosting Support.
Overriding CSS files in Drupal 6 + 7
How to do this in D6 and D7 is explained here: http://drupal.org/node/263967
Short css_alter to do this in Drupal7
I was surprised to find that even in D7, you can't have both per-module css files as overrides in your theme AND the efficient conditional inclusion only when needed that #attached etc supports.
The magic override-matching-filename process does work in drupal_get_css(), but only if you've also registered the per-module css file in your themes .info.
So here's a THEME_css_alter() that behaves as I thought we would want it to.
.dan. is the New Zealand Drupal Developer working on Government Web Standards