Customize the Purple theme product page for each color

Customize the Purple WooCommerce theme so the product page follows each color variation: colors, photo, buttons and lightbox, with CSS and a little JS.

Tested withWordPress 7.1.4WooCommerce 11.2.1Purple theme 1.0.3

On this page
  1. What the color buttons tell CSS
  2. The glitch I had to hide
  3. The 3D photo needs a little JavaScript
  4. A lightbox you can move through
  5. Add it to your Purple store

I saw a product page design on Pinterest where the whole page changes when you pick a jacket color. I loved it, and wondered how it would look on a WooCommerce store using Purple.

So I opened Purple’s default product template in the Site Editor and kept myself to what was already there. No plugin and no custom template, only the block settings and a few lines of CSS.

Out of the box, picking a color on Purple’s product page swaps the photo, and that’s all. The buttons, the Sale badge and the page around them stay exactly as they were, so the page never really answers the choice you just made.

Here’s where it ended up.

What the color buttons tell CSS

Purple’s product page uses WooCommerce’s Add to Cart + Options block for the color picker. When I opened the page source, each color was a button with role="radio", an id built from the attribute and the color, and aria-checked:

Code
<button class="wc-block-product-filter-chips__item" role="radio"
  id="attribute_color-blue" value="Blue" aria-checked="true">

That aria-checked flips to true on the color you pick. CSS can’t run code, but it can ask whether the page has a checked Blue button, with :has(). So I gave the page three color variables and let each color set them:

Code
@property --pp-accent { syntax: "<color>"; inherits: true; initial-value: #1f0342; }
@property --pp-tint { syntax: "<color>"; inherits: true; initial-value: #ffffff; }

body.single-product {
	background-color: var(--pp-tint);
	transition: --pp-accent 0.9s ease, --pp-tint 0.9s ease;
}
body.single-product:has(#attribute_color-orange[aria-checked="true"]) {
	--pp-accent: #d9531e;
	--pp-tint: #f7e9df;
}
body.single-product:has(#attribute_color-blue[aria-checked="true"]) {
	--pp-accent: #2340b8;
	--pp-tint: #e4eaf6;
}

The @property lines matter. A normal CSS variable jumps from one color to the next. Registered as a color, it fades, so the whole page moves from orange to blue together instead of snapping.

From there, everything on Purple’s product page that should carry the color reads var(--pp-accent): the picked color and size buttons, Add to cart, and the Sale badge. The page background and Purple’s lavender shipping and returns box use the softer tints.

The glitch I had to hide

My first try was a circle that opened the new photo from the center. It looked fine in screenshots and glitchy when I clicked through it, so I measured what was going on.

WooCommerce swaps the photo about a tenth of a second after the click. My animation started at the click, so the old photo was still showing when it began, and then the new one jumped in halfway through.

So I flipped the idea. The photo blurs fast and peaks right at that tenth of a second, then comes back into focus slowly:

Code
@keyframes pp-focus-a {
	0% { filter: none; scale: 1; }
	18% { filter: blur(18px) saturate(0.7); scale: 1.04; opacity: 0.75; }
	100% { filter: none; scale: 1; opacity: 1; }
}

The swap now happens under the blur, so you never see it. There are two copies of this keyframe with different names, one per color. CSS only replays an animation when its name changes, and that’s what makes it play on every click.

I also hid the gallery thumbnails. WooCommerce showed them for the first color and hid them after a switch, and the photo jumped sideways when that happened. One big photo looks calmer anyway.

The 3D photo needs a little JavaScript

On hover, the photo tilts toward your mouse like a card, with a soft light spot that follows it. That part can’t be pure CSS, because CSS has no way to know where the mouse is.

The script only measures the mouse and writes four CSS variables. The stylesheet does the tilt, the shadow and the light:

Code
document.querySelectorAll( '.wc-block-product-gallery-large-image' ).forEach( ( card ) => {
	if ( ! matchMedia( '(hover: hover) and (pointer: fine)' ).matches || matchMedia( '(prefers-reduced-motion: reduce)' ).matches ) return;
	card.addEventListener( 'pointermove', ( e ) => {
		const r = card.getBoundingClientRect();
		const x = ( e.clientX - r.left ) / r.width;
		const y = ( e.clientY - r.top ) / r.height;
		card.style.setProperty( '--ry', ( x - 0.5 ) * 22 + 'deg' );
		card.style.setProperty( '--rx', ( 0.5 - y ) * 16 + 'deg' );
		card.style.setProperty( '--mx', x * 100 + '%' );
		card.style.setProperty( '--my', y * 100 + '%' );
	} );
	card.addEventListener( 'pointerleave', () => [ '--rx', '--ry', '--mx', '--my' ].forEach( ( v ) => card.style.removeProperty( v ) ) );
} );

It does nothing on phones or for anyone who has reduced motion turned on. Add it with a code snippets plugin like WPCode, as a JavaScript snippet in the footer, on product pages only.

One mistake cost me a while here. I first put perspective on the gallery wrapper, and the full-screen view stopped covering the screen. Any element with perspective or transform becomes the box that a fixed element sits in, and the lightbox lives inside the gallery. Moving perspective() into the photo’s own transform fixed it.

A lightbox you can move through

Clicking the photo on Purple opens WooCommerce’s own full-screen view. By default it stacked the photos in one long column, so I turned it into one photo per screen. Scroll or swipe, and scroll-snap brings the next one to the center.

Two round ↑ and ↓ buttons step between photos, and they’re CSS too, made with ::scroll-button(). They work in Chrome and Edge today. Safari and Firefox don’t support them yet, according to MDN’s browser data, so there you scroll, swipe or use the arrow keys.

Each photo tips in from below like a card being dealt, and tips away as it leaves. That’s a scroll-driven animation on view(), with no JavaScript.

The last photo wouldn’t center at first. It stopped in the bottom half of the screen, because there was no room below it to scroll further. Padding the scroll area by half the leftover height fixed it, and both photos now land in the exact center.

Add it to your Purple store

The full stylesheet, with a note on every part, is in this gist. On Purple, add it in the Site Editor under Styles, then Additional CSS. Two things to change for your products:

  1. The two color ids. They come from the attribute and the color name, like attribute_color-blue. Right-click a color button and choose Inspect to see yours.
  2. The color values for each, one strong accent and two soft tints.

It works on other block themes too, since the color picker and gallery are WooCommerce blocks. Two lines in the gist are marked “Purple only”: they point at Purple’s info box and its muted text color, so swap them for your theme’s own.

@property works in Chrome, Edge, Safari 16.4 and later, and Firefox 128 and later. In an older browser, the colors still change, just without the fade.

When you test it, clicking the color that’s already picked unselects it, and the page goes back to its plain colors. That’s how WooCommerce’s color buttons work, so pick a color again and it comes back.

This page started with a Pinterest screenshot, Purple’s own blocks and a few lines of CSS. You don’t need a new theme or a page builder to make a WooCommerce store feel like yours. Mostly you need an idea.

So what would you make with Purple? A product page that changes with the season, a size guide that slides in, a cart that celebrates when it fills up? Share your idea with me on X, and I’d love to try building one of them next.

Did this fix work on your site?

If it didn't, tell me what happened. I re-test reported fixes and update the post.

Tell me what didn't work

Shameem Reza

Shameem Reza Happiness Engineer at Automattic

I fix WooCommerce problems for a living and review plugins for WordPress.org. Every fix here is tested on a clean site first.

No comments yet. Ask the first question.

No account needed. Comments appear after a quick check.