demosthenes.info

Independent notes on CSS, SVG, animation and front-end design.

Articles / Article

CSS 3D Captioned Domino Image

While Codrops and CodePlayer have shown recent variations of this technique, I felt their solutions were lacking in several regards: the images weren’t...

While Codrops and CodePlayer have shown recent variations of this technique, I felt their solutions were lacking in several regards: the images weren’t mobile-ready, the markup lacked semantic value, and the CSS tended to be overly complex. Thus, this derivation and tutorial…

Markup

The HTML5 code is very simple, relying primarily on <figure> and <figcaption> elements:

<div>
<figure>
<figcaption>Autumn, by Lucien Agasse</figcaption>
</figure>
</div>

The <div> element contains the context of 3D perspective; it will also ensure that user interactions are captured by an element that remains static on the screen.

Styling

div {
perspective: 1000px; width: 33%;
margin: 0 auto;
margin-top: 3rem;
}

The <figure> contains a full-width background image that is cut off by a height set in vw units (and thus responds to the width of the browser window).

figure {
margin: 0; width: 100%; height: 29.5vw;
position: relative; background-size: 100%;
background: url("winter-hat.jpg");
transform-origin: center bottom;
transform-style: preserve-3d;
transition: 1s transform;
}

The transform-origin of the <figure> element is set to “swing” from its lower edge, like a trapdoor. Next, the image caption:

figcaption {
width: 100%; height: 50px;
position: relative; top: 29.5vw;
background: linear-gradient(rgba(0, 0, 0, 0.4), rgba(0, 0, 0, 0.4)),
url("winter-hat.jpg");
background-size: 100%;
background-position: bottom;
color: #fff;
transform-origin: center top;
transform: rotateX(-89.9deg);
font-size: 1.2vw; text-align: center;
line-height: 3;
}

The <figcaption> element is provided with a set height and moved to the exact position where the <figure> is cut off. The element uses the same background-image as the <figure>, only starting from the bottom of the element, rather than the top. This background is overlaid with a “wash” of rgba color to fade it, a technique I’ve discussed before. Then, the <figcaption> is “hinged” from the top and folded back by a little less than 90 degrees.

Creating The Shadow

The shadow is a pseudo-element generated from the <figure>, its size and shape determined by the rule that absolutely positioned elements take their cues from relatively positioned parents:

figure:before {
content: '';
position: absolute; top: 0; left: 0;
width: 100%; height: 100%;
box-shadow: 0 0 100px 50px rgba(0, 0, 0, 0.1),
inset 0 0 250px 250px rgba(0, 0, 0, 0.1);
transition: 1s;
transform: rotateX(95deg) translateZ(-80px) scale(0.75);
transform-origin: inherit;
}

The shadow is given the appearance of “solidity” by using both a standard outer box-shadow and an inset one. Then, it is rotated back while being moved and scaled down, providing the impression of a “ground”.

Adding The Transition

The movement of the <figure> and its shadow are initiated by hovering over the <div> element:

div:hover figure {
transform: rotateX(75deg) translateZ(5vw);
}
div:hover figure:before {
box-shadow: 0 0 25px 25px rgba(0, 0, 0, 0.5),
inset 0 0 250px 250px rgba(0, 0, 0, 0.5);
transform: rotateX(-5deg) translateZ(-80px) scale(1);
}

The <figure> is rotated back while being moved down, and the box-shadow rotated up to meet it. At the same time, the shadow darkens and focuses (note the altered alpha and blur values). As part of the <figure> (and because we added transform-style: preserve-3d earlier) the <figcaption> moves in synchronicity.

Adding Breakpoints

The image is perfect for large viewports, but requires some intervention at smaller sizes: realistically, we can’t leave the <div> at ⅓rd the browser window width if the screen is only 320 pixels wide. <figcaption> will also need some intervention, as set vw units do not remain appropriate for text across the entire spectrum of screen sizes.

@media screen and (max-width: 800px) {
div { width: 50%; }
figure { height: 45vw; }
figcaption { top: 45vw; font-size: 2vw; }
}
@media screen and (max-width: 500px) {
div { width: 80%; margin-top: 1rem; }
figure { height: 70vw; }
figcaption { top: 70vw; font-size: 3vw; }
}

Adaption For Mobile

Support for :hover is inconsistent across mobile platforms; a quick, albeit imperfect solution is to add an empty onclick action for the <div>:

<div onclick="">

There’s much more that can be done with this interaction pattern, as I’ll show in future articles.

Photograph by Lucien Agasse, licensed under Creative Commons Play with code for the CSS 3D Domino Image on Codepen