Position sticky iPhone flickering
I fight oddities with iOS vs everything else all the time. It's usually involving stacking context issues. It appears to me that the position: sticky
and left: 0
element become relative to that first row on iOS. iOS doesn't handle stacking context the same as all the other browsers.
I've never really figured out exactly what causes this. Technically your iPhone cell is stuck to the left even when it's scrolling because it's relative to it's parent which does not have left: 0
. I'm assuming this has to do with how iOS handles position: sticky
. Sticky starts relative and then changes to fixed. All the other browsers at that point would make it stick to the left. You have a position: sticky;
element inside a position: sticky;
element. That is a new stacking context. I believe iOS makes it fixed to it's parent and not the way you would expect. Since the parent row doesn't have left: 0
it's going to scroll with everything else. I hope this helps. I saw no flickering, but I had a few broken components in my company's web framework after iOS 13 came out involving scrolling and stacking contexts. I would test on multiple iOS devices.
edit after playing around some more with it, I'm confident it is a stacking context issue. I cranked the z-index up to 1000 on the iphone cell only and the rows below STILL appear above it.
If you don't have to support internet explorer I would use CSS grids to achieve this layout. Then you won't have to worry about position: sticky
https://css-tricks.com/snippets/css/complete-guide-grid/
https://css-tricks.com/using-css-grid-the-right-way/
I use it for dynamic data heavy content in business applications so it can be incredibly flexible if leveraged properly.
Updated Again -- If you can't change the DOM at all then you're going to have to deal with the flickering as even the grid solution will require wrappers around some elements. Just to clarify.... With a grid solution you DO NOT need to know how many columns or rows you will have. You seem hung up on that aspect. Grid areas also create a new stacking context and make everything relative to the grid area that it's in while allowing flexible units. I cannot give you an answer until you show how your dynamic data is coming in. We need more context to give you a code solution.
Again, the flickering is happening because you have a sticky positioned element inside another sticky element. That's just iOS and if you want to use it like this, you will have to just deal with it.
Here's documentation about stacking contexts and how they work. As I stated in a comment, you are going to have to take a different approach or just deal with it.
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context
Also --
Hide the overflow on your HTML and Body. Put a wrapper around the table. Put -webkit-overflow-scrolling: auto
on the wrapper. Run it on iOS 12 and you will see it not flicker. You won't have momentum scrolling though. iOS13 removed the need for the -webkit-overflow-scrolling
so you can't even override it. If you put the value of touch
on -webkit-overflow-scrolling
you will now get flickering. Run this code below and you'll see it not flicker. Long story short, as I've said many times you WILL have to find a different approach. You can't fix this now that iOS13 is out and you really wouldn't have wanted to disable momentum scrolling anyways.
html {
overflow: hidden;
width: 100%;
height: 100%;
}
body {
overflow: hidden;
height: 100%;
width: 100%;
}
.wrapper {
overflow: auto;
-webkit-overflow-scrolling: auto;
width: 100%;
height: 100%;
}
.table {
width: 2000px;
position: relative;
}
.tr {
overflow: visible;
display: block;
white-space: nowrap;
font-size: 0;
}
.tc {
border: 1px solid #DDD;
display: inline-block;
width: 100px;
height: 100px;
text-align: center;
font-size: 12px;
}
.trh {
background: #000;
color: #FFF;
position: -webkit-sticky;
position: sticky;
top: 0;
z-index: 1;
}
.tc.first {
background: #000;
color: #FFF;
position: -webkit-sticky;
position: sticky;
left: 0;
}
<html>
<head>
<link rel="stylesheet" href="css.css">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div class="wrapper">
<div class="table">
<div class="tr trh">
<div class="tc first">Iphone</div>
<div class="tc">value</div>
<div class="tc">value</div>
<div class="tc">value</div>
<div class="tc">value</div>
<div class="tc">value</div>
<div class="tc">value</div>
<div class="tc">value</div>
<div class="tc">value</div>
</div>
<div class="tr">
<div class="tc first">a set</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">2</div>
</div>
<div class="tr">
<div class="tc first">a set</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
</div>
<div class="tr">
<div class="tc first">a set</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
</div>
<div class="tr">
<div class="tc first">a set</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
</div>
<div class="tr">
<div class="tc first">a set</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
</div>
<div class="tr">
<div class="tc first">a set</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
</div>
<div class="tr">
<div class="tc first">a set</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
</div>
<div class="tr">
<div class="tc first">a set</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
<div class="tc">0</div>
</div>
</div>
</div>
</body>
</html>