Wobbly text on transform scale - html

When I try to scale a div on mouse hover, the text wobbles/jitters and the animation is not smooth. This is especially apparent in FireFox, but can also be seen in Chrome.
Are there any changes I can do to make the animation smooth?
JS Fiddle: https://jsfiddle.net/jL4dbxf9/
.mtw {
max-width: 200px;
margin: 0 auto;
}
.mt .mp {
text-align: center;
}
.mt .mp .ma {
color: #fff;
font: 800 40px OpenSansBold, Arial, Helvetica, sans-serif;
min-height: 60px;
}
.mt .header-blue {
background: blue;
}
.mt {
transition: all 0.4s linear;
}
.mt:hover{
z-index: 1;
transform: scale(1.1);
-webkit-transform: scale(1.1);
-moz-transform: scale(1.1);
-o-transform: scale(1.1);
-ms-transform: scale(1.1);
}
<div class="mtw">
<div class="mt">
<div class="header-blue">
<h2 class="mp">
<span class="ma">49</span>
</h2>
</div>
</div>
</div>

So you've got multiple things going on here, and unfortunately it's going to require various things between browsers as you tackle some of the nuances of the measure / arrange passes, anti-aliasing, hardware acceleration, perspective, etc...
.mtw {
max-width: 200px;
margin:0 auto;
}
.mt .mp { text-align: center }
.mt .mp .ma {
color: #fff;
font: 800 40px OpenSansBold, Arial, Helvetica, sans-serif;
min-height: 60px;
}
.mp { margin: 0 }
.mt .header-blue {
background: blue;
}
.mt {
transition: all 0.4s linear;
backface-visibility: hidden;
-webkit-font-smoothing: subpixel-antialiased;
}
.mt:hover {
z-index: 1;
-webkit-transform: scale(1.1) translate3d( 0, 0, 0) perspective(1px);
-moz-transform: scale(1.1) translate3d( 0, 0, 0) perspective(1px);
-o-transform: scale(1.1) translate3d( 0, 0, 0) perspective(1px);
-ms-transform: scale(1.1) translate3d( 0, 0, 0) perspective(1px);
transform: scale(1.1) translate3d( 0, 0, 0) perspective(1px);
}
/* --- cleaner way --- */
#boom {
color: #fff;
background-color: blue;
font: 800 40px OpenSansBold, Arial, Helvetica, sans-serif;
min-height: 60px;
max-width:200px;
margin:0 auto;
text-align: center;
transition: transform 0.4s linear;
backface-visibility: hidden;
-webkit-font-smoothing: subpixel-antialiased;
will-change: transform;
}
#boom:hover {
-webkit-transform: scale(1.1) translate3d( 0, 0, 0) perspective(1px);
-moz-transform: scale(1.1) translate3d( 0, 0, 0) perspective(1px);
-o-transform: scale(1.1) translate3d( 0, 0, 0) perspective(1px);
-ms-transform: scale(1.1) translate3d( 0, 0, 0) perspective(1px);
transform: scale(1.1) translate3d( 0, 0, 0) perspective(1px);
}
/* --- Another way --- */
#weee {
color: #fff;
background-color: blue;
font: 800 40px OpenSansBold, Arial, Helvetica, sans-serif;
min-height: 60px;
max-width:200px;
margin:0 auto;
text-align: center;
transition: font-size 0.4s linear;
backface-visibility: hidden;
-webkit-font-smoothing: subpixel-antialiased;
will-change: font-size;
}
#weee:hover {
font-size: 120px;
}
<div class="mtw">
<div class="mt">
<div class="header-blue">
<h2 class="mp">
<span class="ma">49</span>
</h2>
</div>
</div>
</div>
<br/><br/>
Or, cleaner way....
<div id="boom">50</div>
<br/><br/>
Or, an entirely different way...
<div id="weee">51</div>
So if we look through the changes, we see some things added...
backface-visibility: hidden; = The user doesn't care about the back, remove it from the compositor consideration...
-webkit-font-smoothing: subpixel-antialiased; = I'm sure the font is cool, but you re-try redrawing all the pixel specific shading crap on the fly smoothly....
translate3d( 0, 0, 0) = 'ol hack to force hardware acceleration in some instances and let the gpu help out.
margin: 0 = on your h2 to remove the user agent margin garbage from consideration...
perspective(1px) = Because you're transforming, remind it where home is...
Between these hopefully you should see the result you're expecting, hope it helps, cheers!
Oh, and just a quick PS: You don't need that many elements to accomplish the same thing (unless there's more to your example than what we see), I would try to shake that habit. One element and some text could deliver the same result with a cleaner DOM and less for the compositor thread to care about while doing its thing.
ADDENDUM; Eventually with scale you're going to run into a resolution loss as it's resizing an elements dimensions and its children on a 2d plane with a rasterization. Avoiding blurry effect the larger something is scaled is inevitable (as far as I know today) unless you want refactor into say a canvas with zoom, or easier yet treat the instance for what it is and instead just target the font in this scenario since it's the only thing actually needing to stay legible. So see the added example, which is targeting font-size as a vector instead. Cheers!

I think a couple things are happening. But this should fix it:
.mt {
transition: transform 0.4s linear;
transform: scale(.9);
}
.mt:hover{
z-index: 1;
transform: scale(1);
-webkit-transform: scale(1);
-moz-transform: scale(1);
-o-transform: scale(1);
-ms-transform: scale(1);
}
It is difficult to scale text. The reason I believe you are seeing it jump is that the text is recalculating line height and letter spacing during your animation.
The more important problem that I saw was that you set scale to over 1. Scale should start small and end at 1 as the biggest. You can see scale jank when you scale a picture over 1 really clearly.

When animating a modal the text was jumping and this solved my issue:
.modal > * {
transform: scale(1.000001);
}
Which don't seems to modify dimensions too much, and worked out :)

Related

CSS clip-path interfering with nested divs in a 'playing card flip' animation

Long story made short I am trying to work on a page that will be showing a playing card that I want to animate flipping over to the back side and back again at certain points. So far I've been using a lot of the code from this useful blog post to do so: https://manjitkarve.com/posts/card-flip-interaction/
What I'm trying to add on now is a clip-path as the majority of my card images are not 'clean' and have some jank white lines around the image and using clip-path in CSS seemed like the cleanest way to nail this. And so far isolated on its own it is doing the job swimmingly.
However with the clip-path added in, my card flip transitions are messed up. As an example: If I am sitting on the 'front' face of the card and ask it to flip to the back, it flips to a mirrored version of the front face instead. Once I take clip-path out, it's back to normal.
There's a LOT of moving parts to my code now but I'll post what I can/what's relevant. As an addition note, I'm also using the SWUP JS library in here but that functionality is working fine and best I can tell is not interfering with this currently. If I call these card transitions manually outside of SWUP, I get the same behavior:
HTML:
<main id="swup">
<div id="swup-card-img card_img_overlay" class="card-left-half card transition-flip center">
<div class="front face" style="background-image:url('{{ card.card_image.url }}')"></div>
<div class="back face" style="background-image:url('{% static 'img/fow_cardback.png' %}')"></div>
</div>
</main>
CSS:
.transition-flip {
transition: transform 1.0s;
transform-style: preserve-3d;
}
.transition-flip .card .front {
transform: rotateX(0deg);
}
.transition-flip .card .back {
transform: rotateX(180deg);
}
html.is-animating .transition-flip {
transform: rotateY(180deg);
transition: transform 1.0s;
}
html.is-leaving .transition-flip­­ {
transform: rotateY(180deg);
transition: transform 1.0s;
}
.card {
/* Card height to width ratio is 1.396 rounded */
width: 50vw;
height: 69.8vw;
position: relative;
perspective: 100vw;
perspective-origin: 50% 50%;
transform-style: preserve-3d;
display: inline-block;
clip-path: inset(0.3% 0.2% 0.0% 0.2% round 3.9%);
background: rgba(0, 0, 0, 1.0);
}
.card .face {
backface-visibility: hidden;
position: absolute;
width: 100%;
height: 100%;
transition: transform 0.35s cubic-bezier(0.13, 1.03, 0.39, 0.98), box-shadow 0.35s cubic-bezier(0.13, 1.03, 0.39, 0.98), border-width 0.35s cubic-bezier(0.13, 1.03, 0.39, 0.98);
box-shadow: 0px 1.2vw 4vw -1vw rgba(0, 0, 0, 0.6);
background-position: 0 0;
background-size: 50vw;
background-repeat: no-repeat;
border: 1px solid rgba(0, 0, 0, 0.3);
border-radius: 1.1vw;
}
.card .front {
}
.card .back {
transform: rotateY(180deg);
transform: rotateX(180deg);
}
.center {
margin:0 auto;
}

Why does 'transform:rotate(Xdeg)' cause the animation to stop?

I tried to rotate an animated font arrow when the window reached a min/max size, but when the rotate takes place the animation stops, also just for testing I tried replacing transform: rotate(90deg) to transform: rotate(0deg) which maintains the same arrow's direction but it causes to stop the animation too. The issue is with transform: rotate() and it can be easily tested by inspecting the element and activating/deactivating it in the browsers developer tools.
An easy way to bypass this can be using two <p> each one with an arrow in different direction and with vertical and horizontal animation each, and using display: none; to alternate between them when the min/max size switches, but what I want is to know why this is happening and how to solve this using this approach
.text-center {
text-align: center;
}
.lnr-x3 {
font-size: 2.4rem;
}
#media (max-width: 991px) {
#catalogArrow_h {
transform: rotate(90deg) !important;
transform-origin: center !important;
}
}
.animated-h {
text-decoration: none;
outline-style: none;
-webkit-animation: movingHorizontally 1.7s ease-in-out infinite;
animation: movingHorizontally 1.7s ease-in-out infinite;
}
#keyframes movingHorizontally {
0% {
transform: translateX(0px);
-webkit-transform: translateX(0px);
}
50% {
transform: translateX(-10px);
-webkit-transform: translateX(-10px);
}
100% {
transform: translateX(0px);
-webkit-transform: translateX(0px);
}
}
#-webkit-keyframes movingHorizontally {
0% {
transform: translateX(0px);
-webkit-transform: translateX(0px);
}
50% {
transform: translateX(-10px);
-webkit-transform: translateX(-10px);
}
100% {
transform: translateX(0px);
-webkit-transform: translateX(0px);
}
}
<!-- Font Icons -->
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" type="text/css">
<link rel="stylesheet" href="https://cdn.linearicons.com/free/1.0.0/icon-font.min.css">
<div class="col-12">
<p class="text-center pt-3 px-5">
<span id="catalogArrow_h" class="lnr lnr-x3 lnr-arrow-right fas animated-h"></span>
</p>
</div>
Why does this happen
The transform property is "shared" for many transform functions and css doesn't combine any property's values.
Because your animation is made with transform: translateX(..), adding transform: rotate(..) will overwrite the property's value, not combine them. I.e. the resulting style is transform: rotate(..), not transform: translateX(..) rotate(..).
It would be the same if you were animating the box-shadow and then wanted an inset box-shadow too, it would overwrite one with the other. Or more simply - if you have .box { color: red; color: blue; } css will choose the last value (blue) to apply to the color property.
If there were css properties rotate: 90deg and translate: 4px (there are but not widely supported), then your animation would work, because the translate animation would be applying to a different property than the rotation, not overwriting one that is essentially shared amongst many transform functions.
Ways around it
There are many ways around this problem.
You can set the translate or rotate on the parent element
<div class="rotate-90">
<span class="translate-animate"></span>
</div>
You can add the rotate to your translate animation properties:
#keyframes movingHorizontallyRotated {
0%, 100% { transform: translateX(0px) rotate(90deg); }
50% { transform: translateX(-10px) rotate(90deg); }
}
You can animate a different property to translate the element:
#keyframes movingHorizontally {
0%, 100% { padding: 5px 10px 5px 0px; }
50% { padding: 5px 0px 5px 10px; }
}
You can use/make an already rotated arrow if your framework/ assets provides one.

Cube rotation with css

I am having a bit of an issue with rotation of a cube. I want to make it cross-browser so I am transforming every side of the cube. When I am rotating from left to right the sides align perfectly on all browsers Chrome, Firefox and IE, BUT when the cube is rotated from top to bottom, the sides align only on Chrome (If I make the animation slower on Chrome the sides are broken the same way as the other browsers, so I think working properly is a bug :D). I have provided an example on jsfiddle:
http://jsfiddle.net/0n9bnxe5/
HTML:
<div class="flip-card-content">
<div class="flip-card-side-a" style="background:red">
FRONT
</div>
<div class="flip-card-side-b" style="background:green">
BACK
</div>
<div class="flip-card-side-c" style="background:aqua">
LEFT
</div>
</div>
<button id="button">Flip-top</button>
<button id="button2">Filp-right</button>
CSS:
.flip-card-content {
position: relative;
margin: 100px;
width: 200px;
height: 200px;
transform-style: preserve-3d;
perspective:1000px;
}
.flip-card-side-a,
.flip-card-side-b,
.flip-card-side-c{
width: 100%;
position: absolute;
height: 100%;
backface-visibility: hidden;
transform-origin:50% 50% 0px;
transition: all .5s ease-in-out;
}
.flip-card-side-a {
transform: rotateY(0deg) translateZ(100px);
z-index: 1;
}
.flip-card-side-b {
transform: rotateX(90deg) translateZ(100px);
}
.flip-card-side-c {
transform: rotateY(-90deg) translateZ(100px);
}
.flip .flip-card-side-a {
transform: rotateX(-90deg) translateZ(100px);
}
.flip .flip-card-side-b {
display:block;
transform: rotateY(0deg) translateZ(100px);
z-index: 1;
}
.flip-right .flip-card-side-a {
transform: rotateY(90deg) translateZ(100px);
}
.flip-
right .flip-card-side-b {
display:none;
}
.flip-right .flip-card-side-c {
transform: rotateY(0deg) translateZ(100px);
z-index:1;
}
JQUERY:
$("#button").on('click', function(){
$(".flip-card-content").removeClass("flip-right");
setTimeout(function(){
$(".flip-card-content").toggleClass("flip");
},500);
});
$("#button2").on('click', function(){
$(".flip-card-content").removeClass("flip");
setTimeout(function(){
$(".flip-card-content").toggleClass("flip-right");
},500);
});
Any advice is welcomed!
Your translateZ doesn't quite work in the way you expect. Have look at how I've positioned the faces on the cube here and compare it to your own. Ultimately, I find the easiest way to rotate items such as cubes etc. is to position all the elements and then just rotate the container.
Also for nice scaling of fonts, images etc. its preferable to leave the front face at its natural size rather than scale up (i.e. move everything backward in 3d space):
.box {
height: 100%;
position: relative;
transform: rotateX(0deg);
transform-origin: 50% 50% -100px;
transform-style: preserve-3d;
transition: all 1s;
width: 100%;
}
.box--rotate-top {
transform: rotateX(-90deg);
}
.box--rotate-left {
transform: rotateY(90deg);
}
.box__face {
backface-visibility: hidden;
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%;
}
.box__face--front {
background: #f90;
}
.box__face--top {
background: #369;
transform: rotateX(90deg) translateZ(200px);
transform-origin: 0 100% 0;
}
.box__face--left {
background: #867;
transform: rotateY(-90deg) translateZ(200px);
transform-origin: 100% 0 0;
}
Here is the fiddle.
Transition in 3d space are tricky, and different browsers can handle them differently.
Here you have your fiddle corrected.
Your best bet is to leave nothing to the browser imagination
so, instead of changing
transform: rotateY(0deg) translateZ(100px);
to
transform: rotateX(-90deg) translateZ(100px);
make the change happen from
transform: rotateX(0deg) rotateY(0deg) translateZ(100px);
to
transform: rotateX(-90deg) rotateY(0deg) translateZ(100px);
Notice that I didn't change the transform from a mathematical point of view; but now every property matches a similar one.
Note just in case you want to know, in the first case IE is making the followng transition: change the angle of rotation from 0 to -90deg. At the same time, change the axis of rotation from Y to X. So, at the middle of the transition, the rotation is wrong (from your point of view), but in a mathematic sense, both ways of understanding the transition make sense.

Amazon book flipping CSS animation: how is it coded?

Link to example. Hover over the book on the left side
As you can see, the book seems to open towards the user.
I already have the first part of the animation: JSFiddle
HTML:
<h1>Boek opendoen animatie</h1>
<div class="achtergrond">
<img class="foto" src="http://i.imgur.com/u19t6iW.jpg" alt="Cover">
</div>
</body>
</html>
CSS:
div.achtergrond {
background-color: black;
width: 250px;
height: 376px;
}
img.foto {
width: 250px;
height: auto;
-webkit-transition: -webkit-transform 1s; /* For Safari 3.1 to 6.0 */
/* -webkit-transform-origin: 0 0;*/
}
img.foto:hover {
/* -webkit-transform: scaleX(1.5)*/
-webkit-transform: matrix3d(0.8660254, 0, 0.5, 0, 0, 1, 0, 0, -0.5, 0, 0.8660254, 0, 0, 0, 0, 1);
}
Now this doesn't seem to enlarge the right corners of the book, so it doesn't seem like the cover is coming towards the user.
I've tried -webkit-perspective, transform-style,... but can't seem to get the desired effect.
try this css on image hover
transform: rotateY(-20deg);
-moz-transform: rotateY(-20deg);
-webkit-transform: rotateY(-20deg);
I found how I need to fix this.
I tried the perspective and perspective-origin options before but didn't put them in the correct place.
These options have to be put in the parent element (here the "achtergrond"-div).
See w3schools with the quote
When defining the perspective-origin property for an element, it is the CHILD elements that are positioned, NOT the element itself.
The new CSS is thus:
div.achtergrond {
background-color: black;
width: 250px;
height: 376px;
-webkit-perspective: 250px; /* Chrome, Safari, Opera */
-webkit-perspective-origin: 100% 30%; /* Chrome, Safari, Opera */
}
img.foto {
width: 250px;
height: auto;
-webkit-transform-origin: 0 0;
-webkit-transform-style: preserve-3d;
-webkit-transition: -webkit-transform 1s; /* For Safari 3.1 to 6.0 */
}
img.foto:hover {
/* -webkit-transform: scaleX(1.5)*/
transform: rotateY(-20deg);
-moz-transform: rotateY(-20deg);
-webkit-transform: rotateY(-20deg);
}

CSS circles shaking on animation

I have drawn a circle in CSS. I tried playing around with the code to fix this issue but to no avail. I have 2 main issues :
In Chrome :
The circles shake while rotating
In Firefox :
There appears a tail-like dot when the circle is animating in circular motions.
This is the CSS styling I am using :
.followers_arc_outer{
position:absolute;
width:300px;
height:300px;
border-radius:100%;
border:2px solid;
}
.followers_arc_start {
border-color:transparent #ecd201 #ecd201 #ecd201;
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
-ms-transform: rotate(45deg);
-o-transform: rotate(45deg);
transform: rotate(45deg);
}
.followers_arc_inner{
position:absolute;
top:18px;
left: 18px;
width: 280px;
height:280px;
border-radius:100%;
border:2px solid;
border-color:transparent #ecd201 #ecd201 #ecd201;
}
.o_circle {
-webkit-animation: rotation 2s infinite linear;
animation: rotation 2s infinite linear;
}
#-webkit-keyframes rotation{
from {-webkit-transform: rotate(0deg);transform: rotate(0deg);}
to {-webkit-transform: rotate(359deg);transform: rotate(359deg);}
}#keyframes rotation{
from {-webkit-transform: rotate(0deg);transform: rotate(0deg);}
to {-webkit-transform: rotate(359deg);transform: rotate(359deg);}
}
.i_circle {
-webkit-animation: rotation2 2s infinite linear;
animation: rotation2 2s infinite linear;
}
#-webkit-keyframes rotation2 {
from {-webkit-transform: rotate(359deg);transform: rotate(359deg);}
to {-webkit-transform: rotate(0deg);transform: rotate(0deg);}
}#keyframes rotation2 {
from {-webkit-transform: rotate(359deg);transform: rotate(359deg);}
to {-webkit-transform: rotate(0deg);transform: rotate(0deg);}
}
<div class="followers_arc_outer followers_arc_start o_circle"></div>
<div class="followers_arc_inner followers_arc_start i_circle"></div>
I have created a fiddle. Here is the link :
http://jsfiddle.net/r8cqet2c/4/
Am I doing something wrong?
If your circles are big then the browsers may take time to render them. And at the same time when you try to rotate and animate them, then it would be hard for the browser to do that smoothly with the CPU graphics(which the browser uses by default).
But you can make use of your GPU in your browser by using some hardware accelerated CSS. Which will boost the performance of you animations. Here is the code you can apply to your circles to make them run smoother.
-webkit-transform: translate3d(0,0,0);
-moz-transform: translate3d(0,0,0);
-ms-transform: translate3d(0,0,0);
-o-transform: translate3d(0,0,0);
transform: translate3d(0,0,0);
or you can use this below one...both will work..
-webkit-transform: translateZ(0);
-moz-transform: translateZ(0);
-ms-transform: translateZ(0);
-o-transform: translateZ(0);
transform: translateZ(0);
If you still see some weird lag or something in chrome or safari then you will have to add this below code as well.
-webkit-backface-visibility: hidden;
-moz-backface-visibility: hidden;
-ms-backface-visibility: hidden;
backface-visibility: hidden;
-webkit-perspective: 1000;
-moz-perspective: 1000;
-ms-perspective: 1000;
perspective: 1000;
Hope it helps..
Maybe transform-origin and perspective-origin properties can help you:
http://www.w3schools.com/cssref/css3_pr_transform-origin.asp
http://www.w3schools.com/cssref/css3_pr_perspective-origin.asp
I think it has to do with anti-aliasing and rounding. I changed to background to plain black and made the animations stop after one round. When the circles are still you can see that the anti-aliasing makes some parts of the circles look less solid, especially when you zoom smaller. I don't see the shaking or the tail.
Any case is shaking
I checked the code in Chrome, Mozilla, Opera and Safari (even 5.17 is working)
Maybe you're using a bad resolution or some graphic card problem.
No problem here stand-alone. (Chrome, Firefox, Safari)
If you see a problem here stand-alone; it may be due to your machine / hardware or browser settings.
But it's likely some other code you have in your application conflicting with this code causing the shake.
It's happens due to anti-aliasing and you can solve it by smoothing the border. You can use box-shadow with inset property instead of color with solid property in order to prevent it:
CSS
.followers_arc_outer {
position:absolute;
width:300px;
height:300px;
border-radius:100%;
box-shadow: 2px 0px 2px 0px #ecd201 inset;
}
.followers_arc_inner {
position:absolute;
top:18px;
left: 18px;
width: 280px;
height:280px;
border-radius:100%;
box-shadow: 2px 0px 2px 0px #ecd201 inset;
}
heres the fiddle to see how it works :
http://jsfiddle.net/heartagramir/xdmuvu9s/
To make transforms more smooth and prevent looking juddery or tattered you can reset translate3d to zero:
.transform {
-moz-transform: rotate(-4.7deg) translate3d(0, 0, 0);
-ms-transform: rotate(-4.7deg) translate3d(0, 0, 0);
-o-transform: rotate(-4.7deg) translate3d(0, 0, 0);
-webkit-transform: rotate(-4.7deg) translate3d(0, 0, 0);
transform: rotate(-4.7deg) translate3d(0, 0, 0);
}
I would suggest to add translate3d(0, 0, 0) whenever you use transform