Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Animate fixed element to the center of the viewport

I have an element that is position: fixed; in the upper right corner of the page.
I want it to "grow and move" to the center of the screen when clicked.

The best solution I'm aware of to position something in the dead center of the page is

position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);

Everything works great if I have the element initially positioned with top and left properties, but there is a nasty jump in the animation if the element is initially positioned with right instead of left.

const myFunc = function() {
  let f = document.getElementById('element')

  if (f.className.includes('bar')) {
    f.className = 'foo'
  } else {
    f.className = 'foo bar'
  }
}
.wrapper {
  position: relative;
  width: 100%;
  height: 100%;
}

.foo {
  position: fixed;
  top: 20px;
  right: 20px;
  width: 200px;
  height: 50px;
  background-color: blue;
  transition: 0.5s all;
}

.bar {
  position: fixed;
  top: 50%;
  left: 50%;
  width: 500px;
  height: 500px;
  background-color: red;
  transform: translate(-50%, -50%);
  transition: 0.5s all;
}
<div class="wrapper">
  <div class="foo" id="element" onclick="myFunc()">
  </div>
</div>

Codepen

How do I get rid of the initial jump in the animation to the horizontal center? (i.e. I want the reverse of the "shrinking back to top right", here everything works fine).

like image 383
TommyF Avatar asked Oct 15 '22 15:10

TommyF


1 Answers

You just need to change the right to left on the foo state.
This also implies you change the translate property to : translate(50%,-50%); as the tanslateX value should be from left to right to center the element :

const myFunc = function () {
  let f = document.getElementById('element')

  if(f.className.includes('bar')) {
    f.className = 'foo'
  }
  else {
    f.className = 'foo bar'
  }
}
.wrapper {
  position: relative;
  width: 100%;
  height: 100%;
}

.foo {
  position: fixed;
  top: 20px;
  right: 20px;
  width: 200px;
  height: 50px;
  background-color: blue;
  transition: 0.5s all;
}

.bar {
  position: fixed;
  top: 50%;
  right: 50%;
  width: 500px;
  height: 500px;
  background-color: red;
  transform: translate(50%, -50%);
  transition: 0.5s all;
}
<div class="wrapper">
  <div class="foo" id="element" onclick="myFunc()">
  </div>
</div>

On a side note, if you know the size of your element in both states you could make the transition only on the top and right properties using calc() like this :

const myFunc = function() {
  let f = document.getElementById('element')

  if (f.className.includes('bar')) {
    f.className = 'foo'
  } else {
    f.className = 'foo bar'
  }
}
.wrapper {
  position: relative;
  width: 100%;
  height: 100%;
}

.foo {
  position: fixed;
  top: 20px;
  right: 20px;
  width: 200px;
  height: 50px;
  background-color: blue;
  transition: 0.5s all;
}

.bar {
  position: fixed;
  top: calc(50% - 250px);
  right: calc(50% - 250px);
  width: 500px;
  height: 500px;
  background-color: red;
  transition: 0.5s all;
}
<div class="wrapper">
  <div class="foo" id="element" onclick="myFunc()">
  </div>
</div>

This changes the animation trajectory and prevents the element from beeing animated in one direction with top/right and in the ohter at the same time by the transform property.

like image 74
web-tiki Avatar answered Oct 20 '22 13:10

web-tiki