Upon revisiting this question after some time, I found PIzmAR's workaround to be helpful. However, it lacks an explanation for the root cause, as pointed out by fy data, and there exists a more effective solution that doesn't involve wrapping HTML elements.
The issue at hand is quite straightforward. The 'sticky' property applies stickiness in both Y and X axes. As the sticky element maintains its position and size within the normal DOM flow, its untransformed state may reach the farthest right edge of the viewport (depending on its width), resulting in overflow. At this point, the sticky element behaves similarly to how it does on the Y axis and stays fixed in position. The culprit here is the 'left: 50%' attribute, much like how 'top:' functions with sticky in a vertical direction.
This outcome wasn't what I needed then, and it's likely not ideal for many others aiming to center-align a sticky element using 'left'. Therefore, the optimal approach is to treat the sticky element as relative and utilize margins for X-axis centering. Here's how:
#box-2 {
top: 0;
left: 0;
transform: translate(0);
margin-left: auto;
margin-right: auto;
}
For demonstration purposes, run the code snippet in fullscreen to view examples:
function updateBoxClasses(boxId, highlighted) {
const box = document.getElementById(boxId);
if (highlighted) {
box.classList.add('highlighted');
box.classList.remove('box');
} else {
box.classList.add('box');
box.classList.remove('highlighted');
}
}
function updateClasses() {
const viewportWidth = window.innerWidth;
if (viewportWidth <= 1000) {
updateBoxClasses('box-ghost', true);
updateBoxClasses('box', true);
updateBoxClasses('box-2', true);
} else {
updateBoxClasses('box-ghost', false);
updateBoxClasses('box', false);
updateBoxClasses('box-2', false);
}
}
updateClasses();
window.addEventListener('resize', updateClasses);
* {
box-sizing: border-box;
}
body {
width: 100%;
padding: 0;
margin: 0;
}
div#container {
height: 2000px;
width: 100%;
position: relative;
}
div#heading {
display: flex;
justify-content: center;
align-items: center;
font-size: 64px;
height: 200px;
border: solid black 2px;
}
#box, #box-2 {
position: sticky;
left: 50%;
transform: translateX(-50%);
display: flex;
justify-content: center;
align-items: center;
font-size: 32px;
color: white;
opacity: 50%;
top: 100px;
}
#box-2 {
top: 210px;
margin-top: 10px;
left: 0;
transform: translate(0);
margin-left: auto;
margin-right: auto;
}
span {
font-size: 12px;
position: absolute;
top: 5px;
left: 10px;
}
#box-ghost {
position: absolute;
top: 0;
left: 50%;
background-color: transparent;
border-style: dashed;
border-width: 10px;
opacity: 70%;
display: flex;
justify-content: center;
align-items: center;
font-size: 32px;
}
/* div#half-width {
position: fixed;
left: 0;
right: 0;
width: 250px;
height: 100px;
background-color: grey;
display: block;
color: lightgray;
display: flex;
justify-content: center;
align-items: center;
font-size: 32px;
} */
.highlighted {
border-color: blue;
color: blue;
background-color: blue;
width: 500px;
height: 100px;
}
.box {
color: red;
background-color: red;
border-color: red;
width: 500px;
height: 100px;
}
<div id="heading"><span>position: relative</span>Resize viewport to see demo</div>
<div id="container">
<div class="box" id="box"><span>position: sticky (left: 50%, transform: translateX(-50%))</span>500px</div>
<div class="box-ghost" id="box-ghost"><span>position: absolute (left: 50%)</span>500px (not transformed)</div>
<div class="box" id="box-2"><span>position: sticky (margin-left: auto, margin-right: auto)</span>500px (solution)</div>
</div>