Pin reader and tab bars to their own compositing layer
Build and Push Docker Image / build-and-push (push) Successful in 5m1s
Build and Push Docker Image / build-and-push (push) Successful in 5m1s
iOS Safari/PWA can strand fixed and sticky bars mid-screen after the toolbar collapses or the page rubber-bands. Add a .fixed-bar class (translateZ(0), will-change: transform) to the reader top/bottom bars and the phone tab bar. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
593769b4f6
commit
d9891ff9fe
3 files changed
+11
-3
No files matched your search
@@ -8,7 +8,7 @@ const iconBtn = 'flex h-9 w-9 items-center justify-center rounded-lg text-[var(-
|
|||||||
|
|
||||||
export function TopBar({ title, onBack, onOpenNavigator, onSearch, onBookmarks, bookmarkCount, onHighlights, highlightCount, onCompare, compareActive, onSettings, onDoneDrawing }) {
|
export function TopBar({ title, onBack, onOpenNavigator, onSearch, onBookmarks, bookmarkCount, onHighlights, highlightCount, onCompare, compareActive, onSettings, onDoneDrawing }) {
|
||||||
return (
|
return (
|
||||||
<div className="safe-top sticky top-0 z-30 border-b border-[var(--r-line)] bg-[var(--r-bar)] font-sans">
|
<div className="fixed-bar safe-top sticky top-0 z-30 border-b border-[var(--r-line)] bg-[var(--r-bar)] font-sans">
|
||||||
<div className="mx-auto flex h-12 max-w-4xl items-center gap-1 px-2">
|
<div className="mx-auto flex h-12 max-w-4xl items-center gap-1 px-2">
|
||||||
<HomeButton onClick={onBack} />
|
<HomeButton onClick={onBack} />
|
||||||
<button type="button" onClick={onOpenNavigator}
|
<button type="button" onClick={onOpenNavigator}
|
||||||
@@ -44,7 +44,7 @@ export function BottomBar({
|
|||||||
}) {
|
}) {
|
||||||
const active = 'text-[var(--r-accent)]';
|
const active = 'text-[var(--r-accent)]';
|
||||||
return (
|
return (
|
||||||
<div className="fixed inset-x-0 bottom-0 z-30 border-t border-[var(--r-line)] bg-[var(--r-bar)] pb-[env(safe-area-inset-bottom)] font-sans">
|
<div className="fixed-bar fixed inset-x-0 bottom-0 z-30 border-t border-[var(--r-line)] bg-[var(--r-bar)] pb-[env(safe-area-inset-bottom)] font-sans">
|
||||||
<div className="mx-auto flex h-14 max-w-4xl items-center gap-0.5 px-2">
|
<div className="mx-auto flex h-14 max-w-4xl items-center gap-0.5 px-2">
|
||||||
<button type="button" onClick={onPrev} disabled={prevDisabled} className={iconBtn} aria-label="Previous chapter" data-tip="Previous chapter (←)"><ChevronLeft /></button>
|
<button type="button" onClick={onPrev} disabled={prevDisabled} className={iconBtn} aria-label="Previous chapter" data-tip="Previous chapter (←)"><ChevronLeft /></button>
|
||||||
<button type="button" onClick={onAudio} className={`${iconBtn} ${audioActive ? active : ''}`} aria-label="Listen" data-tip="Listen to this chapter"><HeadphonesIcon /></button>
|
<button type="button" onClick={onAudio} className={`${iconBtn} ${audioActive ? active : ''}`} aria-label="Listen" data-tip="Listen to this chapter"><HeadphonesIcon /></button>
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ export default function PageShell({ title, onBack, actions, active = null, maxWi
|
|||||||
{phone && (
|
{phone && (
|
||||||
<>
|
<>
|
||||||
<div aria-hidden="true" className="h-[calc(5rem+env(safe-area-inset-bottom,0px))]" />
|
<div aria-hidden="true" className="h-[calc(5rem+env(safe-area-inset-bottom,0px))]" />
|
||||||
<nav aria-label="Main" className="fixed inset-x-0 bottom-0 z-30 grid grid-cols-5 border-t border-[var(--r-line)] bg-[var(--r-bar)] pb-[env(safe-area-inset-bottom)]">
|
<nav aria-label="Main" className="fixed-bar fixed inset-x-0 bottom-0 z-30 grid grid-cols-5 border-t border-[var(--r-line)] bg-[var(--r-bar)] pb-[env(safe-area-inset-bottom)]">
|
||||||
{NAV.map((n) => (
|
{NAV.map((n) => (
|
||||||
<button key={n.id} type="button" onClick={go[n.id]} aria-current={active === n.id ? 'page' : undefined} aria-label={n.label}
|
<button key={n.id} type="button" onClick={go[n.id]} aria-current={active === n.id ? 'page' : undefined} aria-label={n.label}
|
||||||
className={`flex min-h-[52px] flex-col items-center justify-center gap-0.5 text-[11px] ${active === n.id ? 'text-[var(--r-text)]' : 'text-[var(--r-sub)]'}`}>
|
className={`flex min-h-[52px] flex-col items-center justify-center gap-0.5 text-[11px] ${active === n.id ? 'text-[var(--r-text)]' : 'text-[var(--r-sub)]'}`}>
|
||||||
|
|||||||
@@ -79,6 +79,14 @@ input,
|
|||||||
|
|
||||||
/* Top bars leave room for the status bar / notch when the app is installed or full-screen
|
/* Top bars leave room for the status bar / notch when the app is installed or full-screen
|
||||||
(env() is 0 in an ordinary browser tab). */
|
(env() is 0 in an ordinary browser tab). */
|
||||||
|
/* iOS Safari/PWA can leave fixed and sticky bars stranded mid-screen after the toolbar collapses or the page
|
||||||
|
rubber-bands. Giving them their own compositing layer keeps them pinned to the viewport edge. */
|
||||||
|
.fixed-bar {
|
||||||
|
transform: translateZ(0);
|
||||||
|
-webkit-transform: translateZ(0);
|
||||||
|
will-change: transform;
|
||||||
|
}
|
||||||
|
|
||||||
.safe-top {
|
.safe-top {
|
||||||
padding-top: env(safe-area-inset-top, 0px);
|
padding-top: env(safe-area-inset-top, 0px);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user