在昨天的文章中,我們打破了行動作業系統的藩籬,用 Android 8ms 微秒級震動與 iOS 14ms 聲學微脈衝,為計算機注入了媲美原生機械開關的扎實手感。然而,當使用者實際拿起不同型號的手機操作時,另一個讓無數前端開發者崩潰的噩夢隨即浮現:瀏覽器網址列伸縮引發的「排版抽搐」、iPhone 靈動島與底部橫條遮擋、以及在 iPad 分割視窗時按鍵被擠出螢幕的破版尷尬。
線上體驗 Live Demo:https://410355-collab.github.io/Premium-Business-Calculator/
(強烈建議使用 iPhone Safari 或 Android 手機開啟體驗!)
GitHub 開源倉庫:https://github.com/410355-collab/Premium-Business-Calculator
歡迎提出建議與指導
(開發環境:Google Antigravity IDE + Google Gemini 協同開發)
要讓 Web App 具備原生 App 的穩固服貼感,前端工程師在跨平台版面配置上經常遭遇四大致命難題:
在 iOS Safari 與 Android Chrome 中,傳統的 100vh 是以「網址列收合後」的最大可視高度作為計算基準。這會導致使用者一打開網頁,計算機最底部的核心按鍵(等於鍵 = 與小數點 . )直接被手機原生底部的虛擬導航列硬生生遮擋;當使用者稍微往上滑動時,網址列縮小又會引發劇烈的版面跳動,摧毀視覺穩定性。
自 iPhone X 到最新的 iPhone 17 系列,螢幕頂部配備了瀏海或靈動島,底部則有系統級的 Home 指示橫條。若未正確宣告視口邊界,網頁頂部的設定與歷史圖示會被靈動島切掉一半,而底部的按鍵則容易與系統的「滑動返回桌面」手勢發生嚴重誤觸。
在 iPad 或折疊螢幕手機中,使用者常將螢幕切換為左右 1:1 或 1:2 分割模式,筆者平常也會一邊開Line一邊開計算機一邊算帳。許多開發者慣用 justify-content:space-between,但當高度被極度壓縮時,按鍵群會無情地往上推擠,導致頂部重要的數字螢幕與算式被壓扁成一條線,甚至發生文字被截斷的災難。
傳統 CSS 動畫多使用 ease 或 linear,元素展開時如同殭屍,缺乏實體世界中具有「質量」、「剛度」與「阻尼」的彈簧回彈感,整體介面瞬間顯得廉價。
針對上述痛點,我們在架構層面設計了四道核心防禦體系:
在 <meta name="viewport"> 中啟用 viewport-fit=cover,並在 CSS 引入 100dvh搭配 min-height: -webkit-fill-available 雙重保險,動態即時扣除動態網址列的高度,確保介面 100% 精準填滿視口且絕不產生額外捲軸。
修正頂部動作列與底部按鍵區,透過 env(safe-area-inset-top) 與 env(safe-area-inset-bottom) 自動感知設備硬體盲區,讓背景玻璃色塊延伸至螢幕邊緣消除黑邊,而內部互動元件則精準內縮至安全可視區內。
捨棄失控的 space-between,改以 flex-direction: column; justify-content: flex-start 作為主容器基底。將數字螢幕面板(.left-panel)宣告為「貪婪型彈性元素 (flex: 1 1 auto)」,並設有 min-height: 120px 的絕對保險線;同時為外層容器賦予 contain: layout style,將重繪範圍嚴密鎖定,徹底根絕版面跳動。
提煉 iOS 原生 UIKit/SwiftUI 的彈簧動力學參數,建立包含俐落、回彈與高頻互動,三大純 CSS 原生物理貝茲曲線,零 JavaScript 負擔即可達成絲滑 120FPS 動態張力。
以下是專案中負責動態視口鎖定、靈動島避障與 Apple 彈簧貝茲曲線的核心代碼:
/* ─── 1. Apple 原生物理彈簧曲線矩陣 ─── */
:root {
/* 🍏 Apple iOS Native Spring & Easing Physics Curves */
--ios-spring-snappy: cubic-bezier(0.25, 1, 0.5, 1);
--ios-spring-bouncy: cubic-bezier(0.175, 0.885, 0.32, 1.275);
--ios-sheet-curve: cubic-bezier(0.32, 0.72, 0, 1);
--ios-interactive: cubic-bezier(0.16, 1, 0.3, 1);
/* 封裝高效 GPU 合成層轉場微動效 */
--trans-smooth: transform 0.22s var(--ios-spring-snappy), opacity 0.16s ease, background-color 0.18s ease, filter 0.16s ease;
--trans-pop: transform 0.18s var(--ios-spring-bouncy), opacity 0.14s ease, background-color 0.14s ease, filter 0.14s ease;
}
/* ─── 2. 視口鎖定與動態視口三重保險 (配合 viewport-fit=cover) ─── */
html, body {
position: fixed;
top: 0; left: 0;
width: 100%;
height: 100%;
height: 100dvh;
overflow: hidden;
overscroll-behavior: none;
touch-action: none;
background-color: var(--bg-color); /* 防止 iOS 橡皮筋露出底色黑塊 */
}
body {
display: flex; justify-content: center; align-items: stretch;
width: 100%; height: 100%; height: 100dvh;
/* 三重保險:Safari 舊版、新版標準與極限動態視口相容 */
min-height: 100vh;
min-height: -webkit-fill-available;
min-height: 100dvh;
}
/* ─── 3. 主容器隔離與 Safe Area 靈動島避障 ─── */
.phone-container {
width: 100%; max-width: 430px;
height: 100%;
background-color: var(--bg-color);
display: flex; flex-direction: column;
justify-content: flex-start; /* 從頂部排列,避免 space-between 在多工分割時失控 */
overflow: hidden;
position: relative;
transition: var(--trans-smooth);
padding-left: env(safe-area-inset-left, 0px);
padding-right: env(safe-area-inset-right, 0px);
contain: layout style; /* 隔離重排,防止高頻文字渲染波及全域 */
}
/* 頂部 Header Area:靈動島與瀏海避障 (Top Safe Area) */
.header-area {
position: relative; width: 100%;
/* 核心避障公式:Safe Area 加上微距內襯 */
padding: calc(env(safe-area-inset-top, 24px) + 8px) clamp(8px, 4vw, 20px) 0;
display: flex; flex-direction: column; gap: 8px; z-index: 10;
flex-shrink: 0;
}
/* 貪婪擴展螢幕面板,保障極限多工分割下數字不崩潰 */
.left-panel {
flex: 1 1 auto; /* 貪婪佔滿剩餘高度 */
display: flex; flex-direction: column;
min-height: 120px; /* 鋼鐵保險線:確保數字與算式空間絕不被擠壓消失 */
width: 100%;
}
在 Google Antigravity IDE 的實機調校過程中,這套動態佈局展現了令人驚艷的邊界抗壓性:
--ios-spring-bouncy: cubic-bezier(0.175, 0.885, 0.32, 1.275) 中,第二個控制點的數值 Y = 1.275,代表元素在動畫結束前會向外微幅「超調膨脹 27.5%」,隨後在 180ms 內迅速收縮吸附。這種微妙的過沖回彈,正是消除網頁生硬廉價感、呈現蘋果原生動態的靈魂所在。
在 iPad 或 Android 平板開啟多重視窗分割時,傳統使用 space-between 的計算機會將按鍵群強行往上推擠,導致頂部的數字螢幕被壓扁成一條線。我們改採 flex-direction: column 搭配貪婪擴展的 .left-panel,並設定 min-height: 120px 的絕對保險線,確保在極限扁平比例下數字依然清晰可讀。
計算機在高速輸入連續運算時,字元頻繁增減會觸發字型縮放計算。若不加入圖層隔離,瀏覽器每次計算字元寬度都會迫使整個頁面(包含背景毛玻璃與頂部膠囊)全部重新計算佈局。加入 contain: layout style 後,將重排嚴格限制在容器內部,在支援高更新率的中階手機上依然穩穩鎖定 120FPS。
螢幕與視窗響應式版面規則(共 7 種自適應模式)
系統依據裝置視窗的「寬高比」與「高度」自動切換最適排版:
觸發條件:寬高比小於等於 9:11(高度明顯大於寬度)。
排版特點:單欄垂直佈局,數字按鍵維持正圓形(比例 1:1),螢幕靠下對齊。
| 直向手機視圖 | ||
|---|---|---|
![]() |
觸發條件:寬高比介於 9:11 至 3:2 之間(常見於折疊機或多工分割畫面)。
排版特點:鍵盤高度限制在視窗的 55% 以內(最高 350px),按鍵轉為圓角觸控膠囊,防止垂直超出畫面。
| 分割多工視圖 | ||
|---|---|---|
![]() |
觸發條件:寬高比大於 3:2(寬螢幕或平板橫擺)。
排版特點:雙欄橫向佈局(鍵盤在左、顯示螢幕在右),按鍵維持正圓形;若視窗縮窄至 850px 以下,按鍵自動切換為扁圓角矩形以確保觸控面積。

觸發條件:高度小於等於 380px 且寬高比大於 3:2。
排版特點:頂部狀態膠囊極限壓縮至 26px,按鍵均分五列填滿視窗,消除留白並防止內容截斷。

觸發條件:高度小於等於 420px 且呈直向顯示。
排版特點:自動隱藏算式與匯率副文字,僅保留主計算結果,大幅節省縱向空間。
觸發條件:高度小於等於 560px。
排版特點:頂部膠囊高度收縮為 32px,設定選單、彈窗與按鍵全面啟動緊湊排版。
透過 100dvh 與 env(safe-area-inset-*) 雙重機制,完美解決橫向旋轉、多重視窗拖曳與靈動島避障難題,徹底消滅白邊與遮擋。
告別平庸呆板的 CSS 轉場,運用四組精準調校的純 CSS 原生物理彈簧貝茲曲線,讓每次按鍵點擊與選單抽屜滑出都具備實體世界的張力。
版面服貼與動態手感穩固了,但若使用者輸入超過 20 位的長算式,或者想要精準修改算式中間的某一個數字,介面該如何自處? 在下一篇 Day 5 中,我們將深入解析:如何用 autoScaleText 演算法動態縮放字級、縮至 0.48 極限無縫切換 iOS 橫向捲動,以及算式任意字元的局部點擊游標定位插入!