Prepend a div without the screen blinking - javascript

My question is similar to other questions, but with a twist.
I'm trying to inject a div as follows :
var headerDiv = document.getElementById("headerDiv");
if (headerDiv) {
var logo = document.createElement('div');
logo.id = "my-header";
//logo.style.display = "none";
var innerHTML = ' <div id="my-header-image"></div>' +
' <div id="my-header-text">' +
' My header text' +
' </div> ';
logo.innerHTML = innerHTML;
headerDiv.insertBefore(logo, headerDiv.firstChild);
}
headerDiv already previously exists in the page and renders well.
I'm calling my code only when the DOM is ready.
My problem is as follows : when the injection happens, "logo" blits on the page as an entirely white div for a split second. It's almost not noticeable if you don't look well. Then the style gets applied and everything goes back to normal.
It happens both in IE11 (IE10 mode or Edge mode) AND in Chrome.
It didn't happen when I was using jQuery instead of insertBefore.
Here is the CSS :
#my-header {
pointer-events: none; /* the clicks must go through -- to the native Sharepoint buttons underneath. Required for Edge compatibility. */
display:block;
position: absolute;
text-align: center;
width: 100%;
z-index: 1000;
height: 50px;
overflow: auto;
/* fade-in */
-webkit-animation: fadein 2s; /* Safari, Chrome and Opera > 12.1 */
-moz-animation: fadein 2s; /* Firefox < 16 */
-ms-animation: fadein 2s; /* Internet Explorer */
-o-animation: fadein 2s; /* Opera < 12.1 */
animation: fadein 2s;
}
#my-header-text {
display:inline-block;
padding: 0;
position: relative;
bottom: 15px;
margin-left: 18px;
color: white;
font-size: 1.0em;
}
#my-header-image {
display:inline-block;
content: "";
top: 3px;
left: 20px;
width : 184px; /* same size as logo image */
height : 38px;
margin-top: 6px;
background-image: url("https://MY_URL/logo.png");
background-size: contain;
background-repeat: no-repeat;
background-position: center center;
}
/* fade-in animation definition */
#keyframes fadein {
from { opacity: 0; }
to { opacity: 1; }
}
/* Firefox < 16 */
#-moz-keyframes fadein {
from { opacity: 0; }
to { opacity: 1; }
}
/* Safari, Chrome and Opera > 12.1 */
#-webkit-keyframes fadein {
from { opacity: 0; }
to { opacity: 1; }
}
/* Internet Explorer */
#-ms-keyframes fadein {
from { opacity: 0; }
to { opacity: 1; }
}
/* Opera < 12.1 */
#-o-keyframes fadein {
from { opacity: 0; }
to { opacity: 1; }
}
Could it be caused by the fade-in animation? The system doesn't know how to handle a new element that's supposed to start invisible (because of the animation) ?
I've noticed that "logo" blinks above "headerDiv" instead of on top, despite its absolute positionning. One more clue of some property being ignored in the early stage of rendering, between the time when the div gets added and the time when its style gets applied.

I've solved it wth a dirty workaround :
In the JS :
...
var logo = document.createElement('div');
logo.id = "my-header";
logo.style.height = "0"; // <-- new
...
In the CSS :
#my-header {
...
height: 50px !important; /* <-- made it important */
...
}
As you can understand, the object is forcefully made invisible and forced not to take up any on-screen space (by having height = 0) between the time of its creation by the JS and the time when the style gets applied by the CSS.
Therefore, the blinking still conceptually happens but its effect is not visible.

Related

Random animation on Simple Image Slideshow

I want to apply a random animation on my slideshow image. First, I tried adding an animation such as scale but it didn't work as I wanted it to.
Things I want to fix:
Smoothness on fadein
Random animation (can be anything at this point, I just want to see how it's done)
Fiddle: http://jsfiddle.net/jzhang172/e7cLtsg9/1/
$(function() {
$('img').hide();
function anim() {
$("#wrap img").first().appendTo('#wrap').fadeOut(3500).addClass('transition').addClass('scaleme');
$("#wrap img").first().fadeIn(3500).removeClass('scaleme');
setTimeout(anim, 3700);
}
anim();
});
body,
html {
margin: 0;
padding: 0;
background: black;
}
#wrap img {
position: absolute;
top: 0;
display: none;
width: 100%;
height: 100%;
}
.transition {
transition: 10s;
}
.scaleme {
transition: 10s;
transform: scale(1.3);
}
.box {
height: 300px;
width: 500px;
position: relative;
overflow: hidden;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box">
<div id="wrap">
<img src="http://elegantthemes.com/preview/InStyle/wp-content/uploads/2008/11/s-1.jpg" />
<img src="http://elegantthemes.com/preview/InStyle/wp-content/uploads/2008/11/s-5.jpg" />
<img src="http://elegantthemes.com/preview/InStyle/wp-content/uploads/2008/11/s-3.jpg" />
</div>
</div>
Here is a sample using CSS animations and jQuery (for achieving the randomness of animations). If you don't wish to use CSS animations and want to stick to transitions + jQuery effects (like fadeIn), you can still adapt this code to support it because the base idea will still remain the same. I am not too comfortable with jQuery effects and have hence stuck to using CSS animations.
Below is an overview of how it is being done (refer inline comments for more details):
Inside a wrapper there are a group of images that are part of the slide-show (like in your demo).
Using CSS #keyframes, a list of animations (one of which would be used randomly) is created in addition to the default fade-in-out animation. This list is also maintained in an array variable (in JS for picking up a random one from the list).
On load, the default fade-in-out animation and one random animation is added to the 1st element.
An animationend event handler is added to all of the images. This event handler will be triggered when the animation on an element ends. When this is triggered, animation on the current element is removed and the default fade-in-out + a random animation is added to the next element.
The animations are added using inline styles because if we add multiple CSS classes each with one different animation, then the animation in the latest class will override the others (that is, they will not happen together).
A loop effect is achieved by checking if the current element has any other img sibling elements. If there are none, the animation is added back to the 1st element.
$(window).load(function() {
$img = $('img'); // the images
var anim = ['zoom', 'shrink', 'move-down-up', 'move-right-left']; // the list of random animations
var rand = Math.floor(Math.random() * 4) + 1; // random number
$img.each(function() { // attach event handler for each image
$(this).on('animationend', function(e) { // when animation on one image has ended
if (e.originalEvent.animationName == 'fade-in-out') { // check the animation's name
rand = Math.floor(Math.random() * 4) + 1; // get a random number
$(this).css('animation-name', 'none'); // remove animation on current element
if ($(this).next('img').length > 0) // if there is a next sibling
$(this).next('img').css('animation-name', 'fade-in-out, ' + anim[rand - 1]); // add animation on next sibling
else
$img.eq(0).css('animation-name', 'fade-in-out, ' + anim[rand - 1]); // else add animation on first image (loop)
}
});
});
$img.eq(0).css('animation-name', 'fade-in-out, ' + anim[rand - 1]); //add animation to 1st element on load
})
#wrapper {
height: 250px;
width: 300px;
position: relative;
}
img {
position: absolute;
z-index: 1;
bottom: 20px;
left: 10px;
opacity: 0;
transform-origin: left top; /* to be on the safe side */
animation-duration: 3s; /* increase only if you want duration to be longer */
animation-fill-mode: backwards; /* fill mode - better to not change */
animation-iteration-count: 1; /* no. of iterations - don't change */
animation-timing-function: ease; /* better to leave as-is but can be changed */
}
#keyframes fade-in-out {
0%, 100% {
opacity: 0;
}
33.33%, 66.66% { /* duration is 3s, so fade-in at 1s, stay till 2s, fade-out from 2s */
opacity: 1;
}
}
#keyframes zoom {
0%, 100% {
transform: scale(1);
}
50% {
transform: scale(1.5);
}
}
#keyframes shrink {
0%, 100% {
transform: scale(1);
}
50% {
transform: scale(.5);
}
}
#keyframes move-down-up {
0%, 100% {
transform: translateY(0px);
}
50% {
transform: translateY(50px);
}
}
#keyframes move-right-left {
0%, 100% {
transform: translateX(0px);
}
50% {
transform: translateX(50px);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="wrapper">
<img src="https://placehold.it/200/000000/ffffff" />
<img src="https://placehold.it/200/ff0000/ffffff" />
<img src="https://placehold.it/200/00ff00/ffffff" />
<img src="https://placehold.it/200/0000ff/ffffff" />
</div>

Scroll to top unoticably or crop top overflow

This question is a little hard to explain: I have an image at the bottom of a page. On click of that image I load the next page via ajax without removing that image. How can I crop out or remove all the space above the image? Or, maybe a better way to put it is how do I scroll to top unnoticeably?
Here is perfect example of what I'm trying to accomplish - go to the bottom of the page and see what happens when you click the image. What is the concept behind that?
I can tell you specifically what that website is doing.
They have each page in a container called <div class="page-container">. When you click the bottom link, a new <div class="page-container"> is added with a css top property that pushes it off the bottom of the screen and both page containers are set to position:absolute.
The top css properties of both page containers are animated with a Javascript timer until the first <div class="page-container"> is pushed off the top of the screen, then the first page container is removed from the DOM.
At the same time the page containers are moving via manipulated top property, the scrollbar position is animated so it moves along with the containers. After the animation is done and the new page container is set to position:relative, the scrollbar is at the top of the screen again.
Here is a rough example using jQuery for convenience https://jsfiddle.net/0bzt9mmq/
You can also do something like this.
https://jsfiddle.net/vh60oycj/2/
HTML
<div id="container"></div>
CSS
body{
width:100%;
height:100%;
}
#container{
width:100vw;
height:100vh;
}
.img_elems{
width: 640px;
height: 480px;
padding: 5px;
}
.pages{
width: 640px;
height: 480px;
margin: 5px;
background: #000;
color:#fff;
}
.label{
width: 20px;
height: 20px;
background-color: #fff;
padding: 5px;
}
.move{
position: relative;
-webkit-animation-name: slide; /* Chrome, Safari, Opera */
-webkit-animation-duration: 1s; /* Chrome, Safari, Opera */
animation-name: slide;
animation-duration: 1s;
-webkit-animation-fill-mode: forwards; /* Chrome, Safari, Opera */
animation-fill-mode: forwards;
}
#-webkit-keyframes slide {
0% { top: 100%}
100% { top: 0;}
}
#keyframes slide {
0% { top: 100%}
100% { top: 0;}
}
.fade{
position: relative;
-webkit-animation-name: fade; /* Chrome, Safari, Opera */
-webkit-animation-duration: 2s; /* Chrome, Safari, Opera */
animation-name: fade;
animation-duration: 2s;
}
#-webkit-keyframes fade {
0% { opacity : 0;}
100% { opacity : 1;}
}
JS
var get_some_images = "https://placehold.it/640x480";
var get_container = document.getElementById("container");
init(11);
//function that create the it
function create_img_elem(content,index){
var new_elem = document.createElement("div");
var label = document.createElement("div");
new_elem.className = "img_elems";
new_elem.id = "img_elem"+index;
new_elem.style.background = "url('"+ content +"') no-repeat center";
new_elem.setAttribute("data-elem-num", index);
label.className = "label";
label.id = "label" + index;
label.innerHTML = "#" + index;
new_elem.appendChild(label)
get_container.appendChild(new_elem);
}
//function that create the elem
function create_page(content,index){
var new_elem = document.createElement("div");
var label = document.createElement("div");
new_elem.className = "pages";
new_elem.id = "page" + index;
new_elem.innerHTML = content;
new_elem.setAttribute("data-elem-num", index);
get_container.appendChild(new_elem);
$( "#page" + index).addClass("fade");
}
function click_event (clicked_img){
//getting all the elements on container
var array_elems = $('#container').children();
//getting data attributes "data-elem-num" of clicked_element
var clicked_elem = clicked_img[0].attributes[2].value;
//store "data-elem-num" attr
var elem_ids;
for(var j = 0, len_elems = array_elems.length; j <len_elems;j++){
elem_ids = array_elems[j].attributes[2].value;
//store "data-elem-num" attr
if(elem_ids !== clicked_elem){
//instead of fadeout from jquery, you can do css animation. better animation that way
$( "#img_elem" + elem_ids).fadeOut("fast");
}else{
create_page("this is about element " + clicked_elem, clicked_elem);
$("#img_elem" + clicked_elem).addClass('move fade').css("pointer-events", "none");
}
}
}
function init(amount_of_elements){
for(var i=0, len = amount_of_elements; i < len; i++){
create_img_elem(get_some_images,i)
}
$(".img_elems").click(function(){
click_event ($(this));
});
}
I'm accessing the DOM Object that's been click and looping through to see if any of match my clicked items. if not hide them, afterwords fadein the element and any
additional elements. I know you already have solution, this more resources I guess.

Object #<HTMLDivElement> has no method 'remove'

I am creating a Cordova hybrid app. I use the Facebookconnectplugin and show up a tutorial on first start. This works for every Supported Plattform and Version (Android / iOS) but not for Android 4.1
Here the code breaks with "Object # has no method 'remove'". It Breaks all the time at the line when I try to remove the fadeMe div. As said works everywhere else (Android 4.3+ / iOS 7+)
facebookConnectPlugin.login(["public_profile", "email", "user_friends"],
function (response) {
//check if this is startup then remove overlay
if(document.getElementById("fadeMe")){
document.getElementById("fadeMe").remove();//document.body.removeChild(div);
describeTableView();
}
}
);
CSS:
#fadeMe{
background-color: rgba(0,0,0,.75);
width: 100%;
height: 100%;
z-index: 11;
top: 0;
left: 0;
position: fixed;
color: #ffffff;
padding-left: 20px;
padding-top: 20px;
font-size: 0.9em;
font-weight: 300;
webkit-animation: fadein 2s; /* Safari, Chrome and Opera > 12.1 */
-moz-animation: fadein 2s; /* Firefox < 16 */
-ms-animation: fadein 2s; /* Internet Explorer */
-o-animation: fadein 2s; /* Opera < 12.1 */
animation: fadein 2s;
}
And it is created like this:
var div = document.createElement("div");
div.setAttribute('class', 'fadeMe');
div.setAttribute('id', 'fadeMe');
document.body.appendChild(div);
Found a similar question but without answer: Similar Question
Using Polyfill does the trick:
if (!('remove' in Element.prototype)) {
Element.prototype.remove = function() {
this.parentNode.removeChild(this);
};
}

Animate marginLeft to element's -width

I have element with long inline text and want to make animation that will move this text from off-screen right (whole text behind right border of window) to the left off-screen.
My idea is to move element by setting margin-left to minus(width) of element:
var element = $(this);
$("p").animate({
'marginLeft': - element;
}, 4000);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>element with long long long long inline text....</p>
But this does not work. Any ideas?
In that context, as far as I can tell, $(this) is the window. You want to animate the $("p") itself, and you need to specify you're animating based on it's width, not the general DOM element. There also was a rogue ; in your object that you were sending to the animate function (you can see errors like this in your Developer Tools Console).
var $element = $("p");
$element.animate({
'marginLeft': -($element.outerWidth())
}, 4000);
body {
margin: 0;
font-family: sans-serif;
font-size: 12px;
overflow-x: hidden; /* no horizontal scrollbar */
}
p {
white-space: nowrap;
background: #ccc;
display: inline-block;
margin-left: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>element with long long long long inline text....</p>
EDIT
Or, here it is with pure CSS. This is the more effective route to take, if the browsers you're developing for support it. It causes the browser to "repaint" less, and runs on the GPU instead of CPU like JS does.
body {
margin: 0;
font-family: sans-serif;
font-size: 12px;
overflow-x: hidden; /* no horizontal scrollbar */
}
#-webkit-keyframes offscreenLeft {
0% { transform: translateX(0); }
100% { transform: translateX(-100%); }
}
#-moz-keyframes offscreenLeft {
0% { transform: translateX(0); }
100% { transform: translateX(-100%); }
}
#-o-keyframes offscreenLeft {
0% { transform: translateX(0); }
100% { transform: translateX(-100%); }
}
#keyframes offscreenLeft {
0% { transform: translateX(0); }
100% { transform: translateX(-100%); }
}
p {
white-space: nowrap;
background: #ccc;
display: inline-block;
padding-left: 100%; /* translate uses the inner width of the p tag, so the thing pushing it offscreen needs to be *inside* the p, not outside (like margin is) */
-webkit-animation: offscreenLeft 4s forwards; /* Safari 4+ */
-moz-animation: offscreenLeft 4s forwards; /* Fx 5+ */
-o-animation: offscreenLeft 4s forwards; /* Opera 12+ */
animation: offscreenLeft 4s forwards; /* IE 10+, Fx 29+ */
}
<p>element with long long long long inline text....</p>
If I were you, I would toggle a class on the element and using CSS's transform: translateX() combined with transition to move the element off screen.
codepen
css
p {
transform: translateX(0);
transition: transform 0.3s ease;
}
p.off-screen-right {
transform: translateX(100%)
}
js
$(document).ready(function () {
$('button').click(function () {
$('p').toggleClass('off-screen-right')
})
})
Steps
Get the <p> width and save it in a variable.
Then, sets the initial margin-left to the $(window).width()
After that, you can call the animate function to set the margin-left to the negative value of the width you've saved in the variable initially
Working code
$(function() {
var width = $("p").width();
$("p")
.css('margin-left', $(window).width())
.animate({ 'margin-left': -width }, 4000);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>element with long long long long inline text....</p>

webkit animation play state: how to start/stop animation on demand with javascript

I'm working on a game and just found out about -webkit-animation-play-state CSS attribute. I want certain text to show itself as a short animation, then hide and show when called again (in javascript).
I figured out how to start animation when I want to in javascript, but after its finished, the text stays on the screen, which I don't want to.
HTML:
<p id="INFO">
TEST
</p>
CSS:
#-webkit-keyframes pulse {
from {
opacity: 0.0;
font-size: 100%;
}
to {
opacity: 1.0;
font-size: 400%;
}
}
#INFO {
position: absolute;
left: 400px;
top: 200px;
-webkit-animation-name: pulse;
-webkit-animation-duration: 1s;
-webkit-animation-iteration-count: 1;
-webkit-animation-timing-function: ease-in-out;
-webkit-animation-play-state:paused;
visibility: hidden;
}
JS:
var INFO = document.getElementById("INFO");
INFO.innerHTML = "WRONG";
INFO.style.color = "RED";
INFO.style.webkitAnimationPlayState = "running";
INFO.style.visibility = "visible";
I read some questions/answers about -webkit-animation-play-state on this site, but none regarding the issue I am having.
One thing I read about was that animation goes to its default values when its ended. But my default values say that animation is "hidden" ? source: how to stop my webkit frame animation?
If anyone can point me in the right direction I'd be grateful.
If I was not clear enough, ask for more info please.
Thank you
For what you are trying to do, you don't need to use -webkit-animation-play-state.
Instead, try starting the animation by applying a class with the animation properties set. Then use a JavaScript event listener to remove the class once the animation finishes.
You should also keep the element hidden with opacity instead of visibility:hidden since you are manipulating the opacity in the animation.
CSS:
#-webkit-keyframes pulse {
from {
opacity: 0.0;
font-size: 100%;
}
to {
opacity: 1.0;
font-size: 400%;
}
}
#INFO {
opacity:0;
position: absolute;
left: 400px;
top: 200px;
}
.pulse {
-webkit-animation-name: pulse;
-webkit-animation-duration: 1s;
-webkit-animation-iteration-count: 1;
-webkit-animation-timing-function: ease-in-out;
}
JS:
var INFO = document.getElementById("INFO");
INFO.innerHTML = "WRONG";
INFO.style.color = "RED";
INFO.addEventListener('webkitAnimationEnd', function (e) {
this.classList.remove('pulse');
});
DEMO >> CodePen

Categories

Resources