What is the best way to translate css so that it works in a different path. I've looked at a few different libraries (CrushCSS, minify) and they seem to only over this service along with compressing the files (which I don't want to do).
Is my best a regex? If so what are all the possible cases that I will need to handle?
For example, input: /base/my.css
@import url "../another/file.css"
#container {
background: url('example/relative/path.png');
}
#container2 {
background: url('/example/absolute/path.png');
}
Expected output: /base/example/path/my.css
@import url "../../../another/file.css"
#container {
background: url('../relative/path.png');
}
#container2 {
background: url('/example/absolute/path.png');
}
EDIT:
I'm not interested in "best practice" or ways to avoid this type of problem. I'm only interested in how to do the transformation so that the css remains correct in the new path.
I decided that I would refactor some code from Minify to allow for the abstract css transformation I needed.
<?php
//This class is heavy borrowed from Minify_ImportProcessor
class CSSImporter
{
static function changePaths( $content, $current_path, $target_path )
{
$current_path = rtrim( $current_path, "/" );
$target_path = rtrim( $target_path, "/" );
$current_path_slugs = explode( "/", $current_path );
$target_path_slugs = explode( "/", $target_path );
$smallest_count = min( count( $current_path_slugs ), count( $target_path_slugs ) );
for( $i = 0; $i < $smallest_count && $current_path_slugs[$i] === $target_path_slugs[$i]; $i++ );
$change_prefix = implode( "/", array_merge( array_fill( 0, count( $target_path_slugs ) - $i, ".." ), array_slice( $current_path_slugs, $i ) ) );
if( strlen( $change_prefix ) > 0 ) $change_prefix .= "/";
$content = preg_replace_callback(
'/
@import\\s+
(?:url\\(\\s*)? # maybe url(
[\'"]? # maybe quote
(.*?) # 1 = URI
[\'"]? # maybe end quote
(?:\\s*\\))? # maybe )
([a-zA-Z,\\s]*)? # 2 = media list
; # end token
/x',
function( $m ) use ( $change_prefix ) {
$url = $change_prefix.$m[1];
$url = str_replace('/./', '/', $url);
do {
$url = preg_replace('@/(?!\\.\\.?)[^/]+/\\.\\.@', '/', $url, 1, $changed);
} while( $changed );
return "@import url('$url'){$m[2]};";
},
$content
);
$content = preg_replace_callback(
'/url\\(\\s*([^\\)\\s]+)\\s*\\)/',
function( $m ) use ( $change_prefix ) {
// $m[1] is either quoted or not
$quote = ($m[1][0] === "'" || $m[1][0] === '"')
? $m[1][0]
: '';
$url = ($quote === '')
? $m[1]
: substr($m[1], 1, strlen($m[1]) - 2);
if( '/' !== $url[0] && strpos( $url, '//') === FALSE ) {
$url = $change_prefix.$url;
$url = str_replace('/./', '/', $url);
do {
$url = preg_replace('@/(?!\\.\\.?)[^/]+/\\.\\.@', '/', $url, 1, $changed);
} while( $changed );
}
return "url({$quote}{$url}{$quote})";
},
$content
);
return $content;
}
}
?>
I'd say the best way would be to always use URLs relative to the root of your site. /example/absolute/path.png will always work, no matter where you place the CSS file.