UNPKG

holo-card

Version:

A React component for holographic card effects

290 lines (251 loc) 6.85 kB
:root { --pointer-x: 50%; --pointer-y: 50%; --card-scale: 1; --card-opacity: 0; --translate-x: 0px; --translate-y: 0px; --rotate-x: 0deg; --rotate-y: 0deg; --background-x: var(--pointer-x); --background-y: var(--pointer-y); --pointer-from-center: 0; --pointer-from-top: var(--pointer-from-center); --pointer-from-left: var(--pointer-from-center); } :root { --card-edge: hsl(47, 100%, 78%); --card-back: hsl(205, 100%, 25%); --card-glow: hsl(175, 100%, 90%); --sunpillar-1: hsl(2, 100%, 73%); --sunpillar-2: hsl(53, 100%, 69%); --sunpillar-3: hsl(93, 100%, 69%); --sunpillar-4: hsl(176, 100%, 76%); --sunpillar-5: hsl(228, 100%, 74%); --sunpillar-6: hsl(283, 100%, 73%); --sunpillar-clr-1: var(--sunpillar-1); --sunpillar-clr-2: var(--sunpillar-2); --sunpillar-clr-3: var(--sunpillar-3); --sunpillar-clr-4: var(--sunpillar-4); --sunpillar-clr-5: var(--sunpillar-5); --sunpillar-clr-6: var(--sunpillar-6); } .card { --grain: url("assets/img/grain.webp"); --glitter: url("assets/img/glitter.png"); --glittersize: 25%; --space: 5%; --angle: 133deg; --imgsize: cover; --red: #f80e35; --yellow: #eedf10; --green: #21e985; --blue: #0dbde9; --violet: #c929f1; --clip: inset(9.85% 8% 52.85% 8%); --clip-invert: polygon( 0% 0%, 100% 0%, 100% 100%, 0% 100%, 0 47.15%, 91.5% 47.15%, 91.5% 9.85%, 8% 9.85%, 8% 47.15%, 0 50% ); --clip-stage: polygon( 91.5% 9.85%, 57% 9.85%, 54% 12%, 17% 12%, 16% 14%, 12% 16%, 8% 16%, 8% 47.15%, 92% 47.15% ); --clip-stage-invert: polygon( 0% 0%, 100% 0%, 100% 100%, 0% 100%, 0 47.15%, 91.5% 47.15%, 91.5% 9.85%, 57% 9.85%, 54% 12%, 17% 12%, 16% 14%, 12% 16%, 8% 16%, 8% 47.15%, 0 50% ); --clip-trainer: inset(14.5% 8.5% 48.2% 8.5%); --clip-borders: inset(2.8% 4% round 2.55% / 1.5%); } .card_shine, .card_glare { will-change: transform, opacity, background-image, background-size, background-position, background-blend-mode, filter; } .card { -webkit-transform: translate3d(0px, 0px, 0.01px); transform: translate3d(0px, 0px, 00.01px); -webkit-transform-style: preserve-3d; transform-style: preserve-3d; z-index: calc(var(--card-scale) * 2); will-change: transform, visibility, z-index; } .card, .card * { outline: 1px solid transparent; } .card, .card_rotator { aspect-ratio: var(--card-aspect); border-radius: var(--card-radius); } .card.interacting { z-index: calc(var(--card-scale) * 120); } .card.active .card_translater, .card.active .card_rotator { /* prevent pinch/double-tap zooms on card */ touch-action: none; } .card_translater, .card_rotator { display: grid; perspective: 600px; will-change: transform, box-shadow; transform-origin: center; -webkit-transform-origin: center; transform-style: preserve-3d; } .card_translater { width: auto; position: relative; -webkit-transform: translate3d(var(--translate-x), var(--translate-y), 0.1px) scale(var(--card-scale)); transform: translate3d(var(--translate-x), var(--translate-y), 0.1px) scale(var(--card-scale)); } .card_rotator { -webkit-transform: rotateY(var(--rotate-x)) rotateX(var(--rotate-y)); -webkit-transform-style: preserve-3d; transform: rotateY(var(--rotate-x)) rotateX(var(--rotate-y)); pointer-events: auto; } button.card_rotator { border: none; background: transparent; padding: 0; -webkit-appearance: none; appearance: none; } .card_rotator, .card.active .card_rotator:focus { transition: box-shadow 0.4s ease, opacity 0.33s ease-out; box-shadow: 0 0 3px -1px transparent, 0 0 2px 1px transparent, 0 0 5px 0px transparent, 0px 10px 20px -5px black, 0 2px 15px -5px black, 0 0 20px 0px transparent; } .card.active .card_rotator, .card_rotator:focus { box-shadow: 0 0 3px -1px white, 0 0 3px 1px var(--card-edge), 0 0 12px 2px var(--card-glow), 0px 10px 20px -5px black, 0 0 40px -30px var(--card-glow), 0 0 50px -20px var(--card-glow); } .card_rotator * { width: 100%; display: grid; grid-area: 1/1; aspect-ratio: var(--card-aspect); border-radius: var(--card-radius); image-rendering: optimizeQuality; -webkit-transform-style: preserve-3d; transform-style: preserve-3d; pointer-events: none; overflow: hidden; } .card_rotator img { height: auto; } .card_rotator img:not(.card_back) { -webkit-transform: translate3d(0px, 0px, 0.01px); transform: translate3d(0px, 0px, 0.01px); } .card_back { background-color: var(--card-back); -webkit-transform: rotateY(180deg) translateZ(1px); transform: rotateY(180deg) translateZ(1px); backface-visibility: visible; } .card_front, .card_front * { backface-visibility: hidden; } .card_front { opacity: 1; transition: opacity 0.33s ease-out; -webkit-transform: translate3d(0px, 0px, 0.01px); transform: translate3d(0px, 0px, 0.01px); } .card_shine { display: grid; transform: translateZ(1px); overflow: hidden; z-index: 3; background: transparent; background-size: cover; background-position: center; filter: brightness(0.85) contrast(2.75) saturate(0.65); mix-blend-mode: color-dodge; opacity: var(--card-opacity); } .card_shine::before, .card_shine::after { --sunpillar-clr-1: var(--sunpillar-5); --sunpillar-clr-2: var(--sunpillar-6); --sunpillar-clr-3: var(--sunpillar-1); --sunpillar-clr-4: var(--sunpillar-2); --sunpillar-clr-5: var(--sunpillar-3); --sunpillar-clr-6: var(--sunpillar-4); grid-area: 1/1; transform: translateZ(1px); border-radius: var(--card-radius); } .card_shine:after { --sunpillar-clr-1: var(--sunpillar-6); --sunpillar-clr-2: var(--sunpillar-1); --sunpillar-clr-3: var(--sunpillar-2); --sunpillar-clr-4: var(--sunpillar-3); --sunpillar-clr-5: var(--sunpillar-4); --sunpillar-clr-6: var(--sunpillar-5); transform: translateZ(1.2px); } .card_glare { transform: translate(1.41px); overflow: hidden; background-image: radial-gradient( farthest-corner circle at var(--pointer-x) var(--pointer-y), hsla(0, 0%, 100%, 0.8) 10%, hsla(0, 0%, 100%, 0.65) 20%, hsla(0, 0%, 0%, 0.5) 90% ); opacity: var(--card-opacity); mix-blend-mode: overlay; } .card.masked .card_shine, .card.masked .card_shine:before, .card.masked .card_shine:after { -webkit-mask-image: var(--mask); mask-image: var(--mask); -webkit-mask-size: cover; mask-size: cover; -webkit-mask-position: center center; mask-position: center center; }