0

I have two boxes:

<div class='item' style='transform:translateY(100px)'>
</div>

<div class='item' style='transform:translateY(300px)'>
</div>

They both use the same class:

.item {
    position:absolute;
    background:red;
  animation:float 3s ease-in-out infinite;
  width:100px;
  height:100px;
}

The animation looks like:

@keyframes float {
    from, to { transform: translateY(-10px); }
    50% { transform: translateY(10px); }
}

But this makes both boxes go between -10 and 10px. What I'd like is for it to be relative to the current value of the box.

So box1 at y:100px would animate from 90px to 110px and box2 at y:300px would animate from 290px to 310px

Is it possible to do this in css? I'd rather not have a specific animation per box. Because I may have hundred of boxes.

jsfiddle: https://jsfiddle.net/foreyez/1n1en8uk/

This shows that at the point of animation, both boxes are at the same place... but if it were relative animation they would just be floating up and down in their current place.

Note: please don't use top/left to get relative position I'm looking specifically for relative TRANSFORMS. (if you must know why I'm doing this in 3d for the z axis as x,y are already used).

Shai UI
  • 50,568
  • 73
  • 204
  • 309
  • Is `from, to ` valid `css` syntax for `@keyframes`? – guest271314 Sep 21 '16 at 02:50
  • yes because it wouldn't animate otherwise – Shai UI Sep 21 '16 at 02:51
  • Positioning the elements relatively should solve that -> https://jsfiddle.net/adeneo/1n1en8uk/2/ – adeneo Sep 21 '16 at 02:52
  • no it did not, y at 300px looks different than your solution – Shai UI Sep 21 '16 at 02:53
  • You're right, so I'll stick with my original comment, the styles are reset, it doesn't add 10px to what the style was originally, that's just not how it works. – adeneo Sep 21 '16 at 02:54
  • I wouldn't think so, other than using javascript to get the original value and constructing the style – adeneo Sep 21 '16 at 02:57
  • even getting the original value and constructing the style would mean I would have potentially 100s of animation for each of my boxes. so that javascript solution is no good either. – Shai UI Sep 21 '16 at 02:58
  • The bigger problem would probably be that `transform` is just a handy dandy shortcut for setting a matrix, so you won't get those values directly with javascript. – adeneo Sep 21 '16 at 02:59
  • yeah you can get the transform directly with javascript I've done it before.. people just pull out the values from the matrix. see second solution. http://stackoverflow.com/questions/21987596/get-css-transform-property-with-jquery – Shai UI Sep 21 '16 at 03:01
  • Well, that's not "directly" is it, it requires splitting and somewhat parsing the matrix, but it seems fairly straight forward for this value, sometimes it's a pain. – adeneo Sep 21 '16 at 03:05
  • adeneo, just noticed you have 200k rep. respect. – Shai UI Sep 21 '16 at 03:20
  • Interesting. Have not previously viewed `from, to` syntax. Appears to effect of rendering element in a fixed position during animation https://jsfiddle.net/x2qs8w99/. Are you trying to render the two elements appearing to move opposite to the other? While one element is moving vertically down, the other element is moving vertically up? – guest271314 Sep 21 '16 at 03:22
  • Or, are you trying to animate the elements vertically up and down separated by space within the same vertical column? – guest271314 Sep 21 '16 at 03:29
  • Found the specification does mention _"The [``](https://drafts.csswg.org/css-animations/#typedef-keyframe-selector) for a `` consists of a comma-separated list of percentage values or the keywords from or to."_ – guest271314 Sep 21 '16 at 03:47

3 Answers3

1

You can set position of .item elements to relative; use :nth-of-type() pseudo selector to set the top property of each element to the initial position where element should be animated from between the 20px range in relation to its .item sibling.

.item {
  position: relative;
  background: red;
  animation: float 3s infinite ease-in-out;
  width: 100px;
  height: 100px;
}
.item:nth-of-type(1) {
  top: 100px;
}
.item:nth-of-type(2) {
  top: 300px;
}
@keyframes float {
  from, to {
    transform: translateY(-10px);
  }
  50% {
    transform: translateY(10px);
  }
}
<div class="item">
</div>
<div class="item">
</div>

jsfiddle https://jsfiddle.net/1n1en8uk/3/

guest271314
  • 1
  • 15
  • 104
  • 177
  • thanks, I forgot to add I can't use top or left. I'm actually using this in 3 dimensions so need to do this on the Z transform, and all my boxes have the value set as TranslateZ. so this must work in Z. but yeah, the hack of using top/left to get relative is a good one. – Shai UI Sep 21 '16 at 03:47
  • 1
    also instead of nth of type, could've just set the top in the div style. – Shai UI Sep 21 '16 at 03:51
  • @foreyez _"I forgot to add I can't use top or left."_ Original Question did not include that `top` and `left` properties could not be used to meet requirement. – guest271314 Sep 21 '16 at 03:55
  • 1
    yes, for 90% of the time your solution is great though. unfortunately I'm looking for the z axis animation. should've been clearer. – Shai UI Sep 21 '16 at 03:59
0

Here's a nasty javascript solution (yes, I'm looking for a CSS solution that's why I won't mark this as the answer) that injects a dynamic keyframe to the page:

As long as there are less than 100 boxes should work alright I guess.

https://jsfiddle.net/foreyez/6v7n4ro3/

function getTranslateY(obj)
{
 var transformMatrix = obj.css("-webkit-transform") ||
   obj.css("-moz-transform")    ||
   obj.css("-ms-transform")     ||
   obj.css("-o-transform")      ||
   obj.css("transform");
 var matrix = transformMatrix.replace(/[^0-9\-.,]/g, '').split(',');
 var x = matrix[12] || matrix[4];//translate x
 var y = matrix[13] || matrix[5];//translate y
  return parseInt(y);
}

function insertAnimation(idx, yy)
{
  var style1 = document.documentElement.appendChild(document.createElement("style")),
  rule1 = "@keyframes float" + idx + " {\
    from, to { transform: translateY("+ (yy-10) +"px); }\
    50% { transform: translateY(" + (yy+10) + "px); }\
  }";

  style1.sheet.insertRule(rule1, 0);
}

$(".item").each(function(idx) {

var currentTranslateY = getTranslateY($(this));
insertAnimation(idx, currentTranslateY);
  $(this).css('animation','float' + idx + ' 3s ease-in-out infinite');
});
Shai UI
  • 50,568
  • 73
  • 204
  • 309
  • Original requirement at OP appears to be to use `css`? _"How to animate with relative transforms in css?"_ ? – guest271314 Sep 21 '16 at 03:51
  • _"yes, but there's no way unfortunately. :( "_ Are you certain there is "no way" using only `css`? Or is using `css` only not part of requirement? – guest271314 Sep 21 '16 at 03:53
  • _"as of now there is no way, but hopefully someone will come and prove me wrong."_ Well, there is a way using `top`, though the exclusion of `top`, `left` was not described at original Question. Also, original Question is "How to animate with relative transforms in css?", not `css` or `javascript`? – guest271314 Sep 21 '16 at 03:59
  • The `javascript` tag is included at Question. If you believe your Answer to the Question to be the best, you can accept your own Answer. See [Can I answer my own question?](http://stackoverflow.com/help/self-answer) – guest271314 Sep 21 '16 at 04:05
  • If you are seeking a `css` solution, why post a `javascript` solution? Describe "there's no way" referencing a `css` solution? It is your Question, though why invite other `javascript` answers if actual requirement is to use `css`? It is a good `css` Question. – guest271314 Sep 21 '16 at 04:09
  • When title of thread states "in css", that is rational expectation of requirement. E.g., see [How can I make an image carousel with only CSS?](http://stackoverflow.com/questions/30295085/how-can-i-make-an-image-carousel-with-only-css/) . _"do you really have nothing else to do btw then these inane comments?"_ Words are important. Specific parameters of requirements to resolve an issue are important. Calling names does not clarify actual required approach to resolve Question. – guest271314 Sep 21 '16 at 04:14
  • you talk like T-800 model 101 with a glitch of ocd. did cyberdyne systems create you? I should have you go through the turing test. it's like your brain is fried. maybe this will compute: I didn't mark it as the answer. – Shai UI Sep 21 '16 at 04:26
  • _"did cyberdyne systems create you?"_ Better than that. The source of all sources created this energy, and the source of all sources is this energy. – guest271314 Sep 21 '16 at 04:30
  • I do appreciate your answer though, and as mentioned will work 90% of the time, just not in my specific case. thanks again. – Shai UI Sep 21 '16 at 04:41
  • No worries. Composed another `css` solution. Though does not use `transform` entirely to render the expected effect. Created an `html` container element to set vertical position of both elements beginning at `translateY(100px)`, adjust `margin` property at first `.item` element within container element to display space between the elements. – guest271314 Sep 21 '16 at 04:43
  • You could also utilize `html` `
    ` elements to display a space between elements, using `transform` property only, without using `margin` property.
    – guest271314 Sep 21 '16 at 04:52
0

Note: please don't use top/left to get relative position I'm looking specifically for relative TRANSFORMS.

You can adjust html to single .item element as child of a container element with transform set to translateY(100px), position set to absolute; utilize css :after pseudo element at .item element with transform set to translateY(200px)

.float {
  transform: translateY(100px);
  position: absolute;
}
.item {
  animation: float 3s infinite ease-in-out;
}
.item, .item:after {
  display: block;
  position: relative;
  background: red;
  width: 100px;
  height: 100px;
}
.item:after {
  content: "";
  transform: translateY(200px);
}
@keyframes float {
  from, to {
    transform: translateY(-10px);
  }
  50% {
    transform: translateY(10px);
  }
}
<div class="float">
  <div class="item">
  </div>
</div>

jsfiddle https://jsfiddle.net/1n1en8uk/5/

guest271314
  • 1
  • 15
  • 104
  • 177