csscss-transitions

How can I "transform:translate" relative to a previous translate?


I have the following working code which I am attempting to simplify:

[tt] {
  position: relative;
}
[tt]::after {
  bottom: 100%;
  content: attr(tt);
  padding: 5px;
  background: #333;
  color: #fff;
}
[tt]::before,
[tt]::after {
  position: absolute;
/* Middle 3 */
  left: 50%;
  transform: translate(-50%, 50%);
}
/* First 3 */
[tt]:nth-child(-n+3)::before,
[tt]:nth-child(-n+3)::after {
  transform: translate(0 , 50%);
}
/* Last 3 */
[tt]:nth-last-child(-n+3)::before,
[tt]:nth-last-child(-n+3)::after {
  transform: translate(-100%, 50%);
}
/* add animation */
[tt]:hover::before,
[tt]:hover::after {
  animation: tt-move1 100ms ease-out forwards;
  display: block;
}
[tt]:nth-child(-n+3):hover::before,
[tt]:nth-child(-n+3):hover::after {
  animation: tt-move2 100ms ease-out forwards;
}
[tt]:nth-last-child(-n+3):hover::before,
[tt]:nth-last-child(-n+3):hover::after {
  animation: tt-move3 100ms ease-out forwards;
}
@keyframes tt-move1 {
  to {
    transform: translate(-50%, 0);
  }
}
@keyframes tt-move2 {
  to {
    transform: translate(0, 0);
  }
}
@keyframes tt-move3 {
  to {
    transform: translate(-100%, 0);
  }
}

/*For working demo*/
div {
  /*won't work unless set relative, Something that happens in [tt]*/
  top:100px;
  margin: 10px;
  float:left;
  width: 20px;
  height: 20px;
  border: black solid 3px;
}
<div tt="tt1"></div>
<div tt="tt2"></div>
<div tt="tt3"></div>
<div tt="tt4"></div>
<div tt="tt5"></div>
<div tt="tt6"></div>
<div tt="tt7"></div>
<div tt="tt8"></div>
<div tt="tt9"></div>

The above code has a specific animation for each different type of element, something which seems unnecessary. To my knowledge, I am simply applying the same transform to each element (moving the element up along the y-axis) so I expected that the following should also work:

[tt] {
  position: relative;
}
[tt]::after {
  bottom: 100%;
  content: attr(tt);
  padding: 5px;
  background: #333;
  color: #fff;
}
[tt]::before,
[tt]::after {
  position: absolute;
/* Middle 3 */
  left: 50%;
  transform: translate(-50%, 50%);
}
/* First 3 */
[tt]:nth-child(-n+3)::before,
[tt]:nth-child(-n+3)::after {
  transform: translate(0 , 50%);
}
/* Last 3 */
[tt]:nth-last-child(-n+3)::before,
[tt]:nth-last-child(-n+3)::after {
  transform: translate(-100%, 50%);
}

/*****************Changed code*******************/

/* add animation */
[tt]:hover::before,
[tt]:hover::after {
  animation: tt-move 100ms ease-out forwards;
  display: block;
}
@keyframes tt-move {
  to {
    transform: translateY(0);
  }
}
/*///////////////Changed code/////////////////*/

/*For working demo*/
div {
  /*won't work unless set relative, Something that happens in [tt]*/
  top:100px;
  margin: 10px;
  float:left;
  width: 20px;
  height: 20px;
  border: black solid 3px;
}
<div tt="tt1"></div>
<div tt="tt2"></div>
<div tt="tt3"></div>
<div tt="tt4"></div>
<div tt="tt5"></div>
<div tt="tt6"></div>
<div tt="tt7"></div>
<div tt="tt8"></div>
<div tt="tt9"></div>

After some research, I now understand that transform: translateY(Δy); is the same as saying transform: translate(0,Δy); which is causing the unexpected result. Unfortunately that was the only method I have been able to find that looks like it is supposed to do what I wanted.

I am looking for a method to transform:translate that allows the x-axis of a previous transform:translate to stay the same, while only changing the y-axis.

Is there a different way to accomplish this simplification? Or am I stuck using the repetitious code from above?


Solution

  • When you animate transform you have to add any already set values or else they will temporary be overwritten.

    In this case you could animate the bottom instead, which will give the output you want.

    [tt] {
      position: relative;
    }
    [tt]::after {
      bottom: 100%;
      content: attr(tt);
      padding: 5px;
      background: #333;
      color: #fff;
    }
    [tt]::before,
    [tt]::after {
      position: absolute;
    /* Middle 3 */
      left: 50%;
      transform: translate(-50%, 50%);
    }
    /* First 3 */
    [tt]:nth-child(-n+3)::before,
    [tt]:nth-child(-n+3)::after {
      transform: translate(0 , 50%);
    }
    /* Last 3 */
    [tt]:nth-last-child(-n+3)::before,
    [tt]:nth-last-child(-n+3)::after {
      transform: translate(-100%, 50%);
    }
    
    /*****************Changed code*******************/
    
    /* add animation */
    [tt]:hover::before,
    [tt]:hover::after {
      animation: tt-move 100ms ease-out forwards;
    }
    @keyframes tt-move {
      to {
        bottom: 170%;
      }
    }
    /*///////////////Changed code/////////////////*/
    
    /*For working demo*/
    div {
      /*won't work unless set relative, Something that happens in [tt]*/
      top:100px;
      margin: 10px;
      float:left;
      width: 20px;
      height: 20px;
      border: black solid 3px;
    }
    <div tt="tt1"></div>
    <div tt="tt2"></div>
    <div tt="tt3"></div>
    <div tt="tt4"></div>
    <div tt="tt5"></div>
    <div tt="tt6"></div>
    <div tt="tt7"></div>
    <div tt="tt8"></div>
    <div tt="tt9"></div>