CSS3 transitions, using translateX + translateY set to positive values, do not appear to transition properly - css

I'm currently trying to implement some CSS transition effects on a set of different panels, to give the appearance that they are "sliding in" from off screen. I want them each to appear in a different direction (e.g. top to bottom, left to right, etc.)
Presumably, to do bottom to top and right to left, I would just want to set translateX or translateY, but with a positive value, rather than negative. And then for all of them, I would just translate the value to 0 when I want them to appear on screen.
Here is a really simplified version of what I am trying to do:
HTML:
<div class="container">
<div id="about" class="panel">
<h2>About</h2>
<p>I'm Mike and I don't know!</p>
Close
</div>
<div id="projects" class="panel">
<h2>Projects</h2>
<p>Here are some projects I have worked on.</p>
Close
</div>
<div id="contact" class="panel">
<h2>Contact</h2>
<p>You can find me all over the Internet!</p>
Close
</div>
<div id="blog" class="panel">
<h2>Blog</h2>
<p>Here are some blog posts.</p>
Close
</div>
projects
blog
about
contact
</div>
CSS:
.container {
overflow:hidden;
position:relative;
width:100vw;
height:100vh;
}
.panel{
min-width: 100%;
height: 100%;
position: absolute;
box-shadow: 0px 4px 7px rgba(0,0,0,0.6);
z-index: 2;
-webkit-transition: transform .8s ease-in-out;
-moz-transition: transform .8s ease-in-out;
-o-transition: transform .8s ease-in-out;
transition: transform .8s ease-in-out;
}
.panel:target {
-webkit-transition: transform .8s ease-in-out;
-moz-transition: transform .8s ease-in-out;
-o-transition: transform .8s ease-in-out;
transition: transform .8s ease-in-out;
}
.panel#contact {
transform: translateX(110%);
background-color:whitesmoke;
}
.panel#about {
transform: translateX(-110%);
background-color: red;
}
.panel#projects {
transform: translateY(110%);
background-color: blue;
}
.panel#blog {
transform: translateY(-110%);
background-color: gold;
}
.panel#contact:target{
transform: translateX(0%);
}
.panel#about:target{
transform: translateX(0%);
}
.panel#projects:target{
transform: translateY(0%);
}
.panel#blog:target{
transform: translateY(0%);
}
Note that the "About" and "Blog" links are transitioning as expected, whereas the "Projects" and "Contact" links appear to cause weirdness. Those are the two with positive values.
I'm having a really difficult time:
a.) understanding what the problem is exactly
b.) how can I fix it (if at all)
If someone could both explain what the browser is doing right now with those erroneous transitions and provide a solution, I would be much obliged. AFAIK, this is happening in every browser (that supports the :target pseudo element, anyway).
Let me know if you need clarification. Thanks a lot!
UPDATE: Not fixed, but I noticed that if you set the values to <98% for the offending element panels (Projects + Contact), the page transitions properly, though it isn't hidden from the screen. Not sure what that means, but if it helps...
UPDATE 2.0: Thanks for the comments, folks! I tried adding a container, and have updated the HTML and CSS to reflect that. The changes in question are a container div that wraps the panels, as well as the following CSS for that container:
.container {
overflow:hidden;
position:relative;
width:100vw;
height:100vh;
}
I'm still having similar behavior -- this is also updated in the Codepen. I think I understand now the issue, but I'm not quite sure why the page is still jumping to that element in question before applying the transformation. I can imagine there is some hacky way to get around this, but I would rather do it the "right" way.

I decided that using :target and trying to have this be pure CSS wasn't really the way to go, and wound up just using Javascript in a fairly straightforward manner.
Lesson learned: Don't try to do things w/ Pure CSS unless you really have to.

Related

How to animate height with transform without squishing content

In my project I have been using jQuery slideUp() to slide up an element in a 200 item list when the user clicks a button. But, as everyone knows, animating CSS height requires a reflow, making the animation jerky. This animation is an integral part of the application and I am willing to go to extensive work to make it work AND work smoothly.
I have decided that CSS transform is the way to make it work smoothly because of the fact that it is handled on the gpu and on some modern browsers, it is even off the main thread and heavy JS work won't affect the transform. (I do have heavy JS work).
I am looking for a clever solution with CSS transition: transform to replicate jQuery slideUp, which just animates the height property. Below was my attempt, but it seems scale and translate do not sync as expected.
$("button").on("click", function() {
$(".collapsible").addClass("collapsed")
setTimeout(function() {
$(".collapsible").removeClass("collapsed")
}, 5000);
});
.list-item {
width: 400px;
height: 100px;
background-color: blue;
margin-top: 10px;
overflow-y: hidden;
}
.collapsible.collapsed .content {
transition: transform 3s linear;
transform: scale(1, 1) translate(0, -100%);
}
.collapsible.collapsed {
transition: transform 3s linear;
transform: translate(0, -50%) scale(1, 0);
}
.collapsible.collapsed ~ .list-item {
transition: transform 3s linear;
transform: translate(0, -100%);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.3/jquery.min.js"></script>
<button>Collapse</button>
<div class="list-item collapsible">
<div class="content">
Just an example <br>
Just an example <br>
Just an example <br>
Just an example <br>
Just an example <br>
</div>
</div>
<div class="list-item">
</div>
<div class="list-item">
</div>
I played with the values some and got it closer by changing the content transform to transform: scale(1, 3) translate(0, -50%);.
It seems I am so close to achieving, but never quite succeeding. Is there any cut and dried trick out there for this?
Requirements:
Preferably no JS
Off the main thread

Choppy transition: transform scalling animation on Safari

I have hard time making scaling animation that is not choppy in Safari (mobile). By choppy I mean you can clearly see that it's not 60FPS fluid animation. I need to say that element is absolutely positioned so it should not affect layout, should it?
First thing that I tried is animating element by creating CSS animation with 2 keyframes, going from transform: scale(0); to transform: scale(1);. For the effect I want to achieve I also used transform-origin: top right;. I also tried to optimize it by setting will-change: transform; but it was choppy.
I scrapped it and reworked it so it uses transition: transform. So by default element has transform: scale(0);, when certain class attaches to it, it gets transform: scale(1); which transition is animating, but it is still choppy.
After some research I found out that you want to avoid animating properties that require browsers to recalculate layout. I found out this site which says that WebKit (which Safari is using as far as I know) pretty much recalculates layout for every property change. Is that true, and if it is how do you make 60FPS fluid animations on mobile Safari (on other platforms using Safari it's not that noticeable because they have much more resources to recalculate everything and it appears a bit smoother than on mobile)?
There are 2 things that you can try:
avoid using scale(0). In some browsers this gives problems. scale(0.01) is almost the same, and will be better for the browser.
Try to make the animation handled by the GPU instead of the CPU. this can be done with the following code
from: {transform: scale(0.01) translateZ(1px);}
to: {transform: scale(1) translateZ(1px);}
In reference to this article section Animate Changes in CSS Properties, you can animate with keyframes, but need use a percentage like this:
More examples in w3s article.
PD: if you add an example, i'll try to help you.
function animateStart(){
document.getElementById('ball').classList.add('bounce');
}
function animationPause(){
document.getElementById('ball').style.webkitAnimationPlayState='paused';
}
function animationContinue(){
document.getElementById('ball').style.webkitAnimationPlayState='running';
}
#-webkit-keyframes bounce {
0% {top: 100px; left: 1px; -webkit-animate-timing-function: ease-in;}
25% {top: 150px; left: 76px; -webkit-animate-timing-function: ease-out;}
50% {top: 100px; left: 151px -webkit-animate-timing-function: ease-in;}
75% {top: 150px; left: 226px -webkit-animate-timing-function: ease-out;}
100% {top:100px; left: 301px;}
}
.bounce {
-webkit-animation-name: bounce;
-webkit-animation-duration: 2s;
-webkit-animation-timing-function: linear;
-webkit-animation-iteration-count: infinite;
-webkit-animation-direction: alternate;
}
.ball-style {
position:absolute; top: 100px; left: 10px;
height:100px; width:100px; border-radius:50px;
background:-webkit-radial-gradient(30% 30%, white, red 10%, black);;
}
.wall {
position:absolute; left: 400px; top: 100px;
height: 150px;
background: black;
}
<input type="button" value="Animate alternative"
onclick="document.getElementById('ball').classList.add('bounce');">
<input type="button" value="Animate" onclick="animateStart()">
<input type="button" value="Pause" onclick="animationPause()">
<input type="button" value="Continue" onclick="animationContinue()">
<div id="ball" class="ball-style"></div>
<div class="wall"> </div>
I don't know if this helps but are you using javascript to add a class and start the animation with the class change?
jQuery for example can cause long depth analysis in the dom when manipulating elements, this is likely to interfere with the performance you need for achieving the desired fps.

Simple AngularJS with CSS animation

I have read a couple of tutorials online, but I can't seem to get a cross-browser working example together.
HTML:
<div ng-include="show ? 'views/registration/form_activation.html' : null" ng-animate class="drop-down"></div>
CSS:
/* ANIMATIONS */
.drop-down {
-webkit-transition: all linear 1s;
-moz-transition: all linear 1s;
-ms-transition: all linear 1s;
-o-transition: all linear 1s;
transition: all linear 1s;
line-height: 100%;
}
.drop-down.ng-enter,
.drop-down.ng-leave-active {
opacity: 0;
max-height: 0px;
}
.drop-down.ng-enter-active,
.drop-down.ng-leave {
opacity: 1;
max-height: 100%;
}
What I would like to accomplish is that when the template is loaded with ng-include, it fades in from 0 to 100 opacity, and that it simultaneously opens like a dropdown (starting from 0, to full height that it needs). And vice versa when the form gets hidden.
The opacity already works, but changing the height does not, the div instantly appears with full height. Can some help me build the CSS with a cross-browser solution?
you have to define max-height in px in .drop-down class to make it work.
you can put any high value to max-height in px as you are anyways not defining the height.
also define overflow: hidden in .drop-down so that content is hidden on transition of height.
worked for me.
example demo here :- http://plnkr.co/edit/rXQQHTogKzAG91xw3JUx?p=preview

How to completely center a Unicode math symbol within its parent element?

I am trying to implement a CSS-based animation involving a single Unicode character:
HTML
<div class="spinner">⊗</div>
CSS
.spinner {
display: inline-block;
font-size: 42pt;
margin: 50px;
animation: spin 0.5s infinite linear;
}
#keyframes spin {
to { transform: rotate(360deg); }
}
* I've omitted the vendor-specific prefixes in this example.
However, when I view the page in my browser (Firefox 20.0), the character is slightly off-center, resulting in a "wobbly" animation.
You can see it live here: http://jsfiddle.net/bBaVN/77/
How can I completely center the character?
Proof of Concept using SVG
Consider the following:
<div class="wrap">
<span class="spinner">
<svg {...many other attributes...} class="logo">
...path code...
</svg>
</span>
</wrap>
See the fiddle: http://jsfiddle.net/audetwebdesign/3G3U7/
I found a SVG version of the symbol at:
http://www.fileformat.info/info/unicode/char/2297/index.htm
I had to take the SVG, open it in Adobe Illustrator and then reset the view port (bounding box?) using object->artboards->fit to artwork bounds.
I then saved as SVG and then cut-paste the <svg> block into the demo, and finally, I added the class="logo" attribute to the <svg> tag.
For styling, I used the following CSS:
.spinner {
display: block;
width: 50px;
height: 50px;
position: relative;
top: 75px;
left: 75px;
animation: spin 1s infinite linear;
}
.logo {
display: block;
width: 50px;
height: 50px;
}
I set the display type to block for both .logo and .spinner, and both have the same height and width (use a square box for best results.
Seems to work. The hardest part was learning how to set up the SVG inline image. I found the following reference useful: http://css-tricks.com/using-svg/
You could set the line-height to 45px on .spinner, this will ensure that the containing span element is as high as it is wide. Here's a jsFiddle. Now there is a little less movement, but it still doesn't look like it is not moving around at all.
Another way to get it to rotate around the center of character instead of around the center of the containing span would be to play around with -vendorspecificprefix-transform-origin. You could set it to rotate around another point e.g. setting it to: 23px 34px would set the x and y coordinates for the point to rotate around.
I think the fact that it still looks like it moves around a little bit might be due to the character not being rendered as a perfect circle, you could try rendering it in a different font, changing point sizes of the font, or even turning text-rendering: optimizelegibility; on or off might make a difference there.
The default value for -vendorspecificprefix-transform-origin is 50% 50%, this suggests that if you make sure that the character inside the element is perfectly centered, and you set the animation on the containing element, it should rotate exactly around the the center, and then playing with -vendorspecificprefix-transform-origin would only make things worse.
Another thought I'm having, by setting the point size of the text to 42pt, the width of the containing span becomes 45px, now 50% of that would be 22.5px, maybe it would work if you made the point size of the text a bit bigger, or just set the width and the height of the containing span to 46px, then 50% would be 23px, which might make the difference with the current movement.
Update:
I was able to get it to be centered perfectly in Chrome (and in FireFox) by using a mono-space font Courier, manually setting the line-height, height and width of the span to center the character, and then forcing the character to look more like a circle by moving it over by 0.5px using -webkit-transform: translate().
.spinner {
display: inline-block;
font-size: 42pt;
line-height: 50px;
height: 46px;
width: 46px;
margin: 50px;
-webkit-animation: spin 1s infinite linear;
-moz-animation: spin 1s infinite linear;
-ms-animation: spin 1s infinite linear;
-o-animation: spin 1s infinite linear;
animation: spin 1s infinite linear;
font-family: courier;
}
#-webkit-keyframes spin {
from { -webkit-transform: rotate(0deg) translate(0.5px, 0px)}
to { -webkit-transform: rotate(360deg) translate(0.5px, 0px)}
}
I think the fact that I need 2 jsFiddle's to demonstrate for different browsers kind of answers the question about if you should be doing it this way, I think the differences in font-rendering between browsers will ensure that you can't do this reliably without browser detection.

css animation to set height of div

i am wondering if it is possible to set the height of a div with css animation.
I have a div that when you hover over it opens up but i want it to stay that height not shrink back to the original height.
Is this possible?
it needs to be done in pure css not javascript as its a website for college
You can do something like this:-
HTML:
<div class="divAnimate" onmouseout="this.className='setHeight'">Div Height Animation</div>​
CSS:
.divAnimate {
border: 1px solid;
}
.divAnimate:hover {
height: 200px;
}
.setHeight {
height: 200px;
border: 1px solid;
}
Refer LIVE DEMO
You should use jQuery. CSS3 is not supported in all browsers. However, it is possible to use CSS3 to achieve this.
CSS:
#myDiv {
height:20px;/* initial height */
width:100px;
background:#aaa;
-webkit-transition: height .4s linear; /* you can replace 'height' with the attribute you are changing (eg: color, width...)*/
-moz-transition: height .4s linear;
-o-transition: height .4s linear;
-ms-transition: height .4s linear;
transition: height .4s linear;
}
#myDiv:hover {
height:100px; /* desired height */
}
HTML:
<div id="myDiv">
Hello World!
</div>
Hope this helps.
EDIT: Sorry, I didn't see that you needed it to stay that height. In order to do that, you would need to use something like onmouseout (or another event listener), which in the end would use Javascript anyway.
Yes, this is possible with just CSS3, but will only work in Safari/Chrome and recent versions of Opera, Mozilla Firefox, and IE10 as you need CSS3 animation keyframes to preserve the end-state of the transition.
http://jsfiddle.net/rPc88/3/

Resources