Infinitely rolling image using CSS - css

I would like to have a slowly and repeatedly rolling panoramic image - as if we have a slow rolling drum with the picture pasted on its side. See https://imgur.com/a/AOdQC7T for an animation of such a drum. Ideally I would like to do this in HTML/CSS and my attempt at trying is here:
However, the animation does not wrap around nicely as in the drum animation.
.verticalSpin {
animation: spinVertical 5s linear infinite;
}
.verticalRoll {
animation: rollVertical 5s linear infinite;
}
.verticalRoll:hover, .verticalSpin:hover {
animation-play-state: paused
}
#keyframes spinVertical {
0% {
transform: rotateY(0deg);
}
100% {
transform: rotateY(360deg);
}
}
#keyframes rollVertical {
0% {
margin-left: 100px;
margin-right: -100px;
}
100% {
margin-left: -100px;
margin-right: 100px;
}
}
<div style="text-align: center;">
<div class="verticalRoll">
<img style="width: 100%; max-width: 300px;"
alt="home" src="https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png" />
</div>
<p style="font-family: arial, helvetica, serif; color: blue; border: 1px solid blue; padding: 10px; border-radius: 5px; background-color: lightblue; color: blue;">
Image Animation.
</p>
</div>
Would appreciate any help/pointers to make this happen! Many thanks!!

Related

Make blinking cursor disappear at end of CSS animation

I have a blinking cursor animation set up with two lines of text.
I want to have the cursor appear as the text appears, and vanish at the end of the first line – but leave it blinking at the end of the second line.
Someone asked a very similar question, but the solution makes the cursor completely invisible:
Stopping a blinking cursor at end of css animation
Tested this answer code (on several browsers), and it just doesn't work.
Here's what I have:
Code:
.typewriter1 p {
overflow: hidden;
border-right: .15em solid #00aeff;
white-space: nowrap;
margin: 0 auto;
letter-spacing: 0;
color: #fff;
padding-left: 10px;
animation: typing 3.5s steps(40, end), blink-caret .75s step-end infinite;
}
.typewriter2 p {
overflow: hidden;
/* Ensures the content is not revealed until the animation */
border-right: .15em solid #00aeff;
white-space: nowrap;
margin: 0 auto;
letter-spacing: 0;
color: #fff;
padding-left: 10px;
opacity: 0;
animation: typing 3.5s steps(40, end), blink-caret .75s step-end infinite, slidein 1s ease 3.5s forwards;
animation-delay: 3.5s;
}
/* The typing effect */
#keyframes typing {
from {
width: 0
}
to {
width: 100%
}
}
#keyframes slidein {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
/* The typewriter cursor effect */
#keyframes blink-caret {
from,
to {
border-color: #00aeff
}
50% {
border-color: transparent;
}
}
<div class="typewriter1">
<p>A well defined plan will identify problems,</p>
</div>
<div class="typewriter2">
<p> address challenges, and help restore confidence.</p>
</div>
Only Example 2 is fully explained at the moment. Example 3 is exactly the same HTML and CSS as the question with minor changes.
Example 1 — Redesign for background images and gradients
HTML
First, we can clean up the HTML. This is a single paragraph, so let's wrap it in one paragraph element:
<p class="typewriter">
A well defined plan will identify problems,
address challenges, and help restore confidence.
</p>
Second, we need to reveal each line individually, so we wrap each line in a nested span element and manually break the line with a line break:
<p class="typewriter">
<span class="slide">
<span class="inner-slide">A well defined plan will identify problems,
</span>
</span><br>
<span class="slide">
<span class="inner-slide">address challenges, and help restore confidence. </span>
</span>
</p>
Full Example 1
Current Limitation: We have to set a fixed pixel width for left.
.typewriter {
position: relative;
height: 500px;
margin: 0 auto;
width: 310px;
overflow: hidden;
}
.typewriter .slide,
.inner-slide {
display: inline-block;
overflow: hidden;
height: 1.1em;
}
.typewriter .slide {
position: relative;
animation: typing 2s steps(30, end) forwards, blink-caret .75s step-end infinite;
left: -310px;
border-right: .15em solid transparent;
}
.typewriter .slide:nth-of-type(1) {
animation: typing 2s steps(30, end) forwards, blink-caret .75s step-end 2.6;
}
.inner-slide {
position: relative;
animation: typing2 2s steps(30, end) forwards;
white-space: nowrap;
left: 310px;
}
.typewriter .slide:nth-of-type(2),
.typewriter .slide:nth-of-type(2) .inner-slide {
animation-delay: 2s;
}
#keyframes typing {
from {
left: -310px;
}
to {
left: 0;
}
}
#keyframes typing2 {
from {
left: 310px;
}
to {
left: 0;
}
}
/*The typewriter cursor effect */
#keyframes blink-caret {
0,
100% {
border-color: transparent
}
50% {
border-color: #00aeff
}
}
body {
background: linear-gradient(to bottom right, #CCC 0, #F00 100%) no-repeat;
}
<p class="typewriter">
<span class="slide">
<span class="inner-slide">A well defined plan will identify problems,
</span>
</span><br>
<span class="slide">
<span class="inner-slide">address challenges, and help restore confidence.</span>
</span>
</p>
Example 2 — Original. Suitable for solid colour backgrounds
The HTML
First, we can clean up the HTML. This is a single paragraph, so let's wrap it in one paragraph element:
<p class="typewriter">
A well defined plan will identify problems,
address challenges, and help restore confidence.
</p>
Second, we need to reveal each line individually, so we wrap each line in a span element and manually break the line with a line break:
<p class="typewriter">
<span>A well defined plan will identify problems,</span><br>
<span> address challenges, and help restore confidence.</span>
</p>
The CSS
Now we need an element that will cover our text and act as an animated cursor. We can use a pseudo-element that will start at 100% width and have a left border, like so:
.typewriter > span::before {
content: '';
border-left: .15em solid #00aeff;
position: absolute;
background: white;
height: 1.1em;
right: -5px;
width: 100%;
}
The height is just enough to cover all the text including below the baseline.
The right negative value will pull it outside its parent so the cursor doesn't show on the first line thanks to overflow-hidden on the parent.
It starts at 100% width which is animated to 0.
It is positioned absolute to the span which has a relative position.
In order to keep the cursor on the last line, we need to give it a 0 right value:
.typewriter > span:last-of-type::before {
right: 0;
}
Now it will no longer be pulled outside the parent.
The second line needs to be delayed by the same amount of time as the animation run time:
.typewriter > span:nth-of-type(2)::before {
animation-delay: 2s;
}
Because we want the paragraph widths to be determined by the width of the text and the span to accept widths, we need to make them inline-block:
.typewriter,
.typewriter > span {
display: inline-block;
}
Lastly, we reverse the typing animation to go from 100% to 0:
#keyframes typing {
from {
width: 100%
}
to {
width: 0
}
}
Full Example 2
.typewriter,
.typewriter > span {
display: inline-block;
}
.typewriter > span {
position: relative;
overflow: hidden;
padding-right: 4px;
}
.typewriter > span::before {
content: '';
position: absolute;
border-left: .15em solid #00aeff;
background: white;
height: 1.1em;
right: -5px;
width: 100%;
animation: blink-caret .75s step-end infinite, typing 2s steps(30, end) forwards;
}
.typewriter > span:nth-of-type(2)::before {
animation-delay: 2s;
}
.typewriter > span:last-of-type::before {
right: 0;
}
/* The typing effect*/
#keyframes typing {
from {
width: 100%
}
to {
width: 0
}
}
/*The typewriter cursor effect */
#keyframes blink-caret {
from,
to {
border-color: #00aeff
}
50% {
border-color: transparent
}
}
<p class="typewriter">
<span>A well defined plan will identify problems,</span><br>
<span> address challenges, and help restore confidence.</span>
</p>
Example 3 — Using exactly the example from the question
Change the iteration count as appropriate for the first line caret. In this example the value is 4.1. This animation will iterate 4.1 times and then stop:
animation: blink-caret .75s step-end 4.1
The border that creates the caret is changed to transparent:
border-right: .15em solid transparent
and the animation is flipped:
#keyframes blink-caret {
0,
100% {
border-color: transparent
}
50% {
border-color: #00aeff
}
}
Now the stopped state is transparent and the first line will disappear on the first line.
Full Example 3
body {
width: 330px;
}
.typewriter1 p {
overflow: hidden;
border-right: .15em solid transparent;
white-space: nowrap;
margin: 0 auto;
letter-spacing: 0;
padding-left: 10px;
animation: typing 3.5s steps(40, end), blink-caret .75s step-end 4.1;
}
.typewriter2 p {
overflow: hidden;
/* Ensures the content is not revealed until the animation */
border-right: .15em solid transparent;
white-space: nowrap;
margin: 0 auto;
letter-spacing: 0;
padding-left: 10px;
opacity: 0;
animation: typing 3.5s steps(40, end), blink-caret .75s step-end infinite, slidein 1s ease 3.5s forwards;
animation-delay: 3.5s;
}
/* The typing effect */
#keyframes typing {
from {
width: 0
}
to {
width: 100%
}
}
#keyframes slidein {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
/* The typewriter cursor effect */
#keyframes blink-caret {
0,
100% {
border-color: transparent
}
50% {
border-color: #00aeff
}
}
<div class="typewriter1">
<p>A well defined plan will identify problems,</p>
</div>
<div class="typewriter2">
<p> address challenges, and help restore confidence.</p>
</div>
I just changed infinite from .typewriter1 p { to 5.
.typewriter1 p {
overflow: hidden;
border-right: .15em solid #00aeff;
white-space: nowrap;
margin: 0 auto;
letter-spacing: 0;
color: #fff;
padding-left: 10px;
animation: typing 3.5s steps(40, end), blink-caret .75s step-end 5;
}
.typewriter2 p {
overflow: hidden;
/* Ensures the content is not revealed until the animation */
border-right: .15em solid #00aeff;
white-space: nowrap;
margin: 0 auto;
letter-spacing: 0;
color: #fff;
padding-left: 10px;
opacity: 0;
animation: typing 3.5s steps(40, end), blink-caret .75s step-end infinite, slidein 1s ease 3.5s forwards;
animation-delay: 3.5s;
}
/* The typing effect */
#keyframes typing {
from {
width: 0
}
to {
width: 100%
}
}
#keyframes slidein {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
/* The typewriter cursor effect */
#keyframes blink-caret {
from,
to {
border-color: #00aeff
}
50% {
border-color: transparent;
}
}
<div class="typewriter1">
<p>A well defined plan will identify problems,</p>
</div>
<div class="typewriter2">
<p> address challenges, and help restore confidence.</p>
</div>
If you're not necessarily glued to writing your own animations for this, TypeIt's (https://typeitjs.com) API makes it possible w/ a lot less custom code:
https://codepen.io/alexmacarthur/pen/MWWEPxa
const secondInstance = new TypeIt('.typewriter2 p');
const firstInstance = new TypeIt('.typewriter1 p', {
afterComplete: function (instance) {
document.querySelector('.typewriter1 p .ti-cursor').remove();
secondInstance.go();
}
}).go();
The only downside to this approach is that you have less control over the animation itself (you'd need to override the CSS animation provided by the library).

How can I animate several elements on the same orbital path in sequence?

I want to create an animation showing a few circles moving one after another in orbit. Currently, I created three circles but they appear on separate lines and thus move in a circular movement, but as a line. How can I change the code to achieve the movement that I want? Here's a codepen with the current status.
Here's the code that I use:
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Lato', sans-serif;
font-size: 18px;
line-height: 1.6;
background-image: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
min-height: 100vh;
}
.loader {
height: 50px;
animation: rotate 6s linear infinite;
}
.circle {
display: inline-block;
background-color: purple;
height: 40px;
width: 40px;
border-radius: 50%;
transform: scale(0);
animation: grow 1.5s linear infinite;
margin: -20p;
}
.circle:nth-child(2) {
background-color: palevioletred;
transform: scale(0);
animation-delay: 0.20s;
}
#keyframes rotate {
to {
transform: rotate(360deg)
}
}
#keyframes grow {
50% {
transform: scale(1);
}
}
<div class="loader">
<div class="circle"></div>
<div class="circle"></div>
<div class="circle"></div>
</div>
I'm creating full-size "plates" which I can set to an initial rotation point. The circles end up as pseudo-elements on the plates (to avoid extra markup). Modify the initial rotation values to bring the circles closer together.
.loader {
width: 100px;
height: 100px;
animation: rotate 6s linear infinite;
position: relative;
}
.plate {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.plate:nth-child(2) {
transform: rotate(120deg);
}
.plate:nth-child(3) {
transform: rotate(240deg);
}
.plate:before {
content: '';
position: absolute;
background-color: red;
height: 40px;
width: 40px;
border-radius: 50%;
transform: scale(0);
animation: grow 1.5s linear infinite;
}
.plate:nth-child(2):before {
background: green;
}
.plate:nth-child(3):before {
background: blue;
}
#keyframes rotate {
to {
transform: rotate(360deg);
}
}
#keyframes grow {
50% {
transform: scale(1);
}
}
* {
box-sizing: bordr-box;
margin: 0;
padding: 0;
}
body {
font-family: "Lato", sans-serif;
font-size: 18px;
line-height: 1.6;
background-image: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
min-height: 100vh;
}
<body>
<div class="loader">
<div class="plate"></div>
<div class="plate"></div>
<div class="plate"></div>
</div>
</body>
#isherwood provided a great solution that's easily workable in most modern browsers. But let's say you want more complex motion, like an elliptical orbit.
SVG Animation
You could build the whole thing into an SVG since that supports lots of cool animation while being quite performant. But building SVGs and animating them from scratch is kinda complicated. Luckily, there are tools to help. Here's a few examples: Snapsvg (code library), SVGGator (Web-based animation tool) or Bodymovin (After Effects workflow).
But let's say you want to stick with what can be done in HTML/CSS.
CSS Motion Path
Sadly support is, not great as of Summer 2019 but it will likely be improving. If your audience is using the right browsers (Chrome, Opera, Edge or Chromium based mobile browsers). It's actually pretty easy to use but there are some gotchas. For example, it appears that only the path() property works right now. So you can't use shape keywords like circle() or ellipse() though they're in the spec.
main {
position: relative;
margin: 20px;
}
main,svg {
width: 100px;
height: 100px;
}
path {
stroke-width: 1px;
}
svg {
position:absolute;
opacity: 0.5;
}
#c1 {
stroke: red;
}
#c2 {
stroke: blue;
}
#c3 {
stroke: green;
}
div[class*="c"] {
width: 15px;
height: 15px;
border-radius: 50%;
position: absolute;
box-shadow: 5px 5px 10px 0 rgba(0,0,0,0.3);
}
.c1 {
background-color: red;
offset-path: path('M50,2 C78.2166667,2 98,22.2364005 98,50.5 C98,78.7635995 75.5694444,99 50,99 C24.4305556,99 2,76.5476997 2,50.5 C2,24.4523003 21.7833333,2 50,2 Z');
animation: moveme 5s ease-in-out infinite;
}
.c2 {
background-color: blue;
offset-path: path('M55,13 C80.2774306,13 98,30.9415509 98,56 C98,81.0584491 77.9059606,99 55,99 C32.0940394,99 12,79.0938368 12,56 C12,32.9061632 29.7225694,13 55,13 Z');
animation: moveme 5.25s linear infinite;
}
.c3{
background-color: green;
offset-path: path('M36.0041619,30.5873511 C61.3414991,12.7718541 90.4202796,4.99194919 98.2799065,16.2635432 C106.139533,27.5351371 85.805943,52.9370587 62.845696,69.0811471 C39.885449,85.2252355 7.31148243,93.0730731 1.30061213,84.4528052 C-4.71025818,75.8325372 10.6668246,48.4028481 36.0041619,30.5873511 Z');
animation: moveme 5.5s linear infinite;
}
#keyframes moveme {
100% {
motion-offset: 100%;
offset-distance: 100%;
}
}
<main>
<!-- paths for example -->
<svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="orbit" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<path d="M50,2 C78.2166667,2 98,22.2364005 98,50.5 C98,78.7635995 75.5694444,99 50,99 C24.4305556,99 2,76.5476997 2,50.5 C2,24.4523003 21.7833333,2 50,2 Z" id="c1"></path>
<path d="M55,13 C80.2774306,13 98,30.9415509 98,56 C98,81.0584491 77.9059606,99 55,99 C32.0940394,99 12,79.0938368 12,56 C12,32.9061632 29.7225694,13 55,13 Z" id="c2"></path>
<path d="M36.0041619,30.5873511 C61.3414991,12.7718541 90.4202796,4.99194919 98.2799065,16.2635432 C106.139533,27.5351371 85.805943,52.9370587 62.845696,69.0811471 C39.885449,85.2252355 7.31148243,93.0730731 1.30061213,84.4528052 C-4.71025818,75.8325372 10.6668246,48.4028481 36.0041619,30.5873511 Z" id="c3"></path>
</g>
</svg>
<div class="c1"></div>
<div class="c2"></div>
<div class="c3"></div>
</main>

Transition right after animation

On my element, I have a CSS animation running as long as it has a certain class (wiggle), and a transition as soon as it has a different one (right):
<div class="outer">
<div class="inner wiggle"></div>
</div>
#keyframes wiggle {
from {
left: 10%;
}
50% {
left: 30%;
}
to {
left: 10%;
}
}
.inner {
left: 0;
&.wiggle {
animation: wiggle 2s infinite;
}
&.right {
left: 90%;
transition: left 2s;
}
}
Now, if remove the wiggle class and add right at the same time, the transition doesn't play out; left: 90% applies immediately. However, if there's a delay between removing the former and adding the latter, the transition will happen as expected.
Here's a JSFiddle illustrating the issue.
It looks like when coming from an animation, values (such as left in this case) don't have an explicit value to transition from, so they're just rendered to their final state.
Is this expected behavior, i.e. is it part of a specification? Or are browsers free how to handle that case?
I've tested on the lastest versions of Firefox and Chromium.
Clarification: I'm not mainly looking for workarounds, especially not complicated ones, but more for a reason why exactly browsers behave like they do.
I think this may be a bug in browser rendering or so, but If you want a solution I can give you one alternative method with transform
A working fiddle for you:
$('#toggle').click(() => {
$('.inner').removeClass('wiggle').addClass('right');
});
#keyframes wiggle {
from {
left: 10%;
}
50% {
left: 30%;
}
to {
left: 10%;
}
}
.outer {
height: 5em;
background-color: black;
position: relative;
}
.inner {
height: 100%;
width: 10%;
position: absolute;
transform: translate(0%);
background-color: green;
transition: transform 2s ease-in-out;
}
.inner.wiggle {
animation: wiggle 2s infinite;
}
.inner.right {
transform: translate(900%);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h2>
Animated
</h2>
<div class="outer">
<div class="inner wiggle"></div>
</div>
<h2>
Not animated
</h2>
<div class="outer">
<div class="inner"></div>
</div>
<hr>
<button id="toggle">
move right
</button>
I hope this was helpful for you.
Its look it is the expected behavior. I think when you are adding the right class with left:90%, its not able to pick the starting value for the left css property. As an alternate you can create another keyframe for the .right class
$('#toggle').click(() => {
$('.inner').removeClass('wiggle').addClass('right');
});
#keyframes wiggle {
0% {
left: 10%;
}
50% {
left: 30%;
}
100% {
left: 10%;
}
}
#keyframes right {
100% {
left: 90%;
}
}
.outer {
height: 5em;
background-color: black;
position: relative;
}
.inner {
height: 100%;
width: 10%;
position: absolute;
left: 0;
background-color: green;
transition: left 2s;
}
.wiggle {
animation: wiggle 2s infinite;
}
.right {
animation: right 2s forwards;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h2>
Animated
</h2>
<div class="outer">
<div class="inner wiggle"></div>
</div>
<h2>
Not animated
</h2>
<div class="outer">
<div class="inner"></div>
</div>
<hr>
<button id="toggle">
move right
</button>
This workaround might help you, the idea is to use the css variables, the idea is to set the animation with an alternate function, so in this way we will only need From and To... on the other hand we need to set up and event for every iteration, in that way we know when an iteration ends,
So when we click the button you can change the variable value and remove the class...
$('#toggle').click(() => {
$('.inner').addClass('right');
});
let flag = false;
$(".inner").on("animationiteration webkitAnimationIteration oAnimationIteration MSAnimationIteration", function(){
flag && $(".inner").removeClass('wiggle');
if($(".inner").hasClass('right')) flag = true;
});
:root {
--from: 10%;
--to: 30%;
}
#keyframes wiggle {
from {
left: var(--from);
}
to {
left: var(--to);
}
}
.outer {
height: 5em;
background-color: black;
position: relative;
}
.inner {
height: 100%;
width: 10%;
position: absolute;
transform: translate(0%);
background-color: green;
transition: transform 2s ease-in-out;
left:90%;
}
.inner.wiggle {
left:10%;
animation: wiggle 1s infinite;
animation-direction: alternate;
}
.inner.right {
--to:90%;
animation-direction: normal;
animation-duration:2s;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h2>
Animated
</h2>
<div class="outer">
<div class="inner wiggle"></div>
</div>
<hr>
<button id="toggle">
move right
</button>
Consider that this has a bug when the animation is moving back to the start point...

Making pure css image slider responsive

The following pure css slider is working well, but I need to make it responsive. I've tried replacing the pixel-based sizes with percentages and with vw, but it doesn't line up. I'd be grateful for any ideas.
Here's the html:
<section class="slideshow">
<div class="slideshow-container slide">
<img src="images/anim/home-animation1.jpg" alt="pills">
<img src="images/anim/home-animation2.jpg" alt="scientist">
<img src="images/anim/home-animation3.jpg" alt="chemical structure">
<img src="images/anim/proudmembermassbio.jpg" alt="proud member of MassBio"> </div>
</section>
And the css:
/*general styles*/
html { box-sizing: border-box; }
*, *:before, *:after { box-sizing: inherit; }
/* SLIDESHOW STYLES */
.slideshow-container {
width: 1400px; /* the entire "stage" */
font-size: 0;
transition: 1s ease;
height: 315px;
}
.slideshow-container:hover { animation-play-state: paused; }
.slideshow { /* the visible "stage" */
width: 350px;
margin: 1rem auto -1rem;
overflow: hidden;
border: solid 1px white;
}
img, .text-container {
width: 350px;
height: auto;
display: inline-block;
font-size: 16px;
text-align: center;
}
.text-container { /* for text slides */
height: 195px;
position: relative;
}
.slide { animation: slide 10s ease infinite; }
#keyframes slide {
0% { transform: translateX(0%); }
12.5% { transform: translateX(0%); }
25% { transform: translateX(-25%); }
37.5% { transform: translateX(-25%); }
50% { transform: translateX(-50%); }
62.5% { transform: translateX(-50%); }
75% { transform: translateX(-75%); }
87.5% { transform: translateX(-75%); }
99% { transform: translateX(-75%); }
100% { transform: translateX(0); }
}
.p {
margin-top: 140px;
text-align: center;
}
Maybe this is too late for the user that posted this question, but can be helpful for someone else that want a pure responsive CSS slider.
I have created a working example in this CodePen that is working as requested using percentages for widths and in the animation, and for this reason it is responsive and works really well in each resolutions.
All the main solution to have the responsiveness is here:
slider__container {
display: flex;
position: relative;
animation: 30s slide infinite;
font-size: 0;
width: 1000%; /* because I am using 10 slides */
}
The width should be calculated accordingly to how many slides are there in the slider: slides x 100% (slides times 100%, in my example 1000%).

CSS animation image of leaf (as if blowing in the wind)

This was a personal challenge and I'm reasonably happy with the approach I have come up with below but I'd be keen to see if there are any alternative approaches.
I am working on a site where the logo contains a leaf image.
I thought it might be eye-catching to have the leaf appearing to be "wind-blown" to its final logo position.
I wanted to improve on the first (very basic) version of the CSS #keyframes animation I had written:
#keyframes leafanimation {
0% {transform:translate(900px,500px); color:rgba(255,0,0,0);}
80% {transform:translate(0,0); color:rgba(255,0,0,0);}
100% {transform:translate(0,0); color:rgba(255,0,0,1);}
}
.my-logo {
position:absolute;
top:0;
left:0;
height: 40px;
line-height: 40px;
font-size: 36px;
color: rgb(255,0,0);
animation: leafanimation 6s linear;
}
.my-logo div {
display: inline-block;
width: 20px;
height: 40px;
vertical-align: middle;
background-color: rgb(255,0,0);
border-radius: 20px;
}
<div class="my-logo">
My Logo
<div></div>
</div>
This was the solution I came up with (eventually) using a series of translate and rotate CSS transforms:
#keyframes leafanimation {
0% {transform:translate(900px,500px) rotate(0deg); color:rgba(255,0,0,0);}
20% {transform:translate(850px,450px) rotate(360deg); color:rgba(255,0,0,0);}
40% {transform:translate(450px,200px) rotate(720deg); color:rgba(255,0,0,0);}
60% {transform:translate(100px,100px) rotate(1080deg); color:rgba(255,0,0,0);}
80% {transform:translate(0,0) rotate(1440deg); color:rgba(255,0,0,0);}
100% {transform:translate(0,0) rotate(1440deg); color:rgba(255,0,0,1);}
}
.my-logo {
position:absolute;
top:0;
left:0;
height: 40px;
line-height: 40px;
font-size: 36px;
color: rgb(255,0,0);
animation: leafanimation 6s linear;
}
.my-logo div {
display: inline-block;
width: 20px;
height: 40px;
vertical-align: middle;
background-color: rgb(255,0,0);
border-radius: 20px;
}
<div class="my-logo">
My Logo
<div></div>
</div>

Resources