Skip to content
Advertisement

Css transition absolute to fixed

I have a child inside a parent and I would like to animate child from its start position to page bottom into fixed position. Obviously animation is not “full” because position changes from absolute to fixed when animation starts, which I understand breaks the animation. Would this be possible to achive somehow ? I dont mind some more html if necessary.

  var a = document.querySelector('.mini')

  document.body.addEventListener('click', function() {

    a.classList.add('hov')

  })
.parent {
  position: absolute;
  left: 0;
  top: 0;
  background: #ccc;
  height: 300px;
  width: 300px;

}

.mini {
  position: absolute;
  bottom: 200px;
  right: 0;
  background: orange;
  height: 100px;
  transition: all 0.5s;
  width: 300px;

}

.hov {
  position: fixed;
  bottom: 0;
  right: 0;

}
<div class="parent">
  <div class="mini">

    <div class="b">Maecenas eu erat condimentum neque molestie tincidunt. Fusce egestas, est ut fringilla facilisis, quam purus blandit dui, eget egestas mauris nibh ut diam. Phasellus volutpat. Sed fringilla tellus in sem.</div>

  </div>
</div>

Advertisement

Answer

An approach I’ve used is animating the element while it still has absolute positioning, then right after it’s done animating, add a fixed position value to it.

And to achieve this, the element is first appended to the body, so it can move within the bounds of the document, which is basically the entire screen. And in case the element is to be returned back to it’s original position, the takeMeBack() function does the whole job, which in this case every successive click either does the animation or undoes it.

var a = document.querySelector('.mini')
var p = document.querySelector('.parent')

let counter = 1;
document.body.addEventListener('click', function() {

    /* Obsolete Section -- Use in case tweaking position is needed
    when element is not at the edge of the page*/
    let pos_childTop = a.offsetTop;
    let pos_childLeft = a.offsetLeft;
    let pos_parentTop = p.offsetTop;
    let pos_parentLeft = p.offsetLeft;
    
    let absLeft = pos_childLeft + pos_parentLeft;
    let absTop = pos_childTop + pos_parentTop;

    // console.log(absLeft)
    // console.log(absTop)
    /* End of tweaking section */
    
    if(counter%2 != 0){
        // make the body its parent
        document.body.appendChild(a);
        a.style.setProperty('--right-location', 'calc(100% - 300px)');
        a.style.setProperty('--bottom-location', 'calc(100% - 100px)');

        a.classList.add('hov');
        setTimeout(() => {
            a.style.position = "fixed";
        }, 1001)
        // give fixed position after placement in document
    }
    else {
        // Take element back to its original position
        // And make the '.parent' div its parent again
        takeMeBack();
    }

    counter++;
})

function takeMeBack(){
    p.appendChild(a);
    a.classList.remove('hov')
    a.style.position = "absolute";
    // revert element's position
}
:root {
    --right-location: 0;
    --bottom-location: 0;
}

body {
    padding: 0;
    margin: 0;
}

.parent {
    position: absolute;
    left: 0;
    top: 0;
    background: #ccc;
    height: 300px;
    width: 300px;
}

.mini {
    position: absolute;
    bottom: 200px;
    right: 0;
    background: orange;
    height: 100px;
    width: 300px;
}

.hov {
    animation: shift 1s forwards;
}

@keyframes shift {
    from { right: var(--right-location); bottom: var(--bottom-location); }
    to { right: 0px; bottom: 0px; }
}

#revert {
    position: fixed;
    top: 0;
    right: 0;
}
<body>
    <div class="parent">
        <div class="mini">
        
            <div class="b">Maecenas eu erat condimentum neque molestie tincidunt. Fusce egestas, est ut fringilla facilisis, quam purus blandit dui, eget egestas mauris nibh ut diam. Phasellus volutpat. Sed fringilla tellus in sem.</div>
        
        </div>
    </div>
</body>
User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement