Changing background-image (metafields) when hover over product card

Topic summary

Goal: Change the entire collection page background to a product-specific image when hovering each product card, using a product metafield (custom.wallpaper_url).

Key context:

  • Metafields = custom fields on products holding the wallpaper URL.
  • Initial CSS attempt in theme.liquid only changed the card’s image, not the page background. Moving CSS into the product-card template was suggested but still limited to the card (CSS can’t target a parent like body from a child hover).
  • Screenshots clarify the target is the page/body background; a video link was shared but not a final fix.

Latest updates:

  • Confirmed requirement is for the collection page only.
  • Conclusion: Needs JavaScript; CSS alone won’t work.
  • Temporary workaround implemented by OP:
    • Inline JS on card__content (onmousemove/onmouseout) sets backgroundImage to the metafield URL.
    • Added a fixed, full-page element (#bgpreview) via theme.liquid to display the image behind content (z-index -100).

Status:

  • Workaround functions but is not clean; OP requests a cleaner JS-only solution. No finalized code or resolution yet.
Summarized with AI on December 12. AI used: gpt-5.

i have setup a metafield for product called wallpaper_url

i want the background of the whole page to change to this by using metafield wallpaper_url

what i have is this under theme.liquid but the mainpage background-image does not change no matter what ways i try

.card-wrapper:hover .media.media–hover-effect {
background-image: url(‘{{ product.metafields.custom.wallpaper_url.value }}’) !important;

}

if i dont input the metafield, and replace with an actual url instead, the background changes but only for the product card and not the mainpage background .

please help :disappointed_face:

my web is www.bookooj.com pw: bookooj1234

i have attached screen shot, what im trying to do is when i move the mouse over each product card, the mainscreen background changes to specific image linked in product metafields.

Hello, @bookooj you can watch this video, hope you will find your solution

Thanks!

1 Like

ah maybe my explanation is incorrect, sorry. let me start over. i want the whole background (currently in black) to change to specific url or each different product. i know i will have to setup a metafield for each product which i did. the metafield name is wallpaper_url.

now, when i hover over the card, i want the whole background (in black) to change to that specific url i input in the metafields value.

Hi @bookooj

It looks like you’re adding CSS directly in the theme.liquid file and using the variable {{product.metafields.custom.wallpaper_url.value}}.

If you’re using a variable like this, the CSS needs to be added to the product-card file instead. Depending on the theme you’re using, the file name might differ, so please check your theme files to locate the correct one.

I hope this helps

Best,

Daisy

1 Like

Hi @bookooj ,

Did you add the code at card-product.liquid file?

Please send me the code of card-product.liquid file, I will check it for you

1 Like

sorry for the late reply, let me give it a try now

below is my card-product.liquid, i have not yet added the code. trying to figure out where to add it

{% comment %}
Renders a product card

Accepts:

  • card_product: {Object} Product Liquid object (optional)
  • media_aspect_ratio: {String} Size of the product image card. Values are “square” and “portrait”. Default is “square” (optional)
  • image_shape: {String} Image mask to apply to the product image card. Values are “arch”, “blob”, “chevronleft”, “chevronright”, “diamond”, “parallelogram”, and “round”. (optional)
  • show_secondary_image: {Boolean} Show the secondary image on hover. Default: false (optional)
  • show_vendor: {Boolean} Show the product vendor. Default: false
  • show_rating: {Boolean} Show the product rating. Default: false
  • extend_height: {Boolean} Card height extends to available container space. Default: true (optional)
  • lazy_load: {Boolean} Image should be lazy loaded. Default: true (optional)
  • skip_styles: {Boolean} Don’t include component styles. Useful when rendering multiple product cards in a loop. Default: false (optional)
  • quick_add: {Boolean} Show the quick add button.
  • section_id: {String} The ID of the section that contains this card.
  • horizontal_class: {Boolean} Add a card–horizontal class if set to true. Default: false (optional)
  • horizontal_quick_add: {Boolean} Changes the quick add button styles when set to true. Default: false (optional)
  • placeholder_image: {String} The placeholder image to use when no product exists. Default: ‘product-apparel-2’ (optional)

Usage:
{% render ‘card-product’, show_vendor: section.settings.show_vendor %}
{% endcomment %}
{%- unless skip_styles -%}
{{ ‘component-rating.css’ | asset_url | stylesheet_tag }}
{{ ‘component-volume-pricing.css’ | asset_url | stylesheet_tag }}

{{ ‘component-price.css’ | asset_url | stylesheet_tag }}
{{ ‘quick-order-list.css’ | asset_url | stylesheet_tag }}
{{ ‘quantity-popover.css’ | asset_url | stylesheet_tag }}
{%- endunless -%}
{%- if card_product and card_product != empty -%}
{%- liquid
assign ratio = 1
if card_product.featured_media and media_aspect_ratio == ‘portrait’
assign ratio = 0.8
elsif card_product.featured_media and media_aspect_ratio == ‘adapt’
assign ratio = card_product.featured_media.aspect_ratio
endif
if ratio == 0 or ratio == null
assign ratio = 1
endif
-%}

{%- if card_product.featured_media -%}
{% comment %}theme-check-disable ImgLazyLoading{% endcomment %} {{ card_product.featured_media.alt | escape }} {% comment %}theme-check-enable ImgLazyLoading{% endcomment %}

{%- if card_product.media[1] != null and show_secondary_image -%}
<img
srcset="
{%- if card_product.media[1].width >= 165 -%}{{ card_product.media[1] | image_url: width: 165 }} 165w,{%- endif -%}
{%- if card_product.media[1].width >= 360 -%}{{ card_product.media[1] | image_url: width: 360 }} 360w,{%- endif -%}
{%- if card_product.media[1].width >= 533 -%}{{ card_product.media[1] | image_url: width: 533 }} 533w,{%- endif -%}
{%- if card_product.media[1].width >= 720 -%}{{ card_product.media[1] | image_url: width: 720 }} 720w,{%- endif -%}
{%- if card_product.media[1].width >= 940 -%}{{ card_product.media[1] | image_url: width: 940 }} 940w,{%- endif -%}
{%- if card_product.media[1].width >= 1066 -%}{{ card_product.media[1] | image_url: width: 1066 }} 1066w,{%- endif -%}
{{ card_product.media[1] | image_url }} {{ card_product.media[1].width }}w
"
src=“{{ card_product.media[1] | image_url: width: 533 }}”
sizes=“(min-width: {{ settings.page_width }}px) {{ settings.page_width | minus: 130 | divided_by: 4 }}px, (min-width: 990px) calc((100vw - 130px) / 4), (min-width: 750px) calc((100vw - 120px) / 3), calc((100vw - 35px) / 2)”
alt=“”
class=“motion-reduce”
loading=“lazy”
width=“{{ card_product.media[1].width }}”
height=“{{ card_product.media[1].height }}”

{%- endif -%}

{%- endif -%}
{%- if card_product.available == false -%} {{- 'products.product.sold_out' | t -}} {%- elsif card_product.compare_at_price > card_product.price and card_product.available -%} {{- 'products.product.on_sale' | t -}} {%- endif -%}

{{ card_product.title | escape }}

{%- if show_vendor -%} {{ 'accessibility.vendor' | t }}
{{ card_product.vendor }}
{%- endif -%}

{{ block.settings.description | escape }}

{%- if show_rating and card_product.metafields.reviews.rating.value != blank -%}
{% liquid
assign rating_decimal = 0
assign decimal = card_product.metafields.reviews.rating.value.rating | modulo: 1
if decimal >= 0.3 and decimal <= 0.7
assign rating_decimal = 0.5
elsif decimal > 0.7
assign rating_decimal = 1
endif
%}

{{- card_product.metafields.reviews.rating.value }} / {{ card_product.metafields.reviews.rating.value.scale_max -}}

({{ card_product.metafields.reviews.rating_count }}) {{- card_product.metafields.reviews.rating_count }} {{ 'accessibility.total_reviews' | t -}}

{%- endif -%}

{% render ‘price’, product: card_product, price_class: ‘’, show_compare_at_price: true %}
{%- if card_product.quantity_price_breaks_configured? -%}
{% if card_product.variants.size == 1 and quick_add == ‘bulk’ %}
{% liquid
assign quantity_rule = card_product.selected_or_first_available_variant.quantity_rule
assign has_qty_rules = false
if quantity_rule.increment > 1 or quantity_rule.min > 1 or quantity_rule.max != null
assign has_qty_rules = true
endif
%}


{{ ‘products.product.volume_pricing.note’ | t }}


{{ ‘products.product.volume_pricing.note’ | t }}

{% else %}

{{ 'products.product.volume_pricing.note' | t }}
{% endif %} {% if card_product.variants.size == 1 and quick_add == 'bulk' %}
{%- if has_qty_rules -%}
{%- if quantity_rule.increment > 1 -%} {{- 'products.product.quantity.multiples_of' | t: quantity: quantity_rule.increment -}} {%- endif -%} {%- if quantity_rule.min > 1 -%} {{- 'products.product.quantity.min_of' | t: quantity: quantity_rule.min -}} {%- endif -%} {%- if quantity_rule.max != null -%} {{- 'products.product.quantity.max_of' | t: quantity: quantity_rule.max -}} {%- endif -%}
{%- endif -%} {{- 'icon-close.svg' | inline_asset_content -}} {%- if card_product.selected_or_first_available_variant.quantity_price_breaks.size > 0 -%}
  • {{ card_product.selected_or_first_available_variant.quantity_rule.min }}+ {%- assign price = card_product.selected_or_first_available_variant.price | money_with_currency -%} {{ 'sections.quick_order_list.each' | t: money: price }}
  • {%- for price_break in card_product.selected_or_first_available_variant.quantity_price_breaks -%}
  • {{- price_break.minimum_quantity -}} + {%- assign price = price_break.price | money_with_currency -%} {{ 'sections.quick_order_list.each' | t: money: price }}
  • {%- endfor -%}
{%- endif -%}
{% endif %} {%- endif -%}
{{ card_product.metafields.custom.short_description }}
{% assign product_form_id = 'quick-add-' | append: section_id | append: card_product.id %} {% if quick_add == 'standard' %}
{%- liquid assign qty_rules = false if card_product.selected_or_first_available_variant.quantity_rule.min > 1 or card_product.selected_or_first_available_variant.quantity_rule.max != null or card_product.selected_or_first_available_variant.quantity_rule.increment > 1 assign qty_rules = true endif -%} {%- if card_product.variants.size > 1 or qty_rules -%} {{ 'products.product.choose_options' | t }} {%- if horizontal_quick_add -%} {{- 'icon-arrow.svg' | inline_asset_content -}} {%- endif -%} {%- render 'loading-spinner' -%}
{{- 'icon-close.svg' | inline_asset_content -}}
{%- else -%} {%- form 'product', card_product, id: product_form_id, class: 'form', novalidate: 'novalidate', data-type: 'add-to-cart-form' -%} {%- if card_product.selected_or_first_available_variant.available -%} {{ 'products.product.add_to_cart' | t }} {%- else -%} {{ 'products.product.sold_out' | t }} {%- endif -%} {{ 'products.product.sold_out' | t }} {%- if horizontal_quick_add -%} {{- 'icon-plus.svg' | inline_asset_content -}} {%- endif -%} {%- render 'loading-spinner' -%} {%- endform -%} {%- endif -%}
{% elsif quick_add == 'bulk' %} {% if card_product.variants.size == 1 %} {% if card_product.selected_or_first_available_variant.available == false %} {{ 'products.product.sold_out' | t }} {{ 'products.product.sold_out' | t }} {% else %} {% render 'quantity-input', variant: card_product.selected_or_first_available_variant, min: 0 %} {% endif %} {% else %}
{%- liquid assign product_form_id = 'quick-add-' | append: section_id | append: card_product.id assign qty_rules = false if card_product.selected_or_first_available_variant.quantity_rule.min > 1 or card_product.selected_or_first_available_variant.quantity_rule.max != null or card_product.selected_or_first_available_variant.quantity_rule.increment > 1 assign qty_rules = true endif -%} {{ 'products.product.choose_options' | t }} {%- render 'loading-spinner' -%}
{{- 'icon-close.svg' | inline_asset_content -}}
{%- if card_product.featured_media -%}
{% comment %}theme-check-disable ImgLazyLoading{% endcomment %} {{ card_product.featured_media.alt | escape }} {% comment %}theme-check-enable ImgLazyLoading{% endcomment %}
{%- endif -%} {{ 'products.product.view_full_details' | t -}} {{- 'icon-arrow.svg' | inline_asset_content -}}

{{ card_product.title | escape }}

{% render 'price', product: card_product, price_class: '', show_compare_at_price: true %} {%- if card_product.quantity_price_breaks_configured? -%}
{{ 'products.product.volume_pricing.note' | t }}
{%- endif -%}

{{ card_product.title | escape }}

{% render 'price', product: card_product, price_class: '', show_compare_at_price: true %} {%- if card_product.quantity_price_breaks_configured? -%}
{{ 'products.product.volume_pricing.note' | t }}
{%- endif -%}
{% endif %} {% endif %}
{%- if card_product.available == false -%} {{- 'products.product.sold_out' | t -}} {%- elsif card_product.compare_at_price > card_product.price and card_product.available -%} {{- 'products.product.on_sale' | t -}} {%- endif -%}
{%- else -%} {%- liquid assign ratio = 1 assign placeholder = true if media_aspect_ratio == 'portrait' assign ratio = 0.8 endif -%}
{%- if placeholder_image -%} {{ placeholder_image | placeholder_svg_tag: 'placeholder-svg' }} {%- else -%} {{ 'product-apparel-2' | placeholder_svg_tag: 'placeholder-svg' }} {% endif %}

{{ 'onboarding.product_title' | t }}

{%- if show_vendor -%} {{ 'accessibility.vendor' | t }}
{{ 'products.product.vendor' | t }}
{%- endif -%} {% render 'price', placeholder: placeholder, show_compare_at_price: true %}
{%- endif -%}

Hi @bookooj ,

Please change all code:

{% comment %}
Renders a product card

Accepts:
- card_product: {Object} Product Liquid object (optional)
- media_aspect_ratio: {String} Size of the product image card. Values are "square" and "portrait". Default is "square" (optional)
- image_shape: {String} Image mask to apply to the product image card. Values are "arch", "blob", "chevronleft", "chevronright", "diamond", "parallelogram", and "round". (optional)
- show_secondary_image: {Boolean} Show the secondary image on hover. Default: false (optional)
- show_vendor: {Boolean} Show the product vendor. Default: false
- show_rating: {Boolean} Show the product rating. Default: false
- extend_height: {Boolean} Card height extends to available container space. Default: true (optional)
- lazy_load: {Boolean} Image should be lazy loaded. Default: true (optional)
- skip_styles: {Boolean} Don't include component styles. Useful when rendering multiple product cards in a loop. Default: false (optional)
- quick_add: {Boolean} Show the quick add button.
- section_id: {String} The ID of the section that contains this card.
- horizontal_class: {Boolean} Add a card--horizontal class if set to true. Default: false (optional)
- horizontal_quick_add: {Boolean} Changes the quick add button styles when set to true. Default: false (optional)
- placeholder_image: {String} The placeholder image to use when no product exists. Default: 'product-apparel-2' (optional)

Usage:
{% render 'card-product', show_vendor: section.settings.show_vendor %}
{% endcomment %}
{%- unless skip_styles -%}
{{ 'component-rating.css' | asset_url | stylesheet_tag }}
{{ 'component-volume-pricing.css' | asset_url | stylesheet_tag }}

{{ 'component-price.css' | asset_url | stylesheet_tag }}
{{ 'quick-order-list.css' | asset_url | stylesheet_tag }}
{{ 'quantity-popover.css' | asset_url | stylesheet_tag }}
{%- endunless -%}
{%- if card_product and card_product != empty -%}

{%- if card_product.metafields.custom.wallpaper_url.value != blank -%}

{%- endif -%}

{%- liquid
assign ratio = 1
if card_product.featured_media and media_aspect_ratio == 'portrait'
assign ratio = 0.8
elsif card_product.featured_media and media_aspect_ratio == 'adapt'
assign ratio = card_product.featured_media.aspect_ratio
endif
if ratio == 0 or ratio == null
assign ratio = 1
endif
-%}

{%- if card_product.featured_media -%}

{% comment %}theme-check-disable ImgLazyLoading{% endcomment %}

{% comment %}theme-check-enable ImgLazyLoading{% endcomment %}

{%- if card_product.media[1] != null and show_secondary_image -%}

{%- endif -%}

{%- endif -%}

### 

{{ card_product.title | escape }}

{%- if card_product.available == false -%}

{{- 'products.product.sold_out' | t -}}

{%- elsif card_product.compare_at_price > card_product.price and card_product.available -%}

{{- 'products.product.on_sale' | t -}}

{%- endif -%}

### 

{{ card_product.title | escape }}

{%- if show_vendor -%}
{{ 'accessibility.vendor' | t }}

{{ card_product.vendor }}

{%- endif -%}

{{ block.settings.description | escape }}

{%- if show_rating and card_product.metafields.reviews.rating.value != blank -%}
{% liquid
assign rating_decimal = 0
assign decimal = card_product.metafields.reviews.rating.value.rating | modulo: 1
if decimal >= 0.3 and decimal <= 0.7
assign rating_decimal = 0.5
elsif decimal > 0.7
assign rating_decimal = 1
endif
%}

{{- card_product.metafields.reviews.rating.value }} /
{{ card_product.metafields.reviews.rating.value.scale_max -}}

({{ card_product.metafields.reviews.rating_count }})

{{- card_product.metafields.reviews.rating_count }}
{{ 'accessibility.total_reviews' | t -}}

{%- endif -%}

{% render 'price', product: card_product, price_class: '', show_compare_at_price: true %}
{%- if card_product.quantity_price_breaks_configured? -%}
{% if card_product.variants.size == 1 and quick_add == 'bulk' %}
{% liquid
assign quantity_rule = card_product.selected_or_first_available_variant.quantity_rule
assign has_qty_rules = false
if quantity_rule.increment > 1 or quantity_rule.min > 1 or quantity_rule.max != null
assign has_qty_rules = true
endif
%}

{% endif %}
{%- endif -%}

{{ card_product.metafields.custom.short_description }}

{% assign product_form_id = 'quick-add-' | append: section_id | append: card_product.id %}
{% if quick_add == 'standard' %}

{%- liquid
assign qty_rules = false
if card_product.selected_or_first_available_variant.quantity_rule.min > 1 or card_product.selected_or_first_available_variant.quantity_rule.max != null or card_product.selected_or_first_available_variant.quantity_rule.increment > 1
assign qty_rules = true
endif
-%}
{%- if card_product.variants.size > 1 or qty_rules -%}

{%- else -%}

{%- endif -%}

{% elsif quick_add == 'bulk' %}
{% if card_product.variants.size == 1 %}

{% else %}

{%- liquid
assign product_form_id = 'quick-add-' | append: section_id | append: card_product.id
assign qty_rules = false
if card_product.selected_or_first_available_variant.quantity_rule.min > 1 or card_product.selected_or_first_available_variant.quantity_rule.max != null or card_product.selected_or_first_available_variant.quantity_rule.increment > 1
assign qty_rules = true
endif
-%}

{% endif %}
{% endif %}

{%- if card_product.available == false -%}

{{- 'products.product.sold_out' | t -}}

{%- elsif card_product.compare_at_price > card_product.price and card_product.available -%}

{{- 'products.product.on_sale' | t -}}

{%- endif -%}

{%- else -%}
{%- liquid
assign ratio = 1
assign placeholder = true
if media_aspect_ratio == 'portrait'
assign ratio = 0.8
endif
-%}

{%- if placeholder_image -%}
{{ placeholder_image | placeholder_svg_tag: 'placeholder-svg' }}
{%- else -%}
{{ 'product-apparel-2' | placeholder_svg_tag: 'placeholder-svg' }}
{% endif %}

### 

{{ 'onboarding.product_title' | t }}

{%- if show_vendor -%}
{{ 'accessibility.vendor' | t }}

{{ 'products.product.vendor' | t }}

{%- endif -%}
{% render 'price', placeholder: placeholder, show_compare_at_price: true %}

{%- endif -%}
1 Like

i have just replaced it and its currently semi working, when i move the mouse over the card, it changes the background of the card but not the body background.

the image i attached was with the mouse over the ‘laughing buddha’ which changed the background of the laughing buddha. i want it to change the whole body background image so the black gets replaced with the background.

i have added these at the bottom to make the header and body transparent

.section-template--18219701666020__rich_text_yyMRPM-padding { background: Transparent !important } .section-template--18219701666020__product-grid-padding{ background: Transparent !important } body { background-color: black !important; background-repeat: no-repeat !important; background-size: cover !important; }

but seems no matter what i try, i cant get the child to target the parent element, only parent to target child element

Hi @bookooj ,

Are you referring to this background?

I still don’t understand the content you are referring to, because the current code will change the image’s background.

Please let me know, I will check it.

1 Like

AH, i get it. i want it to target this element background when hover over a product card

Hi @bookooj ,

When you hover over each card, the body background changes?

And will depend on each product, the main background will be different?

1 Like

yes, i want the body backgroundimage to change based on the wallpaper_url metafield.

Hi @bookooj ,

This will need to be changed by JS code, you can’t add it with CSS.

You just want it to work for this page?

1 Like

yes, only this page (collection page)

since i have 0 knowledge with JS, i found a work around for this finally
cardproduct.liquid, i added this next to card__content

and under theme.liquid, i added this at the very bottom before

i think this created a table and indexed it to the very bottom

i dont think this is the cleanest way to perform this, but it is working. if you dont mind helping me with the JS code, i’ll use your JS code over mine anytime!