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:
parent
11c1cdf8cc
commit
6b13cfff70
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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 {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user