I am trying to create my own website, where it has an initial quote in the center:
"Welcome to my website", and when you hover over the menu options, the quote should change.
For example: if I hover over About it could say: "This is my About me Page". (The example is obviously simplified).
HTML Snippet:
About
Contact
Home
<div>
<p>
Welcome to my Website!
</p>
</div>
CSS Snippet:
.fade {
animation: fadein 2s;
}
#keyframes fadein {
from {
opacity:1;
}
50% {
opacity: 0;
}
to {
opacity:1;
}
}
JS Snippet
let myP = document.querySelector('p');
let titleWords = document.querySelector('a.titleAbout');
titleWords.addEventListener('mouseenter', function(){
myP.classList.add("fade");
setTimeout(function(){
myP.innerHTML = "This is my about Me page";
}, 1000);
setTimeout(function(){
text.classList.toggle("fade");
}, 2000);
});
titleWords = document.querySelector('a.titleContact');
titleWords.addEventListener('mouseenter', function(){
myP.classList.add("fade");
setTimeout(function(){
myP.innerHTML = "This is my Contact page";
}, 1000);
setTimeout(function(){
text.classList.toggle("fade");
}, 2000);
});
However - it only does the fade properly the first time I hover over a menu item, the other times it changes the innerHTML, but doesn't fade in and out.
Why exactly is this happening an how can I fix it?
you have not defined the text variable in your javascript. I think you mean myP.classList.toggle("fade");
let myP = document.querySelector('p');
let titleWords = document.querySelector('a.titleAbout');
titleWords.addEventListener('mouseenter', function(){
myP.classList.add("fade");
setTimeout(function(){
myP.innerHTML = "This is my about Me page";
}, 1000);
setTimeout(function(){
myP.classList.toggle("fade");
}, 2000);
});
titleWords = document.querySelector('a.titleContact');
titleWords.addEventListener('mouseenter', function(){
myP.classList.add("fade");
setTimeout(function(){
myP.innerHTML = "This is my Contact page";
}, 1000);
setTimeout(function(){
myP.classList.toggle("fade");
}, 2000);
});
.fade {
animation: fadein 2s;
}
#keyframes fadein {
from {
opacity:1;
}
50% {
opacity: 0;
}
to {
opacity:1;
}
}
About
Contact
Home
<div>
<p>
Welcome to my Website!
</p>
</div>
You can do it shorter and without setTimeout:
let myP = document.querySelector('p');
function show(textToShow){
myP.innerHTML = textToShow;
myP.classList.add("fade");
}
function hide(){
myP.classList.remove("fade");
}
.fade {
animation: fadein 3s;
}
#keyframes fadein {
from {
opacity:1;
}
50% {
opacity: 0;
}
to {
opacity:1;
}
}
About
Contact
Home
<div>
<p>
Welcome to my Website!
</p>
</div>
I have refactored your code to a more generic version, so you can have as many links as you want and do not need to repeat your code. It takes a title attribute from the a tag as text. Maybe this behaves more like you intended, you can play around uncommenting that timeout.
const myPContainer = document.getElementById('pContainer');
const titleWords = document.querySelectorAll('a');
let i;
function attachHandlers(i, elem) {
let timeoutHandle;
const pElem = document.createElement('p');
pElem.innerHTML = elem.getAttribute('title');
myPContainer.appendChild(pElem);
elem.addEventListener('mouseenter', function(){
timeoutHandle = null;
pElem.classList.add("fadein");
});
elem.addEventListener('mouseleave', function(){
// timeoutHandle = setTimeout(() => {
pElem.classList.remove("fadein");
// }, 2000);
});
}
for (i = 0; i < titleWords.length; ++i) {
attachHandlers(i, titleWords[i]);
}
#pContainer {
position: relative;
height: 20px;
}
#pContainer p {
position: absolute;
display: block;
opacity: 0;
}
.fadein {
animation: fadein 2s;
display: block;
}
#keyframes fadein {
from {
opacity: 0;
}
50% {
opacity: 1;
}
to {
opacity: 0;
}
}
About
Contact
Home
<div id="pContainer"></div>
Related
I want to make h1 disappear and after 3 sec appear again. It disappears but dont appear again.
Or do i need inline style for it? And any other useful loop for this except if?
let head1 = document.querySelector(".asd")
let head1style = getComputedStyle(head1);
let head1disp = head1style.display;
let changedisp = function() {
if (head1disp === "block") {
head1.style.display = "none";
} else if (head1disp === "none") {
head1.style.display = "block"
} else {
console.log("Something Wrong!")
}
};
setInterval(changedisp, 3000);
h1 {
display: block;
}
<body>
<h1 class="asd">Look at me!</h1>
<script src="app.js"></script>
</body>
</html>
You don't need JavaScript for that in a modern browser. CSS animations with keyframes are fully capable of delivering the same effect:
<style>
#keyframes fade-out-in {
0% {
opacity: 1;
}
25% {
opacity: 0;
}
75% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.box {
animation: fade-out-in 5000ms;
/* wait time at the beginning */
animation-delay: 2000ms;
}
</style>
<div class="box">
Hello World
</div>
You will probably need to adjust the timing. Learn more about CSS keyframe animations in this fantastic article - https://www.joshwcomeau.com/animation/keyframe-animations/
You can use setTimeout to do it once.
const h1 = document.querySelector('h1');
h1.style.display = 'none';
setTimeout(() => h1.style.display = 'block', 3000);
Or you can use setInterval to do it every 3 seconds.
const h1 = document.querySelector('h1');
function switchDisplay() {
if (h1.style.display === 'block') h1.style.display = 'none';
else h1.style.display = 'block';
}
setInterval(switchDisplay, 3000);
I have a JavaScript function that types out, letter by letter, a message. However, where the current character to be typed is located, I have a blinking css animation. What I need is to stop this animation and make it disappear.
I am using a css with #id::after to put the animation after the text in question. The animation works fine, I need a way to set content: '█'; to content: ''; via JavaScript.
(function type_p(){
let msg = 'This is a message to type out! Spooky!';
let element = document.getElementById('typehere');
typeOut(msg, '', 0, element);
}());
function typeOut(text, letter, index, element){
letter = text.slice(0, ++index);
element.textContent = letter;
if (letter.length == text.length){
stop();
}
setTimeout(typeOut, 100, text, letter, index, element);
}
#typehere {
position: relative;
}
#typehere::after {
content: '█';
position: absolute;
animation: blink 1.5s infinite;
/* animation-iteration-count: 2; */
}
#keyframes blink {
0% {
opacity: 0;
}
50% {
opacity: 1;
}
51% {
opacity: 0;
}
100% {
opacity: 0;
}
}
<p id="typehere">Here</P>
I am aware of CSS animation-iteration-count: however this will stop the animation but it will still be visible (motionless). How do I remove this?
I would just add a class to your element and change the content based on class.
(function type_p(){
let msg = 'This is a message to type out! Spooky!';
let element = document.getElementById('typehere');
typeOut(msg, '', 0, element);
}());
function typeOut(text, letter, index, element){
letter = text.slice(0, ++index);
element.textContent = letter;
if (letter.length == text.length){
element.classList.add('stop');
stop();
}
setTimeout(typeOut, 100, text, letter, index, element);
}
#typehere {
position: relative;
}
#typehere::after {
content: '█';
position: absolute;
animation: blink 1.5s infinite;
/* animation-iteration-count: 2; */
}
#typehere.stop::after {
content: '';
}
#keyframes blink {
0% {
opacity: 0;
}
50% {
opacity: 1;
}
51% {
opacity: 0;
}
100% {
opacity: 0;
}
}
<p id="typehere">Here</P>
This is similar to the other answer, but I find it easier/cleaner than adding multiple classes to something that will no longer be visible.. You can add the animation styling as a class, and then remove that class when you no longer want it to animate.
Change to class in css:
.typehereclass::after {
content: '█';
position: absolute;
animation: blink 1.5s infinite;
}
Add the class to your element in html:
<p id="typehere" class="typehereclass">Here</P>
And then when you want to stop the blinking in JS:
element.classList.remove('typehereclass')
I'm trying to display text from a list of texts declared in the script file which I managed to do but now I'm trying to add the animation class(text-anim) to each text every time the inner HTML is updated.
In the below code it is evident the animation is applied only to the first item of the list when the page is loaded.
I guess the class needs to be removed and then added again but nothing has worked so far.
var quotes = [
" The purpose of our lives is to be happy",
"You only live once, but if you do it right, once is enough.",
"Not how long, but how well you have lived is the main thing.",
"web just isn't the same without you.",
"The unexamined life is not worth living."
];
var index = 0;
var len = quotes.length;
var c = true;
function textincoming(){
var element = document.getElementById("dynamic");
element.classList.add('text-anim')
if(index == len)
{
index = 0;
document.getElementById("dynamic").innerHTML = quotes[index];
index++;
}
else
{
document.getElementById("dynamic").innerHTML = quotes[index];
index++;
}
setTimeout(textincoming, 1000);
}
<html>
<head>
<script src="script.js"> </script>
<style>
#dynamic{
font-size:50px;
}
.text-anim{
animation: textIn .5s ease;
}
#keyframes textIn{
0%{
transform: translateY(100%);
}
100%{
transform: translateY(0%);
}
}
</style>
</head>
<body onload="textincoming()">
<p id="dynamic" class="container"> </p>
</body>
</html>
A better way to do this would be to use animationend event:
var quotes = [
" The purpose of our lives is to be happy",
"You only live once, but if you do it right, once is enough.",
"Not how long, but how well you have lived is the main thing.",
"web just isn't the same without you.",
"The unexamined life is not worth living."
];
var index = 0;
var len = quotes.length;
var element = document.getElementById("dynamic");
element.addEventListener('animationend', () => {
element.classList.remove('text-anim');
});
function textincoming() {
if (index === len) {
index = 0;
}
element.innerHTML = quotes[index];
element.classList.add('text-anim');
index++;
}
setInterval(textincoming, 1500);
#dynamic {
font-size: 50px;
}
.text-anim {
animation: textIn .5s ease;
}
#keyframes textIn {
0% {
transform: translateY(100%);
}
100% {
transform: translateY(0%);
}
}
<body onload="textincoming()">
<p id="dynamic" class="container"> </p>
</body>
You can set another setTimeout to remove the class:
var quotes = [
" The purpose of our lives is to be happy",
"You only live once, but if you do it right, once is enough.",
"Not how long, but how well you have lived is the main thing.",
"web just isn't the same without you.",
"The unexamined life is not worth living."
];
var index = 0;
var len = quotes.length;
var c = true;
function textincoming(){
var element = document.getElementById("dynamic");
element.classList.add('text-anim')
if(index == len)
{
index = 0;
document.getElementById("dynamic").innerHTML = quotes[index];
index++;
}
else
{
document.getElementById("dynamic").innerHTML = quotes[index];
index++;
}
setTimeout(function()
{
element.classList.remove('text-anim');
}, 500);
setTimeout(textincoming, 1000);
}
<html>
<head>
<script src="script.js"> </script>
<style>
#dynamic{
font-size:50px;
}
.text-anim{
animation: textIn .5s ease;
}
#keyframes textIn{
0%{
transform: translateY(100%);
}
100%{
transform: translateY(0%);
}
}
</style>
</head>
<body onload="textincoming()">
<p id="dynamic" class="container"> </p>
</body>
</html>
var myIndex = 0;
var lastIndex = null;
var slides;
window.onload = function ()
{
slides = document.getElementsByClassName("mySlides");
slidePictures();
}
function slidePictures() {
slides[myIndex].style.display = "block";
slides[myIndex].className += " fadeIn";
console.log(slides[myIndex]);
setTimeout(function ()
{
slides[myIndex].className = "mySlides";
console.log(slides[myIndex]);
setTimeout(function ()
{
slides[myIndex].style.display = "none";
console.log("display none");
}, 1000);
}, 2000);
lastIndex = myIndex;
myIndex++;
if (myIndex >= 3)
return;
setTimeout(slidePictures, 4000);
}
.slidesDiv>img {
width: 80%;
height: 80%;
margin-left: 10%;
opacity: 0;
transition: opacity 1s;
}
.fadeIn {
opacity: 1 !important;
transition: opacity 1s;
}
<div class="slidesDiv">
<img class="mySlides" src="//placehold.it/200x80/0fb">
<img class="mySlides" src="//placehold.it/200x80/0bf">
<img class="mySlides" src="//placehold.it/200x80/fb0">
<img class="mySlides" src="//placehold.it/200x80/0fb">
<h1 id="indicator"> Indicator </h1>
</div>
So my issue is that, the image fades in the first time, but then doesn't fade out afterwards, nor does it disappear?
It's definitely problem with the setTimeout functions and I'm wondering what I'm doing/assuming incorrectly.
I edited your code a bit for cleanliness and I also removed the extra transition from .fadeIn as you already had it part of slidesDiv>img.
In your example your program flow is a bit hard to understand, and you are using a lot of variables which are not clear where they come from (like slides and myIndex) so that was part of the reason why it was difficult to figure why it was failing.
Hopefully I understood correctly what you were trying to achieve and the below should work for you. It's definitely not the best in terms of readability and you might be able to extract some of the nested setTimeouts into other functions, but I didn't want to modify too much of your initial code:
var myIndex = 0;
var lastIndex = null;
var slides;
window.onload = function() {
slides = document.querySelectorAll(".mySlides");
slidePictures(slides);
}
function slidePictures(slides) {
var time = 0;
slides.forEach((slide) => {
setTimeout(() => {
slide.style.display = "block";
slide.className += " fadeIn";
setTimeout(function() {
slide.className = "mySlides";
setTimeout(function() {
slide.style.display = "none";
}, 1000);
}, 2000);
}, time);
time += 4000;
});
}
.slidesDiv>img {
width: 80%;
height: 80%;
margin-left: 10%;
opacity: 0;
transition: opacity 1s;
}
.fadeIn {
opacity: 1 !important;
}
Please see this Pen for complete example: http://codepen.io/rarmatei/pen/apramB
var myIndex = 0;
var lastIndex = null;
var slides;
window.onload = function ()
{
slides = document.getElementsByClassName("mySlides");
slidePictures();
}
function slidePictures() {
slides[myIndex].style.display = "block";
slides[myIndex].className += " fadeIn";
console.log(slides[myIndex]);
setTimeout(function ()
{
slides[myIndex].className = "mySlides";
console.log(slides[myIndex]);
setTimeout(function ()
{
slides[myIndex].style.display = "none";
console.log("display none");
// Move indexes here
lastIndex = myIndex;
myIndex++;
}, 1000);
}, 2000);
if (myIndex >= 3)
return;
setTimeout(slidePictures, 4000);
}
.slidesDiv>img {
width: 80%;
height: 80%;
margin-left: 10%;
opacity: 0;
transition: opacity 1s;
}
.fadeIn {
opacity: 1 !important;
transition: opacity 1s;
}
<div class="slidesDiv">
<img class="mySlides" src="//placehold.it/200x80/0fb">
<img class="mySlides" src="//placehold.it/200x80/0bf">
<img class="mySlides" src="//placehold.it/200x80/fb0">
<img class="mySlides" src="//placehold.it/200x80/0fb">
<h1 id="indicator"> Indicator </h1>
</div>
It's pretty hard to tell what you're trying to achieve from your code. I assume that you want the pictures to fade in, and after a certain delay to fade out again?
For that I would highly suggest you to use jQuery. Here's a fiddle I made.
The slidePictures function would now just look like this:
function slidePictures() {
$(".mySlides").each(function(element){
console.log(this);
// 2000 is the duration of the fading in milliseconds
$(this).fadeIn(2000, function(){
// fadeout is delayed 4000 milliseconds
$(this).delay(4000).fadeOut(2000);
});
});
}
If that's not what you need, please provide additional information.
grwag
I want to stay with final properties of css animation, but remove animation property itself, exmeple:
#keyframes('foo')
{
0% { opacity: 0; }
to { opacity: 1; }
}
at the begining :
.my_element
{
opacity: 0;
}
I apply animation by Javascript, so I got :
.my_element
{
opacity: 0;
}
element.style
{
animation: foo 1s forwards; #with opacity: 1; at the end.
}
And now I need clean up :
.my_element
{
opacity: 0;
}
element.style
{
opacity: 1;
}
How can I do that?
This does exactly what you're asking. On animationEnd, the cleanUp function is passed an object containing the class to remove after the animation, the property to replace on the element, and the property value to replace on the element. Check out the DOM before and after clicking button the and you'll see that this works properly.
var el = document.querySelector(".my_element"),
cleanUp = function(data) {
el.classList.remove(data.remove);
el.style[data.prop] = data.val;
},
startAnimation = function() {
el.classList.add("animate");
};
el.addEventListener("animationend", function() {
var cleanup_data = {
remove: "animate",
prop: "opacity",
val: 1
};
cleanUp(cleanup_data);
});
#keyframes foo {
from { opacity: 0; }
to { opacity: 1; }
}
.animate {
animation: foo 3s forwards;
}
.my_element {
opacity: 0;
}
<div class="my_element">some text</div>
<button onclick="startAnimation()">Start Animation</button>