Pokemon cards implemented in CSS and javascript
A friend suggested that I create a pokemon card of myself for my website. When we were googling Pokemon cards and CSS, the top hit was Simon Goellner's Pokemon Cards Gallery which led us to the pokemon-cards-css GitHub project. I was pretty excited by this and immediately wanted to understand how it worked. Simon has posted a comprehensive Wiki site that explains the architecture of the effect which helped me get a grasp of things but I also learned a lot by looking at the card in the Firefox inspector and trying to reverse engineer the effect myself.
Here are some things to look at and steps I followed to integrate this into my website without using Svelte since this website is very static.
I won't go into everything because there are so many details. The more I look at this effect, the more impressed I am at how much attention to detail there is! So this explanation will just cover the big ideas that I learnt.
Part 1: Movement
I'm going to divide this up into multiple posts because it takes awhile to explain. Each concept is a bit of work so in the interests of getting other stuff done, I'll make this a series.
First of all, to see the holographic effect, the card needs to move and catch the light. Simon has published a stand-alone component for this but I went for something even simpler. Also, the architecture with all the details is explained on the wiki. Given a basic card HTML div, you can make it rotate in response to the mouse with some pretty basic JS:
<div class="card" id="holocard">
<div class="card__rotator">
<div class="card__front">
</div>
</div>
</div>
Here are the styles that rotate the card__rotator element (and everything inside
it). The rotation is controlled using --rotate-x and --rotate-y which are
set by the javascript.
.card {
border: gray solid 1px;
width: 330px;
height: 460px;
perspective: 600px; /* has to be on the parent element */
}
.card__rotator {
/* The rotate-x/y variables changed in the javascript make the div move */
transform-style: preserve-3d;
transform: rotateY(var(--rotate-x)) rotateX(var(--rotate-y));
}
.card__front {
width: 330px;
height: 460px;
background-color: grey;
}
Here is the most basic javascript to react to mouse pointer events:
const card = document.getElementById('holocard');
/* A simple function to keep a value inside expected bounds */
function clamp(v, min, max) {
return Math.min(Math.max(v, min), max);
}
/* Interact is called by mouse events */
function interact(e) {
/* Calculate the cursor position as x/y coordinates normalised to 100% values */
const rect = card.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
const pointerXPc = clamp((x / rect.width) * 100, 0, 100);
const pointerYPc = clamp((y / rect.height) * 100, 0, 100);
/* rotation is set to a scaled value based on the x/y position */
card.style.setProperty('--rotate-x', `${(pointerXPc - 50) * -20/50}deg`);
card.style.setProperty('--rotate-y', `${(pointerYPc - 50) * 20/50}deg`);
}
function interactEnd(e) {
card.style.setProperty('--rotate-x', '0deg');
card.style.setProperty('--rotate-y', '0deg');
}
card.addEventListener('pointermove', interact);
card.addEventListener('pointerleave', interactEnd);
And the result is a card you can hover the mouse over.
Next: Add the Shine Layer