Animation Of Girl Who Turns To Doll
Animation Of Girl Who Turns To Doll
Here's a fun one. How might we create a set of those absurd Matryoshka dolls where they nest inside 1 another… just in CSS?
I toyed with this idea in my caput for a little while. Then, I saw a tweet from CSS-Tricks and the article image had the dolls. I took that as a sign! Information technology was time to put fingers to the keyboard.
Our goal here is to make these fun and interactive, where nosotros tin click on a doll to open it upward and reveal another, smaller doll. Oh, and stick with just CSS for the functionality. And while we're at it, allow's supervene upon the dolls with our own graphic symbol, say a CodePen bear. Something like this:
Nosotros won't dwell on making things pretty to start. Permit's become some markup on the folio and thrash out the mechanics get-go.
Nosotros can't accept an infinite amount of dolls. When we achieve the innermost doll, it'd be nice to be able to reset the dolls without having to exercise a page refresh. A neat trick for this is to wrap our scene in an HTML form. That way we can use an input and gear up the type
aspect to reset
to avoid using whatever JavaScript.
<form> <input type="reset" id="reset"/> <label for="reset" championship="Reset">Reset</characterization> </form>
Next, we need some dolls. Or bears. Or something to start with. The key hither will be to utilise the classic checkbox hack and any associated form labels. As a notation, I'k going to use Pug to handle the markup because information technology supports loops, making things a footling easier. Merely, you tin can certainly write the HTML by mitt. Here'southward the start with course fields and labels that set up the checkbox hack.
Endeavor clicking some of the inputs and hit the Reset input. They all become unchecked. Dainty, we'll use that.
We have some interactivity but nothing is actually happening nonetheless. Hither's the plan:
- We'll only show one checkbox at a fourth dimension
- Checking a checkbox should reveal the label for the adjacent checkbox.
- When we get to the final checkbox, there our merely option should be to reset the form.
The flim-flam will be to make employ of the CSS adjacent sibling combinator (+
).
input:checked + characterization + input + label { brandish: block; }
When a checkbox is checked, nosotros need to show the label for the next doll, which will exist three siblings along in the DOM. How practice we brand the first label visible? Give it an explicit display: block
via inline styles in our markup. Putting this together, nosotros have something forth these lines:
Clicking each characterization reveals the adjacent. Concur on, the last characterization isn't shown! That's correct. And that's because the last label doesn't have a checkbox. Nosotros demand to add together a rule that caters to that final label.
input:checked + label + input + label, input:checked + label + characterization { display: block; }
Cool. We're getting somewhere. That'south the basic mechanics. Now things are going to go a little trickier.
Basic styling
And then, y'all might be thinking, "Why aren't we hiding the checked characterization?" Proficient question! Simply, if we hide it direct abroad, we won't accept any transition between the current doll and the side by side. Before we starting time animative our dolls, let'south create basic boxes that will correspond a doll. We tin can fashion them up then they mimic the doll outline without the detail.
.doll { color: #fff; cursor: pointer; superlative: 200px; font-size: 2rem; left: 50%; position: accented; text-align: centre; top: 50%; transform: translate(-l%, -50%); width: 100px; } .doll:nth-of-type(even) { background: #00f; } .doll:nth-of-type(odd) { groundwork: #f00; }
Clicking one doll instantly reveals the adjacent 1 and, when we've reached the last doll, we can reset the form to get-go over again. That's what nosotros want here.
The mechanics
We are going to animate the dolls based on a heart bespeak. Our animation will consist of many steps:
- Slide the electric current doll out to the left.
- Open the doll to reveal the next ane.
- Move the next doll where the current one started.
- Make the current doll fade out.
- Assign the next doll as the current doll.
Permit's offset past sliding the electric current doll out to the left. We apply an animation when nosotros click a label. Using the :checked
pseudo-selector we can target the current doll. At this point, information technology's worth noting that nosotros are going to use CSS variables to control animation speed and behavior. This will make information technology easier to chain animations on the labels.
:root { --speed: 0.25; --base-slide: 100; --slide-altitude: 60; } input:checked + label { animation: slideLeft calc(var(--speed) * 1s) forwards; } @keyframes slideLeft { to { transform: translate(calc((var(--base of operations-slide) * -1px) + var(--slide-distance) * -1%), 0); } }
That looks great. Merely there's an issue. As soon as we click a label, we could click it again and reset the animation. We don't want that to happen.
How can we go around this? We can remove pointer events from a characterization once it'due south been clicked.
input:checked + label { animation: slideLeft calc(var(--speed) * 1s) forwards; arrow-events: none; }
Keen! Now once we have started, nosotros tin't stop the animation chain from happening.
Side by side up, we demand to crack open the doll to reveal the next one. This is where things get tricky considering we are going to need some extra elements, non only to create the issue that the doll is opening upwardly, but also to reveal the next doll inside of it. That'due south right: nosotros need to indistinguishable the inner doll. The trick here is to reveal a "faux" doll that we bandy for the real one one time we've animated it. This besides means delaying the reveal of the side by side characterization.
At present our markup updates labels so that they contains span elements.
<label course="doll" for="doll--1"> <span class="doll doll--dummy"></span> <span class="doll__half doll__half--top">Pinnacle</bridge> <span form="doll__half doll__half--lesser">Bottom</span> </characterization>
These will act as the "dummy" doll as well equally the chapeau and base of operations for the current doll.
.doll { color: #fff; cursor: pointer; height: 200px; font-size: 2rem; position: absolute; text-marshal: heart; width: 100px; } .doll:nth-of-type(even) { --bg: #00f; --dummy-bg: #f00; } .doll:nth-of-type(odd) { --bg: #f00; --dummy-bg: #00f; } .doll__half { groundwork: var(--bg); position: absolute; width: 100%; height: 50%; left: 0; } .doll__half--peak { top: 0; } .doll__half--lesser { lesser: 0; } .doll__dummy { background: var(--dummy-bg); height: 100%; width: 100%; position: accented; tiptop: 0; left: 0; }
The chapeau requires three translations to create the opening effect: 1 to popular it upward, one to motion information technology left and and then i to pop it downwards.
@keyframes open { 0% { transform: translate(0, 0); } 33.333333333333336% { transform: interpret(0, -100%); } 66.66666666666667% { transform: translate(-100%, -100%); } 100% { transform: translate(-100%, 100%); } }
Adjacent is where we can employ CSS custom properties to handle changing values. Once the doll has slid over to the left, we tin open it. Simply how do we know how long to filibuster information technology from opening until that happens? We can use the --speed
custom property we defined before to calculate the correct delay.
It looks a little quick if we use the --speed
value as it is, so permit'due south multiply it by two seconds:
input:checked + .doll { animation: slideLeft calc(var(--speed) * 1s) forwards; pointer-events: none; } input:checked + .doll .doll__half--top { animation: open calc(var(--speed) * 2s) calc(var(--speed) * 1s) forwards; // highlight }
Much better:
Now we need to move the inner "dummy" doll to the new position. This animation is like the open up blitheness in that it consists of three stages. Again, that's i to motion upward, i to move right, and one to set downwards. It's like the slide animation, too. Nosotros are going to use CSS custom properties to determine the distance that the doll moves.
:root { // Introduce a new variable that defines how high the dummy doll should pop out. --pop-height: lx; } @keyframes motility { 0% { transform: translate(0, 0) interpret(0, 0); } 33.333333333333336% { transform: translate(0, calc(var(--pop-acme) * -1%)) translate(0, 0); } 66.66666666666667% { transform: translate(0, calc(var(--popular-height) * -one%)) translate(calc((var(--base-slide) * 1px) + var(--slide-distance) * 1%), 0); } 100% { transform: interpret(0, calc(var(--pop-height) * -i%)) interpret(calc((var(--base-slide) * 1px) + var(--slide-distance) * 1%), calc(var(--pop-height) * 1%)); } }
Almost there!
The only thing is that the next doll is available equally soon equally we click a doll. that means we can spam click our way through the ready.
Technically, the next doll shouldn't show until the "fake" one has moved into place. It's simply once the "faux" doll is in place that we tin hide it and reveal the real i. That ways nosotros going to use zero-second scale animations! That's correct. We can play pretend by delaying two zip-second animations and using animation-make full-mode
.
@keyframes appear { from { transform: scale(0); } }
We actually simply need one set of @keyframes
. because we tin re-use what nosotros have to create the reverse motility with animation-management: reverse
. With that in mind, all our animations go applied something similar this:
// The next doll input:checked + .doll + input + .doll, // The last doll (doesn't have an input) input:checked + .doll + .doll { animation: appear 0s calc(var(--speed) * 5s) both; display: block; } // The current doll input:checked + .doll, // The current doll that isn't the first. Specificity prevails input:checked + .doll + input:checked + .doll { animation: slideLeft calc(var(--speed) * 1s) forwards; pointer-events: none; } input:checked + .doll .doll__half--acme, input:checked + .doll + input:checked + .doll .doll__half--top { blitheness: open calc(var(--speed) * 2s) calc(var(--speed) * 1s) forrad; } input:checked + .doll .doll__dummy, input:checked + .doll + input:checked + .doll .doll__dummy { animation: movement calc(var(--speed) * 2s) calc(var(--speed) * 3s) forwards, appear 0s calc(var(--speed) * 5s) contrary frontward; }
Note how important the variables are, peculiarly where we are chaining animations. That gets u.s.a. almost where we demand to be.
I can hear information technology now: "They're all the same size!" Yep. That's the missing piece. They need to calibration down. The trick hither is to accommodate the markup again and brand utilise of CSS custom properties yet once again.
<input id="doll--0" type="checkbox"/> <label class="doll" for="doll--0" style="display: cake; --doll-index: 0;"> <span class="doll__dummy-container"> <span class="doll__dummy"></bridge> </span> //highlight <span class="doll__container"> <bridge class="doll__half doll__half--meridian"></bridge> <bridge class="doll__half doll__half--bottom"></span> </span> </label>
We just introduced a CSS custom property inline that tells us the index of the doll. We can use this to generate a scale of each half as well as the fake inner doll. The halves volition have to scale to match the bodily doll size, just the imitation inner doll scale will need to match that of the next doll. Catchy!
We can apply these scales inside the containers so that our animations are not affected.
:root { --scale-footstep: 0.05; } .doll__container, .doll__dummy-container { height: 100%; left: 0; position: absolute; top: 0; width: 100%; } .doll__container { transform: scale(calc(1 - ((var(--doll-index)) * var(--scale-stride)))); transform-origin: bottom; } .doll__dummy { height: 100%; left: 0; position: accented; tiptop: 0; transform: scale(calc(one - ((var(--doll-index) + 1) * var(--scale-pace)))); transform-origin: lesser center; width: 100%; }
Note how the .doll__dummy
class uses var(--doll-alphabetize) + 1)
to calculate the calibration so that it matches the side by side doll. 👍
Lastly, nosotros re-assign the blitheness to the .doll__dummy-container
class instead of the .doll__dummy
class.
input:checked + .doll .doll__dummy-container, input:checked + .doll + input:checked + .doll .doll__dummy-container { animation: move calc(var(--speed) * 2s) calc(var(--speed) * 3s) forrard, appear 0s calc(var(--speed) * 5s) reverse forwards; }
Here'due south a demo where the containers have been given a background color to see what's happening.
We tin come across that, although the content size changes, they remain the same size. This makes for consistent animation behavior and makes the lawmaking easier to maintain.
Finishing touches
Wow, things are looking pretty slick! All we demand are some finishing touches and we are done!
The scene starts to look chaotic because nosotros're stacking the "onetime" dolls off to the side when a new one is introduced. Then let's slide a doll out of view when the adjacent one is revealed to clean that mess upward.
@keyframes slideOut { from { transform: interpret(calc((var(--base-slide) * -1px) + var(--slide-distance) * -1%), 0); } to { opacity: 0; transform: translate(calc((var(--base-slide) * -1px) + var(--slide-altitude) * -two%), 0); } } input:checked + .doll, input:checked + .doll + input:checked + .doll { animation: slideLeft calc(var(--speed) * 1s) forwards, slideOut calc(var(--speed) * 1s) calc(var(--speed) * 6s) frontward; pointer-events: none; }
The new slideOut
animation fades the doll out while information technology translates to the left. Perfect. 👍
That'southward information technology for the CSS trickery nosotros need to brand this effect work. All that's left style the dolls and the scene.
We have many options to style the dolls. We could utilize a background image, CSS illustration, SVG, or what have y'all. Nosotros could fifty-fifty throw together some emoji dolls that utilize random inline hues!
Let'southward go with inline SVG.
I'g basically using the same underlying mechanics we've already covered. The difference is that I'g besides generating inline variables for hue and lightness and so the bears sport different shirt colors.
In that location nosotros take it! Stacking dolls — err, bears — with zilch just HTML and CSS! All the code for all the steps is available in this CodePen collection. Questions or suggestions? Feel free to reach out to me here in the comments.
DOWNLOAD HERE
Animation Of Girl Who Turns To Doll
Posted by: clarkanot1950.blogspot.com
0 Response to "Animation Of Girl Who Turns To Doll"
Post a Comment