2

I have read as much as I can cope with about position sticky in css, but it is not behaving the way I expect. Can somebody please explain?

Here is what I have so far:

#upper {
  width: 200px;
  height: 200px;
  background-color: blue;
}

#middle {
  width: 200px;
  height: 200px;
  background-color: yellow;
  position: sticky;
  left: 100px;
  top: 100px;
}

#lower {
  width: 200px;
  height: 200px;
  background-color: red;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>sticky position</title>
  <link rel="stylesheet" href="sticky.css">
</head>

<body>
  <div id="upper"></div>
  <div id="middle"></div>
  <div id="lower"></div>
</body>

</html>

What I expect

A blue box top left. An overlapping yellow box (top left of yellow box overlapping bottom right of blue box. A red box below the blue box, with a gap of the size of a box.

What happens

The blue and red boxes are where I expect. The yellow box is shifted to the right as expected, but is not shifted vertically and does not overlap the blue box.

What I have discovered

If I change top:100; to top:300; in the css for middle, the yellow box moves down and overlaps with the red box, as I would expect.

Mark Schultheiss
  • 32,614
  • 12
  • 69
  • 100
Mark Stern
  • 31
  • 3
  • 1
    `position: sticky` will not change the actual position of the element. It will remain wherever it is placed as per html and css. What top, left , right and bottom do here is that they tell the browser where to stick the element. Like `top: 0;` will mean it will stick whenever it touches top position of the parent(which is position:relative) – Aniket Pandey Jun 21 '23 at 12:13
  • Reference https://developer.mozilla.org/en-US/docs/Web/CSS/position - note that "sticky" really sort of means "keep it where it is relative to the view window when the view window scrolls" and not keep it relative to the rest of the document. On that reference page choose each and scroll to see what that means. – Mark Schultheiss Jun 21 '23 at 12:21
  • I noticed you have not accepted any of these answers SO I added a second example based on your colored blocks BUT made those "sticky" to further illustrate what sticky does/is used for. IF none of these answers clarify the sticky for you please add more clarification on your remaining challenge to your question. – Mark Schultheiss Jun 21 '23 at 20:45
  • @AniketPandey My example shows that that is not true. The yellow box moved to the right when I added position: sticky; and left: 100px; The question is why it did not also move vertically. – Mark Stern Jun 22 '23 at 13:37
  • Does this answer your question? [How does the "position: sticky;" property work?](https://stackoverflow.com/questions/43707076/how-does-the-position-sticky-property-work) – tom Jun 22 '23 at 13:38
  • Sticky uses the top and bottom for the position where element is supposed to stick. Left and right can stilll be used for relative positioning when `position:sticky`. I neve understood why is that. – Aniket Pandey Jun 22 '23 at 13:59
  • Never use left/right with sticky. Use margin/padding to shift left/right. – Aniket Pandey Jun 22 '23 at 14:00

5 Answers5

2

I guess position: absoulte is what you are looking for:

#upper {
    width: 200px;
    height:200px;
    background-color:blue;
}
#middle {
    width: 200px;
    height:200px;
    background-color:yellow;
    position:absolute;
    left:100px;
    top:100px;
}
#lower {
    width: 200px;
    height:200px;
    background-color:red;
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>sticky position</title>
    <link rel="stylesheet" href="sticky.css">
</head>
<body>
<div id="upper"></div>
<div id="middle"></div>
<div id="lower"></div>
</body>
</html>
tom
  • 9,550
  • 6
  • 30
  • 49
  • this does not have a "gap" as the OP describes - perhaps question as stated lacks clarify what "gap" means if this does not satisfy the question. I edited the question to make a working example which may enhance that clarity – Mark Schultheiss Jun 21 '23 at 12:34
  • The purpose of the question was not to achieve particular functionality. The purpose of the question was to understand what position:sticky; does. I thought I understood it, but my example proved that I did not. Telling me that position:absolute; is what I am looking for misses the point. Also, as @MarkSchultheiss already pointed out, this does not have a gap between the blue and red boxes where the normal position of the yellow box would be. – Mark Stern Jun 22 '23 at 13:28
1

You should not use position to be sticky, instead by using absolute solves the issue. Here is the code:

#upper {
    width: 200px;
    height:200px;
    background-color:blue;
}
#middle {
    width: 200px;
    height:200px;
    background-color:yellow;
    position:absolute;
    left:100px;
    top:100px;
}
#lower {
    margin-top: 200px;
    width: 200px;
    height:200px;
    background-color: red;
}

I have also added a top margin of 200px to the red box so that there is a gap of one box that you wanted.

PS. Position sticky is used when you want some element to stick to a location when scrolling a web page. You may have noticed that navigation bar of some websites remains on the top of the page even if you are scrolling down, in this case position sticky is used.

omerfarooq
  • 36
  • 4
1

Perhaps what you really want is to have the yellow positioned relative to the other elements from its natural "flow" position within the containing element? Here I used a relative position of -100px to do that.

I added a container with a background color so you can see the three elements are positioned within that block.

.container {
  display: block;
  top: 1;
  left: 1;
  border: solid 1px lime;
  padding: 1em;
  background-color: #FF00FF22;
}

#upper {
  width: 200px;
  height: 200px;
  background-color: blue;
  top: 1;
  left: 1;
}

#middle {
  width: 200px;
  height: 200px;
  background-color: yellow;
  position: relative;
  left: 100px;
  top: -100px;
}

#lower {
  width: 200px;
  height: 200px;
  background-color: red;
}
<div class="container">
  <div id="upper"></div>
  <div id="middle"></div>
  <div id="lower"></div>
</div>

Another option is using display: grid like so: Here I did the following:

  • Set a "standard" font size of 16px = 1em
  • set a box size to 9em by 18em
  • Set the three original boxes
  • Added a new "green" box that sticks out past the grid since it is in column 3 and 4 (4 I did not specify so it is just there automatically) and rows 3-5 of the 6 rows of 3em each height.
  • Set the blocks to be sticky but 1em from the top - so it stops scroll there. Go ahead, scroll this sample up/down to see!

body,
* {
  margin: 0;
  padding: 0;
  font-size: 16px;
  box-sizing: border-box;
}

.container {
  position: sticky;
  top: -1em;
  left: 12em;
  margin: 2em;
  display: grid;
  width: 9em;
  height: 18em;
  border: solid 1px lime;
  padding: 1em;
  background-color: #FF00FF22;
  display: grid;
  grid-template-rows: repeat(6, 3em);
  grid-template-columns: 3em 3em 3em;
}

.blocky {
  width: 6em;
  height: 6em;
}

#upper {
  background-color: blue;
  grid-row: 1 / 2;
  grid-column: 1 / 2;
}

#middle {
  background-color: yellow;
  grid-row: 2 / 4;
  grid-column: 2 / 3;
}

#lower {
  background-color: red;
  grid-row: 5 / 6;
  grid-column: 1 / 2;
}

#green {
  background-color: #00FF0040;
  grid-row: 3 / 5;
  grid-column: 3 / 4;
  border: solid 2px #00FF00;
  z-index: -1;
}

.my-list {
  display: inline-block;
  border: solid 1px blue;
  padding: 3em;
  height: 100vh;
}
<div class="container">
  <div class="blocky" id="upper"></div>
  <div class="blocky" id="middle"></div>
  <div class="blocky" id="lower"></div>
  <div class="blocky" id="green"></div>
</div>
<div class="my-list">
  <ol>
    <li>Set a "standard" font size of 16px = 1em</li>
    <li>Set a box size to 9em by 18em</li>
    <li>Set the three original boxes</li>
    <li>Added a new "green" box that sticks out past the grid since it is in column 3 and 4 (4 I did not specify so it is just there automatically) and rows 3-5 of the 6 rows of 3em each height.</li>
    <li>Set the blocks to be sticky but 1em from the top - so it stops scroll there.</li>
  </ol>
</div>
Mark Schultheiss
  • 32,614
  • 12
  • 69
  • 100
0

What you expected can be done with setting the position of the "middle" element as "relative" and changing the "top" property value like below:

#middle {
    position: relative;
    top: -100px;
    /* It should be negative because the initial position (top: 0;) is when the yellow box touches the blue box at the bottom */
}

And "position: sticky" is not applicable here.

Md. Rakibul Islam
  • 2,140
  • 1
  • 7
  • 14
0

I have not found anybody who says this, but I think the answer to my question is that for position: sticky; the left, right, top and bottom attributes specify the minimum distance of the element from the specified edges. So in my case, the normal position of the yellow box is already more than 100 pixels from the top edge of the viewport, so it does not move vertically. However, the normal position is touching the left edge, so it needs to move 100 pixels to the right. That also explains why top:300px; does what I expected.

Mark Stern
  • 31
  • 3