Weekend in Lisbon
Three days of tiles, tarts and trams.
A folded greeting card lying on a table. On hover the cover swings up on its crease and a heart stands up out of the fold, like a pop-up book. Cover, base and heart share one tilted 3D plane.
Also known as: pop up greeting card css, 3d card opening, pop up book hover.
<div class="hfx-pop-up-card">
<div class="hfx-pop-up-card-table">
<div class="hfx-pop-up-card-base"><span>Thank you!</span></div>
<svg class="hfx-pop-up-card-heart" viewBox="0 0 24 22" aria-hidden="true"><path d="M12 21S3 15.5 1.2 9.6A5.6 5.6 0 0 1 12 5.2a5.6 5.6 0 0 1 10.8 4.4C21 15.5 12 21 12 21z"/></svg>
<div class="hfx-pop-up-card-cover">
<div class="hfx-pop-up-card-inside"></div>
<div class="hfx-pop-up-card-outside"><span>For you</span></div>
</div>
</div>
</div>.hfx-pop-up-card {
--c: var(--hfx-color, #3b82f6);
font-size: var(--hfx-size, 16px);
display: grid;
place-items: center;
width: 13em;
height: 11em;
perspective: 40em;
font-family: system-ui, sans-serif;
}
.hfx-pop-up-card-table {
position: relative;
width: 11em;
height: 5em;
transform-style: preserve-3d;
transform: translateY(1.4em) rotateX(58deg);
}
.hfx-pop-up-card-base,
.hfx-pop-up-card-inside,
.hfx-pop-up-card-outside {
position: absolute;
inset: 0;
display: grid;
place-items: center;
backface-visibility: hidden;
}
.hfx-pop-up-card-base {
align-items: end;
padding-bottom: 0.8em;
border-radius: 0 0 0.4em 0.4em;
background: color-mix(in srgb, var(--c) 6%, #fff);
box-shadow: 0 0 0 1px color-mix(in srgb, var(--c) 20%, transparent), 0 1em 1.5em color-mix(in srgb, #000 12%, transparent);
color: color-mix(in srgb, var(--c) 80%, #000);
font-weight: 700;
}
.hfx-pop-up-card-cover {
position: absolute;
left: 0;
right: 0;
bottom: 100%;
height: 100%;
transform-style: preserve-3d;
transform-origin: 50% 100%;
transform: rotateX(-178deg);
transition: transform 0.7s cubic-bezier(0.3, 1.25, 0.5, 1);
}
.hfx-pop-up-card-inside {
border-radius: 0.4em 0.4em 0 0;
background: linear-gradient(color-mix(in srgb, var(--c) 18%, #fff), color-mix(in srgb, var(--c) 6%, #fff));
box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--c) 25%, transparent);
}
.hfx-pop-up-card-outside {
border-radius: 0.4em 0.4em 0 0;
background:
radial-gradient(circle, color-mix(in srgb, #fff 35%, transparent) 0 0.12em, transparent 0.15em) 0 0 / 0.9em 0.9em,
var(--c);
color: #fff;
font-size: 1.1em;
font-weight: 700;
transform: rotateX(180deg);
}
.hfx-pop-up-card-heart {
position: absolute;
left: 50%;
top: -1.6em;
width: 3.4em;
height: 3.2em;
margin-left: -1.7em;
fill: var(--c);
transform-origin: 50% 100%;
transform: rotateX(0deg) scale(0);
transition: transform 0.6s cubic-bezier(0.3, 1.4, 0.5, 1);
}
.hfx-pop-up-card:hover .hfx-pop-up-card-cover {
transform: rotateX(-80deg);
}
.hfx-pop-up-card:hover .hfx-pop-up-card-heart {
transform: rotateX(-90deg) scale(1);
transition-delay: 0.15s;
}
@media (prefers-reduced-motion: reduce) {
.hfx-pop-up-card, .hfx-pop-up-card *, .hfx-pop-up-card::before, .hfx-pop-up-card::after, .hfx-pop-up-card *::before, .hfx-pop-up-card *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}--hfx-color on the element or a parent.
Currently previewing #3b82f6.--hfx-size. Every other dimension is in
em, so the whole thing scales together. Currently previewing 16px.transition or animation
shorthand. Staggered delays are relative, so they keep their rhythm.