I'm using Drupal 7.10, an Adaptive Theme subtheme and having a Views block with caching in a side bar on my site.

Caching configuration of my block:

Block caching: Cache once for everything (global) 
Cache: Time-based | 1 Hour/1 Hour 

Adaptive Theme adds in adaptivetheme_preprocess_html() a generated CSS file with drupal_add_css(). The generated CSS file is added after the base layout file. This generated CSS file should overwrite the base layout settings.

However, the generated CSS file gets a lower weight than the base layout file due to views_plugin_cache->restore_headers(). This function readds all existing CSS files with drupal_add_css().

The weight calculation of drupal_add_css() is:

$options['weight'] += count($css) / 1000;

During the CSS readdition of views_plugin_cache->restore_headers() the count($css) remains constant and count($css) / 1000 weight is added again to all CSS files inserted until now.

CSS files which are added after views_plugin_cache->restore_headers() do not have a "double weight", i.e. they get a smaller weight. drupal_get_css() outputs them first. But this is wrong. The CSS files should be outputted in the order of insertion.

Example:

1. CSS files are added by drupal_bootstrap() with drupal_add_css():

     4: _drupal_theme_initialize() (Array, 2 elements)
     3: drupal_theme_initialize() (Array, 2 elements)
     2: _drupal_bootstrap_full() (Array, 2 elements)
     1: drupal_bootstrap() (Array, 2 elements)
     0: main() (Array, 2 elements)
Called from includes/common.inc, line 2882   

Weight calculation:
count($css): 1
sites/all/themes/adaptivetheme/adaptivetheme/css/at.layout.css before => weight: 0
$options['weight'] += count($css) / 1000;
sites/all/themes/adaptivetheme/adaptivetheme/css/at.layout.css after => weight: 0.001

2. CSS files are readded by views_plugin_cache->restore_headers() with drupal_add_css():

    16: views_plugin_cache->restore_headers() (Array, 2 elements)
    15: views_plugin_cache->cache_get() (Array, 2 elements)
    14: view->render() (Array, 2 elements)
    13: views_plugin_display_block->execute() (Array, 2 elements)
    12: view->execute_display() (Array, 2 elements)
    11: views_block_view() (Array, 2 elements)
    10: call_user_func_array() (Array, 1 element)
     9: module_invoke() (Array, 2 elements)
     8: _block_render_blocks() (Array, 2 elements)
     7: block_list() (Array, 2 elements)
     6: block_get_blocks_by_region() (Array, 2 elements)
     5: block_page_build() (Array, 2 elements)
     4: drupal_render_page() (Array, 2 elements)
     3: drupal_deliver_html_page() (Array, 2 elements)
     2: drupal_deliver_page() (Array, 2 elements)
     1: menu_execute_active_handler() (Array, 2 elements)
     0: main() (Array, 2 elements)
Called from includes/common.inc, line 2882   

Weight calculation:
count($css): 41
sites/all/themes/adaptivetheme/adaptivetheme/css/at.layout.css before => weight: 0.001
$options['weight'] += count($css) / 1000;
sites/all/themes/adaptivetheme/adaptivetheme/css/at.layout.css after => weight: 0.042

3. The generated CSS file is added by adaptivetheme_preprocess_html() with drupal_add_css():

     7: adaptivetheme_preprocess_html() (Array, 2 elements)
     6: theme() (Array, 2 elements)
     5: drupal_render() (Array, 2 elements)
     4: drupal_render_page() (Array, 2 elements)
     3: drupal_deliver_html_page() (Array, 2 elements)
     2: drupal_deliver_page() (Array, 2 elements)
     1: menu_execute_active_handler() (Array, 2 elements)
     0: main() (Array, 2 elements)
Called from includes/common.inc, line 2884

Weight calculation:
count($css): 41
public://at_css/bergamotte.responsive.layout.css before => weight: 0
$options['weight'] += count($css) / 1000;
public://at_css/bergamotte.responsive.layout.css after => weight: 0.041

The weight of public://at_css/bergamotte.responsive.layout.css (0.041) is smaller than sites/all/themes/adaptivetheme/adaptivetheme/css/at.layout.css (0.042). That's not OK. The order of insertion is not respected.

In my case the layout of my site is broken due to the wrong CSS files order (see #1390750: Main column sometimes narrow).

Adding CSS files in hook_preprocess_html() with drupal_add_css() seems to be OK since Bartik and Garland do it as well.

There's a workaround. The weight attribute can manually be increased in the drupal_add_css() call in the hook_preprocess_html() hook (Example in #1390750: Main column sometimes narrow). Thus, such a CSS file is output later.

Context information: Issue #92877: Add numeric weight to drupal_add_css added the Drupal core weight calculation.

I don't know how a proper fix looks like.

Comments

dawehner’s picture

Puh

So do it see it right that restore_headers() is called after preprocess_html? This seems to be an interesting problem
and i guess the only way to really fix it is to adapt the calls in preprocess_html as you said.

scito’s picture

No, restore_headers() is not called after preprocess_html.
The order of calls is

  1. drupal_bootstrap() with drupal_add_css()
  2. views_plugin_cache->restore_headers() with drupal_add_css()
  3. adaptivetheme_preprocess_html() with drupal_add_css()

The actual problem is that the weight of all the CSS files which are readded with drupal_add_css() in views_plugin_cache->restore_headers() are increased. They'll get higher weight. The real insertion order is not reflected by the weight value anymore. Then Drupal "thinks" that these files were added at the end. And so Drupal outputs them at the end.

The order of the CSS files is important for Adaptive themes. Adaptive themes relies on the insertion order which is reflected by the weight value. That's why the bug is visible there and may not be remarked with other themes.

An idea to fix this:
We could compensate the weight in views_plugin_cache->restore_headers() before or after we call drupal_add_css():

$options['weight'] -= count($css) / 1000

Or we could save the weight value before we call drupal_add_css() in views_plugin_cache->restore_headers() and we restore the weight value after the call.

Thus, the weight will finally not be changed. Then the real insertion order is correctly reflected by the weight value.

scito’s picture

How to reproduce:

  1. Place a Views block with caching on a page.
  2. Add a CSS file A in the .info file of a theme.
  3. Add a CSS file B in a theme_preprocess_html().
  4. Check the order of the CSS files output on that page.

Expected: The the CSS file A is output before the CSS file B.
Actual: The the CSS file A is output after the CSS file B.

nanotube’s picture

I confirm this same bug. I had issues where things looked fine on the first load after clearing the cache. However, the ordering of the CSS moved on the next refresh. This problem does not exist after I turn off the all Views caching on that page.

Jeff Burnz’s picture

Reported again here: #1472146: Sidebar width changes due to order of stylesheets changing in certain scenarios, is there a potential fix for this in the works or should I move on a workaround in my theme? Also is this 7.x-3.x-dev bug or does it apply to 7.x-3.3?

phizes’s picture

I've had this bug in Views 7.x-3.3, but todays dev seems to have fixed it. I don't have the same level of detail as OP though.

dawehner’s picture

This is still a problem of 7.x-3.x.

tim.plunkett’s picture

This sounds to me like a duplicate of #1388546: Adding CSS or JS files twice changes weight

damiankloip’s picture

Status: Active » Closed (duplicate)

Closing as duplicate issue in #8, which is a core issue.