62

I have a reference inside my CSS file that refers to a static image:

#logo
{
  background: url('/static/logo.png')
}

This works just fine on my dev machine but not on my production environment since the url should be static.mydomain.com/logo.png. How do I dynamically change the css file according to the STATIC_URL in my settings file?

the_drow
  • 18,571
  • 25
  • 126
  • 193

9 Answers9

46

Use a relative path. Relative to the folder where the css file reside

Riccardo Galli
  • 12,419
  • 6
  • 64
  • 62
  • 1
    But the css and the files might be on a different server than the origin of the request. Will this still work? Is the path relative to the path of the css file? – the_drow May 05 '11 at 13:58
  • 2
    For example you have `http://static.mydomain.com/images/logo.png` and `http://static.mydomain.com/css/style.css`. Then you can use `background: url('../images/logo.png')` – DrTyrsa May 05 '11 at 14:00
  • 29
    This is not a solution. If I decide to change my static url to `/my/super/static/files/` ? – Silver Light May 05 '11 at 14:18
  • 2
    Search+replace? That can happen with any project, but CSS, JS, etc. are rarely generated just for that. You should have a good reason to make a static resource anything but static, otherwise, take advantage of tools already available such as sed, awk, etc. on *nix boxes or the "Search and replace across files" option most good IDEs have. – Chris Pratt May 05 '11 at 15:16
  • 10
    This answer doesn't address the question. A relative path will not work if your static assets are hosted on a different site. – Adam Donahue Sep 16 '15 at 17:07
  • 1
    @AdamDonahue css is a static asset, you supposedly have the static assets on the same domain. – Riccardo Galli Sep 17 '15 at 08:17
  • 1
    @RiccardoGalli But the whole point here is that the user will be generating the CSS file itself from a non-static site (using a template) in order to leverage the {% static %} template tag. At least that's how I read it. Hence using a relative URI inside the template would make it relative to the template site, even though the images are likely stored on the static site. This is not an uncommon problem and I believe it's answered below - use regular views, and add caching. – Adam Donahue Sep 17 '15 at 17:47
  • Interesting conundrum. I think this answer works. @AdamDonahue if you are generating the CSS inside a template than using the {% static %} tag works, there is no need for this answer. The question is about how to reference static files from inside a CSS file, where the {% static %} tag doesn't work. The CSS file is a static file, so it's relative path to the static location in django is fixed in relation to other static files, which are all fixed in relation to the static location ( as set up in the settings.py file ). Its all static so hard-coding is fine. – jeffery_the_wind Aug 25 '16 at 12:27
  • yes, definitely it works in the development but this doesn't in production. – Aditya Prasad Dhal Jun 03 '21 at 20:38
29

You can move any CSS that contains static file paths to inline CSS, contained in the template.

i.e.

<div style="background: url('{% static 'logo.png' %}')"></div>

The catch here is that it won't work for @media queries, you'd need to put those in a block, e.g.

<style>
    @media (min-width: 1200px){
       background: url('{% static 'logo.png' %}');
    }
</style>
Nexus
  • 749
  • 6
  • 12
  • 8
    Sorry no. Enterprise deployment and those of us who write valid HTML do not allow. Bad HTML/CSS. – Marc Dec 07 '17 at 01:49
  • 2
    Inline – Nexus Oct 01 '18 at 05:06
  • 2
    No FUD. Inline style and style tags are bad mojo because of order of precedence. If you are in a large project/production and CSS is getting compiled then inline operations can drain time and disrupt execution. Seen it MANY TIMES. Validator not barking does not mean good idea. Inline solicits !important, slippery slope. Also, inline on element + DOM manipulation can cause considerable problems. Any project I have been on for the past 10 years never allow the practice. Keep CSS separate avoid sloppy, lazy, and foolish. Additionally, modern MVC FE has almost no HTML. #antipattern – Marc Oct 03 '18 at 18:09
  • 9
    I agree, but that's beside the point. No one is arguing that using style tags pervasively throughout your project as a design pattern is a good idea, that's a straw man you are attacking there. This is an edge case where not using the style tag means you have to hard code static asset URIs, which I would consider a greater evil. If it isn't appropriate for your project that's fine, but its still a perfectly valid solution. – Nexus Oct 04 '18 at 21:47
  • 1
    This was the only way I could get background-image to work for me, even after trying all the other accepted answers from several SO questions. – Evan Jun 08 '20 at 17:20
24

Use absolute URL from base directory, this will point to any file in a static folder within an app

settings.py:

STATIC_URL = '/static/'

style.css:

background-image: url('/static/img/sample.jpg');
Pierre
  • 460
  • 4
  • 11
  • This will work in production, it is probably the best way, you can use external storage providers, like AWS S3, the settings will be the same. – Pierre Jun 13 '21 at 11:21
16

If you want to use {% static %} tag in your CSS file, you should use {% include %} tag. Here is an example to do so:

foo.html

{% load static %}
{% load i18n %}
{% load widget_tweaks %}

<!DOCTYPE html>
<html>
<head>
    <style>
        {% include "path/to/custom_styles_1.css" %}
    </style>
    <link rel="stylesheet" href="{% static 'css/custom_styles_2.css' %}">
</head>
<body>
<!-- Your HTML body -->
</body>
</html>

custom_styles_1.css

{% load static%}

{
     background: url('{% static "/img/logo.png" %}')
}

custom_styles_2.css

.fa {
    position: relative;
    text-align: center;
    font-family: BTitrBold;
    font-size: 3.5em;
}

.name {
    position: absolute;
    top: 37%;
    right: 15%;
}

.school {
    position: absolute;
    top: 530px;
    right: 200px;
}

.id {
    position: absolute;
    top: 700px;
    right: 200px;
}

.degree {
    position: absolute;
    top: 740px;
    left: 195px;
}

custom_styles_1.css is the CSS file that includes {% static %} tag. You should integrate it with your foo.html file with {% include %} tag. In this way, Django will put all the styles you need at the appropriate place and render the static tags correctly.

custom_styles_2.css is a normal CSS file located in STATIC_ROOT directory, so you can use {% static %} tag for it without any problem.

Amir
  • 433
  • 4
  • 10
5

See this similar stackoverflow question.

The only way to do what you want is to generate your CSS through Django. HTML is usually associated with Django views and templates, but in truth, you can return any file type: CSS, JavaScript, plain text, etc. However, doing so will add overhead to your site, so setting proper HTTP headers and server-side caching of the generated file will be very important.

Basic method:

return render_to_response('stylesheet.css',
    { 'domain': 'http://static.mydomain.com/' },
    context_instance=RequestContext(request),
    mimetype='text/css'
)

Alternatively, you can set up hosts on your system that map the static domains back to localhost for development purposes. Then, you can reference the domain as normal, but it'll still pull from your development files. Also, if you happen to have Ruby installed on your system, you can make use of a rubygem called Ghost. It lets you easily create, enable, disable, and delete custom hosts right from the command-line with no fuss.

Community
  • 1
  • 1
Chris Pratt
  • 232,153
  • 36
  • 385
  • 444
  • 1
    What are hosts? Can you explain? – CodyBugstein Jun 14 '14 at 23:00
  • 1
    Hosts are people you invite for dinner. Virtual hosts are people you invited for dinner and didn't come. Just a joke I was used to say to my students. It's bad I know... anyway just google for "apache virtual hosts" and you'll have a good explanation. – Olivier Pons Apr 25 '17 at 08:39
  • 1
    Those would be "guests". "Hosts" in that context are the people who are responsible for the event, i.e. the people doing the inviting, not the ones invited. So, yeah, pretty bad joke. ;) – Chris Pratt Apr 25 '17 at 13:31
4

If you're using django-libsass to generate your css, you can use custom functions to bridge django and the sass precompiler.

As a matter of fact, the function static is already implemented, and you can use it:

.foo {
    background: url(static("myapp/image/bar.png"));
}

as described here: https://github.com/torchbox/django-libsass#custom-functions

yoshpe
  • 370
  • 1
  • 2
  • 11
3

There might be a way to get django to treat the CSS file like a template (I'm not very familiar with django) but you might want to try a different solution instead: use a dynamic stylesheet language such as LESS or Sass. With LESS it would be as simple as

@base: "//static.example.com/"

#logo {
    background: url(%("%s/logo.png", @base))
}
Matt Ball
  • 354,903
  • 100
  • 647
  • 710
0

Okay, 10 years down the line and I am facing this now. Here is my fix which will save you some trouble.

PS Not really sure if it is ethical however

  • grab your CSS file and place it in Templates

In your html file,

<style>
     {% include 'path/to/css' %}
</style>

Solved my problems.

Surveyor Jr
  • 346
  • 2
  • 12
-6

If your images aren't too big you can use data URIs, which can be embedded right in the css file without any links. They look like this:

.box-with-background {
  background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgI=')
  background-repeat: repeat;
}

Usually they're a bit longer then the one I've shown. You can generate them with javascript and you can find some online generators.

Jeremy S.
  • 1,086
  • 8
  • 18