Question

I'm cleaning up my big crazy style sheets (possibly pertinent to a future question) and I'm wondering the best way to add custom CSS to a specific node or page.

In particular, my work site's home page is a Panel Page and it has a bunch of different styling. Right now the CSS is just included with the main theme style sheet.

Is there a way to say, "if this is node Foo, then add foo.css"? Is CSS Injector what I'm looking for?

I might be interested in generalizing this to other nodes/sections/etc, but at the moment I just want to handle this one item.

What I ended up doing.

I'm using a Zen subtheme, and discovered in actually reading through template.php that there's some commented out code for including conditional style sheets. Code below did exactly what I needed:

if (drupal_is_front_page()) {
  drupal_add_css(path_to_theme() . "/foo.css", 'theme','all'); 
}

(Line 80 in a stock Zen template.php file, FWIW.)

Was it helpful?

Solution

This is the sort of thing that I'd do by code, but that's because that's just the way I roll.

In the template.php you will want something like:

function MYTHEME_preprocess_node($vars) {
  if (drupal_get_path_alias("node/{$vars['#node']->nid}") == 'foo') {
    drupal_add_css(drupal_get_path('theme', 'MYTHEME') . "/css/foo.css");
  }
}

Replace foo with values related to your own code.

OTHER TIPS

You could have a look at the Code per Node module. It is also featured in this blog post.

Create a Context for your page/section and then use the Context Assets module to load CSS and/or javascript for that given context.

Context:

Context allows you to manage contextual conditions and reactions for different portions of your site. You can think of each context as representing a "section" of your site. For each context, you can choose the conditions that trigger this context to be active and choose different aspects of Drupal that should react to this active context.

Think of conditions as a set of rules that are checked during page load to see what context is active. Any reactions that are associated with active contexts are then fired.

Context Add Assets:

Context add assets allows you to do this. It has an easy to use UI to allow you to do this all without writing any code. Because it uses ctools all of this is also exportable.

If it's a small amount of CSS, maybe considering making your CSS selectors based on the node and including the css in your theme's CSS? Drupal 7 provides the body.page-node-NODEID selector, and Zen for Drupal 6 provides similar body CSS classes.

You could create a custom module and use hook_preprocess_node() to load stylesheets selectively based on the node id.

Here's an example:

function MYMODULE_preprocess_node($vars) {
  $nid = 3;
  if (arg(0) == 'node' && is_numeric(arg(1)) && arg(1) == $nid) {
    drupal_add_css(drupal_get_path('theme', 'MYTHEME') . "/foo.css");
  }
}

Replace MYMODULE with the name of your module and replace MYTHEME with the name of the theme that contains the css file.

If the criteria for which adding a CSS style depends from some properties of a node, then I would implement MYTHEME_preprocess_node(&$variables); one of the values passed to the function is $variables['node'] (to notice it's not $variables['#node']).

MYTHEME_preprocess_node(&$variables) {
  if ($variables['node']->nid == 3) {
    drupal_add_css(drupal_get_path('theme', 'MYTHEME') . "/foo.css");
  }
}

If the criteria don't depend from any node properties, then I would implement MYTHEME_preprocess_page(&$variables); $variables['node'] contains a node object, if the page being shown is a node page. In Drupal 6, the process function also gets $variables['is_front'], but in Drupal 7 the same variable is not passed; if you need to know if the page is the front page, you need to use drupal_is_front_page().

MYTHEME_preprocess_page(&$variables) {
  if ($variables['is_front']) {
    drupal_add_css(drupal_get_path('theme', 'MYTHEME') . "/foo.css");
  }
}

For an admin based way of doing it I'd look at the CSS module. It adds a field where you can add CSS to the node/add and node/edit pages.

CSS:

The CSS module adds, for users with enough permissions and enabled nodes, a CSS field on the node creation page.

Users might insert CSS rules in the CSS node field and those rules will be parsed on the node viewing.

This way CSS experienced users might create complex CSS based design for nodes contents.

Important: note that the CSS editing permissions should be given only to trusted users (administrators). Malicious users which have this permission might broke your site design and also introduce security issues (XSS).

CodePerNode is great, but CSS Injector is simpler to install (no libraries needed). The module allows the content manager to dynamically add CSS to specific pages, without touching PHP code or INFO files at all. 15777 installs can't be wrong - this is a social proof this module works. The CSS is also cached with the regular caching system.

Since you're already using Panels, it might be easier to to just add your CSS as a Panel Style for each region of your homepage panel. You can define custom markup there and reuse it across your site.

You can also just go to the General section of the page manager variant rule for your homepage. There is a section here for adding CSS IDs and rules for only the current panel.

Note: this is all in D7, so it might be that this approach is better supported by Panels than it was in prior versions.

/* An example using bartik theme to add css based on content type */

function bartik_preprocess_node(&$variables) {
if(!empty($variables['node'])) {
    if($variables['node']->type == 'my_custom_content_type')
    {
      drupal_add_css(drupal_get_path('theme', 'any_theme_name') . "/css/foo.css");   
    }
  }
  // Some other code here
}

Try to add this in your 'template.php' file:

function mytheme_preprocess_page (&$variables)
{
  if (drupal_is_front_page()) {
    drupal_add_css(drupal_get_path('theme','mytheme'). '/css/front.css');
  } 
}

Replace 'mytheme' with name of your theme directory and '/css/front.css' with path where is your CSS file.

To unset 'front.css' file from other pages try to add to 'template.php':

function hook_css_alter(&$css) {
  if (!drupal_is_front_page()) {
    unset($css[drupal_get_path('theme', 'mytheme') . '/css/front.css']);
  }
}

Again, replace 'mytheme' with name of your theme directory.

If you need to unset 'styles.css' from front page just combine these two codes.

Lets assume that you need 'front.css' without 'styles.css' on front page, and 'style.css' without 'front.css' on all other pages. Code will look something like this:

function mytheme_preprocess_page (&$variables)
{
  if (drupal_is_front_page()) {
    drupal_add_css(drupal_get_path('theme','mytheme'). '/css/front.css');
  } 
  else {
    drupal_add_css(drupal_get_path('theme','mytheme'). '/css/styles.css');
  }
}

function hook_css_alter(&$css) {
  if (drupal_is_front_page()) {
    unset($css[drupal_get_path('theme', 'mytheme') . '/css/styles.css']);
  }
  else {
    unset($css[drupal_get_path('theme', 'mytheme') . '/css/front.css']);
  } 
}

Also, replace 'mytheme'.

I hope this will be helpful.

I would've skipped touching template.php altogether and just add another item in your theme's .info file

Say your stylesheet is in css/foo.css.

This is how your theme_name.info file would look:

name = Theme Name
...
stylesheets[all][] = css/foo.css

Then you benefit from having it cached with the main stylesheets, and since I'm assuming this is for your homepage it would make sense.

Aside the Drupal approach, when you only need a short piece of css inside your HTML5 body, you have the css scoped Attribute. See https://stackoverflow.com/a/4607092/195812

This solution will save you from editing code and installing more modules

You can print the page node in the body-tag

<body page-node-26419 ...>

Then you can restrict

body.page-node-26419 {
    background: red
}

This is useful for minor quick changes

Licensed under: CC-BY-SA with attribution
Not affiliated with drupal.stackexchange
scroll top