An HTML element with CSS position: sticky
applied might not work in a flexbox layout for the following reasons:
- Sticky Element Has Same or Larger Height Than Parent;
- Sticky Element Is Stretched to Same Height As Parent;
- No Threshold Is Specified;
- Overflowing Parent or Ancestor Doesn't Have Height.
If neither of these help you solve your issue, then you might want to check for browser compatibility and other common issues.
#Sticky Element Has Same or Larger Height Than Parent
Problem
If the sticky element's height
is explicitly (or implicitly) set to an equal or larger value than its parent, then the sticky element ends up having no room for scrolling within its container. For example:
#parent { display: flex; gap: 5px; }
#parent > div { height: 200px; }
#sticky { position: sticky; top: 0; }
This will make all flex items the same height
, producing an output like the following:
height: 200px
height: 200px
position: sticky
height: 200px
As you can see in this example, the sticky has no place to move within as it occupies the entire height of its container.
Solution
To make the sticky element stick to its container in this instance, you can do either of the following:
- Make the height of the sticky smaller, or;
- Make the height of the parent larger.
With either of the changes, the idea is to make room for the sticky element to move within. For example, you can make the height
of the sticky element smaller than its parent when all flex items are explicitly set to the same height:
#parent { display: flex; gap: 5px; }
#parent > div { height: 200px; }
#sticky { height: 60px !important; position: sticky; top: 0; }
With these changes, the output will be like the following:
height: 200px
height: 200px
position: sticky
height: 60px
#Sticky Element Is Stretched to Same Height As Parent
Problem
Whenever the sticky element is stretched, it will occupy the entire height of its container, leaving no room for it to move within. This can be the case in the following scenarios:
#parent |
#sticky |
Description |
---|---|---|
align-items: normal (default) |
align-self: auto (default) |
These default values are implicitly set, and behave as stretch in a flexbox. |
align-items: stretch |
align-self: auto (default) |
All flex items will compute to the parent's align-items value, and end up being enlarged to fill the container. |
align-items: ... /* any value */ |
align-self: stretch |
align-self takes precedence, and consequently, the sticky item is stretched to fill the container. |
You can see the result of applying these combinations in the following examples:
-
When both, parent and sticky elements have the default value (i.e.,
align-items: normal
andalign-self: auto
respectively), the sticky element is stretched:OneTwo
has
extra
text
to
stretch
the
container#sticky
align-self: auto
In this case,
align-items: normal
andalign-self: auto
are implicitly set if no other value is specified (as they're both default values):#parent { display: flex; gap: 5px; /* align-items: normal; */ } #sticky { /* align-self: auto; */ position: sticky; top: 0; }
You can also explicitly set these values and have the same result:
#parent { display: flex; gap: 5px; align-items: normal; } #sticky { align-self: auto; position: sticky; top: 0; }
-
When the parent and the sticky element have
align-items: stretch
andalign-self: auto
respectively, then all flex items will compute to the parent'salign-items
value, and end up being stretched to fill the container:OneTwo
has
extra
text
to
stretch
the
container#sticky
align-self: auto
In this case,
align-self: auto
is the default value for flex items, and is implicitly set if no other value is specified:#parent { display: flex; gap: 5px; align-items: stretch; } #sticky { /* align-self: auto; */ position: sticky; top: 0; }
You can also explicitly set flex items to
align-self: auto
to the same effect:#parent { display: flex; gap: 5px; align-items: stretch; } #sticky { align-self: auto; position: sticky; top: 0; }
-
When the sticky element has
align-self: stretch
, it takes precedence over parent'salign-items
value, resulting in the sticky element being stretched to fill the container, like so:OneTwo#sticky
align-self: stretch
For example:
#parent { display: flex; gap: 5px; align-items: center; } #sticky { align-self: stretch; position: sticky; top: 0; }
Solution
In these cases, you need to make sure the sticky element is not stretched, i.e.:
- It has a value other than
align-self: stretch
, or; - When it is set to
align-self: auto
(default), the parent is not set toalign-items: normal
(default), oralign-items: stretch
.
To fix issues with the previously shown stretched sticky elements, you can, for example, simply set align-self: start
on the sticky elements to make them appear at the start and avoid them from being stretched:
-
OneTwo
has
extra
text
to
stretch
the
container#sticky
align-self: start
-
OneTwo
has
extra
text
to
stretch
the
container#sticky
align-self: start
-
OneTwo
#sticky
align-self: start
#No Threshold Is Specified
Problem
To ensure proper behavior in sticky positioning, you need to define a threshold to a value other than "auto
" using at least one of the following: top
, right
, bottom
, or left
.
If a threshold isn't specified for the sticky element, its behavior becomes indistinguishable from relative positioning, as you can see in the following example:
#sticky
top: auto
Solution
If you specify a threshold, for example, by setting top
to a value other than auto
, then the sticky will flow within its container till it meets the opposite edge of its containing block:
#sticky
top: 10px
#Overflowing Parent or Ancestor Doesn't Have Height
Problem
The sticky element won't move within its parent if the parent or any of its ancestors compute to an overflow
property other than overflow: visible
— i.e., one of the following:
overflow: hidden
overflow: scroll
overflow: auto
For example:
has
extra
text
to
stretch
the
container
#sticky
align-self: start
Learn more about why position: sticky
does not work with the CSS overflow
property and how to fix it.
Solution
In such a case, you must specify a height
on the overflowing container, which in this case is the parent of the sticky element:
has
extra
text
to
stretch
the
container
#sticky
align-self: start
This post was published (and was last revised ) by Daniyal Hamid. Daniyal currently works as the Head of Engineering in Germany and has 20+ years of experience in software engineering, design and marketing. Please show your love and support by sharing this post.