Ajax image page transition - javascript

I just saw a really cool page transition on Behance where you click a image and it just expands to a new div (I think) with a with of 50%. Can someone explain to me how to make this work or have an example? Transition here:
https://vimeo.com/162486588

You can use css transitions if you like. Check the example that I wrote for you.
.normal {
float: left;
margin-right: 10px;
width: 10%;
height: auto;
transition: width 2s, height 2s;
}
.transition {
width: 50%;
height: auto;
}
Basically they work by defining 'start' values (in our case width & height inside .normal) and also a definition of how to make the transition and what properties to apply it to (in our case width and height with 2s duration each).
If you now add a class to the element that has the properties with different values (in our case .transition), they'll be animated to the new value.
To complete the example, I also added some text that is faded in after the transition has been completed.
The javascript part is fairly simple: When clicking the image, add the .transition class, then wait for 2 seconds (the transition duration) and finally fade in the text.
$('img').click(function() {
$(this).addClass('transition');
setTimeout(function() {
$('.text').fadeIn();
}, 2000);
});

Related

Why doesn't a css transition fire immediately after display change

TL;DR A css transition on opacity does not work immediately after display change, but works with setTimeout(.., 100). Why?
What do I want?
I want to flash a message for a couple of seconds and then fade it out. Seems pretty basic, right?
What do I have?
Well, here's a jsfiddle, but let me explain in detail.
Say I have a message block
<div id="message" class="message">
Here be dragons
</div>
Which starts hidden but opaque
.message {
opacity: 1;
display: none;
}
Once I've prepared my message I want to show it.
document.getElementById("message").style.display = "block"
Now I want the message to fade out so I added a simple transition on opacity.
.flash {
opacity: 0;
transition: opacity 2s ease-out 1s;
}
Which I apply with the following
document.getElementById("message").classList.add("flash")
What goes wrong?
The message div is shown but it stays invisible as the opacity: 0 immediately applies. Besides, the transitionend event is not firing, which makes me think the transition does not happen at all for some reason. Weird, right?
However, everything's fine once I add the timeout
document.getElementById("message").style.display = "block"
setTimeout(() => (document.getElementById("message").classList.add("flash")), 100)
That works but seems like a totally dirty hack. Why is it like this?
You can see this behaviour on jsfiddle with two buttons aptly named 'Working' and 'Not working';
There are two things that together cause this:
When items have display: none the opacity is ignored (as not relevant). And so when you apply display: block to them they render the provided opacity with the current value without any transition effect.
Changes you apply to the style attribute all apply together at the moment a paint (asynchronous) happens, and so the transition definition comes too late.
First, make sure to set the transition effect definition before the actual application of it, in the message CSS class.
I would then suggest using height instead of display to get the same effect. You would need to switch the border on and off also (through its width):
document.getElementById("working").addEventListener("click" , () => {
document.getElementById("message").classList.add("flash");
})
// reset
document.getElementById("message").addEventListener("transitionend" , () => {
document.getElementById("message").classList.remove("flash")
})
.message {
border: solid 0px;
background: grey;
opacity: 1;
transition: opacity 2s ease-out 1s;
overflow: hidden;
height: 0;
}
.flash {
height: 100%;
opacity: 0;
border-width: 1px
}
<div id="message" class="message">
Here be dragons
</div>
<button id="working"> Working </button>
Why it doesn't work is because you are applying display:block and opactiy: 0 at the same time. When you set the attribute display in css it ignores all transition, there has to be an event in between setting display and transitions. An alternative is using visibility:hidden and visibility:visible instead of display but note that this only hides the element and the element is still present in its position

Transition elements below a transitioned v-if

I have two elements, and the top one's visibility is controlled by a v-if on a simple boolean.
transition(name="fade")
#element1(v-if="showFirst")
p Foo
#element2
p Bar
The first element is wrapped in a <transition> tag, exactly as per the Vue documentation.
However, while this does create a fading animation, the rest of the content on the page still jumps very jarringly.
How can I create a transition that will also smoothly transform the position of any and all siblings that follow?
A fiddle demoing this issue.
You need to use a transition-group and key your dynamic div and static div
<transition-group name="fade">
<div v-if="switc" key="dynamic" class="animated">
...
</div>
<div key="main-content" class="animated">
...
</div>
</transition-group>
And use this css classes
.fade-enter,
.fade-leave-active {
opacity: 0;
transform: translateY(-10px);
}
.fade-leave-active {
position: absolute;
}
.animated {
transition: all 0.5s;
/*display: flex;*/
width: 100%;
}
The real trick is to change position to absolute when leaving, then any other content can take correct position.
To know more about how Vue animate things please see this FLIP explanation post
And please see this working fiddle
https://jsfiddle.net/bjfhth7c/4/
Edit
By mistake I did set display: flex; in .animated class, that was causing to every inner element to render in a strange way.
So now, I completely remove .animate class, and instead apply transition: all 0.5s and width:100% to every direct inner element of .wrapper
My final scss looks like this:
.wrapper {
display: flex;
flex-direction: column;
>* {
transition: all 0.5s;
width:100%;
};
}
.fade-enter,
.fade-leave-active {
opacity: 0;
transform: translateY(-10px);
}
.fade-leave-active {
position: absolute;
}
Flex layout is a extend subject, but in short for this particular case flex-direction: column is arranging elements one bellows previous one.
If one of those elements has absolute position will be ignored in flex layout so any other elements will be redistributed on available space.
Please see this guide about flexbox and last working fiddle hope it helps.
You can use a slideDown/slideUp animation instead. For achieve this you don't need to know a height of a sliding element, the principles of max-height transition explained there.
So, as a result it will cause animated moving of elements below target.
Check out my example based on your fiddle.
vue js provides different transition classes, you have to use those properly to smooth the transition, I have tried with your example in this fiddle with some CSS, have a look.
.fade-enter-active, .fade-leave-active {
transition: all .5s;
height: 100px;
opacity: 0.5;
}
.fade-enter, .fade-leave-to /* .fade-leave-active in <2.1.8 */ {
height: 0px;
opacity: 0;
}
Some details from documentation:
There are six classes applied for enter/leave transitions.
v-enter: Starting state for enter. Added before element is inserted, removed one frame after element is inserted.
v-enter-active: Active state for enter. Applied during the entire entering phase. Added before element is inserted, removed when transition/animation finishes. This class can be used to define the duration, delay and easing curve for the entering transition.
v-enter-to: Only available in versions >=2.1.8. Ending state for enter. Added one frame after element is inserted (at the same time v-enter is removed), removed when transition/animation finishes.
v-leave: Starting state for leave. Added immediately when a leaving transition is triggered, removed after one frame.
v-leave-active: Active state for leave. Applied during the entire leaving phase. Added immediately when leave transition is triggered, removed when the transition/animation finishes. This class can be used to define the duration, delay and easing curve for the leaving transition.
v-leave-to: Only available in versions >=2.1.8. Ending state for leave. Added one frame after a leaving transition is triggered (at the same time 7. v-leave is removed), removed when the transition/animation finishes.
You can as well use CSS animations where you can provide on different phases of transition what will be your css property to make your transitions more smooth, like following and demo fiddle:
.fade-enter-active {
animation: bounce-in .5s;
}
.fade-leave-active {
animation: bounce-out .5s;
}
#keyframes bounce-in {
0% {
height: 5px;
}
30% {
height: 30px;
}
50% {
height: 50px;
}
100% {
height: 100px;
}
}
#keyframes bounce-out {
0% {
height: 90px;
}
50% {
height: 50px;
}
100% {
height: 0px;
}
}

jQuery opacity animation not working but any other animation does

I have a really strange problem: I am using jQuery v11 on the latest Chrome on localhost. While I manage to use jQuery.animate() on my website with any elements and features (including opacity), I have one element that I just can't.
I tried to trigger the animation within and outside the $(document).ready() function and they both resulted in the same thing. I tried with fadeTo, fadeIn/fadeOut, animate opacity, all of them the same thing. The animation starts but after a certain percentage it just doesn't continue and jumps right to the end. I also tried it with e.g. padding and it works perfectly.
I am using the callback too but removing or adding it did not affect performance on either cases. Also, I have browsed through dozens or even more questions already, so I feel I did my research.
Thank you for your help!
JavaScript:
$("#nb_copy").stop().animate({ opacity: 0 }, 300, function()
{
$(this).css("background-position", "-16px").stop().animate({ opacity: 1 }, 300);
});
HTML:
<div id='notes_buttons'>
<a id='nb_copy' data-info=''>C</a>
</div>
CSS:
div#notes_buttons
{
width: 18px;
position: absolute;
top: 180px;
right: -24px;
opacity: 0;
filter: alpha(opacity=0);
}
div#notes_buttons a
{
cursor: pointer;
display: block;
width: 18px;
height: 18px;
margin-bottom: 1px;
background: red url("/db/sprite.png") no-repeat;
background-position: 0px 0px;
}
Note: I would like to use this animation in the following situation: I am animating the opacity (see, here it works...) of the parent div, then when the nb_copy button is pressed, it fades out, changes the bg position and fades back.
If I use really long animations (3000) and add a delay, the first animation interrupts after about 40%, then after the 3000 ms are over, it counts the delay and then the new animation. This way I have no problem with the animation. Also, if I do not use the callback, it is working. But the two interrupt each other somehow...
if I only use the .css in the callback, it applies instantly (the background position) but the animation runs smoothly.
I already spent about 1.5 hours on such a small thing... Well, if I reproduce the code above in JSfiddle, it is working: https://jsfiddle.net/g6z4xx16/. I am also using Zeroclipboard with the same button, may it be the problem?
In case I get it out of the Zeroclipboard nest, and put it into a simple click trigger, the same result.
Why to make simple work complicated, just use fadeToggle() instead.
Simply change your code to this :
$("#nb_copy").fadeToggle(function()
{
$(this).css("background-position", "-16px").fadeToggle();
});
Using fadeToggle() is better because animate() is used to make custom animations.
In your code place your <style> tag before the <script> tag.

How to transition a div between two parents?

I have two containers:
<div class="left">
<div id="myDiv">A Div</div>
<div id="myDiv2">A Div</div>
</div>
<div class="right">
<div id="myDiv3">A Div</div>
</div>
The first contains div elements, which are moved with the following jQuery:
$(".left > div").click(function(){
$(this).appendTo('.right');
});
The above, however, provides no animation. I would like to use a CSS transition to animate each div between the two parent elements (From .left to .right).
By the way, this is my CSS:
.left, .right{
position: absolute;
display: block;
box-sizing: border-box;
width: 50%;
height: 100%;
}
.left{background:red;}
.right{background:green; left: 50%;}
.left > div, .right > div{
display: block;
height: 100px;
width: 100px;
margin: 10px;
float: left;
background: #fff;
color: #000;
}
And a Fiddle: http://jsfiddle.net/x270Lndz/
I figure I need to get coordinates and transition between them, outside both .left and .right.
This has already been answered: https://stackoverflow.com/a/974765/2725684
The problem is 2 parts, moving elements in the DOM, and animating that movement, but the suggested is:
Store the position of the div, in its resting state, in the first column.
Append the div to the second column, store that position.
Turn off the visibility of the div.
Create a clone of the div, positioned where the resting state one was at.
Animate this clone across to the position of the appended div.
Turn off the visibility of this clone.
Turn back on the original div that was appended.
The javascript/jquery will execute this so fast you won't see the turning off/on of the divs and it will just appear as if the div they are seeing is the only one that ever existed.
Try adding transition: 0.5s ease-in to the .left div
Ultimately, this is going to be a lot of work, and I don't think I have the time to write every step out in full. But, if you're committed, here goes:
Call getBoundingClientRect() or similar on the first element to get its absolute document position relative to the document / viewport.
Use the same function, and getComputedStyle()s padding to determine the exact pixel at which content would begin in the second div.
Determine the difference between the two coordinates, in order to fake the transition while the elements are still inside their first parent. (Or, move them first, and fake the transition after)
Apply the correct transform: translate style to the elements, so that they'll appear to move into the other container. (This is assuming you have the transition properties set up correctly in CSS)
On the transitionend event, turn off transitions, remove the transform property, and do the actual child move.
Pat yourself on the back and go home early.
So there you have it. There's likely going to be a lot of math involved and small additions/subtractions I'm not able to predict. Hopefully, that outline helps you get started at least. You might also be lucky enough to find an animation library that does all of this for you. (Also note that I assumed the presence of several functions not supported on all browsers, so check to make sure they're okay by your book)
I wrote a jQuery plugin:
$.fn.transitionTo = function(target){
this.each(function(){
$this = $(this);
marginLeft = parseInt($this.css('marginLeft').replace("px", ""));
marginTop = parseInt($this.css('marginTop').replace("px", ""));
offset = $this.offset();
$new = $this.clone().appendTo(target);
offsetNew = $new.css('opacity',0).offset();
$this.css({
position: 'absolute',
left: offset.left - marginLeft,
top: offset.top - marginTop
}).appendTo("body");
setTimeout(function(a,b){
a.css({
left: offsetNew.left - marginLeft,
top: offsetNew.top - marginTop
});
setTimeout(function(a,b){
b.replaceWith(a.removeAttr('style'));
},2000,a,b); //Anim time
},10,$this,$new);
});
};
It is called similarly to .appendTo:
$(".left > div").click(function(){
$(this).transitionTo('.right');
});
...and only requires transition: top 2s ease, left 2s ease; on the div.
Fiddle: http://jsfiddle.net/d9yxrmvo/1/
The only known issue with this plugin is the lack of support for animating the original element's siblings.

How to change height of parent div when using css trasition?

I have a problem with a CSS transition. I need to change the height of the parent div relative to the child divs in the transition.
I am using CSS which has a number of steps which slide from right to left as the user clicks continue (Magento onepage checkout with progress bar).
The problem is that the parent container .opc has a height of 970px but the heights of the additional steps vary so I need to find a way to make the parent DIV .opc change height to accommodate the sizes of the remaining steps.
.opc { position:relative; overflow:hidden; height:970px; padding-top:20px; text-align:center; }
I've tried adding height: auto; or height: 100%; but the remaining pages still don't fill the page and I am not sure how to solve it!
Is there a way to affect the height using jQuery or Javascript, maybe pure CSS?
I'm thinking jQuery to detect which step the user is on the adjust the height of the container to fit the content?
<script>
jQuery(document).ready(function(){
if('#opc-billing'){
jQuery('.opc').height(1200);
}
if('#opc-shipping'){
jQuery('.opc').height(500);
}
})
</script>
Although the above solution doesn't work :(
Any help would be appreciated guys!
Here is a quick demo that might help:
I am simply adding a CSS transition property to the parent as well, and adjusting the height at the same time as the position of the child.
http://jsfiddle.net/qF3u7/
.parent {
background-color: lightyellow;
-webkit-transition: height 2s;
height: 50px;
}
.transit {
position: relative;
top: 0;
width: 50px;
height: 50px;
border: 1px solid red;
-webkit-transition: top 2s;
}
PS: Run this in chrome as I didn't bother with the other browser prefixes for the CSS.
Although it is not a very dynamic function what you have is getting there. Try this:
$(document).ready(function{
var x = $("#opc-billing").height();
var y = $("#opc-shipping").height();
var opc = $(".opc");
if (x === 600){ // - The number values are just examples of course.
opc.height(1200);
}
if (y === 200){
opc.height(400);
} else {opc.height(300);} // - default height, could be left blank if set by CSS(example - else{})
})
DEMO
Keep in mind that when using the height() method results may be unexpected because height() returns the computed value of an element which does not include padding, border or margin and does not take into account something like when a page is zoomed in. Learn more about height() here. To get total height including padding, border and margins use outerHeight().
UPDATE: I added some extra bells and whistles to the JSFiddle. Check it out!

Categories