After turning on "Optimize CSS files" invalid css is generated.

#electro_cover a {
	background: url(../images/loop_cover.gif);
	display: block;
	height: 206px;
	width: 207px;
}

is turned into

#electro_cover a{background:url(/sites/all/themes/xhtml/css/./display:block;height:206px;width:207px;}

Issue fork drupal-413296

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

jax’s picture

When parsing the css file the preg_replace_callback calls _drupal_build_css_path with the following matches:

array(2) {
  [0]=>
  string(318) "url(./display:block;height:206px;width:207px;}#electro_loop{background:url(./display:block;height:207px;margin:15px 0;width:207px;}#electro_loop #flash_content{margin:0;}#patners{}#col_center{padding:1px 20px 15px 40px;width:586px;}#col_center #search-box{display:none;}#col_right{background:url(../images/collage.png)"
  [1]=>
  string(313) "./display:block;height:206px;width:207px;}#electro_loop{background:url(./display:block;height:207px;margin:15px 0;width:207px;}#electro_loop #flash_content{margin:0;}#patners{}#col_center{padding:1px 20px 15px 40px;width:586px;}#col_center #search-box{display:none;}#col_right{background:url(../images/collage.png"
}

Let's see if I can find out what's wrong with the regexp....

jax’s picture

When trying the expression in python:

>>> matches = re.findall(r'url\([\'"]?(?![a-z]+:|\/+)([^\'")]+)[\'"]?\)', content, re.IGNORECASE)
>>> print matches
['../images/bg.jpg', '../images/loop_cover.gif', '../images/loop_electro.gif', '../images/collage.png']

it works. So it might be a PHP version issue.

jax’s picture

StatusFileSize
new1.88 KB

It chokes on the attached file with a stock PHP 5.2.5 and a 5.2.0-8+etch13 (on Debian). So it must be something with the expression. I've attached the file for further inspection.

jax’s picture

Actually the css is already botched when

function drupal_load_stylesheet($file, $optimize = NULL) {

is called on the css file

@charset "utf-8";

@import "reset.css";
@import "structure.css";
@import "forms.css";
@import "menu_footer.css";
@import "content.css";

@import "admin.css";
jax’s picture

Ok, I'm pretty sure that I've found where it is going wrong.
The style.css is the file described above. When it comes in drupal_load_stylesheet() it encounters:

$contents = preg_replace_callback('/@import\s*(?:url\()?[\'"]?(?![a-z]+:)([^\'"\(\)]+)[\'"]?\)?;/', '_drupal_load_stylesheet', $contents);

Which recursively calls _drupal_load_stylesheet() for the matched elements. If tracked what it the call returns when it was called with 'structure.css' and that css is still valid. But when I check what the preg_replace has returned it is botched.

#electro_cover{margin:15px 0;}#electro_cover a{background:url(../images/loop_cover.gif);display:block;height:206px;width:207px;}

becomes

#electro_cover a{background:url(./display:block;height:206px;width:207px;}

So, there is definately something wrong with the @import replacement css.

jax’s picture

Test case:
structure.css:

 #elektro_cover a { background: url(../images/loop_cover.gif); }

style.css:

@charset "utf-8";

@import "structure.css";

Resulting css code:

@charset "utf-8";

 #elektro_cover a{background:url(./}
jax’s picture

Sigh, I didn't see the underscore. The culprit is:

function _drupal_load_stylesheet($matches) {
  $filename = $matches[1];
  // Load the imported stylesheet and replace @import commands in there as well.
  $file = drupal_load_stylesheet($filename);
  // Alter all url() paths, but not external.
  return preg_replace('/url\(([\'"]?)(?![a-z]+:)([^\'")]+)[\'"]?\)?;/i', 'url(\1'. dirname($filename) .'/', $file);
}

That last one is incorrect.

jax’s picture

I'm pretty sure that last regexp should have a "@import" in there as well because else it replaces all the url() instances that match and not only the @import statements.

jax’s picture

Title: CSS optmization fails on relative paths » CSS optmization fails on css files that use @import
Version: 6.10 » 7.x-dev
StatusFileSize
new416 bytes

I've tested this issue with 7.x dev and it's still there. I've attached a theme that allows testing. Follow these steps to reproduce:

  • Download theme and extract in sites/all/themes
  • Go to admin/settings/performance and enable CSS optimization
  • Go to admin/build/themes and enable/set as default the testtheme
  • After submitting look at the source to determine the name of the generated css file
  • You'll notice that it generates invalid css, the css ends with #elektro_cover a{background:url(./}

There is probably something wrong with the regexp in _drupal_load_stylesheet($matches).

jax’s picture

StatusFileSize
new465 bytes

Damn, I screwed up the testtheme, it has a path outside the theme's dir. Here's a better test theme.

jax’s picture

Status: Active » Needs review
StatusFileSize
new859 bytes

I'm pretty sure that the original code has never worked. The first back reference is whether or not the url starts with a quote. The whole point of the replace is to add the sub-path within the theme directory.

The patch seems to resolve the problem for first and second level @imports.

grim assim’s picture

whoa!

I have been looking into why the css optimization fails on my site D6 but only under IE (I have seen a few posts about this) it seems that FF/Chrome will still pass the broken css file.

I jimmied your patch into my site and it works flawlessly.

Mainly wanted to thank you for the time you have put into this bug!

*Thanks*

jax’s picture

Status: Needs review » Reviewed & tested by the community

I've been using it on a couple of sites as well now and I really want this to hit D7 and D6.11 since I'd rather not have to patch core each time I turn on css optimization with a design that uses @import.

Since it works for you and me I'm putting this in reviewed and tested.

hass’s picture

Status: Reviewed & tested by the community » Needs review

I wonder about this thought to have this tested while developing the optimizer #113607: Import @import commands when building CSS cache in D6 times... isn't there a way to fix the regex if there is something wrong? Don't set your own patches to RTBC, please.

Have you tested all @import variants? for e.g.

@import url(http://localhost/drupal5/sites/all/themes/mytheme/css/screen/test1.css);
@import "http://localhost/drupal5/sites/all/themes/mytheme/css/screen/test1.css" screen;
@import 'http://localhost/drupal5/sites/all/themes/mytheme/css/screen/test1.css';
@import url("http://localhost/drupal5/sites/all/themes/mytheme/css/screen/test1.css") print, embossed;
@import url('http://localhost/drupal5/sites/all/themes/mytheme/css/screen/test1.css');
@import url('css/modules/example1.css');
@import url("css/modules/example2.css");
@import url(css/modules/example3.css);
...
hass’s picture

jax’s picture

It's not really a duplicate, this one is just one more thing that is wrong with the CSS parsing.

caktux’s picture

just some extra info about @import i read the other day : http://ajaxian.com/archives/souders-dont-use-import

cburschka’s picture

Status: Needs review » Needs work

Duplicate or not, the indentation needs to be fixed on one of the added lines. :)

That page about @import is very interesting; I've always wondered which way is better. However, Drupal's CSS aggregator needs to support all directives including @import, even if we don't use it in core...

casey’s picture

Issue tags: +CSS aggregation

tagging

casey’s picture

Component: system.module » base system
dropiopio’s picture

Priority: Normal » Major

I have the same issue still in drupal 7.2

Draggable icon of dashboard.css from misc dir is not loaded after css aggregation.

Views UI also suffers.

I tried various browser, web servers, base url at settings.php.
Nothing worked.

Any other idea? Or it is a bug in rare cases?

sun’s picture

Title: CSS optmization fails on css files that use @import » CSS optimization/aggregation fails on files that use @import
Version: 7.x-dev » 8.x-dev
Priority: Major » Normal
Issue tags: -CSS aggregation +Needs backport to D7
cburschka’s picture

Version: 8.x-dev » 7.x-dev
Status: Needs work » Needs review
Issue tags: -Needs backport to D7

The bug is no longer in Drupal 8. While the replacement string wasn't changed, the pattern was fixed to only match the string up to the (optional) opening quote. Instead of capturing the actual path, it is now only checked with a lookahead assertion that makes sure it is not an absolute URL (starting with / or a protocol identifier). The #electro_cover example above works correctly.

I have not checked if the bug is still in 7.x. If not, this should be closed.

lundj’s picture

Version: 7.x-dev » 7.12

I still see the bug in the latest Drupal 7 version. Is there a patch/backport planned for this?

Version: 7.12 » 7.x-dev

Core issues are now filed against the dev versions where changes will be made. Document the specific release you are using in your issue comment. More information about choosing a version.

anrikun’s picture

Issue summary: View changes
Parent issue: » #2936067: CSS aggregation fails on many variations of @import
StatusFileSize
new725 bytes

Here's a direct port of the patch committed for D9 at #2936067: CSS aggregation fails on many variations of @import

avpaderno’s picture

StatusFileSize
new725 bytes

The previous patch did not run tests. I attached the same patch with a different filename.

avpaderno’s picture

I created a merge request, since patches are no longer tested.

poker10’s picture

Title: CSS optimization/aggregation fails on files that use @import » CSS optimization/aggregation fails on files that use specific variations of @import
Status: Needs review » Needs work
Issue tags: +Needs issue summary update, +Needs tests

Thanks for working on this! It seems like there is still some work needed.

Issue summary seems to be outdated, as we are not fixing relative paths, but @imports.
Parent issue updated the tests, here the test changes are missing.

I am also a bit confused about #25, which states that the issue no longer affected D8 (13 years ago) and then there was a commit/fix in D9 3 years ago (in this issue #2936067: CSS aggregation fails on many variations of @import, started 7 years ago). So we need to be sure what we are fixing here.

avpaderno’s picture

Comment #9 changed from CSS optmization fails on relative paths to CSS optmization fails on css files that use @import, although the same comment still describes the issue being with relative paths.

avpaderno’s picture

#2936067: CSS aggregation fails on many variations of @import does not seem to fix an issue with relative paths. It seems this issue and that issue are not related.
We should check for an issue for Drupal 8+ which changes the regular expression this issue propose to change.

avpaderno’s picture

Comment #25 seems to hit the nail.

The bug is no longer in Drupal 8. While the replacement string wasn't changed, the pattern was fixed to only match the string up to the (optional) opening quote. Instead of capturing the actual path, it is now only checked with a lookahead assertion that makes sure it is not an absolute URL (starting with / or a protocol identifier).

Status: Needs work » Closed (outdated)

Automatically closed because Drupal 7 security and bugfix support has ended as of 5 January 2025. If the issue verifiably applies to later versions, please reopen with details and update the version.