Fading in iframe using JavaScript - javascript

I am trying to fade in my iframe smoothly with JavaScript. I have seen links online and most of the answers were related to jQuery. Why must I use jQuery for a simple fading? Can anyone explain?
Also I do not mind using JQuery, after all its a part of javascript. I am just looking for a simple solution. Since I am using the below fadeIn() function, does jQuery perform better than the below function?
<iframe id="iframe" style="
position: fixed;
opacity: 0;
height: 100%;
width: 100%;
overflow: hidden;
z-index: 10;
display: none;
">
</iframe>
<script>
//Creation of button before this code
button_01.onPointerUpObservable.add(function () {
let iframe = document.getElementById("iframe");
iframe.src = "LINK";
fadeIn(iframe, 2000);
iframe.style.display = 'Block';
});
function fadeIn(el, duration) {
/*
* #param el - The element to be faded out.
* #param duration - Animation duration in milliseconds.
*/
var step = 10 / duration;
var opacity = 0;
function next() {
if (opacity >= 1) { return; }
el.style.opacity = (opacity += step);
setTimeout(next, 10);
}
next();
}
</script>

Some people suggest jQuery because there's a function called x.fadeIn(300) which causes it to animate pretty nicely, you don't actually need this and it can be accomplished by adding a class or using vanilla animations and removing it later
Both:
Option 1: Class
.shown {
opacity: 1;
}
iframe {
transition: .3s opacity;
}
iframe.classList.add('shown');
Option 2: JS only
iframe.style.transition = '.3s';
iframe.style.opacity = '1';
// remove it after it's done
setTimeout(() => {
iframe.style.transition = '';
}, 300);

Related

Display some element user scrolling

I would like to display some element (div for example) when the user scrolling.
I seeing that a scrollTop, but isn't work. Because for sure I use badly.
I can't find some help without JQuery. I don't want to use JQuery.
I try this :
var scroll = document.body.scrollTop;
var divLis = document.querySelectorAll("div");
for(let i = 0; i < divLis.length; i++) {
if(scroll === divLis[i]) {
divLis[i].style.transform = "translateX(0)";
divLis[i].style.transition = "2s";
}
}
I honestly can't really tell what you're trying to do, but given your response to #uom-pgregorio's answer, I'm guessing you might just want a pure JS scroll listener:
window.addEventListener('scroll', function() {});
Edit: Sorry I just noticed that you didn't want jQuery but I'll just leave this here in case you change your mind.
$(window).scroll(function() {
// show the div(s)
});
That's an event handler where the function runs or fires up whenever the window or viewport scrolls.
Ok... I understand.
I wanted to try this :
* {
margin: 0;
padding: 0;
border: 0;
}
body {
height: 200vh;
}
.left {
width: 300px;
height: 300px;
background-color: red;
position: absolute;
top: 150%;
transform: translateX(-300px);
transition: 5s;
}
// HTML :
<div class="left"></div>
// JS
var divLis = document.querySelector(".left");
window.addEventListener("scroll", function (e) {
if(window.pageYOffset > 500) {
console.log(window.pageYOffset)
divLis.style.transform = "translateX(0)";
}
})
So, it's very simple and I took my head for nothing.
So thanks so much for answering me !
Enjoy your Weekend

Image animate down javascript (no jQuery)

I know how to fix the animation that goes down only when the image is showing up in the window with jQuery, but now I want to do that with JavaScript. Struggling with that. The image must be fluently go down (+50px for 1.6 seconds). Have googling around, but most of them are done with jQuery I suggest and that is not what I want. Furtermore the animation should start when the scrollTop is between 600px and 800px.
function scrollFunction() {
var animate = document.getElementById("picture");
var position = 0;
var top = 0;
var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
if(scrollTop > 600 && scrollTop < 800){
position++;
animate.style.top = position + "50px";
} else {
stop();
}
}
function stop() {
clearTimeout(animate);
}
#picture {
width: 100%;
height: auto;
top: -5px;
position: relative;
display: block;
margin-left: auto;
margin-right: auto;
margin-bottom: 20px;
}
<div class="col-sm-12 col-xs-12">
<h1 class="responsive-h1">Mi<span class="logo-orange"> Pad2</span></h1>
<p class="edition-title above-text-black">Black Edition</p>
<img src="Img/picture.jpg" id="picture"/>
</div>
jsFiddle : https://jsfiddle.net/n1q3fy8w/
Javascript
var imgSlide = document.getElementById('slidedown-image');
var slideDown = setInterval(function() {
var topVal = parseInt(window.getComputedStyle(imgSlide).top, 10);
imgSlide.style.top = (topVal + 1) + "px";
}, 15);
setTimeout(function( ) { clearInterval( slideDown ); }, 1600);
You get the element first, after that you setup a setInterval which will basically move our img downwards, we then also set a setTimeout which after 1600ms remvoes the slideDown interval and the image stops. Your image however may need position: absolute.
The above answer will only work in Chrome, this however should work in all browswers
jsFiddle : https://jsfiddle.net/n1q3fy8w/1/
javascript
var imgSlide = document.getElementById('slidedown-image');
var slideDown = setInterval(function() {
var topVal = parseInt(imgSlide.style.top, 10);
imgSlide.style.top = (topVal + 1) + "px";
}, 15);
setTimeout(function( ) { clearInterval( slideDown ); }, 1600);
Ok so getComputedStyle only works in chrome, so to get this to work on all other browsers, you have to specifically set the css property on the element and not via CSS.
When you use javascript to access an element and change its style like so element.style.bottom = '150px' the .style gets you all of the css values for your inline styles on that element, so any css changes on an element that is done via a .css/.less file you can't access via javascript.
So all the above code does is we set a top: 0 on the element itself and in our code we use imageSlide.style.top instead of chrome's window.getComputedStyle
Have you considered using a CSS transition? if you are changing the value of top you should be able to add transition: top 1.6s in your css (to picture). (Then the vendor prefixed versions when you get it working)

Raw Javascript for JQuery's fade In for background

I need to disable background in order to show a small popup window with a video once a user clicks on an image.
I could do it with JQuery but can't seem to understand it in Javascript.
Here what I've done in JQuery:
style snippet:
.overlay {
z-index: 4;
position:absolute;
display:none;
background-color: rgba(0, 0, 0, 0.7);
top: 0;
left: 0;
bottom: 0;
right: 0;
}
Jquery snippet:
$(".overlay").fadeToggle();
Html snippet:
<div id="bck" class="overlay"></div>
In javascript I have tried many things, like:
var el = document.getElementById("bck");
function fadeIn(el) {
el.style.opacity = 0;
var tick = function() {
el.style.opacity = +el.style.opacity + 0.01;
if (+el.style.opacity < 1) {
(window.requestAnimationFrame && requestAnimationFrame(tick)) || setTimeout(tick, 16)
}
};
tick();
}
fadeIn(el);
but it's not working
help, please!
You should use the Jquery plugin overlay.js. It will make your life much easier.
http://jquerytools.github.io/documentation/overlay/
However, if that is not the route you want to go, I did notice a little problem in your code. You have the timeout set to 16 ms. That is too quick to get a proper fade in. Adjusting it to at least 100 ms would have the fade-in take place in one second.

Trigger CSS transition on appended element

As this question observes, immediate CSS transitions on newly-appended elements are somehow ignored - the end state of the transition is rendered immediately.
For example, given this CSS (prefixes omitted here):
.box {
opacity: 0;
transition: all 2s;
background-color: red;
height: 100px;
width: 100px;
}
.box.in { opacity: 1; }
The opacity of this element will be set immediately to 1:
// Does not animate
var $a = $('<div>')
.addClass('box a')
.appendTo('#wrapper');
$a.addClass('in');
I have seen several ways of triggering the transition to get the expected behaviour:
// Does animate
var $b = $('<div>')
.addClass('box b')
.appendTo('#wrapper');
setTimeout(function() {
$('.b').addClass('in');
},0);
// Does animate
var $c = $('<div>')
.addClass('box c')
.appendTo('#wrapper');
$c[0]. offsetWidth = $c[0].offsetWidth
$c.addClass('in');
// Does animate
var $d = $('<div>')
.addClass('box d')
.appendTo('#wrapper');
$d.focus().addClass('in');
The same methods apply to vanilla JS DOM manipulation - this is not jQuery-specific behaviour.
Edit - I am using Chrome 35.
JSFiddle (includes vanilla JS example).
Why are immediate CSS animations on appended elements ignored?
How and why do these methods work?
Are there other ways of doing it
Which, if any, is the preferred solution?
The cause of not animating the newly added element is batching reflows by browsers.
When element is added, reflow is needed. The same applies to adding the class. However when you do both in single javascript round, browser takes its chance to optimize out the first one. In that case, there is only single (initial and final at the same time) style value, so no transition is going to happen.
The setTimeout trick works, because it delays the class addition to another javascript round, so there are two values present to the rendering engine, that needs to be calculated, as there is point in time, when the first one is presented to the user.
There is another exception of the batching rule. Browser need to calculate the immediate value, if you are trying to access it. One of these values is offsetWidth. When you are accessing it, the reflow is triggered. Another one is done separately during the actual display. Again, we have two different style values, so we can interpolate them in time.
This is really one of very few occasion, when this behaviour is desirable. Most of the time accessing the reflow-causing properties in between DOM modifications can cause serious slowdown.
The preferred solution may vary from person to person, but for me, the access of offsetWidth (or getComputedStyle()) is the best. There are cases, when setTimeout is fired without styles recalculation in between. This is rare case, mostly on loaded sites, but it happens. Then you won't get your animation. By accessing any calculated style, you are forcing the browser to actually calculate it.
Using jQuery try this (An Example Here.):
var $a = $('<div>')
.addClass('box a')
.appendTo('#wrapper');
$a.css('opacity'); // added
$a.addClass('in');
Using Vanilla javaScript try this:
var e = document.createElement('div');
e.className = 'box e';
document.getElementById('wrapper').appendChild(e);
window.getComputedStyle(e).opacity; // added
e.className += ' in';
Brief idea:
The getComputedStyle() flushes all pending style changes and
forces the layout engine to compute the element's current state, hence
.css() works similar way.
About css()from jQuery site:
The .css() method is a convenient way to get a style property from the
first matched element, especially in light of the different ways
browsers access most of those properties (the getComputedStyle()
method in standards-based browsers versus the currentStyle and
runtimeStyle properties in Internet Explorer) and the different terms
browsers use for certain properties.
You may use getComputedStyle()/css() instead of setTimeout. Also you may read this article for some details information and examples.
Please use the below code, use "focus()"
Jquery
var $a = $('<div>')
.addClass('box a')
.appendTo('#wrapper');
$a.focus(); // focus Added
$a.addClass('in');
Javascript
var e = document.createElement('div');
e.className = 'box e';
document.getElementById('wrapper').appendChild(e).focus(); // focus Added
e.className += ' in';
I prefer requestAnimationFrame + setTimeout (see this post).
const child = document.createElement("div");
child.style.backgroundColor = "blue";
child.style.width = "100px";
child.style.height = "100px";
child.style.transition = "1s";
parent.appendChild(child);
requestAnimationFrame(() =>
setTimeout(() => {
child.style.width = "200px";
})
);
Try it here.
#Frizi's solution works, but at times I've found that getComputedStyle has not worked when I change certain properties on an element. If that doesn't work, you can try getBoundingClientRect() as follows, which I've found to be bulletproof:
Let's assume we have an element el, on which we want to transition opacity, but el is display:none; opacity: 0:
el.style.display = 'block';
el.style.transition = 'opacity .5s linear';
// reflow
el.getBoundingClientRect();
// it transitions!
el.style.opacity = 1;
Anything fundamentally wrong with using keyframes for "animate on create"?
(if you strictly don't want those animations on the initial nodes, add another class .initial inhibitin animation)
function addNode() {
var node = document.createElement("div");
var textnode = document.createTextNode("Hello");
node.appendChild(textnode);
document.getElementById("here").appendChild(node);
}
setTimeout( addNode, 500);
setTimeout( addNode, 1000);
body, html { background: #444; display: flex; min-height: 100vh; align-items: center; justify-content: center; }
button { font-size: 4em; border-radius: 20px; margin-left: 60px;}
div {
width: 200px; height: 100px; border: 12px solid white; border-radius: 20px; margin: 10px;
background: gray;
animation: bouncy .5s linear forwards;
}
/* suppres for initial elements */
div.initial {
animation: none;
}
#keyframes bouncy {
0% { transform: scale(.1); opacity: 0 }
80% { transform: scale(1.15); opacity: 1 }
90% { transform: scale(.9); }
100% { transform: scale(1); }
}
<section id="here">
<div class="target initial"></div>
</section>
Rather than trying to force an immediate repaint or style calculation, I tried using requestAnimationFrame() to allow the browser to paint on its next available frame.
In Chrome + Firefox, the browser optimizes rendering too much so this still doesn't help (works in Safari).
I settled on manually forcing a delay with setTimeout() then using requestAnimationFrame() to responsibly let the browser paint. If the append hasn't painted before the timeout ends the animation might be ignored, but it seems to work reliably.
setTimeout(function () {
requestAnimationFrame(function () {
// trigger the animation
});
}, 20);
I chose 20ms because it's larger than 1 frame at 60fps (16.7ms) and some browsers won't register timeouts <5ms.
Fingers crossed that should force the animation start into the next frame and then start it responsibly when the browser is ready to paint again.
setTimeout() works only due to race conditions, requestAnimationFrame() should be used instead. But the offsetWidth trick works the best out of all options.
Here is an example situation. We have a series of boxes that each need to be animated downward in sequence. To get everything to work we need to get an animation frame twice per element, here I put once before the animation and once after, but it also seems to work if you just put them one after another.
Using requestAnimationFrame twice works:
Works regardless of how exactly the 2 getFrame()s and single set-class-name step are ordered.
const delay = (d) => new Promise(resolve => setTimeout(resolve, d));
const getFrame = () => new Promise(resolve => window.requestAnimationFrame(resolve));
async function run() {
for (let i = 0; i < 100; i++) {
const box = document.createElement('div');
document.body.appendChild(box);
// BEFORE
await getFrame();
//await delay(1);
box.className = 'move';
// AFTER
await getFrame();
//await delay(1);
}
}
run();
div {
display: inline-block;
background-color: red;
width: 20px;
height: 20px;
transition: transform 1s;
}
.move {
transform: translate(0px, 100px);
}
Using setTimeout twice fails:
Since this is race condition-based, exact results will vary a lot depending on your browser and computer. Increasing the setTimeout delay helps the animation win the race more often, but guarantees nothing.
With Firefox on my Surfacebook 1, and with a delay of 2ms / el, I see about 50% of the boxes failing. With a delay of 20ms / el I see about 10% of the boxes failing.
const delay = (d) => new Promise(resolve => setTimeout(resolve, d));
const getFrame = () => new Promise(resolve => window.requestAnimationFrame(resolve));
async function run() {
for (let i = 0; i < 100; i++) {
const box = document.createElement('div');
document.body.appendChild(box);
// BEFORE
//await getFrame();
await delay(1);
box.className = 'move';
// AFTER
//await getFrame();
await delay(1);
}
}
run();
div {
display: inline-block;
background-color: red;
width: 20px;
height: 20px;
transition: transform 1s;
}
.move {
transform: translate(0px, 100px);
}
Using requestAnimationFrame once and setTimeout usually works:
This is Brendan's solution (setTimeout first) or pomber's solution (requestAnimationFrame first).
# works:
getFrame()
delay(0)
ANIMATE
# works:
delay(0)
getFrame()
ANIMATE
# works:
delay(0)
ANIMATE
getFrame()
# fails:
getFrame()
ANIMATE
delay(0)
The once case where it doesn't work (for me) is when getting a frame, then animating, then delaying. I do not have an explanation why.
const delay = (d) => new Promise(resolve => setTimeout(resolve, d));
const getFrame = () => new Promise(resolve => window.requestAnimationFrame(resolve));
async function run() {
for (let i = 0; i < 100; i++) {
const box = document.createElement('div');
document.body.appendChild(box);
// BEFORE
await getFrame();
await delay(1);
box.className = 'move';
// AFTER
//await getFrame();
//await delay(1);
}
}
run();
div {
display: inline-block;
background-color: red;
width: 20px;
height: 20px;
transition: transform 1s;
}
.move {
transform: translate(0px, 100px);
}
Edit: the technique used in the original answer, below the horizontal rule, does not work 100% of the time, as noted in the comments by mindplay.dk.
Currently, if using requestAnimationFrame(), pomber's approach is probably the best, as can be seen in the article linked to in pomber's answer. The article has been updated since pomber answered, and it now mentions requestPostAnimationFrame(), available behind the Chrome flag --enable-experimental-web-platform-features now.
When requestPostAnimationFrame() reaches a stable state in all major browsers, this will presumably work reliably:
const div = document.createElement("div");
document.body.appendChild(div);
requestPostAnimationFrame(() => div.className = "fade");
div {
height: 100px;
width: 100px;
background-color: red;
}
.fade {
opacity: 0;
transition: opacity 2s;
}
For the time being, however, there is a polyfill called AfterFrame, which is also referenced in the aforementioned article. Example:
const div = document.createElement("div");
document.body.appendChild(div);
window.afterFrame(() => div.className = "fade");
div {
height: 100px;
width: 100px;
background-color: red;
}
.fade {
opacity: 0;
transition: opacity 2s;
}
<script src="https://unpkg.com/afterframe/dist/afterframe.umd.js"></script>
Original answer:
Unlike Brendan, I found that requestAnimationFrame() worked in Chrome 63, Firefox 57, IE11 and Edge.
var div = document.createElement("div");
document.body.appendChild(div);
requestAnimationFrame(function () {
div.className = "fade";
});
div {
height: 100px;
width: 100px;
background-color: red;
}
.fade {
opacity: 0;
transition: opacity 2s;
}

Changing Opacity of Div With javascript timer

Hey guys the solution to this should be simple, but im having difficulty figuring out what's going on.
I have a timerScript.js file that looks like this
//global variables
var timerInterval = null; // the timer that changes opacity every 0.1 seconds.
function StartTimer()
{
//disable the button
document.getElementById('startOpacityTimerButton').disabled=true;
timerInterval = window.setInterval(ChangeOpacity(), 100);
}
function StopTimer()
{
window.clearInterval(timerInterval);
timerInterval = 0;
}
function ChangeOpacity()
{
var object = document.getElementById('opacityZone');
var currentOpacity = (+object.style.opacity);
var newOpacity = currentOpacity + 0.1;
object.style.opacity = newOpacity;
if(newOpacity == 1.0)
{StopTimer();}
}
This is what my code is supposed to do
Click button -> Calls StartTimer
StartTimer -> Disables button, calls ChangeOpacity every 100 milliseconds.
ChangeOpacity -> gets the div element(opacityZone), gets its current opacity,
increments by 0.1 and checks if it is at max opacity in which case it calls StopTimer.
StopTimer -> clears the timer.
This is what it does:
Timer starts, changes opacity to 0.1, and just seems to stop!?!
I tried debugging with safari Web Inspector, but im not too sure what's going on, maybe one of you JavaScript experts can help me out (im a noob at js). Thanks!
Your problem is here:
window.setInterval(ChangeOpacity(), 100);
Instead of passing a reference to the function, you're now executing it inline and scheduling its return value. Change it to:
window.setInterval(ChangeOpacity, 100);
Apart from that, you should really use CSS transitions for stuff like this.
Thanks guys, i'll take a look at the suggestions. Was just trying to do it with JavaScript for the purpose of learning the language, here are the JavaScript functions i came up with to solve the problem.
//global variables
var opacityIncreasing; //boolean to know if opacity is increasing or decreasing.
var animationInterval;//time in millseconds to do animation.
var timerInterval;//the timer that changes opacity depending on interval.
var object;//object we are doing the animation on.
var currentOpacity;//currentOpacity of object.
//var buttonMessage;//message to make object appear or dissapear depending on animation.
function init(elementName,rateOfAnimation)
{
var object = document.getElementById(elementName);
animationInterval = rateOfAnimation;
currentOpacity = Truncate((+object.style.opacity),1);
document.getElementById('messageContainer').innerHTML=currentOpacity;
if (currentOpacity==0)
{
opacityIncreasing = true;
}
else
{
opacityIncreasing = false;
}
StartTimer();
}
function StartTimer()
{
//disable the button
document.getElementById('startOpacityTimerButton').disabled=true;
timerInterval = window.setInterval(ChangeOpacity, animationInterval);
}
function StopTimer()
{
window.clearInterval(timerInterval);
timerInterval = 0;
//enable Button
document.getElementById('startOpacityTimerButton').disabled=false;
}
function Truncate (number, digits)
{
var multiplier = Math.pow(10, digits),
adjustedNum = number * multiplier,
truncatedNum = Math[adjustedNum < 0 ? 'ceil' : 'floor'](adjustedNum);
return truncatedNum / multiplier;
}
function ChangeOpacity()
{
var object = document.getElementById('opacityZone');
var stringOpValue = "";
if(opacityIncreasing)
{
currentOpacity += 1/10;
stringOpValue = String(currentOpacity.toFixed(1));
object.setAttribute("style","opacity:"+currentOpacity+"; -moz-opacity:"+currentOpacity+";");// filter:alpha(opacity="++")");
document.getElementById('messageContainer').innerHTML= stringOpValue;
if(currentOpacity.toFixed(1) == 1.0)
{
document.getElementById('startOpacityTimerButton').value = "Disappear";
StopTimer();
}
}
else
{
currentOpacity -= 1/10;
stringOpValue = String(currentOpacity.toFixed(1));
object.setAttribute("style","opacity:"+currentOpacity+"; -moz-opacity:"+currentOpacity+";");// filter:alpha(opacity="++")");
document.getElementById('messageContainer').innerHTML= stringOpValue;
if(currentOpacity.toFixed(1) == 0.0)
{
document.getElementById('startOpacityTimerButton').value = "Appear";
StopTimer();
}
}
}
This is the HTML and CSS
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<meta charset="utf-8">
<title>Opacity Test</title>
<style>
body
{
text-align: center;
}
#opacityZone
{
width: 350px;
height: 25px;
background-color: #F50;
text-align: center;
margin:0 auto;
margin-top: 10px;
margin-bottom: 10px;
padding-top: 5px;
/*opacity number between 0.0 and 1.0*/
opacity: 0.0;
}
#messageContainer
{
width: 100px;
min-height: 100px;
background-color:red;
color: white;
font-weight: bolder;
font-size: 72px;
text-align: center;
margin:0 auto;
padding-top: 10px;
}
.roundedContainer
{
-webkit-border-radius: 15px;
-moz-border-radius: 15px;
border-radius: 15px,15px,15px,15px;
}
</style>
</head>
<body>
<h2>Opacity Test</h2>
<form>
<input type="button" id="startOpacityTimerButton" value="Appear" onclick="init('opacityZone',50);" />
</form>
<div id="opacityZone">Do you see me?</div>
<p id="messageContainer" class="roundedContainer"></p>
</body>
</html>
pass a function reference to window.setInterval. so pass ChangeOpacity and not ChangeOpacity()
timerInterval = window.setInterval(ChangeOpacity, 100);
Have you considered using CSS3 transition effects instead of making it using JavaScript? Performance wise it should be much better:
For example:
-webkit-transition: opacity 1s ease-in-out;
-moz-transition: opacity 1s ease-in-out;
-o-transition: opacity 1s ease-in-out;
transition: opacity 1s ease-in-out;
What everyone else above has been saying I completely agree with.
Just use CSS3 Animations to change the opacity of the button.
Simply use something along these lines:
#keyframes opacityChange{
from {opacity: 0.1}
to {opacity: 1}
}
You can also declare the timeframe in which the change would take place.
And add a class via javascript/jquery to your button.
(class = "opacityChange")
And when clicking on a new button be sure to remove that class, so that it can be reimplemented to the button later on.
However, to fix your particular problem.
(If for some reason you can't use css3)
Simply add this to the Change Opacity function:
if(newOpacity == 1.0){
StopTimer();
}else{
ChangeOpacity();
}
Looking at how you have it set up, that should work, unless i'm looking over something.
I had same problem and after so many time searching this is my solution:
instead of this line
var currentOpacity = (+object.style.opacity);
var newOpacity = currentOpacity + 0.1;
you have to use this line:
let newOpacity = String(parseInt(window.getComputedStyle(Object).getPropertyValue('opacity'))+0.2))
for alternative answer you can do this (if you have a white background :) ):
let i =0 ;
let interval = setInterval(()=>{
i+=0.1
Object.style.color = `rgba(0,0,0,${i})`;
},1000)
if(Object.style.color === 'rgba(0,0,0,1)')
clearInterval(interval)
console.log()

Categories

Resources