Bug animation in translate with percentage on Safari/iOS adding via JavaScript - javascript

I think I found a bug related with percentages on Safari in the animations. I would like to know if really it is a bug or a Safari custom.
Explanation of the bug:
On Safari or iOS when you start an animation with a translate with percentages, the position is wrong and the animation is shown in another place.
In the next example, the square should not move because the transform is the same and it should start with a 10% 10% "margin" of its size. The bug occurs when it is adding via JavaScript after some time (like 500 ms).
If you see the bug, you will see a jump from 0 0 to 10% 10% in Safari and iOS.
var div = document.createElement('div');
setTimeout( function(){
document.body.appendChild(div);
}, 500);
div {
background: red;
width: 200px;
height: 200px;
-webkit-transform: translate(10%, 10%);
-webkit-animation: 1s bugAnimation;
}
#-webkit-keyframes bugAnimation {
from {
-webkit-transform: translate(10%, 10%);
background: blue; /* To see the animation */
}
to {
-webkit-transform: translate(10%, 10%);
background: red; /* To see the animation */
}
}
Possible solutions:
Changing the percentage values by viewport units or another.
Obviously that options is not valid for all cases because I need the percentage but it could be a small solution for now if I know the size of the div (vw, vh, px...).
Do somebody know this bug?
Tested on Safari 10.1.1 and iOS 9.3.1 (with webview).
EDIT:
Really I need the translate2D because I am rotating a DIV in the center of the page and the size is unknown, an example:
var div = document.createElement('div');
setTimeout( function(){
document.body.appendChild(div);
}, 500);
div {
background: red;
width: 200px;
height: 200px;
position: fixed;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%, -50%);
-webkit-animation: 1s bugAnimation;
-webkit-transform-origin: center center;
}
#-webkit-keyframes bugAnimation {
from {
-webkit-transform: rotate(0deg) translate(-50%, -50%);
}
to {
-webkit-transform: rotate(360deg) translate(-50%, -50%);
}
}

Ok, a workaround maybe using em instead of %
var div = document.createElement('div');
setTimeout( function(){
document.body.appendChild(div);
}, 500);
div {
background: red;
width: 200px;
height: 200px;
-webkit-animation: 1s bugAnimation forwards;
}
#-webkit-keyframes bugAnimation {
from {
-webkit-transform: translate(0, 0);
background: blue; /* To see the animation */
}
to {
-webkit-transform: translate(1.3em, 1.3em);
background: red; /* To see the animation */
}
}
Ok, please take another look at that approach. I wondered why you are using keyframed animation. Maybe the example is not representative but in this case you can just animate with a simple transition. Please take another look here:
setTimeout(function() {
document.getElementById("div").classList.add("animated");
}, 1000);
div {
background: red;
width: 200px;
height: 200px;
position: absolute;
top: 50%;
left: 50%;
-webkit-transition: transform 1s;
-moz-transition: transform 1s;
-ms-transition: transform 1s;
-o-transition: transform 1s;
transition: transform 1s;
}
.animated {
transform: translate(-50%, -50%) rotate(360deg);
}
<div id="div"></div>

Looks like a Mac Safari issue,
I removed -webkit-transform property from keyframes which fixes the jumping problem on Safari and also works fine on Chrome too. Try this code,
var div = document.createElement('div');
setTimeout( function(){
document.body.appendChild(div);
}, 500);
div {
background: red;
width: 200px;
height: 200px;
-webkit-transform: translate(10%, 10%);
-webkit-animation: 1s bugAnimation;
}
#-webkit-keyframes bugAnimation {
from {
background: blue; /* To see the animation */
}
to {
background: red; /* To see the animation */
}
}

Related

Is there a way to make an element spin around without a variable telling how far it has already turned?

I have an experimental website that plays music, and I want the forward and backward buttons to spin when you click them. But, I also don't want to have 2 variables to be how far they have turned, or a function to get how far they have turned from the CSS transform property. They have a transition, for hover effects. I have tried
backward.classList.add("notrans");
backward.style.transform = "rotateZ(0deg)";
backward.classList.remove("notrans");
backward.style.transform = "rotateZ(-360deg)";
and some closely related things, and also have a setTimeout to reset it afterwards, which it too long for a post.
Animate is what you are searching for.
This should be a working example: (Tested in FF and Chrome)
/* THIS IS A JAVASCRIPT CLASS THAT ADDS AND
REMOVES THE CSS CLASS FROM YOUR ELEMENT
USING THE ELEMENT'S ID VALUE TO REFERENCE. */
function startStop(strstp) {
var infinite = document.getElementById("imSpinning");
var once = document.getElementById("imSpinningOnce");
if(strstp == 1)
{
infinite.classList.add("spin");
once.classList.add("spinOnce");
timer = setTimeout(function() {
once.classList.remove("spinOnce");
},1000);
}
else
{
infinite.classList.remove("spin");
once.classList.remove("spinOnce");
}
}
/* THIS IS THE CSS CLASS THAT CREATES INFINITE ROTATION */
.spin {
-webkit-animation:spin 1s linear infinite;
-moz-animation:spin 1s linear infinite;
animation:spin 1s linear infinite;
}
#-moz-keyframes spin { 100% { -moz-transform: rotate(360deg); } }
#-webkit-keyframes spin { 100% { -webkit-transform: rotate(360deg); } }
#keyframes spin { 100% { -webkit-transform: rotate(360deg); transform:rotate(360deg); } }
/* THIS IS THE CSS CLASS THAT ROTATES ONCE */
.spinOnce {
-webkit-animation:spin 1s linear;
-moz-animation:spin 1s linear;
animation:spin 1s linear;
}
#-moz-keyframes spinOnce { 100% { -moz-transform: rotate(360deg); } }
#-webkit-keyframes spinOnce { 100% { -webkit-transform: rotate(360deg); } }
#keyframes spinOnce { 100% { -webkit-transform: rotate(360deg); transform:rotate(360deg); } }
<div style="width: 100px; height: 30px; background-color: green; color: white; margin: 20px; text-align: center; cursor: pointer;" onclick="startStop(1)">
GO
</div>
<div style="width: 100px; height: 30px; background-color: red; color: white; margin: 20px; text-align: center; cursor: pointer;" onclick="startStop(0)">
STOP
</div>
<!-- ELEMENT TO ROTATE INFINITLY WITH "spin" CLASS -->
<div id="imSpinning" class="spin" style="position: absolute; top: 10px; right: 30px; height: 140px; width: 140px; background-image: url(https://icons.iconarchive.com/icons/thehoth/seo/256/seo-web-code-icon.png); background-size: 100% 100%; background-position: center center; border-radius: 50%; overflow: hidden;"></div>
<!-- ELEMENT TO ROTATE ONCE WITH "spin" CLASS -->
<div id="imSpinningOnce" class="spinOnce" style="position: absolute; top: 10px; right: 200px; height: 140px; width: 140px; background-image: url(https://icons.iconarchive.com/icons/thehoth/seo/256/seo-web-code-icon.png); background-size: 100% 100%; background-position: center center; border-radius: 50%; overflow: hidden;"></div>
Simply copy the CSS class above to the style section/sheet of your page and modify it as needed. Ensure you reference the class in your html element.
Also I edited in a small JavaScript class that add/removes the spin class from the DIV element if it helps you in starting and stopping the animation.
Hope this helps, and best of luck!

Transitioning anchor side

I've got a container, which contains some things including a box at the bottom. I have a need to transition that box from the bottom to the top.
from {
bottom: 4px;
top: auto;
}
to {
bottom: auto;
top: 4px;
}
For obvious reasons, this doesn't work. You can't transition/animate with an auto value. I've worked around this by having the box fade out and slide off the bottom, then fade in and slide on the top. This works, but it feels longer than it needs to be.
The box has dynamic height, and the entire thing is responsive so pre-calculated values are right out.
Any ideas? Or is what I have now the best I can do?
So it's definitely possible, but instead of trying to achieve it with a combination of top and bottom, you can achieve it with using top and translate. This will allow you to have a clear point for your stop and start whilst still giving you the freedom of a responsive container.
It would look something like this:
from {
top: 4px;
transform: translateY(0);
}
to {
top: calc(100% - 4px);
transform: translateY(-100%);
}
Here's an example in action, (I've used a textarea so that you can resize and keep testing, the button(+js) is just there to help facilitate the class change)
$('.go').click(function(){
$('textarea').toggleClass('up');
});
textarea {
position: fixed;
top: 0;
-webkit-transform: translateY(0);
transform: translateY(0);
-webkit-transition: all 1s ease 0s;
transition: all 1s ease 0s;
left: 150px;
}
textarea.up {
top: 100%;
-webkit-transform: translateY(-100%);
transform: translateY(-100%);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="go">
TRANSITION
</button>
<textarea></textarea>
And a Fiddle if you prefer that instead.
You can simulate the top property by using the calc() CSS function :
from {
bottom: 4px;
}
to {
bottom: calc(100% - 4px - yourContainerHeight);
}
You can use animations to do this. You don't have to change bottom to top. Just use one of them. I chose to use 'bottom' . Then to simulate the top:4px you move the box with bottom:calc(100% - 4px) and together with transform:translateY(100%) . This is equal to top:4px .
see snippet below
.container {
height: 300px;
width: 300px;
border: 1px solid red;
position: relative;
}
.box {
position: absolute;
bottom: 4px;
background: red;
width: 100%;
height: 10px;
animation-name: fromBottom;
animation-delay: 1s;
animation-duration: 0.8s;
animation-fill-mode: forwards;
animation-timing-function: ease-out;
transform: translateY(0%)
}
#keyframes fromBottom {
0% {
bottom: 0;
transform: translateY(0%)
}
100% {
bottom: calc(100% - 4px);
transform: translateY(100%)
}
}
<div class="container">
<div class="box">
</div>
</div>

Alternative to using position absolute for page transitions in a SPA

I am building a Single Page Application and I am using position absolute on my views (pages) in order to achieve page transitions while I navigate to different pages. I am using css animations and the effect I am after is one page to slide out to the right and at the same time the next page to slide in from the left.
This works fine as it is, but the problem is that most mobile browsers render the absolute positioned elements as a different layout and this has a negative effect on performance.
I wonder if there is an alternative to absolute positioning in order to achieve the effect I described above. I have tried to use display: flex and float: left, but could not achieve the same effect.
Check a very basic example of what I am doing:
#-webkit-keyframes moveFromLeft {
from { -webkit-transform: translateX(-100%); }
}
#keyframes moveFromLeft {
from { -webkit-transform: translateX(-100%); transform: translateX(-100%); }
}
#-webkit-keyframes moveToRight {
from { }
to { -webkit-transform: translateX(100%); }
}
#keyframes moveToRight {
from { }
to { -webkit-transform: translateX(100%); transform: translateX(100%); }
}
.moveFromLeft {
-webkit-animation: moveFromLeft .7s ease both;
animation: moveFromLeft .7s ease both;
}
.moveToRight {
-webkit-animation: moveToRight .7s ease both;
animation: moveToRight .7s ease both;
}
html,
body,
.page-container {
height: 100%;
position: relative;
width: 100%;
}
.page {
height: 400px;
color: #FFF;
position: absolute;
left: -100%;
top: 0;
width: 100%;
display: none;
}
.page.active {
display: block;
left: 0;
}
.page1 {
background: #000;
}
.page2 {
background: #0F0;
}
Fiddle

How can I recreate this masking effect in CSS/JavaScript?

I'm trying to recreate the effect shown in the gif here. It's fine even to have two separate images - I don't need to recreate the greyscale/blur effect (although I can with webkit filters) - it's just the masking that I'm having trouble with.
Basically I've got a carousel slider, and as it slides left and right, the background underneath the current slide will be blurred, to make the text on top more visible. I can't manage to keep the background in the same place as the slider moves along as a mask. How can I recreate this?
edit: I've managed to figure this out: http://jsfiddle.net/9xk410wk/18/
I used CSS transforms in opposite directions:
.tile {
-webkit-transform: translate3d(-400px, 0px, 0px);
}
.blur > div {
-webkit-transform: translate3d(400px, 0px, 0px);
}
.tile:hover {
-webkit-transform: translate3d(400px, 0px, 0px);
}
.tile:hover .blur > div {
-webkit-transform: translate3d(-400px, 0px, 0px);
}
You could use a webkit grayscale filter for this:
FIDDLE (hover over the image to see the effect)
Markup
<div class="pic">
<div class="mask">SLIDER</div>
</div>
CSS
.pic {
width:288px;
height: 214px;
background: url(https://dl.dropboxusercontent.com/u/51558405/pic.png) no-repeat;
position:relative;
overflow: hidden;
}
.pic:hover .mask {
-webkit-transform: translate3d(228px, 0, 0);
background-position: 100% 0;
}
.mask {
width: 60px;
height: 214px;
position: absolute;
left:0;
top:0;
color: #fff;
background: url(https://dl.dropboxusercontent.com/u/51558405/pic.png) 0 0 no-repeat;
-webkit-transition: all 1.5s linear;
transition: all 1.5s linear;
-webkit-transform: translate3d(0, 0, 0);
-webkit-filter: grayscale(100%);
z-index:1;
}
I'm not sure exactly the issue you are running into without seeing code, but here is a crude fiddle that I created which mimics the gif:
http://jsfiddle.net/z71g26by/
I just used a CSS3 linear animation and changed the opacity of the moving panel. I just used colors, but it should work the same with a background image.
CSS:
body {
/*To hide the horizontal scroller */
overflow: hidden;
}
.container {
width: 500px;
height: 420px;
background-color:blue;
}
.panel {
width: 200px;
height: 420px;
background-color: white;
opacity: .8;
-webkit-animation: move 5s linear infinite;
}
#-webkit-keyframes move {
0% {margin-left: 1000px;}
100% {margin-left: -1000px;}
}
HTML:
<div class="container">
<div class="panel"><p>SLIDER</p></div>
</div>
Note: This only works in webkit, but you can add the appropriate pre-fixes to get it working in other browsers.

get #keyframe current value in css3 with javascript

See the demo here:
http://jsfiddle.net/hamidrezabstn/fgcPa/5/
When I click on the middle raindrop , I would like it to rotate to the current position of the spinning circle! I tried below the JS code but it doesn't work! The next thing I want to do is the raindrop rotate with spining circle!
$(function() {
$('#center').click(function() {
var pos = $('#circle').css('transform')
$(this).css('transform', 'pos')
});
});
$(function() {
$('#center').click(function() {
var obj, matrix;
obj = document.getElementById('circle');
matrix = getComputedStyle(obj).getPropertyValue('transform');
console.log(matrix);
//$(this).css('transform', matrix)
});
});
read more here http://dev.opera.com/articles/view/understanding-3d-transforms/
EDITED: I said that it is not posible to get the current status of the transform in an animation, but I was wrong. Sorry about that !
To do what you want, any way, you don't need really to get it; just use it.
I have changed slightly your HTML to put the raindrop inside the rotating div.
Then, with this CSS:
.raindrop {
background:center blue;
width:50px;
height:50px;
border-radius: 100%;
border-top-left-radius: 0;
position: absolute;
margin: auto;
left: 75px;
top: 75px;
animation: ccircle 5s infinite linear;
-webkit-animation: ccircle 5s infinite linear;
}
.raindrop:hover {
animation: none;
-webkit-animation: none;
}
.axis {
width: 200px;
height: 200px;
transform: scaleX(2);
background-color: none;
border: 1px solid black;
left: 50px;
position: absolute;
top: 50px;
border-radius: 50%;
}
.rotate {
width: 100%;
height: 100%;
top: 0px;
animation: circle 5s infinite linear;
-webkit-animation: circle 5s infinite linear;
transform-origin: 50% 50%;
-webkit-transform-origin: 50% 50%;
position: absolute;
}
.counterrotate {
width: 50px;
height: 50px;
animation: ccircle 5s infinite linear;
-webkit-animation: ccircle 5s infinite linear;
}
.planet {
width: 50px;
height: 50px;
position: absolute;
border-radius : 50px;
left: 0px;
top: 0px;
background-color: red;
display: block;
}
#keyframes circle {
from { transform: rotateZ(0deg) }
to { transform: rotateZ(360deg) }
}
#-webkit-keyframes circle {
0% { -webkit-transform: rotateZ(0deg) }
100% { -webkit-transform: rotateZ(360deg) }
}
#keyframes ccircle {
from { transform: rotateZ(360deg) }
to { transform: rotateZ(0deg) }
}
#-webkit-keyframes ccircle {
from { -webkit-transform: rotateZ(360deg) }
to { -webkit-transform: rotateZ(0deg) }
}
You got this fiddle
In it, the raindrop is always rotating with the axis div. But it is also counter-rotating, so it appears to be static.
When you hover it, the count-rotation is disabled, and it points to red circle. And will continue to do so as long as you hover it.
To do that thru a click, just asociate the :hover properties to a class, and set this class in the click.

Categories

Resources