I've tested this with the scroll container being a div and being the body, and when the container is the body, the sticky position doesn't work properly. It seems to me that the only sticky that works on the body is the top: 0
, but I am trying to apply the left: 0
. I still want to use the body as the scroll container because if I use a div container, the mobile's functionalities won't work (e.g. hiding the search bar when scrolling down). These are the tests:
Body as the container, doesn't work properly
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body style="margin: 0">
<div style="background-color: blue; height: 100px; position: sticky; left: 0">
TEST
</div>
<div style="height: 1000px; width: 1000px; background-color: red">
TEST
</div>
</body>
</html>
I've tested this with the scroll container being a div and being the body, and when the container is the body, the sticky position doesn't work properly. It seems to me that the only sticky that works on the body is the top: 0
, but I am trying to apply the left: 0
. I still want to use the body as the scroll container because if I use a div container, the mobile's functionalities won't work (e.g. hiding the search bar when scrolling down). These are the tests:
Body as the container, doesn't work properly
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body style="margin: 0">
<div style="background-color: blue; height: 100px; position: sticky; left: 0">
TEST
</div>
<div style="height: 1000px; width: 1000px; background-color: red">
TEST
</div>
</body>
</html>
Div as the container, works properly
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body style="margin: 0">
<div style="height: 100dvh; overflow: auto">
<div style="background-color: blue; height: 100px; position: sticky; left: 0">
TEST
</div>
<div style="height: 1000px; width: 1000px; background-color: red">
TEST
</div>
</div>
</body>
</html>
Share
Improve this question
asked Apr 1 at 4:46
CristoferCristofer
654 bronze badges
3 Answers
Reset to default 0Building on the answer by @TemaniAfif, it seems that if you style the body with both overflow: auto
and contain: layout
, the horizontal stickiness works as expected.
body {
margin: 0;
overflow: auto;
contain: layout;
}
<div style="background-color: blue; height: 100px; position: sticky; left: 0">
TEST
</div>
<div style="height: 100px; width: 1000px; background-color: red">
TEST
</div>
Use with caution, though ... I don’t have any experience with strong containment, so I have no idea what negative side-effects this may have.
Another potential implementation, rather than having the body do the horizontal scrolling, would be to have the red element do it. Then you wouldn’t need to use sticky positioning on the blue element or containment control on the body. The body can still take care of the vertical scrolling, but each section takes care of its own horizontal scrolling.
There is a special behavior with the scrolling mechanism when the body
element is involved.
Here are both demos where I am adding some padding and borders:
body {
padding: 20px;
margin: 20px;
border: 5px solid green;
}
<div style="background-color: blue; height: 100px; position: sticky; left: 0">
TEST
</div>
<div style="height: 1000px; width: 1000px; background-color: red">
TEST
</div>
body {
margin: 0;
}
.box {
padding: 20px;
margin: 20px;
border: 5px solid green;
}
<div style="height: 50dvh; overflow: auto" class="box">
<div style="background-color: blue; height: 100px; position: sticky; left: 0">
TEST
</div>
<div style="height: 1000px; width: 1000px; background-color: red">
TEST
</div>
</div>
Notice how in both cases, the sticky element is within the boundaries of its parent container but we don't have the same result when it comes to the scrollbar.
In the first case, you are not scrolling the body element but the whole document (due to an overflow propagation). In the second case, you are scrolling the element with set overflow: auto
You are observing this behaviour because the scrolling context is different in both the cases. 1. Div as the container In this case, the outer div has overflow: auto, which means it creates a new scrolling context. The sticky element (the blue div) is contained within this scrolling context. When you scroll horizontally, the blue div sticks to the left edge of the scrolling container.
2. Body as the container If you remove the outer div (the one with overflow: auto), the sticky div no longer has a scrolling context. Instead, it is now relative to the viewport. When you scroll horizontally, the sticky element does not stick because it is not contained within a scrolling context that allows it to behave as sticky.
However, in both scenarios, when you scroll vertically, the sticky element (the blue div) will stick to the top of its containing block (or the viewport if there is no containing block) once it reaches the top of the viewport. This is because the vertical scroll does not depend on the presence of a scrolling container; it simply needs to reach the top of the viewport.
Hope this helps. Thanks