bejames
bejames

Reputation: 453

Can I set svelte style css attribute values using variables passed in to a component

I want to create a svelte component that receives the name and path of an image. I want to have the component set the image as the "background-image" using CSS.

I've tried the following which does not seem to work...

Component called in App.svelte:

<Image image_url='./images/image1.jpg' />

Image.Svelte

<script>
export let image_url;
</script>

<style>
.image{
    position:relative;
    opacity: 0.70;
    background-position:bottom;
    background-size: cover;
    background-repeat: no-repeat;
    background-attachment: fixed;
    background-image: url({image_url});
    min-height: 100%;
}
</style>

<div class="image">
  <p>some text</p>
</div>

When I inspect the component the css for background_image is:

background-image: url({image_url});

Is it possible to have the variable converted in the CSS?

Upvotes: 35

Views: 38987

Answers (4)

coyotte508
coyotte508

Reputation: 9695

You can now pass css variables directly as props: https://svelte.dev/docs#template-syntax-component-directives---style-props

<Image --background-image='url(./images/image1.jpg)' />

In Image.svelte

background-image: var(--background-image, url(./images/default.jpg));

Upvotes: 19

sean_robbins
sean_robbins

Reputation: 693

I was able to achieve what you are asking for in the following way:

<script>
  export let image_url;
</script>

<div class="image" style="--image_url: url({image_url})">
  <p>some text</p>
</div>

<style>
  .image{
    background-image: var(--image-url);
  }
</style>

The in the html part of the component has access to the props, so can pass the prop to style as a CSS variable. The CSS variable can then be used in the background_image directly.

Upvotes: 1

cortopy
cortopy

Reputation: 2867

Think of Svelte block as a CSS black box. You can't use javascript variables in the same way that you can't use them in a css file in the browser.

But...since it's a CSS box, you can always use scss and compile your block using a svelte preprocessor like this one. Then you can just do

<script>
export let image_url;
</script>

<style lang="scss">
@import "my/path/to/variables";

.image{
    position:relative;
    opacity: 0.70;
    background-position:bottom;
    background-size: cover;
    background-repeat: no-repeat;
    background-attachment: fixed;
    background-image: url(#{$image_url});
    min-height: 100%;
}
</style>

<div class="image">
  <p>some text</p>
</div>

Upvotes: 0

Rich Harris
Rich Harris

Reputation: 29585

No. Component styles are shared between all instances of a component, either because they're statically extracted to a .css file, or because they're injected into a single <style> element that all components reference. If it were possible to put variables directly inside the component's <style>, it would mean that Svelte would need to create encapsulated styles per-instance, which would be detrimental to performance and would consume a lot more memory.

There are two ways to approach this. The first is to use inline styles for anything that can change per-instance:

<script>
export let image_url;
</script>

<style>
.image{
    position:relative;
    opacity: 0.70;
    background-position:bottom;
    background-size: cover;
    background-repeat: no-repeat;
    background-attachment: fixed;
    /* background-image: url({image_url}); */
    min-height: 100%;
}
</style>

<!-- <div class="image"> -->
<div class="image" style="background-image: url({image_url});">
  <p>some text</p>
</div>

The second, particularly if you need to use values in multiple places, is to use CSS variables:

<script>
export let image_url;
</script>

<style>
.image{
    position:relative;
    opacity: 0.70;
    background-position:bottom;
    background-size: cover;
    background-repeat: no-repeat;
    background-attachment: fixed;
    /* background-image: url({image_url}); */
    background-image: var(--image);
    min-height: 100%;
}
</style>

<!-- <div class="image"> -->
<div class="image" style="--image: url({image_url});">
  <p>some text</p>
</div>

Upvotes: 81

Related Questions