Reliable way to fade in new element - javascript

In my app, I create a new element every second. They should be faded in as they are created. Here's how I did it:
window.setInterval(() => {
const element = document.createElement('div');
element.classList.add('dot', 'hidden');
document.getElementById('content').appendChild(element);
element.classList.remove('hidden');
}, 1000);
.dot {
display: inline-block;
width: 10px;
height: 10px;
border-radius: 50%;
background-color: rgba(255, 255, 255, .7);
margin: 0 5px 5px 0;
transition: opacity 1s;
}
.hidden {
opacity: 0;
}
I thought this would make the transition work, but it doesn't. I also tried to remove the hidden class after a delay, like this:
setTimeout(() => element.classList.remove('hidden'), 100);
It's interesting, because it works only if the delay is long enough. If I set it to 10 ms, some dots are faded in and other appear instantly.
Is there a better, simple and reliable way to make it work, without guessing the delay of setTimeout()?

You could use CSS animations and avoid using JavaScript if it's a simple fade-in you want. This will only run when the DOM node is painted to the screen. If you need more advanced control over your animations then you can tap into JS.
#keyframes fadein {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.dot {
display: inline-block;
width: 10px;
height: 10px;
border-radius: 50%;
background-color: rgba(255, 255, 255, .7);
margin: 0 5px 5px 0;
animation: 1s linear fadein;
}

Css transition works best when you hide things.
So here is a solution using javascript only.
window.setInterval(() => {
const element = document.createElement('div');
element.classList.add('dot');
document.getElementById('content').appendChild(element);
fade(element,0.1);
}, 1000);
// This will inc opacity by 0.1 each 100ms
function fade(item, i){
i += 0.1;
item.style.opacity = i;
if (i< 1)
setTimeout(()=> fade(item,i), 100);
}
.dot {
display: inline-block;
width: 10px;
height: 10px;
border-radius: 50%;
background-color: rgba(255, 255, 255, .7);
margin: 0 5px 0px 5px;
}
#content {
background:black;
}
<div id="content"></div>

Your original problem makes sense because you are adding the hidden class and removing it inside the same function in your setTimeout block. Remember that the browser gets a chance to rerender only after your function completes executing. This means in the line where you add your hidden class is not useful at all because it is immediately removed later in the function (before the browser can do a render).
I would recommend inserting your DOM element and resetting it using a setTimeout or requestAnimationFrame. Also because the timing of setInterval and setTimeout are not fully dependable, it may make sense to use the use the transitionend event of one element to trigger the addition of the next.
(function() {
const container = document.getElementById('container');
let count = 0;
function addElement() {
const div = document.createElement('div');
div.innerHTML = 'item ' + ++count
container.append(div);
div.classList.add('item')
div.addEventListener('transitionend', addElement)
setTimeout(function() {
div.classList.add('show')
}, 0)
}
addElement()
})()
div {}
div.item {
opacity: 0;
transition: opacity 1s;
}
div.item.show {
opacity: 1;
}
<hr>
<div id="container">
</div>

Related

How to put an element in hover state when scrolled down using javascript

I am trying to make a div element which when scrolled down will change properties drastically. Here is the codepen example of how I want it to work.
Instead of hover I want it so that when scrolled down, the page wide div will turn into that little circle div which when clicked will function as a back to the top button. It doesn't matter if more classes are added or anything of that sort. I am very new to js and I tried a few things and also googled about it, I got the scroll code from w3school's how to make a back to top button guide which specifies that when scrolled down by 20px the code would react, but I don't know how to turn the JavaScript to JS when scrolled down along with the transformation of the div.
Thanks in advance
I think you want to implement scroll to top functionality, very common these days in most of the web app.
You need to keep below things and design that feature.
There is one header, that should have a reference ID with hash to scroll back to top
Create a button that will always static position (JS) button, will show up when user scroll the window
Bind click event on the button that scroll back to top
Here is the you can see this implementation and use it.
.html
<h1 class="intro-copy">
Scroll down to use this simple back-to-top button made with modern vanilla javascript.
</h1>
<a class="top-link hide" href="" id="js-top">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 6"><path d="M12 6H0l6-6z"/></svg>
<span class="screen-reader-text">Back to top</span>
</a>
.css
body {
height: 2000px;
position: relative;
}
.intro-copy {
padding: 1em;
margin: 50vh auto;
max-width: 15em;
font-family: Helvetica;
font-weight: lighter;
font-size: 2em;
line-height: 1.2;
text-align: center;
}
.top-link {
transition: all .25s ease-in-out;
position: fixed;
bottom: 0;
right: 0;
display: inline-flex;
cursor: pointer;
align-items: center;
justify-content: center;
margin: 0 3em 3em 0;
border-radius: 50%;
padding: .25em;
width: 80px;
height: 80px;
background-color: #F8F8F8;
&.show {
visibility: visible;
opacity: 1;
}
&.hide {
visibility: hidden;
opacity: 0;
}
svg {
fill: #000;
width: 24px;
height: 12px;
}
&:hover {
background-color: #E8E8E8;
svg {
fill: #000000;
}
}
}
// Text meant only for screen readers.
.screen-reader-text {
position: absolute;
clip-path: inset(50%);
margin: -1px;
border: 0;
padding: 0;
width: 1px;
height: 1px;
overflow: hidden;
word-wrap: normal !important;
clip: rect(1px, 1px, 1px, 1px);
&:focus {
display: block;
top: 5px;
left: 5px;
z-index: 100000; // Above WP toolbar
clip-path: none;
background-color: #eee;
padding: 15px 23px 14px;
width: auto;
height: auto;
text-decoration: none;
line-height: normal;
color: #444;
font-size: 1em;
clip: auto !important;
}
}
JS:
// Set a variable for our button element.
const scrollToTopButton = document.getElementById('js-top');
// Let's set up a function that shows our scroll-to-top button if we scroll beyond the height of the initial window.
const scrollFunc = () => {
// Get the current scroll value
let y = window.scrollY;
// If the scroll value is greater than the window height, let's add a class to the scroll-to-top button to show it!
if (y > 0) {
scrollToTopButton.className = "top-link show";
} else {
scrollToTopButton.className = "top-link hide";
}
};
window.addEventListener("scroll", scrollFunc);
const scrollToTop = () => {
// Let's set a variable for the number of pixels we are from the top of the document.
const c = document.documentElement.scrollTop || document.body.scrollTop;
// If that number is greater than 0, we'll scroll back to 0, or the top of the document.
// We'll also animate that scroll with requestAnimationFrame:
// https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
if (c > 0) {
window.requestAnimationFrame(scrollToTop);
// ScrollTo takes an x and a y coordinate.
// Increase the '10' value to get a smoother/slower scroll!
window.scrollTo(0, c - c / 10);
}
};
// When the button is clicked, run our ScrolltoTop function above!
scrollToTopButton.onclick = function(e) {
e.preventDefault();
scrollToTop();
}

CSS styles not applying immediately when class toggled with jQuery

I am trying to change the style of an element while some javascript is running in the background, to indicate that the page is 'busy' or 'loading'. I've been attempting to do this by toggling a class on at the start of the JS script with jQuery's .toggleClass(), and toggling it off at the end, with some suitable CSS styling attached to the class.
Although the class is toggled immediately, the CSS styling attached to it doesn't apply until after the JS has finished executing, however. So if the class is toggled both on and off, the user does not see any change in style.
I've included a simple example below. How can I force the change in CSS styling to apply immediately, before the rest of the JS code executes?
$(function() {
$('#box').click(function() {
// Toggle class 'red' on.
$(this).toggleClass('red');
// Do something that takes time.
for (i = 0; i < 10000; i++) {
console.log(i);
}
// Toggle class 'red' off.
$(this).toggleClass('red');
});
});
.wrapper {
margin: 15px;
text-align: center;
color: #000;
}
#box {
margin: 15px 0;
width: 100px;
height: 100px;
line-height: 100px;
cursor: pointer;
background: #ccc;
border: solid 3px #ccc;
-webkit-transition: all .3s linear 0s;
transition: all .3s linear 0s;
}
#box.red {
background: #f43059;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="wrapper">
<div id="box">Click me.</div>
</div>
The problem is that your "something that takes time" is synchronous and blocking - while it's operating, browser repainting will be disabled.
One option would be to listen to a transitionend event, to ensure that the animation to red completes before the resource-intensive operation runs.
So that the removal of .red animates properly too, you could set a setTimeout right after the heavy operations finish. Note that your code will a bit be clearer if you use addClass and removeClass instead of toggleClass:
$('#box').click(function() {
$(this).one('transitionend', () => {
// Do something that takes time.
for (i = 0; i < 1000; i++) {
console.log(i);
}
// Toggle class 'red' off.
setTimeout(() => {
$(this).removeClass('red');
});
});
$(this).addClass('red');
});
.wrapper {
margin: 15px;
text-align: center;
color: #000;
}
#box {
margin: 15px 0;
width: 100px;
height: 100px;
line-height: 100px;
cursor: pointer;
background: #ccc;
border: solid 3px #ccc;
-webkit-transition: all .3s linear 0s;
transition: all .3s linear 0s;
}
#box.red {
background: #f43059;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="wrapper">
<div id="box">Click me.</div>
</div>

Firefox ignoring CSS3 transition?

So I've been trying to get a transition working properly in firefox, This is what I have at the moment:
index.html:
<button type="button" id="pushButton">Push Me!</button>
<div id="loginBackground" class="login-background">
<div id="loginBox" class="login-box-inactive">
</div>
</div>
global_style.css:
.login-background {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
background: rgba(0, 0, 0, 0.4);
}
.login-box-inactive, .login-box-active {
display: flex;
flex-flow: column nowrap;
min-width: 150px;
min-height: 150px;
background: #fff;
margin: auto;
box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.4);
}
.login-box-active {
min-width: 350px;
min-height: 350px;
transition: width 2s, height 2s, ease-in-out, 0.5s;
}
finally, login.js:
"use strict";
var pushButton = document.getElementById("pushButton");
var loginBackground = document.getElementById("loginBackground");
var loginBox = document.getElementById("loginBox");
pushButton.onclick = function() {
loginBackground.style.display = "flex";
loginBox.className = "login-box-active";
}
window.onclick = function(event) {
if(event.target == loginBackground) {
loginBackground.style.display = "none";
loginBox.className = "login-box-inactive";
}
}
AFAIK, pretty much every modern browser to date has standardised the transition tag so why is it that firefox is ignoring the transition tag entirely?
Thanks!
EDIT:
So I now have the following within my CSS file:
transition-property: all;
transition-duration: 1s;
transition-timing-function: ease-in-out;
Chrome plays well and displays this as should. Firefox still continues to ignore them. I even prefixed -moz- on them and it still ignored them.
EDIT 2:
I would like the following to happen once the button is pressed:
1) User presses Press Me! button.
2) loginBackground then overlays any content below (imagine the button is not the only content on page), rendering none of it clickable.
3) User will then have a choice of filling form out within loginBox or clicking a closeButton or loginBackground, both of which have the following outcome:
3.1) Upon user clicking either closeButton or loginBackground the loginBox and loginBackground disappears, leaving content underneath usable.
The problem is both of these browsers handle the display property kind of differently. The execution of your transition depends on the display property of the loginBackground which is "display:none" initially. The box that is changing the dimension is a child of this division. Now, the interesting thing that is happening is:
Firefox is removing the child of the parent which has display:none set
Here's what firefox's mdn doc on display says:
In addition to the many different display box types, the value none lets you turn off the display of an element; when you use none, all descendant elements also have their display turned off. The document is rendered as though the element doesn't exist in the document tree.
That's why when you are toggling display value on firefox the transition's don't occur since it's kind of removed and reinserted; essentially making it have no previous value to start of the transition from.
If you apply the "login-box-active" class with a slight delay, everything starts working as expected
"use strict";
var pushButton = document.getElementById("pushButton");
var loginBackground = document.getElementById("loginBackground");
var loginBox = document.getElementById("loginBox");
pushButton.onclick = function() {
loginBackground.style.display = "flex";
setTimeout(function() {
loginBox.className = "login-box-active";
}, 400)
}
window.onclick = function(event) {
if(event.target == loginBackground) {
loginBackground.style.display = "none";
loginBox.className = "login-box-inactive";
}
}
.login-background {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
background: rgba(0, 0, 0, 0.4);
}
.login-box-inactive, .login-box-active {
display: flex;
flex-flow: column nowrap;
min-width: 150px;
min-height: 150px;
background: #fff;
margin: auto;
box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.4);
}
.login-box-active {
min-width: 350px;
min-height: 350px;
transition: width 2s, height 2s, ease-in-out 0.5s;
}
<button type="button" id="pushButton">Push Me!</button>
<div id="loginBackground" class="login-background">
<div id="loginBox" class="login-box-inactive">
</div>
</div>
In the curious case of Chrome, it kind of does not remove the child of "display:none". That's why the transition works as usual on it.
Although, I would suggest to use simple opacity to achieve such effect instead of playing with display. Something, like this:
"use strict";
var pushButton = document.getElementById("pushButton");
var loginBackground = document.getElementById("loginBackground");
var loginBox = document.getElementById("loginBox");
pushButton.onclick = function() {
loginBackground.style.opacity = "1";
loginBox.className = "login-box-active";
}
window.onclick = function(event) {
if(event.target == loginBackground) {
loginBox.className = "login-box-inactive";
loginBackground.style.opacity = "0";
}
}
.login-background {
opacity: 0;
position: fixed;
display: flex;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -1;
background: rgba(0, 0, 0, 0.4);
transition: opacity 2s;
}
.login-box-inactive, .login-box-active {
display: flex;
flex-flow: column nowrap;
background: #fff;
width: 150px;
height: 150px;
margin: auto;
box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.4);
transition: width 2s, height 2s, ease-in-out 0.5s;
}
.login-box-active {
width: 350px;
height: 350px;
}
<button type="button" id="pushButton">Push Me!</button>
<div id="loginBackground" class="login-background">
<div id="loginBox" class="login-box-inactive">
</div>
</div>
transition: width 2s, height 2s, ease-in-out, 0.5s;
This line seems to be incorrect.
Try to remove last value and move timing function to a separate property.

Queue on click function

I am pretty new to jQuery and I am having a bit of difficulty adapting to it being a Java nerd.
I am trying to make these 3 boxes so that when you click one of them, it comes forward and the two in the back dim and stay there, in the back. The problem is that, I want to make it so when you click more than 1 box consecutively, the second box clicked doesn't come forward until the animation ends, much like a queue of box clicks. Right now it's all mixed up and the dimming is fine but the boxes come forward as soon as I click them and not when they should.
I tried callbacks and deferred to no avail.
Here is the code:
Javascript:
var zindex = 1;
$('.box_listener').click(function() {
$(this).css('z-index', zindex += 1);
$(this).siblings('.box_listener').fadeTo(3000, 0.5);
$(this).fadeTo(1, 1);
});
Here is the JSFiddle:
https://jsfiddle.net/asger/5yvvgoda/14/
var zindex = 1;
$('.box_listener').click(function() {
$(this).css('z-index', zindex += 1);
$(this).siblings('.box_listener').fadeTo(3000, 0.5);
$(this).fadeTo(1, 1);
});
#backgroundbox {
position: absolute;
width: 400px;
height: 200px;
background-color: #E5E8E8;
z-index: -5;
border-style: solid;
border-width: 1px;
}
.box_listener {
position: absolute;
width: 120px;
height: 120px;
background-color: white;
border-style: solid;
border-width: 1px;
}
#redbox {
left: 270px;
top: 20px;
border-color: red;
z-index: 0;
}
#bluebox {
left: 230px;
top: 60px;
border-color: blue;
z-index: 0;
}
#greenbox {
left: 210px;
top: 77px;
border-color: lightgreen;
z-index: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="backgroundbox">
<div class="box_listener" id="redbox">
</div>
<div class="box_listener" id="bluebox">
</div>
<div class="box_listener" id="greenbox">
</div>
</div>
Cheers and thanks!
A more bulletproof approach is to not use jQuery animations at all and instead use CSS transitions. The reason for this is twofold; CSS transitions can be automatically reversed and they can be GPU accelerated. It also means you don't have to artificially wait for the transition to complete before allowing user input.
To accomplish this, just set up two CSS classes; One that tells the elements you're going to animate how they should transition. The other class changes the values on the element, which causes the transition to happen. Then all jQuery needs to do is addClass() and removeClass() in order to cause the transitions to occur.
Below is an example of it in action. I've highlighted the most important aspects with comments.
$('.btn').on('click', function() {
// remove the active class from all buttons,
// this will reverse the transition
$('.btn').removeClass('active');
// apply it to only the current button clicked,
//this will start the transition
$(this).addClass('active');
});
.btn {
display: block;
width: 200px;
padding: 10px 20px;
margin-bottom: 5px;
background: cornflowerblue;
border: 0;
cursor: pointer;
/* set up a transition on any css transformations like
translating, scaling, rotating, etc. */
transition: transform 300ms ease-in-out;
}
/* when this class is added to the button it will scale it, but the
transition already on the button will make sure it happens slowly */
.active {
transform: scale(1.2);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h2>Click the buttons</h2>
<button class="btn">First</button>
<button class="btn">Second</button>
<button class="btn">Third</button>

Change opacity of div background picture

I have a DIV with some text and a background image. I want to reduce the opacity of the background image. But when I apply opacity to the DIV it affects the texts within the DIV. How do I change the opacity of the background image without changing the opacity of the texts in the DIV?
I have this code I got from another question on stackoverflow, which I use to reduce opacity of another div but i dont know how to modify it to achieve the above question.
function convertHex(hex,opacity){
hex = hex.replace('#','');
r = parseInt(hex.substring(0,2), 16);
g = parseInt(hex.substring(2,4), 16);
b = parseInt(hex.substring(4,6), 16);
result = 'rgba('+r+','+g+','+b+','+opacity/100+')';
return result;
}
$(".add_to_cart_button").click(function() {
$(".cart-contents").css("background-color",convertHex('#f47d32',40));
});
First step is add z-index: -1; and position: relative; to your back div css:
Ways to change opacity background:
$("#backDiv").css("opacity", "0.4");
$("#backDiv").css({ opacity: 0.4 });
$("#backDiv").fadeTo("slow", 0.4);
$("#backDiv").fadeTo(1000, 0.4); // fist parameter is animate time in ms
Test button with possibility do some action after the animation:
$("#buttonTest").click(function() {
$("#backDiv").fadeTo("slow" , 0.4, function() {
// Animation complete. You can add some action.
});
});
I hope it helps...
Good Luck!
I think below is something you are looking for:
#d1 {
background: url("http://666a658c624a3c03a6b2-25cda059d975d2f318c03e90bcf17c40.r92.cf1.rackcdn.com/unsplash_527bf56961712_1.JPG");
height: 200px;
width: 500px;
position: relative;
}
.overlay {
position: absolute;
top: 0;
left: 0;
background-color: rgba(255, 255, 255, 0.7);
height: 100%;
width: 100%;
display: block;
}
#d2 {
color: red;
position: relative;
}
<div id="d1">
<div class="overlay"> </div>
<div id="d2">
Test content
</div>
</div>

Categories

Resources