Vue-loader: background-image in style property, what is the best practice?

Created on 15 Feb 2017  路  37Comments  路  Source: vuejs/vue-loader

In .vue template, we usually use img tag to show a image, like

<img src="./link/to/image.png">

which is OK.
However sometime we need to use background-image within inline style property:

<div style="background-image: url(./link/to/image.png)"

But it's not working, somehow I need to write it like this:

<div :style="{'background-image': 'url(' + require('./link/to/image.png') + ')'}">

or the ES2015 way:

<div :style="{'background-image': `url(${require('./link/to/image.png')})`}">

which is still not neat.
So I'm just wondering is there any better way to do this?

Most helpful comment

Hello everyone, if you want to use css background property from your assests, you can use it as follows;
background-image: url('~@/assets/img.jpeg');
If you want to know how this works, you can read it from here. Hope this helps :)

All 37 comments

I have met the same question, especially the image can't be converted as base64

Maybe it's a bad idea to use base64 image in style property, it makes HTML kinda ugly.

Why not just use CSS instead of inline styles?

Required images is transformed to base64 DataURI is due to the limit option of url-loader.
You can reduce the limit, may be 10000 (bytes). It's useful to reduce the number of requests.

Then, vue-loader is piping <style></style> to the corresponding loader (depends on your config).
Such as scss-loader, postcss-loader, css-loader, style-loader, and css-loader will piping the results to url-loader and file-loader.
So you can just write css to instead of inline styles:

url(image.png) => require('./image.png')
url(~module/image.png) => require('module/image.png')

@yyx990803 @blade254353074 I know what we CAN. But it's a little bit annoying to do these workarounds.

For reducing requests, url-loader limit option must be configured......Although it's annoying.

@blade254353074 I believe the size limitation is not relevant in this conversation.

@NemoAlex But you said "base64 image in style property makes HTML kinda ugly"...

@yyx990803 I have the same issue .I need change this background-image frequently by data in component, in css , i can't find a way to solve it

This isn't really vue-loader's fault, but I kept running into a similar issue where an image URL contained a space, so the style was invalid and would not appear on the element.

Ensure your backgroundImage declarations are wrapped in url( and quotes so the style works correctly, no matter the file name.

ES2015 Style:

<div :style="{ backgroundImage: `url('${image}')` }"></div>

Or without ES2015:

<div :style="{ backgroundImage: 'url(\'' + image + '\')' }"></div>

for Googlers, I had success with (using Nuxt):

:style="{ backgroundImage: 'url(' + require(@/assets/img/${page.image}) + ')' }"

for Googlers, I has success with (same using Nuxt):

:style="{ backgroundImage: 'url(' + require('@/assets/imgs/bg'+backgroundId+'.png') + ')' }"

@dimitrieh 's answer is indeed correct, but his Template literals was "absorbed" by github's Markdown parser. If you copy his code from his comment directly, the code is not going to work.

However if you are using ES2015 you should be using Template literals. My code here is just for understanding the concept.

Again, for Googlers...

In my case (an old Vue project) the problem seemed to be that the image wasn't being bundled by Webpack, even if the URL was right. Using require(...) returns the correct URL in the final bundle, but will also "tell Webpack" to bundle the image.

I placed the image inside public/img/ and then referred the image path mentioned in data property

<div class="text-center mb-4" :style="{ backgroundImage:url('${bgImage}')}">

data() {
    return {
      bgImage: "/img/virtual-mac.jpg"
    };
  },

鎴戞病鏈夋壘鍒版洿濂界殑鏂规硶
I didn't find a better way.
浣嗚繖鏍蜂篃鍙互瑙e喅鎴戠殑闂
But it can also solve my problem.
濡備笅:
as follows

<div  :style="{'background-image':'url('+backgroundUrl+');'}">
 data() {
         return { backgroundUrl:require('~/static/img/ads.png') }
        },

or

data(){
         return { backgroundUrl:'http://timgsa.baidu.com/timg?image&quality=80&size=b10000_10000&sec=1532246957&di=5c7453291ff3ca5963cca9c40a0be2ca&imgtype=jpg&src=http%3A%2F%2Fimg6.bdstatic.com%2Fimg%2Fimage%2Fpcindex%2Ftongmengpctufanbingbing.jpg' }
}

I was able to accomplish what I believe is a similar end goal by using a computed property to build a collection of individual CSS attributes (dynamic or not), and then assign the whole group to the DOM element as an inline style.

Template:

<div class="movie-wrapper" :style="styles">
</div>

Computed Props:

<script>
const BACKDROP_BASE = 'https://image.tmdb.org/t/p/w1280';
export default {
    computed: {
        styles() {
            return {
                'background-image': `url(${BACKDROP_BASE}/${this.movie.backdrop_path})`,
                'background-repeat': 'no-repeat',
                'background-size': 'cover'
            }
        }
    }
}

And I could still attach additional properties with normal CSS, but it looks like any properties assigned via the computed property may take precedence as I think they are applied on top of the regular CSS.

Regular CSS:

<style scoped>
.movie-wrapper {
    position: relative;
    padding-top: 50vh;
}
</style>
Vue.filter('ifEmptyFoto',  function(value) {
      if (!value || value == "") { return 'images/foto_padrao.jpg'; }
      else return value;
})
Vue.filter('bgImage',  function(value) {
      return 'background-image: url('+ value +');';
})

<div class="foto" :style="caminhoImagem | ifEmptyFoto| bgImage"></div>
{background-image: url(image link);
background-size:cover;
} 

//place it in style tag..it worked for me

Why not just use CSS instead of inline styles?

Dynamic data.

Hello everyone, if you want to use css background property from your assests, you can use it as follows;
background-image: url('~@/assets/img.jpeg');
If you want to know how this works, you can read it from here. Hope this helps :)

I had to format mine like this with url('')
@import url('https://fonts.googleapis.com/css?family=Montserrat:400,700');

I had difficulties with how to set dynamic background images in nuxt but i did it and it worked perfectly.

_In SCRIPT_
computed: {
service() {
return this.services.find(service => service.id === this.id)
},
backgroundURL() {
return require(~/assets/img/bgheads/${this.service.head})
}
}

_In HTML_

{{service.name}}

    </div>

just in case if someone is also finding the same problems i faced. it took me some hours to figure it out

image
image

I did it,but I fell it is annoying! It would be better if I can wirte the picture path directly! 馃槃

https://github.com/vuejs/vue-loader/issues/646#issuecomment-454959580

Hello everyone, if you want to use css background property from your assests, you can use it as follows;
background-image: url('~@/assets/img.jpeg');
If you want to know how this works, you can read it from here. Hope this helps :)

We need to put this into the nuxt documentation. Please!

#646 (comment)

Hello everyone, if you want to use css background property from your assests, you can use it as follows;
background-image: url('~@/assets/img.jpeg');
If you want to know how this works, you can read it from here. Hope this helps :)

We need to put this into the nuxt documentation. Please!

Let me try it with Nuxt! Then I can send a pr to nuxt docs :)

#646 (comment)

Hello everyone, if you want to use css background property from your assests, you can use it as follows;
background-image: url('~@/assets/img.jpeg');
If you want to know how this works, you can read it from here. Hope this helps :)

We need to put this into the nuxt documentation. Please!

Let me try it with Nuxt! Then I can send a pr to nuxt docs :)

Actually Next Team stated about this issue in the docs, I read it carefully in order to catch the info :)
image

@onuriltan I saw this on nuxt, but your solution had both ~ and @ together and which is not mentioned in the nuxt documentation.

In the sass and css files I need to use the "@" path.
In the scoped css inside the vue files I need to use your solution the "~@" together.

@pratyushtewari actually I tried those

  1. ~assets/img.jpeg = worked
  2. @assets/img.jpeg = didn't work
  3. ~@/assets/img.jpeg = worked

Yes the guide is a little bit misleading, I can open a pr but just in english language :)

@pratyushtewari actually I tried those

  1. ~assets/img.jpeg = worked
  2. @assets/img.jpeg = didn't work
  3. ~@/assets/img.jpeg = worked

Yes the guide is a little bit misleading, I can open a pr but just in english language :)

it doesn't work for me

Don't waste time, @onuriltan is right.

This is Working for me:

:style="
    { backgroundImage: 'url(' + require('../assets/images/bg1.jpg') + ')'}"

But This is throwing compile error:

```
:style="
{ backgroundImage: 'url(' + require('../assets/images/bg1.jpg') + ')' ,
backgroundSize:'cover'}"

Can someone help please.

Error:

Errors compiling template:

invalid expression: Unexpected token ':' in

{ backgroundImage: 'url(' + require('../assets/images/bg1.jpg') + ')' ,
backgroundSize:'cover'}

```

@arijitnaskar - Can you try this and see if this works?

:style="{ backgroundImage: url('" + require('../assets/images/bg1.jpg') + "') , backgroundSize: cover}"

Mine is working with this:

:style="
    [{ backgroundImage: 'url(' + require('../assets/images/bg1.jpg') + ')' 
   },{backgroundSize:'100%'},{backgroundPosition:'center bottom'}]"

Close this.

I am having this same issue. The path is resolving correctly but not as a string.

image

Solutions were provided above.

I was able to accomplish what I believe is a similar end goal by using a computed property to build a collection of individual CSS attributes (dynamic or not), and then assign the whole group to the DOM element as an inline style.

Template:

<div class="movie-wrapper" :style="styles">
</div>

Computed Props:

<script>
const BACKDROP_BASE = 'https://image.tmdb.org/t/p/w1280';
export default {
    computed: {
        styles() {
            return {
                'background-image': `url(${BACKDROP_BASE}/${this.movie.backdrop_path})`,
                'background-repeat': 'no-repeat',
                'background-size': 'cover'
            }
        }
    }
}

And I could still attach additional properties with normal CSS, but it looks like any properties assigned via the computed property may take precedence as I think they are applied on top of the regular CSS.

Regular CSS:

<style scoped>
.movie-wrapper {
    position: relative;
    padding-top: 50vh;
}
</style>

how if hving multiple image?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

C0deZLee picture C0deZLee  路  3Comments

fuyan-run picture fuyan-run  路  3Comments

flashios09 picture flashios09  路  3Comments

frangio picture frangio  路  3Comments

amorphine picture amorphine  路  3Comments