How can CSS translate elements away from one point? - css

I'm trying to emulate a special effect of Instagram with CSS. In Instagram, clicking on a group of photos will make each photo grow and fly away from their original position.
Currently, I only know how to do the growing part. I don't know how to make them translate starting from their original point.
HTML
<div id="photoSet">
<img src="1.jpg" />
<img src="2.jpg" />
<img src="3.jpg" />
</div>
CSS
#-moz-keyframes fly {
from {
-moz-transform: scale(0.5);
}
to {
-moz-transform: scale(1.0);
}
}
img {
-moz-animation: fly 1s;
}

In this case, you'll want to animate the left and top properties. The unfortunate piece of this is that you'll need to have one class/selector for each item you're planning to transition, along with a separate. You can then set transition: left 0.2s, top 0.2s; for the general selector. Just change the className of each to invoke the transition:
.photo {
transition: left 0.2s, top 0.2s;
position: absolute;
left: 0;
top: 0;
}
.photo.photo1 { left: 0; top: 0; }
.photo.photo2 { left: 50px; top: 0; }
.photo.photo3 { left: 100px; top: 0; }
/* etc */
.photo.photo6 { left: 100px; top: 50px; }
There is a downside to this, which is that some rendering engines don't actually hardware accelerate left/top transitions.

Related

Collapsing a div with Animation: how to improve this code?

I'm trying to make a div that appear and disappear on touch, like the navigation bar of android phones.
Should I use transition for this or is animation ok? In the fiddle example i use the mouse click and the setTimeout to simulate the touches and the auto disappear if you dont touch the screen for some seconds.
.custom-row{
position: fixed;
width: 100%;
height: 50px;
bottom: -100px;
left: 0px;
background-color: yellow;
opacity: 0;
}
.slidein {
animation: slidein 1s ease-in forwards;
}
.slideout {
animation: slideout 1s ease-in forwards;
}
#keyframes slidein {
0% {
}
100% {
bottom: 0px;
opacity: 1;
}
}
#keyframes slideout {
0% {
bottom: 0px;
opacity: 1;
}
100% {
bottom: -100px;
opacity: 0;
}
}
https://jsfiddle.net/1rm64q8z/1/
For this use case, transition seems to be a better solution. With animation, alerting position is a compute-intensive approach. The CSS will also be much more readable and scalable with transitions in this case.
const bar = document.getElementById("bottom-bar");
bar.addEventListener("click", (el) => {
el.target.classList.toggle("slide-out");
setTimeout(() => {
el.target.classList.toggle("slide-out");
el.target.classList.toggle("slide-in");
}, 2000)
})
body {
overflow: hidden;
}
#bottom-bar {
position: absolute;
bottom: 0px;
left: 0px;
width: 100%;
background: yellow;
padding: 16px;
text-align: center;
transform-origin: bottom;
transition: transform 0.4s ease-in-out;
}
.slide-in {
transform: translateY(0%);
}
.slide-out {
transform: translateY(100%);
}
<div id="bottom-bar">
Hello
</div>
The performance of CSS transitions and animations should be almost the same as they are both hardware accelerated so on most modern browsers the behaviour should be the same.
Animations are often used to create a more complex series of movements and they do not lift the rendering process to the GPU and resulting in being slower than transitions.
This article gives a great breakdown of when to use animations vs transitions.

CSS transition to fade in image isn't working

Please can you help troubleshoot the transition in this CSS? My browser can see the code in the inspector but no transition is taking place. I have tried operating the transition on different properties including width and position but nothing works.
#header-image {
position: absolute;
top: 30px;
right: 30px;
background: transparent;
width: 250px;
margin-left: 10px;
opacity: 1;
transition: opacity 2s linear 1s;
}
I know I'm probably being thick so apologies in advance.
In order for the transition to work.. the property value should change. only then it will trigger the transition.
i.e) lets say #header-image initially has opacity: 0; width: 50px;.
but when you hover it you want to increase the opacity and width opacity: 1; width: 250px;
so your css will look like..
#header-image {
position: absolute;
top: 30px;
left: 30px;
background: blue;
width: 100px;
height: 100px;
margin-left: 10px;
animation: fadeIn 2s linear;
}
#keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
<div id="header-image"></div>
Then your transition will work. So basically transition will work only when there is a change in the value. But in your case you are setting the opacity:1 initially by default.
If you want to add this effect on page load then you have to use css animation or javascript. Below I have given an example snippet on how it can be achieved using css animation.
However if you are planning to use many animations then I recommend to use some popular libraries like Animista, Animate.css, wow.js

moving div from outside to inside the div and out again in pure css not using keyframe

content1.className = 'start';
window.getComputedStyle(document.getElementById('content1')).opacity;
content1.style.marginLeft = "0px";
content1.className = 'transition1';
.main {
width: 300px;
height: 250px;
top: 0px;
left: 0px;
overflow: hidden;
position: relative;
background-color: grey;
cursor: pointer;
}
#content1 {
background-color: red;
width: 300px;
height: 250px;
top: 0px;
left: 0px;
margin-left: -300px;
}
.start {
opacity: 0
}
.transition1 {
opacity: 1;
visibility: hidden;
/*margin-left: -300px !important;*/
-webkit-transition: margin-left 1.5s ease 1.5s, margin-left 1.5s ease 1.5s, visibility 1.5s ease 1.5s
}
<div id="main" class="main">
<div id="content1" class="content1 hidden">
</div>
</div>
I want the red div to start from outside and go into the grey div slowly then after a few seconds it would go out slowly again. I tried using transition but it seems to now work.
My guess is timing is wrong?
UPDATE
I have the above now What I lack is the timing to show the red div then go out again to left. I have set a visibility but I think there is a way to just use margins?
If you're wanting to do this without keyframes, then I have two ideas.
First idea is to add the transition css property to the actual #content1 element. Because as you're removing the .transition1 class, you're taking away the transition details.
If that doesn't work, then you might need to break this into 4 different "states".
That is:
Start State: Red div starts unseen
Start-to-End Transition State: .transition1 class gets added
End State: A class is added to ensure that the red div has the same margin from the .transition1 even after the .transition1 class gets taken away.
End-to-State Transition State: Essentially do the opposite of what you did in the .transition1 class.
EDIT:
Maybe ignore the "4 steps" because I likely was overthinking what you were asking.
I'm not 100% sure why you wouldn't want a keyframe, but I've added a few options you can reference depending on your overall use case. Each of these rely on some sort of trigger or event. In my case, a click. But this can be determined by any sort of event.
var main2 = document.getElementById('main2');
var content2 = document.getElementById('content2');
main2.addEventListener('click', function() {
content2.classList.toggle('active');
});
var main4 = document.getElementById('main4');
var content4 = document.getElementById('content4');
main4.addEventListener('click', function() {
content4.classList.add('animate');
setTimeout(function() {
content4.classList.remove('animate');
}, 1500)
});
.main {
width: 300px;
height: 250px;
position: relative;
background-color: grey;
cursor: pointer;
overflow: hidden;
}
#content1 {
position: absolute;
background-color: red;
width: 100%;
height: 100%;
top: 0px;
left: 0px;
transform: translate(-100%, 0);
-webkit-transition: transform 1.5s ease;
}
.main:hover #content1 {
transform: translate(0, 0);
}
/* Toggle Option */
#content2 {
position: absolute;
background-color: red;
width: 100%;
height: 100%;
top: 0px;
left: 0px;
transform: translate(-100%, 0);
-webkit-transition: transform 1.5s ease;
}
#content2.active {
transform: translate(0, 0);
}
/* SetTimeout Option */
#content4 {
position: absolute;
background-color: red;
width: 100%;
height: 100%;
top: 0px;
left: 0px;
transform: translate(-100%, 0);
-webkit-transition: transform 1.5s ease;
}
#content4.animate {
transform: translate(0, 0);
}
<h2>Hover Option</h2>
<p>Animation happens on hover and disappears after hover</p>
<div class="main">
<div id="content1">
</div>
</div>
<h2>Toggle Option</h2>
<p>Animation happens on click and disappears on second click</p>
<div id="main2" class="main">
<div id="content2">
</div>
</div>
<h2>SetTimeout Option</h2>
<p>Animation happens on click and disappears after 1 second</p>
<div id="main4" class="main">
<div id="content4">
</div>
</div>

What can I use to replace translate3d

So, the code transform: translate3d(0,0,0); makes position:fixed; not work. and by removing it, I am now allowed to use position:fixed; again. one problem, my navigation bar was using the transform code to open, what other way can I use to make it do the same?
heres the code with the transform code, keep in mind this have been removed.
.nav-content {
flex: 1;
box-shadow: 0 0 5px rgba(0,0,0,1);
transform: translate3d(0,0,0);
transition: transform .3s;
}
.nav-content.isOpen {
transform: translate3d(220px,0,0);
}
.nav-content.isClosed {
transform: translate3d(0,0,0);
}
Transforms establish a containing block even for fixed elements. There is no workaround. Either don't use transforms or fixed positioning becomes somewhat useless.
In this case, if you are only using translate3d to translate in X direction, you can just use relative positioning with a left offset.
.nav-content {
position: relative;
left: 0;
transition: left .3s;
}
.nav-content.isOpen {
left: 220px;
}
.nav-content {
position: relative;
left: 0;
transition: left .3s;
height: 200vh;
border: 3px solid blue;
}
:checked ~ .nav-content {
left: 220px;
}
.fixed {
position: fixed;
}
<input type="checkbox" id="toggle" />
<label for="toggle">Toggle</label>
<div class="nav-content">
<div class="fixed">I am fixed</div>
</div>

Final position after CSS3 animation doesn't stick when using vh units and resizing browser window

I have an image that is absolutely positioned using vh units. I want to animate this positioning use CSS. When doing so, however, the relative nature of vh units seems to be lost. To illustrate, look at the following two examples. In both of them, drag the bottom of your browser up and down to change its height.
No animation
The positioning adjusts correctly in relation to the screen height.
http://codepen.io/maxedison/pen/jPOQPW
#mountain {
position: absolute;
left: 50%;
top: 55vh;
opacity: 1;
}
img {
width: 180vh;
margin-left: -50%;
}
<div id="screen1">
<div id="mountain">
<img src="http://upload.wikimedia.org/wikipedia/commons/2/20/Red_Slate_Mountain_1.jpg">
</div>
</div>
Animation
The positioning does NOT adjust at all. It's like the vh unites have turned into static px, maintaining the same distance from the top of the window regardless of screen height.
http://codepen.io/maxedison/pen/QbWJbj
#mountain {
position: absolute;
left: 50%;
top: 100vh;
opacity: 0;
-webkit-animation: lincoln_page_load 2s ease forwards;
animation: lincoln_page_load 2s ease forwards;
}
img {
width: 180vh;
margin-left: -50%;
}
#-webkit-keyframes lincoln_page_load {
to {
opacity: 1;
top: 55vh
}
}
#keyframes lincoln_page_load {
to {
opacity: 1;
top: 55vh
}
}
<div id="screen1">
<div id="mountain">
<img src="http://upload.wikimedia.org/wikipedia/commons/2/20/Red_Slate_Mountain_1.jpg">
</div>
</div>
Any ideas on how to correct this? I know I can resort to JavaScript to make this work :)
This is only a problem when the animation is paused with forwards and the animation is still active:
Place the top: 55vh in #mountain so that when the animation ends it has this value and remove the opacity: 0
Remove forwards so that the animation is completed
Add the opacity: 0 and top: 100vh to from in the keyframes so that these values are present when the page loads
This has the added benefit of showing the image if the browser does not support the animation property.
Codepen Example with SASS (Auto-prefixer is turned on)
Using a transform for animation
Here is another example using a transform — translate (info link) — which seems to provide a slightly smoother animation.
Working Example — vanilla CSS
#mountain {
position: absolute;
left: 50%;
top: 55vh;
-webkit-animation: lincoln_page_load 2s ease;
animation: lincoln_page_load 2s ease;
}
img {
width: 180vh;
margin-left: -50%;
}
#-webkit-keyframes lincoln_page_load {
from {
top: 100vh;
opacity: 0;
}
to {
opacity: 1;
top: 55vh
}
}
#keyframes lincoln_page_load {
from {
top: 100vh;
opacity: 0;
}
to {
opacity: 1;
top: 55vh
}
}
<div id="screen1">
<div id="mountain">
<img src="http://upload.wikimedia.org/wikipedia/commons/2/20/Red_Slate_Mountain_1.jpg">
</div>
</div>

Resources