Sticky to the center of the visible area

32 Views Asked by At

I have a big button with an icon at the center. When the button is partially scrolled off the screen, I need an icon to be still at the center of the visible part of the button. Is it possible to achieve this with CSS sticky or JavaScript intersectionObserver?

This is what I need:

enter image description here

Here's the source code, https://jsfiddle.net/kasheftin/exjv8s5q/1/

const wrapper = document.querySelector('.wrapper')
const button = document.querySelector('.button')
const icon = document.querySelector('.icon')
wrapper.addEventListener('scroll', () => {
    const wrapperBox = wrapper.getBoundingClientRect()
    const buttonBox = button.getBoundingClientRect()
    const iconBox = icon.getBoundingClientRect()
  
  const my = (Math.max(wrapperBox.top, buttonBox.top) + Math.min(wrapperBox.bottom, buttonBox.bottom)) / 2
  const y = Math.min(buttonBox.height - iconBox.height, Math.max(0, my - buttonBox.top - iconBox.height / 2))
    icon.style.top = y + 'px'
  
  const mx = (Math.max(wrapperBox.left, buttonBox.left) + Math.min(wrapperBox.right, buttonBox.right)) / 2
  const x = Math.min(buttonBox.width - iconBox.width, Math.max(0, mx - buttonBox.left - iconBox.width / 2))
    icon.style.left = x + 'px'
})
.wrapper {
  width: 400px;
  height: 300px;
  overflow: scroll;
  position: relative;
}

.container {
  width: 1000px;
  height: 1000px;
  position: relative;
}

.button {
  position: relative;
  top: 300px;
  left: 300px;
  width: 200px;
  height: 100px;
  background-color: #dedede;
}

.icon {
  position: absolute;
  top: 0;
  left: 0;
  width: 20px;
  height: 20px;
  background-color: grey;
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
}
<div class="wrapper">
  <div class="container">
    <div class="button">
      <div class="icon">
        +
      </div>
    </div>
  </div>
</div>

However, I feel there must be a simpler way to achieve what I want using MutationObserver maybe, or something else, without getBoundingClientRect on every scroll.

0

There are 0 best solutions below