Problem
I'm trying to replicate the iOS behavior of native apps, where a search box remains in view (merges with top bar) after the user has scrolled. The header is fixed and only the main content is scrollable. The search box has position: sticky
and I gave it a high z-index. This works fine on Chrome/Safari desktop, but fails on iOS browsers. See behavior in action below (simplified version of my current implementation)
Scrolling on Desktop -- Works Fine
Scrolling on iOS -- Does NOT work
What I tried
- Using translate3d hack
transform: translate3d(0, 0, 0);
-webkit-transform: translate3d(0, 0, 0);
- Using a pseudo-element on the header with background/filter applied to it
-- No apparent change and none of this make it work on iOS.
Code Snippet (try on iOS to see the issue)
body {
margin: 0;
padding: 0;
height: 100vh;
overflow: hidden;
}
header {
padding: 0 20px;
height: 60px;
position: relative;
top: 0;
width: 100%;
z-index: 50;
color: black;
font-size: 24px;
font-weight: bold;
background: rgba(255, 255, 255, 0.8);
backdrop-filter: blur(10px);
}
/* Doesn't work on iOS neither */
/* header:before {
content: "";
background: rgba(255, 255, 255, 0.8);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
width: 100%;
height: 100%;
position: absolute;
top:0;
left:0;
z-index:-1;
} */
main {
height: 100%;
}
.ios-scroll-view {
overflow-y: auto;
overflow-x: hidden;
-webkit-overflow-scrolling: touch;
overscroll-behavior-y: contain;
height: 100%;
width: 100%;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
padding-top: calc(44px + env(safe-area-inset-top, 0px));
padding-bottom: calc(54px + env(safe-area-inset-bottom, 0px));
background: lightgreen;
padding-left: 16px;
}
#search {
width: 20%;
position: sticky;
top: -10px;
z-index: 999 !important;
transform: translate3d(0, 0, 0);
-webkit-transform: translate3d(0, 0, 0);
}
<html>
<body>
<header>
Title
</header>
<main>
<div class="ios-scroll-view">
<h1>Title</h1>
<input id="search" placeholder="Search" />
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>LAST</p>
</div>
</main>
</body>
</html>
Problem
I'm trying to replicate the iOS behavior of native apps, where a search box remains in view (merges with top bar) after the user has scrolled. The header is fixed and only the main content is scrollable. The search box has position: sticky
and I gave it a high z-index. This works fine on Chrome/Safari desktop, but fails on iOS browsers. See behavior in action below (simplified version of my current implementation)
Scrolling on Desktop -- Works Fine
Scrolling on iOS -- Does NOT work
What I tried
- Using translate3d hack
transform: translate3d(0, 0, 0);
-webkit-transform: translate3d(0, 0, 0);
- Using a pseudo-element on the header with background/filter applied to it
-- No apparent change and none of this make it work on iOS.
Code Snippet (try on iOS to see the issue)
body {
margin: 0;
padding: 0;
height: 100vh;
overflow: hidden;
}
header {
padding: 0 20px;
height: 60px;
position: relative;
top: 0;
width: 100%;
z-index: 50;
color: black;
font-size: 24px;
font-weight: bold;
background: rgba(255, 255, 255, 0.8);
backdrop-filter: blur(10px);
}
/* Doesn't work on iOS neither */
/* header:before {
content: "";
background: rgba(255, 255, 255, 0.8);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
width: 100%;
height: 100%;
position: absolute;
top:0;
left:0;
z-index:-1;
} */
main {
height: 100%;
}
.ios-scroll-view {
overflow-y: auto;
overflow-x: hidden;
-webkit-overflow-scrolling: touch;
overscroll-behavior-y: contain;
height: 100%;
width: 100%;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
padding-top: calc(44px + env(safe-area-inset-top, 0px));
padding-bottom: calc(54px + env(safe-area-inset-bottom, 0px));
background: lightgreen;
padding-left: 16px;
}
#search {
width: 20%;
position: sticky;
top: -10px;
z-index: 999 !important;
transform: translate3d(0, 0, 0);
-webkit-transform: translate3d(0, 0, 0);
}
<html>
<body>
<header>
Title
</header>
<main>
<div class="ios-scroll-view">
<h1>Title</h1>
<input id="search" placeholder="Search" />
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>Content here...</p>
<p>LAST</p>
</div>
</main>
</body>
</html>
Share
Improve this question
asked Mar 12 at 14:19
BassemBassem
4,0704 gold badges25 silver badges53 bronze badges
1 Answer
Reset to default 0The -webkit-overflow-scrolling was causing the issue, setting it to auto
solves the problem.
-webkit-overflow-scrolling: auto