I'm working on an animation and I'm trying to understand how keyframes fit into it.
I want to show an element for 3 seconds, fade out for 1 second, wait for 3 seconds, fade in for 1 second, be visible for 3 seconds. So a total of 8 seconds (3 + 1 + 3 + 1).
I don't know how to write that as keyframes. I have alternate set in my animation since it's using percentages. Here is what I have so far:
time = 0;
window.addEventListener("load", function() {
setInterval(function() {
var label = document.getElementById("label");
if (time==0) {
label.innerHTML = ++time;
}
else {
label.innerHTML = ++time;
}
if (time>=8) time = 0;
}, 1000);
})
* {
margin: 0;
padding: 0;
font-family:sans-serif;
}
#Icons_A0 {
position: absolute;
box-sizing: border-box;
transform: translateX(-50%) translateY(-50%);
left: 50%;
top: 50%;
border: 1px solid #A1A1A1;
background: #E5E5E5;
width: 234px;
height: 238px;
background-color: rgba(255,255,255,1);
overflow: hidden;
opacity: 1;
}
#Rectangle_175 {
opacity: 1;
fill: rgba(75,134,193,1);
stroke: rgb(84, 75, 193);
stroke-width: 4px;
stroke-linejoin: miter;
stroke-linecap: butt;
stroke-miterlimit: 4;
shape-rendering: auto;
}
.Rectangle_175 {
position: absolute;
overflow: visible;
width: 134.35028076171875px;
height: 134.3502655029297px;
left: 49.825px;
top: 76.825px;
transform: rotate(45deg);
transform-origin: left;
}
#Ellipse_49 {
opacity: 1;
fill: rgba(180,180,180,1);
stroke: rgb(112, 112, 112);
stroke-width: 1px;
stroke-linejoin: miter;
stroke-linecap: butt;
stroke-miterlimit: 4;
shape-rendering: auto;
}
.Ellipse_49 {
position: absolute;
overflow: visible;
width: 56px;
height: 56px;
left: 72px;
top: 51px;
animation: fadein 8s linear 0s infinite alternate;
}
@keyframes fadein {
0% {
opacity: 1;
}
20% {
opacity: 1;
}
30% {
opacity: 0;
}
60% {
opacity: 0;
}
70% {
opacity: 1;
}
100% {
opacity: 1;
}
}
<div id="Icons_A0">
<svg data-name="Rectangle 175" data-type="Rectangle" class="Rectangle_175">
<rect id="Rectangle_175" rx="0" ry="0" x="0" y="0" width="120" height="70">
</rect>
</svg>
<svg class="Ellipse_49">
<ellipse id="Ellipse_49" rx="28" ry="28" cx="28" cy="28">
</ellipse>
</svg>
<span id="label"></span>
</div>
If I understand your question correctly, then this can be achieved via the following key frame set:
@keyframes fadein {
0% {
opacity: 1;
}
37.5% {
/* 3 / 8 */
opacity: 1;
}
50% {
/* (3 + 1) / 8 */
opacity: 0.0;
}
87.5% {
/* (3 + 1 + 3) / 8 */
opacity: 0.0;
}
100% {
opacity: 1;
}
}
The comments show how the percentages for different key frames are calculated based on your requirements. The other key change to make is to remove the alternate behaviour from your animation rule, to ensure the animation cycle repeats in a consistent fashion as required:
/* remove alternate */
animation: fadein 8s linear 0s infinite;
Here's a stripped down copy of your code to isolate the animated circle:
function animationListener(event) {
var type = event.type;
var label = type;
if (type=="animationiteration") {
if (app.interval!=null) {
clearInterval(app.interval);
}
app.time = 0;
app.startTime = new Date().getTime();
app.interval = setInterval(intervalFunction, 1000);
intervalFunction();
label = "iteration";
}
else if (type=="animationstart") {
label = "start";
}
else if (type=="animationend") {
label = "end";
}
app.stateLabel.innerHTML = label;
}
function intervalFunction() {
var time = new Date().getTime();
app.timeLabel.innerHTML = Math.round((time - app.startTime)/1000);
app.keyframeLabel.innerHTML = window.getComputedStyle(app.ellipse).content;
}
function loadHandler() {
app.ellipse = document.getElementById("Ellipse_49").parentNode;
app.stateLabel = document.getElementById("stateLabel");
app.timeLabel = document.getElementById("timeLabel");
app.keyframeLabel = document.getElementById("keyframeLabel");
app.ellipse.addEventListener("animationiteration", animationListener);
app.ellipse.addEventListener("animationend", animationListener);
app.ellipse.addEventListener("animationstart", animationListener);
}
document.addEventListener("DOMContentLoaded", loadHandler);
var app = {};
* {
font-family: sans-serif;
font-size: 11px;
letter-spacing: .6px;
}
#Ellipse_49 {
opacity: 1;
fill: rgba(180, 180, 180, 1);
stroke: rgb(112, 112, 112);
stroke-width: 1px;
stroke-linejoin: miter;
stroke-linecap: butt;
stroke-miterlimit: 4;
shape-rendering: auto;
}
.Ellipse_49 {
position: absolute;
overflow: visible;
width: 56px;
height: 56px;
left: 72px;
top: 51px;
/* remove alternate */
animation: fadein 8s linear 0s infinite;
}
#container {
top: 130px;
left: 10px;
position: relative;
display: block;
align-items: center;
}
label {
width: 80px;
display: inline-block;
}
@keyframes fadein {
0% {
opacity: 1;
content: "show";
}
37.5% {
/* 3 / 8 */
opacity: 1;
content: "fade out";
}
50% {
/* (3 + 1) / 8 */
opacity: 0.0;
content: "wait";
}
87.5% {
/* (3 + 1 + 3) / 8 */
opacity: 0.0;
content: "fade in";
}
100% {
opacity: 1;
content: "show";
}
}
<svg class="Ellipse_49">
<ellipse id="Ellipse_49" rx="28" ry="28" cx="28" cy="28">
</ellipse>
</svg>
<div id="container">
<label>time: </label>
<span id="timeLabel"></span>
<br>
<label>state: </label>
<span id="stateLabel"></span>
<br>
<label>key frame: </label>
<span id="keyframeLabel"></span>
</div>
If your total length is 8s, and you just need to translate that to percentages the math is pretty simple: 100/8=12.5
So, your keyframes would come in at:
1 sec : 12.5 * 1 = 12.5%
4 sec : 12.5 * 4 = 50%
7 sec : 12.5 * 7 = 87.5%
8 sec : 12.5 * 8 = 100%
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With