fix(admin): 笔记本 14寸 Safari 翻页按钮被截 — 根因三件套修法

用户报:Mac Safari + 14寸笔记本,/admin/records 翻页按钮永远在屏幕外,
拖动能看到内容超出但滚到底也看不见翻页按钮。

根因三个叠加:

1. 100vh 在 Safari 桌面端不可靠 — 算的是含工具栏/书签栏的 layout viewport,
   不是用户实际能看到的 visual viewport。.layout { height: 100vh } 实际比可见高,
   底部被 UI bar 盖住。
2. Flex overflow 经典 bug — .content { flex: 1; overflow-y: auto } 没加 min-height: 0,
   flex 子默认 min-height: auto 跟随内容撑开,Safari/Chrome 都不让 flex 父约束高度,
   导致 overflow-y: auto 形同虚设,.content 不滚动,底部按钮被外层 .layout
   overflow:hidden 切掉。
3. 翻页按钮无 padding-bottom — 即使前两个修了,贴着容器边缘也不舒服。

根因修法(不打 padding 补丁):

1. AdminLayout.module.css .layout — 用 100dvh + fallback 100vh
   (Dynamic Viewport Height,浏览器动态算可见区域,Safari 17+/Chrome 108+/FF 101+ 支持)
2. AdminLayout.module.css .content — 加 min-height: 0,让 flex 子元素正确 shrink
3. 4 个 admin 管理页 .pagination 加 padding-bottom: 8px(RecordsPage/UsersPage/LoginRecordsPage/AuditLogsPage)
   作为视觉缓冲(三件套里最末层的 polish)
4. ProfilePage 同样 100vh 模式 → 加 100dvh fallback,防同款 bug 在用户端复现

为什么不只加 padding-bottom:
- padding 是治标 — 假设 viewport 不会再变,加缓冲就行
- 但 Safari 用户切换 zoom / 显示书签栏 / 切换 fullscreen 时实际可见区会变,
  固定 padding 仍会被切
- 100dvh 是浏览器动态计算可见区域,永远准
- min-height: 0 修的是 flex 容器自身的滚动机制,根因层面解决

验收:
- 14寸笔记本 Safari → /admin/records 翻页按钮可见可点 ✓
- 桌面大屏不受影响(dvh == vh == 视口)
- Safari < 17 fallback 到 100vh,行为同改前(不变好也不变差)
- Chrome / Firefox dvh 都支持,正常

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
seaislee1209 2026-05-12 18:26:54 +08:00
parent 11c1cdf8cc
commit 6b13cfff70
6 changed files with 17 additions and 5 deletions

View File

@ -1,6 +1,10 @@
.layout {
display: flex;
/* fallback for Safari < 17,降级到 vh 行为(包含工具栏可能被遮) */
height: 100vh;
/* Dynamic Viewport Height 自动减去 Safari 工具栏/书签栏,
永远等于用户实际看得到的高度,根因解 14寸 Safari 翻页按钮被截 */
height: 100dvh;
overflow: hidden;
/* V2: transparent 让全局 AmbientBackground pastel aurora 在主区也能隐约透出 */
background: transparent;
@ -186,7 +190,11 @@
.content {
flex: 1;
overflow-y: auto;
padding: 24px 32px;
/* 关键: flex 子元素正确 shrink + 触发 overflow-y;
不加这个 flex 子默认 min-height: auto,内容溢出时 overflow-y: auto 形同虚设,
底部按钮会被外层 .layout overflow:hidden 切掉 */
min-height: 0;
padding: 24px 32px 32px;
transition: margin-left 0.2s ease;
}

View File

@ -43,7 +43,7 @@
.skeletonCell { height: 16px; background: var(--color-border-card); border-radius: 4px; animation: pulse 1.5s ease-in-out infinite; }
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } }
.pagination { display: flex; justify-content: space-between; align-items: center; margin-top: 16px; }
.pagination { display: flex; justify-content: space-between; align-items: center; margin-top: 16px; padding-bottom: 8px; }
.pageInfo { color: var(--color-text-secondary); font-size: 13px; }
.pageButtons { display: flex; gap: 4px; }
.pageButtons button {

View File

@ -35,7 +35,7 @@
.skeletonCell { height: 16px; background: var(--color-border-card); border-radius: 4px; animation: pulse 1.5s ease-in-out infinite; }
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } }
.pagination { display: flex; justify-content: space-between; align-items: center; margin-top: 16px; }
.pagination { display: flex; justify-content: space-between; align-items: center; margin-top: 16px; padding-bottom: 8px; }
.pageInfo { color: var(--color-text-secondary); font-size: 13px; }
.pageButtons { display: flex; gap: 4px; }
.pageButtons button {

View File

@ -2,8 +2,12 @@
max-width: 1200px;
margin: 0 auto;
padding: 24px 20px 60px;
/* Safari < 17 fallback */
min-height: 100vh;
height: 100vh;
/* Dynamic Viewport Height — 自动减去 Safari 工具栏,根因解 14寸 Safari 翻页/底部按钮被截 */
min-height: 100dvh;
height: 100dvh;
overflow-y: auto;
}

View File

@ -57,7 +57,7 @@
.skeletonCell { height: 16px; background: var(--color-border-card); border-radius: 4px; animation: pulse 1.5s ease-in-out infinite; }
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } }
.pagination { display: flex; justify-content: space-between; align-items: center; margin-top: 16px; }
.pagination { display: flex; justify-content: space-between; align-items: center; margin-top: 16px; padding-bottom: 8px; }
.pageInfo { color: var(--color-text-secondary); font-size: 13px; }
.pageButtons { display: flex; gap: 4px; }
.pageButtons button {

View File

@ -51,7 +51,7 @@
.skeletonCell { height: 16px; background: var(--color-border-card); border-radius: 4px; animation: pulse 1.5s ease-in-out infinite; }
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } }
.pagination { display: flex; justify-content: space-between; align-items: center; margin-top: 16px; }
.pagination { display: flex; justify-content: space-between; align-items: center; margin-top: 16px; padding-bottom: 8px; }
.pageInfo { color: var(--color-text-secondary); font-size: 13px; }
.pageButtons { display: flex; gap: 4px; }
.pageButtons button {