Search code examples
javascriptcsscss-position

Anchoring absolutely positioned elements to the top or bottom when they scroll off screen


I have a container that scrolls up and down vertically. Within the container there are some absolutely positioned items. Here is an example to illustrate.

#body {
  height: 200px;
  overflow: scroll;
  font-family: sans-serif;
  font-size: 40px;
}

#container {
  width: 100%;
  height: 600px;
  background-color: rgba(255, 0, 0, 0.1);
  position: relative;
  display: flex;
  align-items: start;
  justify-content: center;
}

#item {
  display: inline;
  background-color: rgba(0, 0, 255, 0.1);
  padding: 10px 20px;
  border-radius: 5px;
  position: absolute;
  top: 150px;
}
<div id="body">
  <div id="container">
    <div id="item">
      Hello
    </div>
  </div>
</div>

I want to make sure a little portion of the item is always visible as the user scrolls up and down, so that the user can always see something there, and doesn't lose track of it. When the user scrolls too far down, it should look like this...

An image showing a small portion of the item at the top of the screen

Conversely, if the user scrolls too far up, it should look like this...

An image showing a small portion of the item at the bottom of the screen

It's also important that the element can be positioned anywhere in the container.

Is this possible with pure CSS? If this is not possible, what's the most efficient approach to achieving the same result with pure CSS & JS (bearing in mind the container might have multiple items in it)?

Proposed duplicate

This question was suggested as a duplicate, but I don't think it is what I am seeking. This question is about anchoring elements to the top AND bottom of a scroll window depending on position. The provided question does not cover that, it only covers how to anchor things on one edge.


Solution

  • Not sure if I understand the conditions correctly, but assuming the goal is to have #item always partially visible while scrolling within the container, perhaps try set position: sticky on #item.

    This way, the offset range of #item when it sticks to the border can be specified by top and bottom.

    Example:

    #body {
      height: 200px;
      overflow: scroll;
      font-family: sans-serif;
      font-size: 40px;
      background-color: rgba(255, 0, 0, 0.1);
    }
    
    #container {
      width: 50%;
      margin: 0 auto;
      height: 900px;
      position: relative;
      display: flex;
      flex-direction: column;
      justify-content: center;
    }
    
    #item {
      background-color: rgba(0, 0, 255, 0.1);
      padding: 10px 20px;
      border-radius: 5px;
      position: sticky;
      top: -50px;
      bottom: -50px;
    }
    
    #spacer {
      height: 220px;
    }
    <div id="body">
      <div id="container">
        <div id="spacer"></div>
        <div id="item">
          Hello
        </div>
      </div>
    </div>