Reputation: 8279
I have a number of questions:
<div id='q1'>question...</div>
<div id='q2'>question...</div>
<div id='q3'>question...</div>
etc...
Only one question div should be visible at any time.
I want each question to fade out and the new question fade in exactly where the previous question was.
I am using this CSS for the fade transitions:
.fade-out {
opacity: 0;
animation-name: fadeOutOpacity;
animation-iteration-count: 1;
animation-timing-function: ease-out;
animation-duration: 1s;
}
.fade-in {
opacity: 1;
animation-name: fadeInOpacity;
animation-iteration-count: 1;
animation-timing-function: ease-in;
animation-duration: 2s;
transition-delay: 4s;
}
@keyframes fadeInOpacity {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes fadeOutOpacity {
0% {
opacity:1;
}
100% {
opacity:0;
}
}
But when the second question has the fade-in
css class applied, it makes the first question jump up before it's faded out.
Ideally, I'd like the first question to fade out and the become display: none;
But I am struggling to get it to work.
Questions
N.B I'd rather a pure CSS solution than a Jquery solution if possible...
Upvotes: 1
Views: 313
Reputation: 1943
Try this sample:
.fade-out {
opacity: 0;
animation-name: fadeOutOpacity;
animation-iteration-count: 1;
animation-timing-function: ease-out;
animation-duration: 2s;
height: 0;
width: 0;
}
.fade-in {
opacity: 1;
animation-name: fadeInOpacity;
animation-iteration-count: 1;
animation-timing-function: ease-in;
animation-duration: 4s;
animation-delay: 0s;
}
@keyframes fadeInOpacity {
0% {
opacity: 0;
}
50% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes fadeOutOpacity {
0% {
opacity: 1;
height: auto;
width: auto;
}
100% {
opacity: 0;
}
}
<div id='q1' class="fade-out">question...1</div>
<div id='q2' class="fade-in">question...2</div>
Upvotes: 0
Reputation:
Like in most pure CSS solutions you might want to utilize input elements. Here I am using radio types with labels inside to reach the next question.
As you are only changing opacity you might want to use a transition instead of an animation. I am using the shorthand here which can be expanded like this:
transition: property-name duration easing delay;
Here is a working example:
/* wrapper to hold absolute positioned children */
.wrapper {
position: relative;
}
/* hide actual radio buttons */
.wrapper input {
display: none
}
.question {
/* float above each other */
position: absolute;
/* transparency by default */
opacity: 0;
/* fade out without delay */
transition: opacity 1s ease-out;
}
input:checked + .question {
/* always put current question first */
z-index: 1;
/* fade in with delay */
opacity: 1;
transition: opacity 2s ease-in 1s;
}
<div class="wrapper">
<input id="question-1" type="radio" name="question" checked>
<div class="question">
<p>Question 1</p>
<label for="question-2">next</label>
</div>
<input id="question-2" type="radio" name="question">
<div class="question">
<p>Question 2</p>
<label for="question-3">next</label>
</div>
<input id="question-3" type="radio" name="question">
<div class="question">
<p>Question 3</p>
<label for="question-1">start over</label>
</div>
</div>
Upvotes: 3
Reputation: 10965
You can do it easily without needing an animation
Instead you only need transition
.
Run this code snippet example:
function doNext() {
let el = document.querySelector('.questions [showing]');
el.removeAttribute('showing');
let temp = el.nextElementSibling;
if (temp === null) {
temp = el.parentElement.firstElementChild;
}
temp.setAttribute('showing', '');
}
const btn = document.querySelector('#next');
btn.addEventListener('click', doNext);
.questions {
height: 60px;
position: relative;
}
.fader {
left: 0;
opacity: 0;
position: absolute;
top: 0;
transition: all 1s ease;
}
.fader[showing] {
opacity: 1;
transition: all 1s ease 0.75s;
}
<div class="questions">
<div id='q1' class="fader" showing>question...1</div>
<div id='q2' class="fader">question...2</div>
<div id='q3' class="fader">question...3</div>
<div id='q4' class="fader">question...4</div>
</div>
<button id="next">Next</button>
When the attribute showing
is removed then the opacity
of the question goes from 1 to 0 over 1 seconds. When the attribute showing
is added then the element waits for 0.75 seconds and then changes opacity
from 0 to 1 over 1 seconds.
The JavaScript I have added simple allows the changing of which element has the attribute showing
. Your code would need to do something similar to change which question is showing.
I set the position of each question to absolute
with top
set to 0
so that all questions show in the same place. BUT doing this requires that you know that maximum size of your questions so the container can be set to the correct height.
Upvotes: 1