Skip to content


host path prepended to urls generated with interpolated strings #294

soychicka opened this Issue · 20 comments

In the latest distribution (1.1.3), if you use this paraphrased example from the home page

@base-url: "";
background-image: url("@{base-url}/images/bg.png");

the compiled result will be

background-image: url("http://localhost:3000/path/to/stylesheets/");

I don't know if this is a regression, as I've never had chance to use the string interpolation functionality before.

It looks like the string that is tested for the presence of a prefix around line 2270 isn't evaluated first, so the conditional isn't testing against the full url.

I see two possible solutions:

1. The easy way - modify the regex used to classify urls as relative/absolute, excluding any string that starts with '@{'
I pulled it off locally - Still, that's just a temporary fix until I can find out how to do it

  1. The right way - use the regex in its current state to test the interpolated value of all urls. I'm not familiar enough with the code base, so I don't know the proper way to eval the string... if anyone could point me in the right direction, I'd be happy to fork and resolve this issue.

I ran into the same issue.

@media_url: "/media";

// in some other scope

background: url("@{media_url}/images/sidebar_bg.png");


background: url("http://localhost:8000/media/less//media/images/sidebar_bg.png");

It basically prepended the path to the .less file to make the URL relative when it was intended to be absolute. This was only the case when I ran the compiler in browser and not from the command line.

Temporary Fix:

@media_url: "/media";

// in some other scope

background: ~"url(@{media_url}/images/sidebar_bg.png)";

@jasonkeene: thanks a bunch for your temporary fix!


Any idea if this will be fixed any time soon? :)



This break string interpolation as documented



This bug still exists in 1.2.0 when run in the browser.



This bug still exists in 1.2.1 when run in the browser.


I'm having the issue in 1.3 as well. Thanks for the temporary fix, @jasonkeene!


Me too!


This bug still exists in 1.3 when run in the browser.


A quick fix in less-1.3.0.js

// I commented out some lines marked with >> to fix the issue

tree.URL = function (val, paths) {
    if ( {
        this.attrs = val;
    } else {
        /* >> just comment these lines out as we don't use any relative urls
        >> // Add the base path if the URL is relative and we are in the browser
        >> if (typeof(window) !== 'undefined' && !/^(?:https?:\/\/|file:\/\/|data:|\/)/.test(val.value) && paths.length > 0) {
        >>    val.value = paths[0] + (val.value.charAt(0) === '/' ? val.value.slice(1) : val.value);
        >> }
        >> */
        this.value = val;
        this.paths = paths;

@jasonkeene Just wanted to add my appreciation for providing a temporary solution to this issue: Thanks!


If this is simply documented better, I'd consider it a feature ;-)


It's worth pointing out that if you call the less parser on a source this isn't a problem at all. It's only a problem with the "automatic" browser version:
<link rel="stylesheet/less" type="text/css" href="styles.less">
<script src="less.js" type="text/javascript"></script>

@neonstalwart neonstalwart referenced this issue

url() bug #807


Thanks soychicka. But is there any solution to fix that as permanently?


Unfortunately, the workaround doesn't seem to work with less.js 1.3.0 in a browser for @import rules. The host path is still prepended and the variables are not interpolated.

Probably related to: #410


@jasonkeene u just saved some hairs on my head :-) thanks a zillion!


I don't want to join development or put out a patch, but I do have an explanation and a fix (version 1.3.0).

Permanent fix (Non-Minified Source) Line 3013 (function tree.URL):

if (typeof(window) !== 'undefined' && !/^(?:https?:\/\/|file:\/\/|data:|\/|@)/.test(val.value) && paths.length > 0) {


@base-url: "";
.thing{ background-image: url("@{base-url}/images/bg.png"); }

During parsing, url("@{base-url}/images/bg.png") matches as a url and currently gets compared to the regular expression: /^(?:https?:\/\/|file:\/\/|data:|\/)/

"@{base-url}/..." doesn't match (since the variable hasn't been interpolated yet).

So its considered a relative path. So it gets turned into: url("http://localhost:3000/path/to/stylesheets/@{base-url}/images/bg.png").

Then variable interpolation takes place, turning it into: url("http://localhost:3000/path/to/stylesheets/");

The fix is to include @ as an initial dis-qualifier of relative paths (as I've done in my fix above). I think it will still be interpolated and then re-ran through the tree.URL transform. If the interpolated value is relative, I think it will then be prefixed with the absolute url; if it is absolute, it will be left alone.

I hope someone else takes this minor fix and puts the energy in to merge it into the code base. (Cuz I'm too busy to do it).

@lukeapage lukeapage closed this in 5b947fd

How is this closed 8 months ago? I still get localhost refernces after toCSS, but why does LESS do that in the first place? I currently run a script to remove them after compilation, but recently I ran into trouble where I cannot guess what the url is so I cannot remove it... how can I prevent the compiler from outputting absolute urls like that?

Less member

@ayyash look at rootpath and relativeUrls options. post a new issue if something is going wrong

@strk strk pushed a commit to CartoDB/carto that referenced this issue
@kapouer kapouer Add test for #294 bd454b4
@lukeapage lukeapage added a commit that referenced this issue
@lukeapage lukeapage Fix depends option Fixes #294 66fe6d8
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.