Search code examples
htmlcssdjangobackground-imagecontent-security-policy

Background image not loading when within <style> tags. It works fine when styled within the <div> itself. Not an incorrect filepath problem


I am unable to put a background image into the <style> tags and I don't know why it's not working.

All of the following was done on my local machine. My website is also hosted on a Linode server.

I have the following code, which works fine. It sets the background image in a style directly in the div within the body (via Django):

<body>
    <div class="scroll-container" style="background-image: url('{% static 'myapp/scroll-L.jpg' %}');">
    </div>
</body>

And when I load the page you can see the scroll image loads fine (image1 https://i.sstatic.net/EeOaq.png)

However when I put the background image into the <style> tag in the <head> everything starts to go wrong:

<style>
    .scroll-container {
        background-image: url("../../static/myapp/scroll-L.jpg")
    }
</style>

When I load the page you can see the scroll image doesn't load (image2 https://i.sstatic.net/RTn7R.png)

I can't use Django's {% static ... %} within the head style tags so that didn't work.

It's clearly something to do with the object storage (eu-central-1.linodeobjects) but I don't know what. Why would it work when using the image in the div style and not within the style tags?

I've searched around for about 2 hours trying to find a fix but I can't figure it out.

The file path is correct however just for confirmation I have tried the following with no success:

.scroll-container {
    background-image: url("static/myapp/scroll-L.jpg")
}

.scroll-container {
    background-image: url("/static/myapp/scroll-L.jpg")
}

.scroll-container {
    background-image: url("/../../static/myapp/scroll-L.jpg")
}

{% load static %}
.scroll-container {
    background-image: url("{% static 'myapp/scroll-L.jpg' %}")
}

And I need to do something other than put the background image directly in the div because I am sorting out the CSP for my site, and I can't set a nonce or hash for it if it is a style set directly to the div.

I also tried putting the image directly in the templates folder so that I could just call:

.scroll-container {
    background-image: url("scroll-L.jpg")
}

However that didn't work either. I also tried putting it into the master.css with little success.

EDIT: Here is the code for my object storage in settings.py:

# Object Storage for Django static files (https://www.codingforentrepreneurs.com/blog/linode-object-storage-for-django-static-files/)
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
STATICFILES_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'

AWS_S3_OBJECT_PARAMETERS = {
    'CacheControl': 'max-age=86400',
}

LINODE_BUCKET = os.environ.get('LINODE_BUCKET', 'hmst-bucket')
LINODE_BUCKET_REGION = os.environ.get('LINODE_BUCKET_REGION', 'eu-central-1')
LINODE_BUCKET_ACCESS_KEY = os.environ.get('LINODE_BUCKET_ACCESS_KEY', '#')
LINODE_BUCKET_SECRET_KEY = os.environ.get('LINODE_BUCKET_SECRET_KEY', '#')

AWS_S3_ENDPOINT_URL = f'https://{LINODE_BUCKET_REGION}.linodeobjects.com'
AWS_ACCESS_KEY_ID = LINODE_BUCKET_ACCESS_KEY
AWS_SECRET_ACCESS_KEY = LINODE_BUCKET_SECRET_KEY
AWS_S3_REGION_NAME = LINODE_BUCKET_REGION
AWS_S3_USE_SSL = True
AWS_STORAGE_BUCKET_NAME = LINODE_BUCKET

AWS_DEFAULT_ACL = None

Solution

  • Here was a fix for anybody that has the same problem in the future.

    Instead of calling the file path to the background image, I instead called the image from my Object Storage bucket directly:

    <style>
        .scroll-container {
            background-image: url("https://hmst-bucket.eu-central-1.linodeobjects.com/myapp/scroll-L.jpg");
        }
    </style>
    

    This then gave a 403 (Forbidden error) with the following message when I tried to open the image:

    This XML file does not appear to have any style information associated with it. The document tree is shown below.
    <Error>
    <Code>AccessDenied</Code>
    <BucketName>hmst-bucket</BucketName>
    <RequestId>#</RequestId>
    <HostId>#</HostId>
    </Error>
    

    So I then needed to change the permissions of the Access Control Lists (ACLs). I changed the Bucket Level ACLs and the Object Level ACLs of my object storage from Private to Public Read.

    I use Linode, so to do this I followed this guide: https://www.linode.com/docs/products/storage/object-storage/guides/acls/. To change the Object Level ACL the guide says you'll need to click the more options ellipsis and select Details, however this is out-dated and you'll need to click the actual object itself.

    Changing these permissions fixed the issue.