81

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.

4

12 Answers 12

70

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.

9
  • so for the home page, would you use if(drupal_is_front_page()) { instead of if(drupal_get_path_alias [etc]?
    – epersonae
    Mar 2, 2011 at 23:59
  • Yes, the conditions are entirely up to you. You could simply do a $vars['#node']->nid == $nid check if you wanted.
    – Decipher
    Mar 3, 2011 at 0:06
  • 10
    Decipher, can't find any fault with your code. But hope you don't mind me pointing out that unless you are talking about Drupal permission configuration, the way you role should actually be the way you roll. ;-)
    – medden
    Jun 28, 2012 at 7:23
  • 2
    FYI, I'm using Drupal 7 and found that I needed to use $vars['elements']['#node']->nid instead in the alias lookup. There's no #node root in vars in the latest Drupal 7 from the looks of it. Feb 14, 2014 at 21:50
  • 1
    Should be $vars['node']->nid instead of $vars['#node']->nid
    – jphelan
    May 4, 2017 at 21:43
16

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.

1
  • I use Context Add Assets in literally every website I make - if your into Context's (which drive every section of my builds) Add Assets is perfect!
    – electblake
    Mar 16, 2011 at 21:03
12

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.

2
  • that's basically what I was doing...and it's almost 200 lines, so it seemed like a good idea to move it elsewhere. (yes, it should probably be shorter. that may be a separate step.)
    – epersonae
    Mar 3, 2011 at 0:27
  • On the other hand, your response inspired me to read the template.php in my (Zen child) template, which got me to the final answer.
    – epersonae
    Mar 3, 2011 at 0:28
7

If the criteria for which adding a CSS style depends from some node properties, then I would implement MYTHEME_preprocess_node(&$variables); one of the values passed to the function is $variables['node'] (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 property, I would implement MYTHEME_preprocess_page(&$variables); $variables['node'] contains a node object, if the shown page is a node page.

The documentation for page.tpl.php lists the variables available in hook_preprocess_page() and the template file. Between them, there is $variables['is_front'], which can be used to determinate when the viewed page is the front page. An implementation of hook_preprocess_page() that needs to add CSS files to the front page could use the following code.

MYTHEME_preprocess_page(&$variables) {
  if ($variables['is_front']) {
    // The viewed page is the front page: Add the desired CSS file.
    drupal_add_css(drupal_get_path('theme', 'MYTHEME') . "/foo.css");
  }
}
6

You could create a custom module and use hook_preprocess_node() to selectively load CSS files based on the node ID.

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

Replace MYMODULE with the module name, and MYTHEME with the name of the theme containing the CSS file.

3
  • Then the next question would be why use arg(1) for the nid when the node variables are passed through $vars :) Which would then lead to the next question of how is this different to my answer :p
    – Decipher
    Mar 3, 2011 at 0:30
  • I guess I should have read the hook_preprocess_node() documentation. You're absolutely right. epersonae, I suggest you accept Decipher's answer.
    – Camsoft
    Mar 3, 2011 at 0:32
  • 1
    This is ok but not ideal for exportable code where the nid might be different on a production or remote environment. It would be better to do an alias pattern match (as answered above) which would most likely be the same in all environments. Jun 12, 2013 at 15:50
5

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).

3

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.

2

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.

2

/* 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
}
2

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.

2
  • The last piece of code is what I needed. And it works, i.e., after I removed stylesheets[all][] = css/front.css from my theme.info - I guess I assumed wrongly that we need to have that along with stylesheets[all][] = css/styles.css. I was also worried that because I'm overriding page.tpl.php with page--front.tpl.php it might not work but everything seems to be holding up nicely. This is truly helpful. Thanks!
    – Sd1
    Aug 13, 2014 at 17:29
  • Just to make sure everybody gets this solution; make sure to remove styles.css (the default) and front.css from your theme.info file. Flush all caches and it should be good to go.
    – Sd1
    Aug 14, 2014 at 17:42
1

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.

2
  • And of course you would need to qualify your selectors based on the node's attributes, i.e. nid, node type, etc Nov 2, 2012 at 20:30
  • The problem with this approach is it will affect all the pages on the site with the css added here
    – pal4life
    Jun 6, 2014 at 15:03
1

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

1
  • welcome to Drupal Answers ! This answer has already been provided above by Dave Reid.
    – Kojo
    Jan 13, 2018 at 17:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.