【 front end 】 This should be the end, add the explanation and modify some concepts.

The basic effect

Example from MDN: position: sticky; top: 20px;

The feature description

Read MDN and the big guys’ explanation, popular summary is as follows:

  • It’s the same as usualposition:static;
  • inDisplays a prerequisite that does not exceed its parent elementDown, as far as possible withRecentlyrolling ancestorMaintain the specified minimum distance
  • Using theposition:sticky;The element creates a new one for its childrenStacking Context

Last scroll ancestor: position:sticky; Element, the first overflow-x or overflow-y ancestor node encountered that is not visible. If it doesn’t, take the ViewPort (that is, the browser window). A simple search algorithm is as follows:

function getStickyParent(node) {
  const parent = node.parentElement;
  if(! parent)return null;
  const style = window.getComputedStyle(parent);
  const overflows = style.overflow.split("");
  if (overflows.some((o) = >o ! = ="visible")) {
    return parent;
  }
  return getStickyParent(parent);
}
Copy the code

Common misconceptions about

The back can be seen or not seen, personal experience in the pit.

Misunderstand “recently-rolled ancestor”

Do not set Overflow :hidden if you see any ancestor element that says sticky; It’s actually a misstatement.

The detailed description should be: If you want an element to sticky to an ancestor element, then the ancestor element needs to set overflow to a non-visible value, and make sure that any element between them cannot have overflow to a non-visible value, otherwise the element will become an unexpected “nearest scrolling ancestor”. Ensure that any ancestor element does not have this value only if you need to sticky the viewPort.

No trigger effect

Let’s start with a demo:

<div style={{ width: 400.height: 400.overflow: "auto"}} ><div style={{ height: 400.background: "green}} ">
    <div style={{ height: 20.width: 20.background: "pink", position: "sticky", top: 0}} / >
  </div>
  <div style={{ height: 400.background: "red}} "/ >
</div>
Copy the code

This makes sense. The pink block initially holds the top 0px as close as possible to the outermost “recent-scrolling ancestor” without going beyond the green block. But at the end of the roll, the red block completely pushed the green block away. At this time, the pink block does not meet the “premise that the display does not exceed its parent element”, so the pink block can only be pushed up against the bottom of the green block.

Let’s put another div#1 on the pink block:

<div style={{ width: 400.height: 400.overflow: "auto"}} ><div style={{ height: 400.background: "green}} ">
    <div id="1">
      <div style={{ height: 20.width: 20.background: "pink", position: "sticky", top: 0}} / >
    </div>
  </div>
  <div style={{ height: 400.background: "red}} "/ >
</div>
Copy the code

This is a common invalidation. Because the parent of the pink block becomes div#1, and the height of div#1 is the height of the pink block by default, the pink block has little room to do anything but scroll along with its parent, div#1

The principle part of this condition: deeply understand the calculation rules of sticky position