After searching for several hours for a clean solution on how to remove a particular core/module stylesheet from the stylesheet queue, I've only found some dirty hacks like this one.

The given solution (replacing print $styles; by $css = drupal_add_css(); unset($css['all']['module']['foo']); print drupal_get_css($css); in page.tpl.php) is definitely not a clean one since it needs code in a place where such code simply shouldn't be.

From a themer's perspective I wondered why there is a drupal_add_css() but not a drupal_remove_css() function. From this POV and taking the time for finding a dirty solution into account, this can certainly be categorized as bug.

To come straight to the point: The attached patch for common.inc introduces the function drupal_remove_css($path = NULL) that

  • extends drupal_add_css() with an argument to remove a given path
  • can be called from a theme (f.e. in template.php) or any module that wants to override another one.

Example: To remove Drupal's default stylesheet from the queue, simply put this line into template.php:

drupal_remove_css('modules/system/defaults.css');

This patch is simple, straightforward and will help many users to get their sites up & running in less time.
Overriding core and contrib module styles is one of the most annoying actions in building a new Drupal theme.

Comments

pwolanin’s picture

Status: Needs review » Needs work

Somehow I thought one could do this already in 5.x, but don't see it now.

Anyhow, this doesn't seem like quote the right approach, since you need to be able to do this after all modules/themes have added their CSS, right?

sun’s picture

Status: Needs work » Needs review

I don't think there is another way to disable specific stylesheets as you do not know if and when a particular one is added to the queue by a core or contrib module. Since this is a theming issue and one Drupal installation could be used to deliver more than one site or theme, a theme designer can only remove stylesheets at theming level, i.e. in template.php. AFAIK, all stylesheets are already added to the queue at theming level.

Please also bear in mind that this is only a bug fix that saves time (and money). It's obvious that a feature request for a more complete CSS handling solution for 6.x+ would likely introduce a more modular concept, so f.e. the current drupal_add_css() would become drupal_manage_css() along with the helper functions drupal_add_css() and drupal_remove_css(). But that is not part of this issue.

smk-ka’s picture

Maybe the approach that drupal_add_js() is using could be of use for you?

drumm’s picture

Version: 5.x-dev » 6.x-dev
Category: bug » feature

This is an API change so I would call it a feature. It needs to go in the development version and will not hit the stable 5.x versions.

pwolanin’s picture

Status: Needs review » Needs work

The patch seems to only really handle the case of media == 'all'.

I'm not sure what the possible concerns are of having such code in template.php, but that's also not a good way to handle this- not all themes have such a file that's included.

One possible approach (requires a module) to this would be to add a call to drupal_alter to drupal_get_css():


function drupal_get_css($css = NULL) {
  $output = '';
  if (!isset($css)) {
    $css = drupal_add_css();
  }
  drupal_alter('css', $css);
  $no_module_preprocess = '';
  $no_theme_preprocess = '';

...

If you want themes to be able to do this - that's harder. The principle of theme functions is to return HTML, not manipulate data. however this seems like a case where something like theme('alter_css', $css) would be justified?

This could be called in function template_preprocess_page()?

$variables['styles']            = drupal_get_css(theme('alter_css', drupal_add_css()));
pwolanin’s picture

Status: Needs work » Needs review
StatusFileSize
new522 bytes

As shown above. A simple one line patch to let modules alter the css queue before it's rendered.

merlinofchaos’s picture

+1, but it seems like you'd also want to allow the theme to alter it. In fact, it's much more valuable to let the theme alter it, I would think.

solipsist’s picture

+1 from me on this one too... I agree that this should be possible at theme level, it's where it's needed the most I would think. It's important from a performance POV too since instead of overriding CSS, themers could disable modules' CSS files and replace them entirely with their own.

pwolanin’s picture

StatusFileSize
new2.17 KB

After discussion with merlinofchaos in IRC, I went ahead an implemented the part to allow the theme to alter too. This diverges a bit from the normal use of theme functions (it has to return an array) but that seems to be the only reasonable way to let themes do this. I tested both parts of the patch. With the latter part you can make your site look ugly by putting in Garland's template.php:

function garland_css_alter($css) {
  unset($css['all']['module']);
  return $css;
}
dmitrig01’s picture

Status: Needs review » Reviewed & tested by the community

yes

alpritt’s picture

Status: Reviewed & tested by the community » Needs review

+1

Just quickly adding that this functionality will be extremely useful from a themer's perspective.

The negative, of course, is that this is not particularly intuitive for a non-coder. But that is a wider and more difficult problem with theming that shouldn't hold up this commit.

alpritt’s picture

Status: Needs review » Reviewed & tested by the community

hmm, not sure how that happened. Changing back the status.

sun’s picture

Looks great!
Thanks, pwolanin, for taking this up.

douggreen’s picture

I checked out the latest code from cvs head, applied the patch with no problems. I ran two tests.

  1. I created a custom module with a hook_css_alter, enabled css aggregation, modified the css differently for different nodes, and confirmed that the correct css was written.
  2. I then ran the same tests with theme_css_alter and confirmed that the correct css was written. The only confusion I ran into is that the themes are now cached (not related to this patch) and I had to clear my cache to get it to recognize my new theme functions.

+1

pwolanin’s picture

Title: CSS files can not be removed from queue » Allow CSS files to be removed from queue

improving the title

Crell’s picture

This works fine for me, and complements this patch wonderfully. (That one adds CSS, this one removes it.) My only problem is the name. theme_* functions are expected to behave in one way. *_alter functions are expected to behave in another. theme_css_alter behaves like... which? My first guess was like an alter hook, but it's actually a theme function. That's confusing.

I'd prefer a name other than "alter_css" for the theme function to avoid confusion with the alter workflow. Otherwise this is ready to go.

Crell’s picture

Like I said, it compliments this patch. *sigh*

dvessel’s picture

+1

I found some workarounds that works well within themes but this would simplify that.

m3avrck’s picture

As the write of the original patch that added drupal_add_css() to core I don't like this approach.

The cleanest approach to do this is to create your phptemplate_variables() and add:

     $new_css = drupal_add_css();
     // removed unnessecary CSS styles
     unset($new_css['all']['module']['modules/poll/poll.css']);
     unset($new_css['all']['module']['sites/all/modules/contrib/cck/content.css']);

     // rebuild CSS
     $vars['styles'] = drupal_get_css($new_css);  

This patch doesn't really make that process any simpler and adds more overhead IMO.

pwolanin’s picture

I think this approach is less overhead - since you alter the css array before the files are loaded and aggregated. With your appreach, won't every file have to be loaded again?

m3avrck’s picture

It's just manipulating an array with that code and then it rebuilds the CSS cache.

I agree -- it's not the best, but I don't think this method here makes it any simpler... or maybe I'm reading it wrong (perhaps too tired ;-))

alpritt’s picture

Status: Reviewed & tested by the community » Needs work

Two issues have been raised (comments #16 and #19) which need to be resolved before we can say this is ready, so I'm pushing this back to 'needs work'.

sun’s picture

Assigned: sun » Unassigned
Status: Needs work » Reviewed & tested by the community

@#16: Please correct me if I'm wrong. theme_css_alter() is both a theme_* and an *_alter function, which is actually doing the trick. Whilst theme_css_alter() is invoked by drupal_alter(), garland_css_alter() is invoked by the Theme system. Each theme can implement its own theme_css_alter() function.

@#19: The great benefit of this patch from a themer's perspective is that there is a official "best practice" to achieve the targeted result - no more custom hacks and a solid ground for further improvements in the future. Without an implementation like this (as of now) we force themers to either use Drupal's default stylesheets or to implement custom hacks found on d.o. I agree, it's far from perfect. But with a simple explanation and a cross-reference to drupal_add_css() in the API, themers won't be stuck anymore.

Setting this back to RTBC.

alpritt’s picture

I'm totally in favour of this feature, but I'm no longer convinced this short term solution is a good response to the problem.

Re: solid ground (#23): I'm not sure this is true. The implementation of this looks like a clever hack to me, and I'm not sure it's really something we can build on. Unless we are gaining something substantial from this in the short term, I'm against it. This is part of the API that themers will have to learn, and I don't want them to have to unlearn something if we can avoid it. This just feels like we are rushing in the hope of getting it into Drupal 6.

I personally think the sister patch (http://drupal.org/node/141725) has a good strategy for this kind of thing. Using the .info file is not only easy, it is arguably easier than coding it with plain old HTML. This is a very positive move. The more theme related stuff we can take out of PHP functions the better.

To avoid a ping-pong match I'll leave the status alone.

sun’s picture

Status: Reviewed & tested by the community » Needs review

@alpritt: The referenced patch deals with adding stylesheets to a theme only. I'm not able to think of a way to remove core and module stylesheets through a definition in a theme's .info file.

Hm. Maybe this way?

theme.info:
remove-stylesheet[all][module] = modules/system/defaults.css
remove-stylesheet[all][module] = modules/node/node.css
remove-stylesheet[all][module] = modules/system/system.css
remove-stylesheet[all][module] = modules/user/user.css

The downside of this approach would be that a themer might not know [all][module] and is not able to determine the array keys without executing PHP again.

alpritt’s picture

Looks like this has hit the code freeze.

I suggest we first make sure there is a clear workaround documented in the handbook and then postpone this for d7.

Hopefully by then I'll have be more comfortable with the core code, so will actually be more useful ;)

pwolanin’s picture

A clarification - I thought that naming the theme function using the same pattern as the _alter function would simply things - but perhaps not. The theme function could be named anything (e.g. theme('ihateothercss', $css)).

webchick’s picture

Version: 6.x-dev » 7.x-dev

Past code freeze.

sun’s picture

Status: Needs review » Needs work

*sigh* just wanted to tell that I'm stuck again creating a new theme. While hacking my way using Ted's workaround in #19 I'm seriously asking from a themer's perspective, how this can be classified as a feature request.
If you'd ask me, this issue is the reason why many Drupal sites look quite similar - since we expect that themers know how to fix this bug.

Another particular use case of drupal_remove_css() was to be able to do

// Include user.css in admin/user *only*.
if (!(arg(0) == 'admin' && arg(1) == 'user')) {
  drupal_remove_css('modules/user/user.css');
}
else {
  drupal_add_css('modules/user/user.css', 'module', 'all', FALSE);
}

in template.php - in short: 1) remove user.css from preprocessed CSS queue, but 2) add it to non-preprocessed queue if needed.

pwolanin’s picture

@sun - well if you feel strongly enough that it's a bug, change the version back and make your case.

eaton’s picture

StatusFileSize
new1.82 KB

Here's a shot at it -- it's definitely kludgey, but it could be a real boost for CSS-only .info file driven themes that just want to, say, turn off all of Drupal's default css files and control stuff like ULs and such themselves.

pwolanin’s picture

Version: 7.x-dev » 6.x-dev

I assume Eaton is still hoping for 6.x.

Anyhow - I don't think this code is good, since themes cannot predict the path where contrib modules may be installed.

Perhaps a simpler patch could provide a mechanism for removing only core CSS or core required module CSS? Or replacing them rather than removing them?

eaton’s picture

Anyhow - I don't think this code is good, since themes cannot predict the path where contrib modules may be installed.

Well, that's one of the reasons it's doing a string comparison -- if you put in modules/system/system.css, it will find that anywhere there's a modules folder. Your point stands, though. I'm not particularly HAPPY with it, but it's cleaner than any other method I was able to come up with.

It is a relatively small change. If it (or any similar improvements) go in, it should go in under the principle that 'anything that prevents users from making a reasonably simple CSS-only theme, without writing PHP code, is a bug in Drupal 6.'

eaton’s picture

Version: 6.x-dev » 7.x-dev
Status: Needs work » Postponed

On pwolanin's suggestion, I'll avoid hijacking THIS issue thread and point directlly to the more 'focused' issue: http://drupal.org/node/163785. Thanks.

sun’s picture

Version: 7.x-dev » 6.x-dev
Status: Postponed » Closed (duplicate)

From a themer's point of view, I'd say that overriding core/module stylesheets is sufficient for creating any custom theme. If 163785 goes in, themers are able to place an empty/modified stylesheet into their theme folder that has the same name like a core/module stylesheet. If CSS preprocessing is enabled, even empty stylesheet files (replacements) won't hurt anyone.

Thus, marking as duplicate of http://drupal.org/node/163785