Here's a codepen illustrating the issue:
When I scroll to the right, the first column does stick to the left as is expected.
However, when scrolling starts nearing the end of the table's horizontal space, the first no longer maintains its sticky position to the left edge of the table.
I've noticed that if I remove the HTML markup for the <aside>
, the sticky column behavior works as expected. However, I need the <aside>
to be present.
Any ideas on how to fix this with CSS while maintaining the DOM structure?
body {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
}
.container {
display: flex;
width: 300px;
padding: 0.5rem;
border: 1px solid red;
}
aside {
padding-right: 1rem;
width: 100px;
}
.table {
min-width: 0;
overflow: scroll;
}
.row {
display: grid;
grid-template-columns: repeat(4, 100px);
}
.col {
border: 1px solid black;
background: #eee;
}
.sticky {
position: sticky;
left: 0;
z-index: 1;
background: lightblue;
}
<div >
<aside>
My aside
</aside>
<div >
<div >
<div >Col 1</div>
<div >Col 2</div>
<div >Col 3</div>
<div >Col 4</div>
</div>
<div >
<div >Col 1</div>
<div >Col 2</div>
<div >Col 3</div>
<div >Col 4</div>
</div>
<div >
<div >Col 1</div>
<div >Col 2</div>
<div >Col 3</div>
<div >Col 4</div>
</div>
<div >
<div >Col 1</div>
<div >Col 2</div>
<div >Col 3</div>
<div >Col 4</div>
</div>
<div >
<div >Col 1</div>
<div >Col 2</div>
<div >Col 3</div>
<div >Col 4</div>
</div>
<div >
<div >Col 1</div>
<div >Col 2</div>
<div >Col 3</div>
<div >Col 4</div>
</div>
<div >
<div >Col 1</div>
<div >Col 2</div>
<div >Col 3</div>
<div >Col 4</div>
</div>
<div >
<div >Col 1</div>
<div >Col 2</div>
<div >Col 3</div>
<div >Col 4</div>
</div>
<div >
<div >Col 1</div>
<div >Col 2</div>
<div >Col 3</div>
<div >Col 4</div>
</div>
<div >
<div >Col 1</div>
<div >Col 2</div>
<div >Col 3</div>
<div >Col 4</div>
</div>
</div>
</div>
CodePudding user response:
So the problem actually falls with the min-width
set on .table
. The width is not defined to the end of the row which is affecting the behavior of the sticky elements at row-end.
You'll notice if you exchange min-width: 0;
to min-width: 100%;
it functions as you would like, but then the table
overflows outside of .container
.
A stickily positioned element is treated as relatively positioned until its containing block crosses a specified threshold (such as setting top to value other than auto) within its flow root.
So with that said, the elements with the scroll need to have a defined width so the sticky element knows to stay sticky.
A simple solution would be to nest all of the .table
elements in another wrapper that has a defined width. I chose 300px
based on the rendered width of the content and the container.
body {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
}
.container {
display: flex;
width: 300px;
padding: 0.5rem;
border: 1px solid red;
}
aside {
padding-right: 1rem;
width: 100px;
}
.table {
min-width: 0;
overflow: scroll;
}
.row {
display: grid;
grid-template-columns: repeat(4, 100px);
}
.col {
border: 1px solid black;
background: #eee;
}
.sticky {
position: sticky;
left: 0;
z-index: 1;
background: lightblue;
}
.wrapper {
width: 300px;
}
<div >
<aside>
My aside
</aside>
<div >
<div >
<div >
<div >Col 1</div>
<div >Col 2</div>
<div >Col 3</div>
<div >Col 4</div>
</div>
<div >
<div >Col 1</div>
<div >Col 2</div>
<div >Col 3</div>
<div >Col 4</div>
</div>
<div >
<div >Col 1</div>
<div >Col 2</div>
<div >Col 3</div>
<div >Col 4</div>
</div>
<div >
<div >Col 1</div>
<div >Col 2</div>
<div >Col 3</div>
<div >Col 4</div>
</div>
<div >
<div >Col 1</div>
<div >Col 2</div>
<div >Col 3</div>
<div >Col 4</div>
</div>
<div >
<div >Col 1</div>
<div >Col 2</div>
<div >Col 3</div>
<div >Col 4</div>
</div>
<div >
<div >Col 1</div>
<div >Col 2</div>
<div >Col 3</div>
<div >Col 4</div>
</div>
<div >
<div >Col 1</div>
<div >Col 2</div>
<div >Col 3</div>
<div >Col 4</div>
</div>
<div >
<div >Col 1</div>
<div >Col 2</div>
<div >Col 3</div>
<div >Col 4</div>
</div>
<div >
<div >Col 1</div>
<div >Col 2</div>
<div >Col 3</div>
<div >Col 4</div>
</div>
</div>
</div>
</div>