Positioning Preference? - css

Of the 4 method listed below, which are more compatible and/or performance driven when animating? To keep the topic more isolated, lets say while animating a navigation pane (drawer) into view from left to right.
margin/padding/border-left` (further reading on negative margins)
position:absolute
position:relative
transform:translateX adjustment (Support for Transforms)
From what I know, position:relative, padding, margin, & borders generate reflows and repaints... is the impact really that big?
whereas positions:absolute/fixed generates reflows only.
I'm not entirely sure what translateY does, although it does pass transitions to the GPU which may not be desirable on mobile, from what I've read (not personally tested). Is this accurate? Is it just splitting hairs?
I'm looking for a well supported method of animating that performs well from mobile to desktop (IE9+) and is CSS based. I haven't tested a particular path but have used all at one point or another, just curious which is preferred and why?
I'll provide one example to demonstrate how they all can achieve the same effect...
Fiddle: http://jsfiddle.net/darcher/94yf1a39/
/* hardware acceleration */
.margin,
.relative,
.absolute,
.translate-x{
transform: translate3d(0, 0, 0)}
/* margin */
.margin{
margin-left:-200px;
transition:margin-left 200ms, color 200ms cubic-bezier(.17,.67,.83,.67) 20ms}
.margin:hover{margin-left:50px}
/* positioning */
.absolute{position:absolute}
.relative-wrap,
.relative{position:relative}
.relative-wrap{margin-bottom:2.4rem}
.relative,
.absolute{
left:-200px;
transition:left 200ms, color 200ms cubic-bezier(.17,.67,.83,.67) 20ms}
.relative:hover,
.absolute:hover{left:50px}
/* translate */
.translate-x{
-webkit-transform: translateX(-200px);
transform: translateX(-200px);
transition:transform 200ms, color 200ms cubic-bezier(.17,.67,.83,.67) 20ms;
-webkit-backface-visibility:hidden;
backface-visibility:hidden;}
.translate-x:hover{
-webkit-transform: translateX(50px);
transform: translateX(50px)}
/* will change */
.will-change .margin{will-change: margin-left}
.will-change .position{will-change: left}
.will-change .translate-x{will-change: transform}
.will-change .margin,
.will-change .position,
.will-change .translate-x{will-change: color}

Related

translate animations behaving oddly on IE11?

I've been investigating and odd behavior when viewing CSS animations on IE11. I've dug up multiple instances where IE11 struggles to digest CSS animations similar to Chrome/Firefox, but, I'd like to produce a solution to this "bug" once and for all.
Demonstration of behavior: http://recordit.co/6urL1s8XgR
As you can see, when the user interacts with the "button", the intended animation is to slide in from the bottom right, scale up and set the opacity to 1. A generic representation of the approach below:
.element {
...
opacity: 1;
animation: animate 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
#keyframes animate {
from {
opacity: 0;
transform: scale3d(0.5, 0.5, 0.5) translate3d(0, 0, 500px);
}
}
However, on IE11, it complete's the animation lower within the DOM than other browsers, causing the animated element to "jump up" from where it (incorrectly) ended (the animation), to where it needed to finish.
A similar demonstration can be observed at the following url: https://chemonics.com/region/
I've resolved this issue with isolating the problem being the animation-fill-mode property of "forwards" was not present. This was causing the animation to (which only had a 0% keyframe defined for the animation) to end (at 100%) by inheriting the styles of the elements initial state (prior to the animation). With more modern browsers, they "fill in the gaps" whereas with IE11, well, it jumps between the gaps.
https://drafts.csswg.org/css-animations-1/#valdef-animation-fill-mode-forwards

any perfomance gain when specifying property to transition instead of all [duplicate]

I have a question about rendering speed for the css3 transition property.
Suppose I have a number of elements:
div, span, a {transition: all}
div {margin: 2px}
span {opacity: .5}
a:hover {background-position: left top}
div:hover {margin: -100px}
span:hover {opacity: 1}
a:hover {background-position: -5px top}
It's much more efficient to target all of the transitions for all of those elements using one declaration div, span, a {transition: all}. But my question is: would it be "faster" in terms of the smoothness and quickness of the animation rendering to target each element's specific transition property? For example:
div {margin: 2px; transition: margin .2s ease-in}
span {opacity: .5; transition: opacity .2s ease-in}
a {background-position: left top; transition: background .2s ease-in}
div:hover {margin: -100px}
span:hover {opacity: 1}
a:hover {background-position: -5px top}
My logic in asking this is that if the css "engine" has to search for "all" transition properties even if there is just one single property for an element, that it might slow things down.
Does anyone know if that's the case? Thanks!
Yes, using transition: all could cause major drawbacks in performance. There can be a lot of cases where the browser would look if it needs to make a transition, even if user won't see it, like the color changes, dimension changes etc.
The simplest example I can think of is this: http://dabblet.com/gist/1657661 — try to change the zoom level or the font's size and you'll see that everything become animated.Of course there couldn't be a lot of such user interactions, but there could be some interface changes that can cause the reflow and repaints in some blocks, that could tell the browser to try and animate those changes.
So, in general, it's recommended that you won't use the transition: all and would use the direct transitions instead.
There are some other things that can go wrong with the all transitions, like the splash of animation on page load, where it would at first render the initial styles for blocks and then apply the style with an animation. In a lot of cases it wouldn't be the thing that you want :)
I've been using all for cases where I needed to animate more than one rule. For example, if I wanted to change the color & background-color on :hover.
But it turns out that you can target more than one rule for transitions, so you never need to resort to the all setting.
.nav a {
transition: color .2s, text-shadow .2s;
}

Translate3d choppy towards the end of the transformation on mobile device

I was initially using jQuery's slide functions to slide a page out of view (to reveal another page beneath it) in a Cordova app I'm making, and whilst this worked perfect on my desktop browser, it (now understandably) was quite choppy on the actual mobile device. So I found out the reason for this and learnt that I should use CSS3 animations/transitions for mobile devices, and more specifically Translate3d for anything that may require GPU rendering. So I've made those changes like this:
#mainpage{
z-index: 10;
top: 0;
-webkit-transition: all .5s linear;
transition: all .5s linear;
border-bottom: 1px solid #111111;
}
#mainpage.out{
-webkit-transform: translate3d(0,-100%,0);
transform: translate3d(0,-100%,0);
}
and I just toggle the 'out' class as necessary.
The transition runs smoothly until about 50px are left on the screen (or the page has about 50px left to reappear), then it stops for about a second before finishing up. I was wondering if anyone has any suggestion as to why this may be the case or if there's maybe an even more efficient way of doing this.
The device I am using has a nVIDIA Tegra 3 CPU with 12-Core High Performance Graphics.
I think this is not the way you should do the animation.
Try the following:
#mainpage {
z-index: 10;
top: 0;
border-bottom: 1px solid #111111;
-webkit-transition: -webkit-transform .5s linear;
transition: transform .5s linear;
-webkit-transform: translate3d(0,0,0);
transform: translate3d(0,0,0);
}
#mainpage.out {
-webkit-transform: translate3d(0,-100%,0);
transform: translate3d(0,-100%,0);
}
First change is, specify the type of the property you want to animate (the transition parameter), not sure what you are animating when you write all.
Second thing, specify the "back" transition with translate3d(0,0,0). Also not sure, if it makes a difference here, though. I hope this helps you.

Fallback for CSS3 transitions

I have a CSS3 transition that resizes/positions an image inside a div on hover.
FIDDLE
This works as desired but my concern is about browsers that don't support CSS3 transitions like IE9-. Would it be possible to write this CSS code so that these browsers have a fallback?
Idealy, the fallback should display the image so it fits the div and isn't zommed (fiddle example) and with no animation on hover.
I would prefer a CSS only solution and to not to alter the markup.
Full code example :
HTML :
<div><img src="http://lorempixel.com/output/people-q-c-1000-500-7.jpg" />
CSS :
div{
overflow:hidden;
width:500px;
height:250px;
position:relative;
}
img{
display:block;
position:absolute;
height:auto;
width:200%;
left:-30%;
top:-60%;
-webkit-transition-property: width, left, top;
-webkit-transition-duration: .8s;
-webkit-transition-timing-function: ease-out;
transition-property: width, left, top;
transition-duration: .8s;
transition-timing-function: ease-out;
}
div:hover img{
width:100%;
top:0;
left:0;
}
You could use Modernizr or go through the javascript feature detection route.
Both ways are detailed here:
Detect support for transition with JavaScript
Generally speaking, CSS transitions (and most of CSS, really) were designed with progressive enhancement in mind. The intended fallback in browsers that don't understand transitions is quite simply to ignore the transition properties themselves. This allows the style changes to still take place, only immediately and not in a smooth transition (as implied by the name), and obviates the need for complex workarounds.
What you're looking to do however is to not have any change in state occur at all; you want your image to be fixed in the unzoomed state. That will take a bit more work.
If #supports had been implemented in the beginning, you could easily get away with
img{
display:block;
position:absolute;
height:auto;
width:100%;
top:0;
left:0;
-webkit-transition-property: width, left, top;
-webkit-transition-duration: .8s;
-webkit-transition-timing-function: ease-out;
transition-property: width, left, top;
transition-duration: .8s;
transition-timing-function: ease-out;
}
#supports (-webkit-transition-property: all) or (transition-property: all) {
div:not(:hover) img{
width:200%;
left:-30%;
top:-60%;
}
}
But of course, not everything works that way. It's a real shame that #supports was proposed so late and implementations still haven't caught on. But I digress.
Looking at the support tables at caniuse.com, it looks like Gecko- and WebKit/Blink-based browsers are extremely well covered (except maybe Firefox 3.6 and older), which is a relief because I can't think of any pure CSS-based solution to cater to those engines (other than ugly hacks).
For other browsers, I can see some other workarounds:
It may be worth including the -o- prefix if you care about Presto Opera.
Likewise with -moz- if you care about Firefox < 16.
For IE, simply hiding the div:not(:hover) img rules in conditional comments is enough, since the first version of IE to support transitions and ignore conditional statements happens to be the same — version 10:
<!--[if !IE]><!-->
<style>
div:not(:hover) img{
width:200%;
left:-30%;
top:-60%;
}
</style>
<!--<![endif]-->
Note the use of div:not(:hover) here, analogous to the hypothetical #supports example above. You will need to swap the declarations with your img rule accordingly.
Lets not lie ourselves, the only browser we are talking about is IE9, so just go add:
width: 200%\9;
left: -30%\9;
top: -60%\9;
and IE9 will use it. We can just hope in 2017 there will be no more need for CSS hacks.

Webkit: CSS force hardware acceleration for 2D transforms without using 3D CSS properties

Is there anyway of forcing hardware acceleration on 2D transform using CSS in webkit without using 3D (e.g. translateZ(0)) (as per Are 2D transforms hardware accelerated in Mobile Safari?).
I'm finding the issue with position: fixed elements, where the element is set to something equivalent to position: absolute, so not positioned relative to the viewport, rather it ends up positioned relative to the parent container (as explained in this article http://meyerweb.com/eric/thoughts/2011/09/12/un-fixing-fixed-elements-with-css-transforms/).
I'm choosing hardware acceleration as the background tends to flicker white on transitions in iOS, in a similar way as this bug outlines https://github.com/jquery/jquery-mobile/issues/2856.
You can add a 3d transform value to null in addition to your 2d transform value :
el {
transform: 2DValue(val) 3DValueSetToNull(0);
transform: 2DValue(val);
}
Which in real CSS can make something like :
div {
/* translateZ(0) will not interfere with the rotate value */
/* Also with -webkit-, -moz-, -o- */
transform: rotate(90deg) translateZ(0);
/* Compatibility for older (yep) browsers */
/* Also with -webkit-, -moz-, -ms-, -o- */
transform: rotate(90deg);
}
Be sure to use a 3D transform value that will not interfere with your 2D transform value.
PS : The 3d transform values are :
translate3d(x, y, z)
translateZ(z)
scale3d(sx, sy, sz)
scaleZ(sz)
rotateX(angle)
rotateY(angle)
rotate3d(x, y, z, angle),
perspective(p)
matrix3d(…)
It looks like setting backface-visibility: hidden does the trick. I've confirmed this only for chrome, using the fps-counter.
.3d-accelerate {
backface-visibility: hidden;
-webkit-backface-visibility: hidden;
}
The FPS counter doesn't show up with only transition. It does shows up when adding translate: transform3d(0, 0, 0). I also shows up with just backface-visibility.

Resources