Scroll to top unoticably or crop top overflow - javascript

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.

Related

Prepend a div without the screen blinking

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.

How to add CSS translation to existing translation?

I am placing a DIV element on the screen using CSS translate. This works fine, except that when the same element is displaced later, the original displacement is discarded.
Set the CSS start position with javascript
div.style.transform ="translate(800px, 400px)";
After setting the starting position randomly with javascript, the CSS animation just resets it back.
CSS Animation
#keyframes testanimation {
0% {
transform: translateY(20px);
}
100% {
transform: translateY(80px);
}
}
How can I combine CSS translations, to take previous displacements into account? In this case, the goal is to have the animation start at randomised locations. The 20px - 80px should be relative.
The best way to do this I would guess is to fetch the previous transform, add something to those values and then apply the new transform.
Another suggestion is to set the position of the element using position, left and top. Using the following code for example:
div.style.position = "absolute";
div.style.left = "800px";
div.style.top = "400px";
That way, the transform would then apply to that position instead of relative to your previous transform.
If it is only about transform, then you need to reset each value in the animation, else it will be overwritten by animation rules.
example:
div {/* translate value reduced to fit in snippet window */
border:solid;
height:40px;
width:40px;
transform:translatex(180px) translatey(140px);
animation:2s testanimation forwards;
}
#keyframes testanimation {
0% {
transform:translatex(180px) translatey(150px)
}
100% {
transform:translatex(180px) translatey(180px)
}
}
<div></div>
Your style to apply to start width should be :
div.style.transform ="translatex(800px) translatey(400px)";
and the animation :
#keyframes testanimation {
0% {
transform:translatex(800px) translatey(420px)
}
100% {
transform:translatex(800px) translatey(480px)
}
}
in order to update only the translatey value
translate or position:relative + coordonates have the same effects/results.
You can also combine them
div {/* value reduced to fit window's demo */
border:solid;
height:40px;
width:40px;
position:relative;
transform:translate(80px,40px);
animation:2s testanimation forwards;
}
#keyframes testanimation {
0% {
top : 20px
}
100% {
top:40px
}
}
<div></div>
the other way round works too :
div {
/* value reduced to fit window's demo */
border: solid;
height: 40px;
width: 40px;
position: relative;
left: 80px;
top: 40px;
animation: 2s testanimation forwards;
}
#keyframes testanimation {
0% {
transform: translatey(20px)
}
100% {
transform: translatey(40px)
}
}
<div></div>
An example of my comment above:
#wrapperDiv {
width: 100px;
height: 100px;
background: green;
transform: translate(400px, 200px) rotate(50deg);
}
#yourDiv {
width: 100px;
height: 100px;
background: red;
animation: testanimation 2s infinite;
}
#keyframes testanimation {
0% {
transform: translateY(20px) rotate(0deg);
}
100% {
transform: translateY(80px) rotate(40deg);
}
}
<div id="wrapperDiv">
<div id="yourDiv">
<div>
<div>
The div#yourDiv will get a transform relative to its parent div#wrapperDiv transform.
I think a more general solution would be to parse the css transform property, as this allows you to keep animating an element without having to worry about its state.
This is the solution I use for this case:
parseTransformMatrix = function(str){
const match_float = "[+\\-]?(?:0|[1-9]\\d*)(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?"
const match_sep = "\\s*,?\\s*"
m = str.match(RegExp(`matrix\\((${match_float}(?:${match_sep}${match_float})*)\\)`))
if(!m || !m.length || m.length < 2) return null
return m[1].match(RegExp(match_float, 'g')).map(x => parseFloat(x))
}
// Test parseTransformMatrix method
console.log(parseTransformMatrix("matrix(1, 0, 0, 1, 96.2351, 309.123)"));
getElementTranslate = function(e){
let t = e.css("transform")
let r = { left: 0, top: 0 }
if(!t) return r
mat = parseTransformMatrix(t)
if(!mat || !mat.length || mat.length != 6) return r
r.left = mat[4]
r.top = mat[5]
return r
}
Here, e is a jQuery element, but you could easily use getPropertyValue instead if you don't want to have this dependency.
Using these functions, you can do something like:
let t = getElementTranslate(e)
e.css({transform:`translate(${t.left+20}px,${t.top+80}px)`})

CSS position transition not working at all when set with JavaScript

I want to do the following things:
show a div element;
move it to a an initial position;
set transition properties;
move it to the target position using CSS transition.
A minimal example:
function bla() {
/*
var obj = $('#box');
obj.css("left", "200px");
obj.css("display", "initial");
obj.addClass("trans");
obj.css("left", "500px");
*/
var elem = document.getElementById('box');
elem.style.left = "200px";
elem.style.display = "initial";
elem.className = "box trans";
elem.style.left = "500px";
}
#btn {
position: fixed;
top: 60px;
left: 0px;
width: 50px;
height: 50px;
background-color: #FEDCBA;
}
.box {
display: none;
position: fixed;
top: 0px;
left: 0px;
width: 50px;
height: 50px;
background-color: #ABCDEF;
}
.box.trans {
-webkit-transition: left 2s;
-moz-transition: left 2s;
transition: left 2s;
}
<div id="box" class="box"></div>
<div id="btn" onclick="bla()">click here</div>
JSFiddle.
It does not work at all. What is wrong?
If I set the element initially visible, I get a smooth transition starting from the origin left:0 which is totally strange because I assign elem.style.left = "200px"; before I actually add the transition properties...
You should avoid using style in javascript, just switch class years put all your animation in your css file.
You can't put transition together with display: none;, you have to use opacity: 0; instead.
function bla()
{
var obj = $('#box');
obj.toggleClass("trans");
}
#btn
{
position:fixed;
top:60px;
left:0px;
width:50px;
height:50px;
background-color:#FEDCBA;
}
.box
{
opacity: 0;
position:fixed;
top:0px;
left:0px;
width:50px;
height:50px;
background-color:#ABCDEF;
-webkit-transition: transform 2s,opacity 2s;
transition: transform 2s,opacity 2s;
}
.box.trans
{
opacity: 1;
-ms-transform: translate(500px,0); /* IE 9 */
-webkit-transform: translate(500px,0); /* Safari */
transform: translate(500px,0);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="box" class="box">
</div>
<div id="btn" onclick="bla()">
click here
</div>
DOM changes don't take effect until they can be rendered. Javascript is single-threaded (meaning you cannot run two pieces of code simultaneously), and run on the same thread as the render cycle.
Because of this, the renderer cannot fire unless you give it time to look at the new state of the DOM by deferring execution of your JS code (using setTimeout or requestAnimationFrame). So unless you give the browser time to render, only the final value before the renderer gets to look at the DOM is what matters.
This answer to a previous question goes over the exceptions to the rule.
Here's an updated version of your jsfidde that uses requestAnimationFrame to get around the issue.
I can not explain why. Maybe someone could, I'd be curious too, but with a time-out works.
setTimeout(function(){
elem.style.left = "500px";
},1);
It is probably too fast assigning properties left 500 and the transition to record the old location 200?
https://jsfiddle.net/StepBaro/s82rj48q/2/
It's because you have the div hidden, so it first need to display it and then add the transition, that is why it needs the delay.

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>

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