延續 Day 17「醫師詳細資訊頁面」的開發,這次開始實作智慧醫院管理平台的「登入」、「註冊」與「個人資料」頁面。
前面幾天主要依照 Figma 設計,逐步完成首頁、醫院介紹、就醫資訊、醫師查詢及醫師詳細資訊頁面的 HTML/CSS。
這次希望繼續將 Figma 的會員相關頁面轉換成 Angular 網頁,並學習如何使用 HTML 表單標籤與 CSS 完成不同類型的輸入欄位。
本次主要目標:
form、label、input 建立表單。fieldset 與 legend 將註冊欄位分組。dl、dt、dd 呈現會員資料。這次主要記錄 HTML/CSS 與畫面實作,登入驗證、註冊資料處理及個人資料儲存等功能,會留到後續 TypeScript 與後端開發階段再深入介紹。
目前智慧醫院管理平台的主要資訊頁面已逐步完成。
在 Day 16,我完成醫師查詢頁面,讓使用者可以瀏覽醫師列表。
Day 17 則接著完成醫師詳細資訊,包含醫師介紹、專長、學經歷與門診時間表。
這次開始處理會員相關的頁面。
目前網站的開發進度:
SmartCare Hospital
│
├── 首頁
│
├── 醫院介紹
│
├── 就醫資訊
│
├── 醫師查詢
│
├── 醫師詳細資訊
│
├── 登入 ← 本次開發
│
├── 註冊 ← 本次開發
│
└── 個人資料 ← 本次開發
├── 查看資料
└── 編輯資料
這次和前幾天比較不同的是,之前主要製作圖片、文字、卡片及表格,而登入、註冊與個人資料會使用到更多輸入欄位。
因此除了要符合 Figma 的外觀,也需要考慮欄位名稱、輸入框、提示文字及操作按鈕之間的關係。
這讓我開始思考:
表單設計不只是將輸入框排列整齊,也需要讓使用者清楚知道每個欄位的用途,以及目前可以進行哪些操作。
這次主要分成三個部分。
登入頁面需要讓使用者快速找到帳號與密碼欄位,因此採用較簡單的單欄表單。
主要包含:
註冊需要填寫的資料比登入多,因此將欄位分成不同群組。
主要包含:
桌面版使用雙欄排列,避免所有欄位都擠在同一條垂直方向上。
個人資料主要分成查看與編輯兩種狀態。
查看時以文字呈現會員資料,編輯時則改成輸入框,讓使用者可以清楚區分目前是查看還是修改資料。
目前三個頁面都先以 UI 展示為主,沒有加入正式登入驗證或資料庫儲存。
另外,Figma 之前已經設計過登出確認 Overlay,但目前 Angular 尚未實作該視窗,因此這次只完成登出按鈕與返回登入展示頁的行為。
這次登入與註冊沒有分別建立 login.html 和 register.html,而是共用同一組 Angular 頁面檔案。
src/app/pages/
│
├── auth.html
├── auth.css
├── auth.ts
│
├── profile.html
├── profile.css
└── profile.ts
其中:
auth.html:登入與註冊的 HTML。auth.css:登入與註冊共用的 CSS。profile.html:個人資料查看與編輯畫面。profile.css:個人資料頁面的 CSS。登入與註冊雖然有不同的欄位,但整體都使用淺藍色背景搭配白色表單卡片,因此可以沿用相同的主要版面。
共用卡片的 HTML:
<div class="auth-page">
<section
class="auth-card"
[class.registration-card]="registering()"
aria-labelledby="auth-title"
>
<a
class="auth-brand"
routerLink="/"
aria-label="SmartCare Hospital 首頁"
>
<img
ngSrc="/image/logo.png"
width="430"
height="94"
priority
alt="SmartCare 智慧醫療服務"
/>
</a>
<h1 id="auth-title">
{{ registering() ? '建立帳號' : '登入' }}
</h1>
<p class="auth-subtitle">
{{ registering() ? '建立您的SmartCare帳戶' : '歡迎回到SmartCare' }}
</p>
</section>
</div>
以上節錄共用卡片結構,實際表單內容會依照登入或註冊狀態顯示。
這次先了解 HTML 的排版結構,不深入介紹 Angular 的條件判斷與資料綁定。
和之前的醫院介紹、醫師查詢頁面不同,登入與註冊依照 Figma 使用獨立的卡片畫面,沒有顯示全站共用的 Header 與 Footer。
登入頁面主要使用淺藍色背景,中央放置白色表單卡片。
目前 CSS:
.auth-page {
min-height: 100vh;
padding: 104px 24px;
background: #eaf4f8;
}
.auth-card {
max-width: 996px;
margin: auto;
padding: 32px 88px 60px;
border: 1px solid #858585;
background: white;
}
min-height: 100vh;
表示登入頁面的最小高度為整個瀏覽器視窗高度。
即使表單內容不多,也可以讓淺藍色背景至少覆蓋一個畫面。
max-width: 996px;
限制登入卡片的最大寬度,避免在大型螢幕上被拉得過寬。
margin: auto;
這裡主要用來讓固定最大寬度的區塊在水平方向置中。
值得注意的是,這次並沒有使用 Flexbox 或 Grid 將整張卡片垂直置中,而是透過外層的 padding 控制卡片與頁面頂部的距離。
padding: 32px 88px 60px;
分別設定:
讓卡片內的 Logo、標題與表單保留適當空間。
這次登入卡片沒有另外設定圓角或陰影,主要以白底與灰色邊框呈現 Figma 的設計。
這次開始接觸比較完整的 HTML 表單。
登入表單的主要 HTML:
<form
class="login-form"
[formGroup]="loginForm"
(ngSubmit)="login()"
>
<div class="account-field">
<label for="login-account">帳號</label>
<input
id="login-account"
formControlName="account"
placeholder="請輸入姓名"
autocomplete="off"
/>
</div>
<div class="account-field">
<label for="login-password">密碼</label>
<input
id="login-password"
type="password"
formControlName="password"
placeholder="請輸入密碼"
autocomplete="current-password"
/>
</div>
<div class="submit-row">
<button class="primary-button" type="submit">
登入
</button>
</div>
</form>
這次主要學習以下 HTML 標籤。
<form>
form 用來將相關輸入欄位與送出按鈕組織成同一個表單。
和之前單純排列圖片或文字不同,表單中的元素具有明確的輸入與提交用途。
<label for="login-account">帳號</label>
label 用來說明輸入欄位的名稱。
其中:
for="login-account"
會對應:
id="login-account"
這樣使用者點擊「帳號」文字時,也可以將焦點移到對應的輸入框。
<input
id="login-account"
placeholder="請輸入姓名"
/>
input 提供使用者輸入資料。
這次帳號欄位沒有另外設定 type,因此瀏覽器會使用預設的文字輸入類型。
<input type="password" />
type="password" 會將輸入內容以遮蔽形式呈現,避免密碼直接顯示在畫面上。
<button type="submit">登入</button>
表示這個按鈕是表單的送出入口。
這次雖然保留表單送出結構,但目前登入仍屬於 UI 展示,尚未串接真正的帳號驗證服務。
完成登入表單的 HTML 後,接著調整標籤與輸入框的排列。
目前 CSS:
.account-field {
display: grid;
align-content: start;
gap: 20px;
min-width: 0;
}
.account-field label {
font-size: 36px;
line-height: 1.5;
}
.account-field input {
width: 100%;
min-width: 0;
height: 84px;
border: 1px solid #858585;
border-radius: 8px;
padding: 14px 20px;
color: #292929;
background: white;
font-size: 32px;
}
這次將每組欄位分成兩個主要元素:
帳號
┌─────────────────────────┐
│ 請輸入姓名 │
└─────────────────────────┘
display: grid;
讓 label 與 input 依照順序垂直排列。
gap: 20px;
控制欄位名稱與輸入框之間的距離。
width: 100%;
讓輸入框填滿可用的欄位寬度。
min-width: 0;
允許欄位在較窄的容器中縮小,避免被內容撐出畫面。
這次也了解到,Grid 不一定只用來製作多欄卡片,也可以用來排列簡單的表單欄位。
登入頁面除了帳號與密碼,也包含「記住我」、「忘記密碼」及註冊入口。
主要 HTML:
<div class="login-options">
<label class="remember">
<input
type="checkbox"
formControlName="remember"
/>
記住我
</label>
<button
class="text-button"
type="button"
(click)="forgotPassword()"
>
忘記密碼?
</button>
</div>
這裡使用了兩種不同的輸入與操作方式。
<input type="checkbox" />
用來呈現可勾選的選項。
<button type="button">忘記密碼?</button>
與登入按鈕的 type="submit" 不同,這個按鈕不會直接提交登入表單。
登入選項 CSS:
.login-options {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 20px;
margin-top: 48px;
font-size: 30px;
}
其中:
justify-content: space-between;
讓「記住我」與「忘記密碼」分別靠向左右兩側。
另外使用:
flex-wrap: wrap;
避免空間不足時,兩個元素被強迫擠在同一列。
登入按鈕 CSS:
.primary-button {
max-width: 100%;
min-width: 258px;
min-height: 76px;
padding: 8px 32px;
border: 0;
border-radius: 16px;
background: #568fab;
color: white;
font-size: 40px;
}
這次使用 min-width 與 min-height 保留按鈕的基本尺寸,但沒有將按鈕大小完全固定。
這次除了輸入框與按鈕的基本外觀,也針對不同操作狀態調整樣式。
目前 CSS:
input::placeholder {
color: #737373;
opacity: 1;
}
.account-field input:hover {
border-color: #44758e;
}
input:focus-visible {
outline: 3px solid #165a80;
outline-offset: 4px;
}
.primary-button:hover {
background: #44758e;
}
.switch-page a:hover {
text-decoration: underline;
}
這次主要複習三個概念。
input::placeholder {
color: #737373;
}
用來調整輸入欄位中提示文字的顏色。
.account-field input:hover {
border-color: #44758e;
}
當滑鼠移到輸入欄位上方時,邊框會改變顏色。
input:focus-visible {
outline: 3px solid #165a80;
outline-offset: 4px;
}
當元素處於符合 :focus-visible 的焦點狀態時,顯示明顯的外框。
這次除了考慮滑鼠操作,也開始注意使用鍵盤切換表單欄位時的視覺提示。
完成登入頁面後,接著開始處理註冊頁面。
和登入相比,註冊需要更多欄位,因此不能直接沿用登入頁面的單欄排列。
目前註冊頁面主要分成:
建立帳號
│
├── 個人基本資料
│ ├── 姓名
│ ├── 身分證字號
│ ├── 出生日期
│ └── 手機號碼
│
├── 帳號設定
│ ├── 帳號
│ ├── 密碼
│ └── 確認密碼
│
├── 隱私權政策與使用條款
│
└── 建立帳號
這次沒有自行增加 Figma 中不存在的 Email 或性別註冊欄位。
另外,出生日期目前採用文字輸入框,並以 YYYY/MM/DD 作為提示,而不是使用日期選擇器。
這次註冊頁面學習到兩個新的 HTML 標籤:
fieldset
legend
目前 HTML:
<fieldset>
<legend>個人基本資料</legend>
<div class="form-grid">
<div class="account-field">
<label for="reg-name">姓名</label>
<input
id="reg-name"
formControlName="name"
placeholder="請輸入姓名"
/>
</div>
<div class="account-field">
<label for="reg-identity">身分證字號</label>
<input
id="reg-identity"
formControlName="identity"
placeholder="請輸入身分證字號"
/>
</div>
</div>
</fieldset>
以上節錄部分欄位,實際個人基本資料還包含出生日期與手機號碼。
<fieldset>
用來將相關的表單欄位組成同一個群組。
<legend>個人基本資料</legend>
用來為這個表單群組提供名稱。
這次了解到,fieldset 和 legend 不只是畫面排版的容器,也具有表達表單欄位群組的語意。
例如姓名、身分證字號、出生日期與手機號碼都屬於「個人基本資料」。
而帳號、密碼及確認密碼則屬於「帳號設定」。
使用這種方式可以讓註冊表單的結構更加清楚。
這次註冊表單最主要的排版方式是 CSS Grid。
目前 CSS:
.form-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 56px 100px;
margin-top: 48px;
}
grid-template-columns: repeat(2, minmax(0, 1fr));
將表單分成兩個等寬欄位。
例如:
個人基本資料
姓名 身分證字號
┌─────────────┐ ┌─────────────┐
│ │ │ │
└─────────────┘ └─────────────┘
出生日期 手機號碼
┌─────────────┐ ┌─────────────┐
│ │ │ │
└─────────────┘ └─────────────┘
gap: 56px 100px;
這裡使用兩個數值:
56px:列與列之間的距離。100px:左右欄位之間的距離。這個寫法在前面醫師卡片的 Grid 已經使用過。
本次將它應用在表單欄位上,避免輸入框或文字內容把欄位撐得過寬。
這次讓我了解到:
CSS Grid 不只能用來排列圖片或卡片,也很適合處理欄位較多、需要對齊的表單。
這次註冊表單中,確認密碼欄位需要跨越兩個欄位。
因此使用:
.full-width {
grid-column: 1 / -1;
}
這裡的:
grid-column: 1 / -1;
代表元素從 Grid 的第一條欄線延伸到最後一條欄線。
因此原本的雙欄表單可以讓特定欄位改成全寬排列。
例如:
帳號設定
帳號 密碼
┌─────────────┐ ┌─────────────┐
│ │ │ │
└─────────────┘ └─────────────┘
確認密碼
┌────────────────────────────────────┐
│ │
└────────────────────────────────────┘
這次沒有重新建立另一個單欄容器,而是直接透過 CSS Grid 的欄位設定完成版面。
這次註冊頁面還有一個值得學習的 CSS 技巧。
Figma 中的資料分組標題旁邊有水平分隔線,因此使用 legend::after 製作。
目前 CSS:
legend {
display: flex;
align-items: center;
gap: 44px;
width: 100%;
padding: 0;
font-size: 36px;
font-weight: 400;
}
legend::after {
content: '';
flex: 1;
border-top: 1px solid #b0b0b0;
}
legend::after
可以在元素內容後面建立一個 CSS 偽元素。
content: '';
建立一個沒有文字內容的偽元素。
flex: 1;
讓分隔線使用標題後方的剩餘空間。
border-top: 1px solid #b0b0b0;
畫出水平線。
這次不需要額外放一張線條圖片,也不需要另外增加 HTML 元素,就可以透過 CSS 完成分隔線。
這是本次註冊頁面比較值得記錄的技術。
註冊頁面除了輸入欄位,還需要呈現帳號與密碼的格式提示。
目前 HTML:
<div class="account-field">
<label for="reg-password">密碼</label>
<input
id="reg-password"
type="password"
formControlName="password"
placeholder="請輸入密碼"
autocomplete="new-password"
aria-describedby="password-hint"
/>
<p class="field-hint" id="password-hint">
※ 8–20 個字元,需包含英文字母與數字
</p>
</div>
這次比較特別的是:
aria-describedby="password-hint"
它將密碼輸入框與下方的格式提示建立關聯。
另外,使用 CSS 調整提示文字:
.field-hint {
font-size: 26px;
color: #666;
line-height: 1.4;
margin-top: -8px;
overflow-wrap: anywhere;
}
同意區塊則包含勾選框、隱私權政策與網站使用條款。
<div class="agreement">
<input
id="reg-agree"
type="checkbox"
formControlName="agree"
/>
<label for="reg-agree">我已閱讀並同意</label>
<span>
<a routerLink="/privacy">《隱私權政策》</a> 與
<a routerLink="/terms">《網站使用條款》</a>
</span>
</div>
CSS:
.agreement {
display: flex;
flex-wrap: wrap;
align-items: baseline;
gap: 8px 16px;
margin-top: 48px;
font-size: 26px;
}
透過 flex-wrap: wrap,讓政策文字在空間不足時可以換行。
另外,這次也使用:
input[type='checkbox'] {
flex: 0 0 24px;
width: 24px;
height: 24px;
accent-color: #326d8b;
}
其中:
accent-color: #326d8b;
可以調整原生 Checkbox 的強調色,不需要完全重新製作一個勾選框。
不過目前表單中的格式文字主要屬於提示,尚未完成完整的正式欄位驗證與錯誤狀態 UI。
完成登入與註冊後,接著開始實作個人資料頁面。
這次個人資料頁面主要分成兩個區塊:
其中會員資料包含:
聯絡資訊包含:
這次和前面的表單不同,個人資料查看畫面主要是呈現既有資料,不是讓使用者直接輸入內容。
因此使用另一組 HTML 標籤來表示。
這次學習到 HTML 的描述清單:
dl
dt
dd
目前 HTML:
<h2 id="member-title">會員資料</h2>
<dl>
<dt>姓名:</dt>
<dd>{{ display().name }}</dd>
<dt>性別:</dt>
<dd>{{ display().gender }}</dd>
<dt>出生日期:</dt>
<dd>{{ display().birthDate }}</dd>
</dl>
<h2 class="contact-title">聯絡資訊</h2>
<dl>
<dt>Email:</dt>
<dd>{{ display().email }}</dd>
<dt>手機號碼:</dt>
<dd>{{ display().phone }}</dd>
</dl>
<dl>
表示描述清單。
<dt>姓名:</dt>
用來表示欄位名稱。
<dd>{{ display().name }}</dd>
用來表示對應的資料內容。
例如:
會員資料
姓名: 王小明
性別: 男
出生日期: 2005/01/01
聯絡資訊
Email: example@email.co
手機號碼: 0912-345-678
這次使用 dl、dt、dd,而不是單純用多個 p 將欄位名稱與資料排列在一起。
讓 HTML 本身可以清楚表達「欄位名稱」與「資料值」的關係。
目前頁面使用的是模擬展示資料,不是真實會員資訊。
個人資料查看頁面使用 CSS Grid,將欄位名稱與資料內容排成左右兩欄。
目前 CSS:
dl {
display: grid;
grid-template-columns: 320px minmax(0, 1fr);
gap: 36px 44px;
font-size: 42px;
}
dd {
min-width: 0;
overflow-wrap: anywhere;
}
grid-template-columns: 320px minmax(0, 1fr);
第一欄固定為 320px,用來放置欄位名稱。
第二欄使用剩餘空間,顯示實際資料。
gap: 36px 44px;
分別控制資料列之間與左右欄位之間的距離。
overflow-wrap: anywhere;
讓較長的 Email 或其他資料在空間不足時可以換行。
這次沒有使用省略號將資料截斷,希望使用者可以看到完整的展示內容。
個人資料頁面沿用網站原本的淺藍色標題區,並將會員資料放在中央卡片中。
目前 CSS:
.profile-banner {
min-height: 254px;
display: grid;
align-content: center;
justify-items: center;
gap: 8px;
padding: 30px 24px;
text-align: center;
background: #eaf4f8;
}
.profile-content {
max-width: 1052px;
margin: auto;
padding: 124px 28px 112px;
}
.member-card {
border: 1px solid #9ad7f7;
border-radius: 20px;
padding: 48px 94px 130px;
box-shadow: 0 3px 5px rgb(0 0 0 / 0.15);
}
這次使用:
max-width: 1052px;
margin: auto;
限制內容最大寬度並水平置中。
另外使用:
border-radius: 20px;
讓個人資料卡片具有圓角。
搭配邊框與陰影,讓資料區塊和頁面背景有所區分。
這次個人資料頁面除了查看資料,也完成編輯畫面。
和登入、註冊不同的是,個人資料查看與編輯共用同一張卡片。
兩種狀態的主要差異:
| 項目 | 查看畫面 | 編輯畫面 |
|---|---|---|
| 資料呈現 | 文字 | Input |
| 欄位名稱 | dt | label |
| 主要操作 | 編輯資料 | 儲存修改 |
| 其他操作 | — | 取消 |
| 版面 | 左欄名稱、右欄內容 | 左欄名稱、右欄輸入框 |
這次不需要建立兩張完全不同的卡片,而是維持相同版面,改變裡面的內容。
目前編輯狀態沒有使用 .editing CSS Class,而是由 Angular 模板切換查看與編輯內容。
本篇先介紹兩種 HTML/CSS 畫面的差異,不深入說明 Angular 狀態切換。
個人資料編輯時,原本的文字會變成輸入欄位。
目前 HTML 節錄:
<div class="profile-field">
<label for="profile-name">姓名:</label>
<input
id="profile-name"
formControlName="name"
autocomplete="off"
/>
</div>
<div class="profile-field">
<label for="profile-gender">性別:</label>
<input
id="profile-gender"
formControlName="gender"
autocomplete="off"
/>
</div>
編輯表單也包含出生日期、Email 與手機號碼。
其中 Email 使用:
<input type="email" />
手機號碼使用:
<input type="tel" />
這次雖然有生日及性別欄位,但目前仍然使用文字輸入框,沒有另外加入日期選擇器或下拉選單。
目前 CSS:
.profile-field {
display: grid;
grid-template-columns: 320px minmax(0, 1fr);
gap: 44px;
align-items: center;
font-size: 40px;
}
.profile-field + .profile-field {
margin-top: 28px;
}
.profile-field input {
min-width: 0;
width: 100%;
min-height: 64px;
padding: 10px 14px;
border: 1px solid #858585;
border-radius: 5px;
background: white;
color: #292929;
font-size: 28px;
}
這次沿用個人資料查看畫面的雙欄配置。
第一欄顯示欄位名稱,第二欄顯示輸入框。
這樣從查看切換成編輯時,主要內容仍然維持相近的排列方式,不需要重新改變整張卡片的閱讀順序。
另外:
.profile-field + .profile-field {
margin-top: 28px;
}
使用相鄰兄弟選擇器,控制連續編輯欄位之間的距離。
這個技巧在 Day 17 的學經歷與專長區塊已經使用過,這次則應用到表單。
這次個人資料頁面主要有三種操作按鈕:
其中「取消」使用不同的顏色,讓它和主要的儲存操作有所區別。
目前 CSS:
.profile-button {
display: inline-flex;
align-items: center;
justify-content: center;
max-width: 100%;
min-width: 224px;
min-height: 86px;
padding: 12px 28px;
border: 1px solid transparent;
border-radius: 14px;
background: #568fab;
color: white;
font-size: 40px;
line-height: 1.5;
overflow-wrap: anywhere;
}
.profile-button:hover {
background: #44758e;
}
.secondary {
border-color: #619fbe;
background: white;
color: #555;
}
.secondary:hover {
background: #eaf4f8;
}
這次將主要按鈕設定為藍底白字,而取消按鈕使用白底與藍色邊框。
編輯畫面的操作區:
.edit-actions {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
gap: 24px;
margin-top: 80px;
}
透過 Flexbox 讓取消與儲存按鈕分別排列。
另外,個人資料編輯目前只有暫時更新展示內容。
按下儲存可以更新頁面顯示的資料,但重新整理或離開後重新進入,資料就會還原。
因此這次不能將它描述為正式會員資料已經儲存成功。
在之前的 Figma Prototype 階段,我已經設計過登出確認視窗。
原本希望使用者點擊登出時,可以先看到確認提示,再決定是否登出。
不過這次 Angular 開發仍然先以主要頁面的 HTML/CSS 為主。
目前已完成的是個人資料頁面中的登出按鈕。
HTML:
<div class="logout-row">
<button
class="profile-button logout"
type="button"
(click)="logout()"
>
登出
</button>
</div>
CSS:
.logout-row {
margin-top: 72px;
text-align: center;
}
.logout {
background: #bc3d3d;
}
.logout:hover {
background: #9e2e2e;
}
這次使用紅色背景,讓登出和一般資料編輯按鈕有所區分。
目前點擊後會直接返回登入展示頁。
登出確認 Overlay 尚未完成 Angular HTML/CSS,因此不列為本次已完成的功能。
後續如果要實作確認視窗,再另外介紹遮罩背景、對話框定位及按鈕排列。
這次同時包含登入、註冊與個人資料頁面,因此 RWD 需要考慮不同類型的排版。
主要使用的斷點:
| 頁面 | Media Query |
|---|---|
| 登入與註冊 | 1199px、599px |
| 個人資料 | 1199px、899px、599px |
這次實際檢查的畫面寬度為:
目前 CSS:
@media (max-width: 1199px) {
.auth-page {
padding: 64px 32px;
}
.auth-card {
padding: 32px 60px 48px;
}
.form-grid {
column-gap: 48px;
}
.account-field input {
font-size: 26px;
height: 74px;
}
}
當畫面縮小時,主要減少卡片內距、欄位距離及輸入框大小。
註冊表單在 768px 的畫面下仍然保留雙欄排列。
目前 CSS:
@media (max-width: 599px) {
.auth-page {
padding: 24px 16px;
}
.auth-card {
padding: 24px 20px 28px;
}
.account-field input {
height: 54px;
font-size: 18px;
}
.primary-button {
min-width: 0;
min-height: 52px;
font-size: 25px;
width: 100%;
border-radius: 10px;
}
.form-grid {
grid-template-columns: minmax(0, 1fr);
margin-top: 28px;
gap: 28px;
}
}
這裡最重要的是:
grid-template-columns: minmax(0, 1fr);
將註冊表單從桌面版的雙欄改成單欄。
例如:
桌面版
姓名 身分證字號
[輸入框] [輸入框]
出生日期 手機號碼
[輸入框] [輸入框]
手機版
姓名
[輸入框]
身分證字號
[輸入框]
出生日期
[輸入框]
手機號碼
[輸入框]
這樣可以避免在手機上將兩個輸入欄位擠在同一列。
另外,主要按鈕改成:
width: 100%;
讓按鈕配合手機版卡片寬度。
個人資料查看與編輯也需要從雙欄改成單欄。
目前 CSS:
@media (max-width: 599px) {
dl {
grid-template-columns: minmax(0, 1fr);
gap: 6px;
margin-top: 28px;
font-size: 23px;
}
dd + dt {
margin-top: 20px;
}
.profile-field {
grid-template-columns: minmax(0, 1fr);
gap: 8px;
font-size: 22px;
}
.profile-field input {
font-size: 20px;
min-height: 48px;
}
}
手機版原本左右排列的資料:
姓名: 王小明
改成:
姓名:
王小明
編輯畫面則改成:
姓名:
┌──────────────────┐
│ 王小明 │
└──────────────────┘
這次讓我了解到,表單 RWD 不能只縮小輸入框,還需要考慮標籤與欄位之間的排列關係。
這次除了畫面排版,也遇到幾個實際需要調整的問題。
由於這次的開發目標是先完成 UI,因此沒有希望提前建立看起來像正式登入的假會員流程。
後續將登入與註冊表單的送出方式調整為展示提示,不再建立模擬的正式登入狀態或帳號。
這樣可以更清楚區分目前完成的是 UI,還不是真正的驗證功能。
這次個人資料編輯主要用來展示查看與編輯的畫面差異。
因此改成只維護本頁的展示內容。
目前可以:
但資料不會永久保存,重新整理後會還原。
這次 auth.css 第一次建置時,超過 Angular 設定的 4KB 樣式警告門檻。
根據開發紀錄,第一次超過約 269 bytes。
後續移除部分重複的 Media Query 與不必要的 CSS 宣告,精簡後仍超過 1 byte。
最後再移除一項全域已經提供的 cursor 宣告,讓 CSS 容量符合原本的設定。
最終建置沒有再出現這項警告。
這次開始了解到,頁面 CSS 不只是要能呈現畫面,也需要注意是否存在重複或不必要的樣式。
這次驗收時發現,手機版「儲存修改」按鈕的白色文字搭配原本的藍色背景,在自動檢查中出現對比不足的問題。
因此調整手機版儲存按鈕的背景色。
目前 CSS:
@media (max-width: 599px) {
.edit-actions button[type='submit'] {
background: #44758e;
}
}
將背景改成較深的藍色,讓白色文字更容易辨識。
調整後重新檢查,該項自動違規已排除。
這次也讓我開始注意:
畫面設計不只是符合 Figma 的配色,也需要考慮文字在不同背景上的可讀性。
和 Day 17 相比,這次開始接觸更多與 HTML 表單有關的內容。
前面幾天主要學習:
Day 15
Grid、圖文排列與就醫資訊 RWD
Day 16
醫師列表 Grid 與 Flexbox
Day 17
HTML Table 與局部水平捲動
Day 18
HTML Form、輸入欄位與會員資料畫面
這次最重要的差異,是開始理解表單中的各種 HTML 標籤。
例如:
登入與註冊
│
├── form
│ └── 組織表單
│
├── label
│ └── 說明欄位名稱
│
├── input
│ └── 輸入資料
│
├── fieldset / legend
│ └── 將相關欄位分組
│
└── button
└── 提供操作入口
個人資料頁面則學習:
查看資料
│
└── dl / dt / dd
└── 欄位名稱與資料值
編輯資料
│
└── label / input
└── 可編輯的表單欄位
這讓我了解到,同樣是呈現使用者資料,查看和編輯可以使用不同的 HTML 元素,讓結構更符合實際用途。
另外,這次也開始注意輸入框的 Focus、按鈕的 Hover、文字對比及手機版欄位的排列。
本次主要學習:
form 建立登入與註冊表單。label for 與 input id 關聯欄位名稱。type="password"、type="tel"、type="email"。type="checkbox" 建立勾選欄位。type="submit" 與 type="button" 的差異。placeholder 與 ::placeholder 設定提示文字。autocomplete 表達欄位的自動填寫用途。fieldset、legend 將註冊欄位分組。grid-column: 1 / -1 建立全寬欄位。legend::after 製作分隔線。accent-color 調整 Checkbox 顏色。aria-describedby 關聯輸入欄位與格式提示。dl、dt、dd 呈現個人資料。本次主要使用 Codex 協助:
fieldset 與 legend 組織表單。這次延續之前的方式,先提供 Figma 截圖與需求,再透過 Codex 協助完成畫面。
完成後,我再閱讀實際 HTML/CSS,了解這次使用的表單標籤、CSS Grid 與不同視覺狀態的用途。
本次主要完成智慧醫院管理平台的登入、註冊與個人資料頁面 UI。
目前包含:
登入頁面:

目前包含:
註冊頁面:

目前包含:
這次使用 dl、dt、dd 呈現欄位名稱與資料內容。
個人資料查看畫面:

這次將原本的資料文字改成輸入框,並提供取消與儲存修改按鈕。
目前可以暫時更新畫面中的展示資料,但不會永久儲存。
個人資料編輯畫面:

本次主要調整:
登入頁面
桌面大卡片 → 手機縮小內距與輸入框
註冊頁面
桌面雙欄 → 手機單欄
個人資料
左側標籤、右側內容
↓
手機改成上下排列
登入或註冊手機版:

目前登入、註冊與個人資料頁面的主要 UI 已經完成。
接下來希望繼續完成尚未開發的前端畫面,並逐步補齊會員相關的 UI。
其中還需要處理:
等主要頁面完成後,再集中深入學習 Angular TypeScript 的表單處理、狀態切換及資料管理。
最後再逐步串接 ASP.NET Core Web API 與 Oracle Database,將目前的展示畫面擴充成真正可以使用的醫院預約掛號平台。
這次最大的收穫,是開始從單純的圖文與卡片排版,進一步學習 HTML 表單與資料顯示結構,也更清楚了解 UI 完成和正式功能完成之間的差異。