iT邦幫忙

2026 iThome 鐵人賽

0

一、今日目標

延續 Day 17「醫師詳細資訊頁面」的開發,這次開始實作智慧醫院管理平台的「登入」、「註冊」與「個人資料」頁面。

前面幾天主要依照 Figma 設計,逐步完成首頁、醫院介紹、就醫資訊、醫師查詢及醫師詳細資訊頁面的 HTML/CSS。

這次希望繼續將 Figma 的會員相關頁面轉換成 Angular 網頁,並學習如何使用 HTML 表單標籤與 CSS 完成不同類型的輸入欄位。

本次主要目標:

  • 根據 Figma 完成登入、註冊與個人資料頁面的 HTML/CSS。
  • 學習使用 form、label、input 建立表單。
  • 完成帳號、密碼、手機號碼等輸入欄位樣式。
  • 學習使用 fieldset 與 legend 將註冊欄位分組。
  • 使用 CSS Grid 建立註冊表單的雙欄排列。
  • 完成登入、註冊按鈕與相關連結的視覺設計。
  • 建立個人資料查看與編輯兩種畫面。
  • 學習使用 dl、dt、dd 呈現會員資料。
  • 設計 Hover 與 Focus 狀態。
  • 使用 Media Query 完成桌面、平板與手機版 RWD。
  • 檢查畫面與 Figma 設計的差異。

這次主要記錄 HTML/CSS 與畫面實作,登入驗證、註冊資料處理及個人資料儲存等功能,會留到後續 TypeScript 與後端開發階段再深入介紹。


二、目前的開發進度

目前智慧醫院管理平台的主要資訊頁面已逐步完成。

在 Day 16,我完成醫師查詢頁面,讓使用者可以瀏覽醫師列表。

Day 17 則接著完成醫師詳細資訊,包含醫師介紹、專長、學經歷與門診時間表。

這次開始處理會員相關的頁面。

目前網站的開發進度:

SmartCare Hospital
│
├── 首頁
│
├── 醫院介紹
│
├── 就醫資訊
│
├── 醫師查詢
│
├── 醫師詳細資訊
│
├── 登入 ← 本次開發
│
├── 註冊 ← 本次開發
│
└── 個人資料 ← 本次開發
    ├── 查看資料
    └── 編輯資料

這次和前幾天比較不同的是,之前主要製作圖片、文字、卡片及表格,而登入、註冊與個人資料會使用到更多輸入欄位。

因此除了要符合 Figma 的外觀,也需要考慮欄位名稱、輸入框、提示文字及操作按鈕之間的關係。

這讓我開始思考:

表單設計不只是將輸入框排列整齊,也需要讓使用者清楚知道每個欄位的用途,以及目前可以進行哪些操作。


三、登入、註冊與個人資料頁面的設計思考

這次主要分成三個部分。

1. 登入頁面

登入頁面需要讓使用者快速找到帳號與密碼欄位,因此採用較簡單的單欄表單。

主要包含:

  • SmartCare Logo。
  • 登入標題與歡迎文字。
  • 帳號輸入框。
  • 密碼輸入框。
  • 記住我。
  • 忘記密碼。
  • 登入按鈕。
  • 註冊入口。

2. 註冊頁面

註冊需要填寫的資料比登入多,因此將欄位分成不同群組。

主要包含:

  • 個人基本資料。
  • 帳號設定。
  • 隱私權政策與網站使用條款。
  • 建立帳號按鈕。
  • 返回登入入口。

桌面版使用雙欄排列,避免所有欄位都擠在同一條垂直方向上。

3. 個人資料頁面

個人資料主要分成查看與編輯兩種狀態。

查看時以文字呈現會員資料,編輯時則改成輸入框,讓使用者可以清楚區分目前是查看還是修改資料。

目前三個頁面都先以 UI 展示為主,沒有加入正式登入驗證或資料庫儲存。

另外,Figma 之前已經設計過登出確認 Overlay,但目前 Angular 尚未實作該視窗,因此這次只完成登出按鈕與返回登入展示頁的行為。


四、登入與註冊頁面的 HTML 結構

這次登入與註冊沒有分別建立 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 建立登入頁面卡片

登入頁面主要使用淺藍色背景,中央放置白色表單卡片。

目前 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;
}

1. min-height

min-height: 100vh;

表示登入頁面的最小高度為整個瀏覽器視窗高度。

即使表單內容不多,也可以讓淺藍色背景至少覆蓋一個畫面。

2. max-width

max-width: 996px;

限制登入卡片的最大寬度,避免在大型螢幕上被拉得過寬。

3. margin: auto

margin: auto;

這裡主要用來讓固定最大寬度的區塊在水平方向置中。

值得注意的是,這次並沒有使用 Flexbox 或 Grid 將整張卡片垂直置中,而是透過外層的 padding 控制卡片與頁面頂部的距離。

4. padding

padding: 32px 88px 60px;

分別設定:

  • 上方:32px。
  • 左右:88px。
  • 下方:60px。

讓卡片內的 Logo、標題與表單保留適當空間。

這次登入卡片沒有另外設定圓角或陰影,主要以白底與灰色邊框呈現 Figma 的設計。


六、使用 HTML Form 建立登入欄位

這次開始接觸比較完整的 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 標籤。

1. form

<form>

form 用來將相關輸入欄位與送出按鈕組織成同一個表單。

和之前單純排列圖片或文字不同,表單中的元素具有明確的輸入與提交用途。

2. label

<label for="login-account">帳號</label>

label 用來說明輸入欄位的名稱。

其中:

for="login-account"

會對應:

id="login-account"

這樣使用者點擊「帳號」文字時,也可以將焦點移到對應的輸入框。

3. input

<input
  id="login-account"
  placeholder="請輸入姓名"
/>

input 提供使用者輸入資料。

這次帳號欄位沒有另外設定 type,因此瀏覽器會使用預設的文字輸入類型。

4. 密碼輸入框

<input type="password" />

type="password" 會將輸入內容以遮蔽形式呈現,避免密碼直接顯示在畫面上。

5. submit 按鈕

<button type="submit">登入</button>

表示這個按鈕是表單的送出入口。

這次雖然保留表單送出結構,但目前登入仍屬於 UI 展示,尚未串接真正的帳號驗證服務。


七、使用 CSS Grid 排列 Label 與 Input

完成登入表單的 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;
}

這次將每組欄位分成兩個主要元素:

帳號
┌─────────────────────────┐
│ 請輸入姓名               │
└─────────────────────────┘

1. display: grid

display: grid;

讓 label 與 input 依照順序垂直排列。

2. gap

gap: 20px;

控制欄位名稱與輸入框之間的距離。

3. width: 100%

width: 100%;

讓輸入框填滿可用的欄位寬度。

4. min-width: 0

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>

這裡使用了兩種不同的輸入與操作方式。

1. checkbox

<input type="checkbox" />

用來呈現可勾選的選項。

2. type="button"

<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 設計 Hover 與 Focus 狀態

這次除了輸入框與按鈕的基本外觀,也針對不同操作狀態調整樣式。

目前 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;
}

這次主要複習三個概念。

1. ::placeholder

input::placeholder {
  color: #737373;
}

用來調整輸入欄位中提示文字的顏色。

2. :hover

.account-field input:hover {
  border-color: #44758e;
}

當滑鼠移到輸入欄位上方時,邊框會改變顏色。

3. :focus-visible

input:focus-visible {
  outline: 3px solid #165a80;
  outline-offset: 4px;
}

當元素處於符合 :focus-visible 的焦點狀態時,顯示明顯的外框。

這次除了考慮滑鼠操作,也開始注意使用鍵盤切換表單欄位時的視覺提示。


十、建立註冊頁面的 HTML 結構

完成登入頁面後,接著開始處理註冊頁面。

和登入相比,註冊需要更多欄位,因此不能直接沿用登入頁面的單欄排列。

目前註冊頁面主要分成:

建立帳號
│
├── 個人基本資料
│   ├── 姓名
│   ├── 身分證字號
│   ├── 出生日期
│   └── 手機號碼
│
├── 帳號設定
│   ├── 帳號
│   ├── 密碼
│   └── 確認密碼
│
├── 隱私權政策與使用條款
│
└── 建立帳號

這次沒有自行增加 Figma 中不存在的 Email 或性別註冊欄位。

另外,出生日期目前採用文字輸入框,並以 YYYY/MM/DD 作為提示,而不是使用日期選擇器。


十一、使用 fieldset 與 legend 將註冊欄位分組

這次註冊頁面學習到兩個新的 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>

以上節錄部分欄位,實際個人基本資料還包含出生日期與手機號碼。

1. fieldset

<fieldset>

用來將相關的表單欄位組成同一個群組。

2. legend

<legend>個人基本資料</legend>

用來為這個表單群組提供名稱。

這次了解到,fieldset 和 legend 不只是畫面排版的容器,也具有表達表單欄位群組的語意。

例如姓名、身分證字號、出生日期與手機號碼都屬於「個人基本資料」。

而帳號、密碼及確認密碼則屬於「帳號設定」。

使用這種方式可以讓註冊表單的結構更加清楚。


十二、使用 CSS Grid 建立註冊雙欄表單

這次註冊表單最主要的排版方式是 CSS Grid。

目前 CSS:

.form-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 56px 100px;
  margin-top: 48px;
}

1. grid-template-columns

grid-template-columns: repeat(2, minmax(0, 1fr));

將表單分成兩個等寬欄位。

例如:

個人基本資料

姓名                    身分證字號
┌─────────────┐        ┌─────────────┐
│             │        │             │
└─────────────┘        └─────────────┘

出生日期                手機號碼
┌─────────────┐        ┌─────────────┐
│             │        │             │
└─────────────┘        └─────────────┘

2. gap

gap: 56px 100px;

這裡使用兩個數值:

  • 56px:列與列之間的距離。
  • 100px:左右欄位之間的距離。

3. minmax(0, 1fr)

這個寫法在前面醫師卡片的 Grid 已經使用過。

本次將它應用在表單欄位上,避免輸入框或文字內容把欄位撐得過寬。

這次讓我了解到:

CSS Grid 不只能用來排列圖片或卡片,也很適合處理欄位較多、需要對齊的表單。


十三、使用 grid-column 製作全寬欄位

這次註冊表單中,確認密碼欄位需要跨越兩個欄位。

因此使用:

.full-width {
  grid-column: 1 / -1;
}

這裡的:

grid-column: 1 / -1;

代表元素從 Grid 的第一條欄線延伸到最後一條欄線。

因此原本的雙欄表單可以讓特定欄位改成全寬排列。

例如:

帳號設定

帳號                    密碼
┌─────────────┐        ┌─────────────┐
│             │        │             │
└─────────────┘        └─────────────┘

確認密碼
┌────────────────────────────────────┐
│                                    │
└────────────────────────────────────┘

這次沒有重新建立另一個單欄容器,而是直接透過 CSS Grid 的欄位設定完成版面。


十四、使用 ::after 製作表單分隔線

這次註冊頁面還有一個值得學習的 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;
}

1. ::after

legend::after

可以在元素內容後面建立一個 CSS 偽元素。

2. content

content: '';

建立一個沒有文字內容的偽元素。

3. flex: 1

flex: 1;

讓分隔線使用標題後方的剩餘空間。

4. border-top

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。


十六、建立個人資料查看頁面

完成登入與註冊後,接著開始實作個人資料頁面。

這次個人資料頁面主要分成兩個區塊:

  1. 會員資料。
  2. 聯絡資訊。

其中會員資料包含:

  • 姓名。
  • 性別。
  • 出生日期。

聯絡資訊包含:

  • Email。
  • 手機號碼。

這次和前面的表單不同,個人資料查看畫面主要是呈現既有資料,不是讓使用者直接輸入內容。

因此使用另一組 HTML 標籤來表示。


十七、使用 dl、dt、dd 呈現個人資料

這次學習到 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>

1. dl

<dl>

表示描述清單。

2. dt

<dt>姓名:</dt>

用來表示欄位名稱。

3. dd

<dd>{{ display().name }}</dd>

用來表示對應的資料內容。

例如:

會員資料

姓名:        王小明
性別:        男
出生日期:    2005/01/01

聯絡資訊

Email:       example@email.co
手機號碼:     0912-345-678

這次使用 dl、dt、dd,而不是單純用多個 p 將欄位名稱與資料排列在一起。

讓 HTML 本身可以清楚表達「欄位名稱」與「資料值」的關係。

目前頁面使用的是模擬展示資料,不是真實會員資訊。


十八、使用 CSS Grid 對齊個人資料

個人資料查看頁面使用 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;
}

1. grid-template-columns

grid-template-columns: 320px minmax(0, 1fr);

第一欄固定為 320px,用來放置欄位名稱。

第二欄使用剩餘空間,顯示實際資料。

2. gap

gap: 36px 44px;

分別控制資料列之間與左右欄位之間的距離。

3. overflow-wrap

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 排列個人資料編輯欄位

目前 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 讓取消與儲存按鈕分別排列。

另外,個人資料編輯目前只有暫時更新展示內容。

按下儲存可以更新頁面顯示的資料,但重新整理或離開後重新進入,資料就會還原。

因此這次不能將它描述為正式會員資料已經儲存成功。


二十四、登出按鈕與 Overlay 的開發狀態

在之前的 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,因此不列為本次已完成的功能。

後續如果要實作確認視窗,再另外介紹遮罩背景、對話框定位及按鈕排列。


二十五、使用 Media Query 完成 RWD

這次同時包含登入、註冊與個人資料頁面,因此 RWD 需要考慮不同類型的排版。

主要使用的斷點:

頁面 Media Query
登入與註冊 1199px、599px
個人資料 1199px、899px、599px

這次實際檢查的畫面寬度為:

  • 1440px。
  • 1024px。
  • 768px。
  • 390px。

1. 登入與註冊的平板版

目前 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 的畫面下仍然保留雙欄排列。

2. 登入與註冊的手機版

目前 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%;

讓按鈕配合手機版卡片寬度。

3. 個人資料手機版

個人資料查看與編輯也需要從雙欄改成單欄。

目前 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 不能只縮小輸入框,還需要考慮標籤與欄位之間的排列關係。


二十六、開發過程中遇到的問題

這次除了畫面排版,也遇到幾個實際需要調整的問題。

1. 原本的登入與註冊會建立模擬登入狀態

由於這次的開發目標是先完成 UI,因此沒有希望提前建立看起來像正式登入的假會員流程。

後續將登入與註冊表單的送出方式調整為展示提示,不再建立模擬的正式登入狀態或帳號。

這樣可以更清楚區分目前完成的是 UI,還不是真正的驗證功能。

2. 個人資料編輯原本會使用暫存資料

這次個人資料編輯主要用來展示查看與編輯的畫面差異。

因此改成只維護本頁的展示內容。

目前可以:

  • 進入編輯畫面。
  • 修改展示欄位。
  • 按取消放棄修改。
  • 按儲存更新目前頁面顯示的內容。

但資料不會永久保存,重新整理後會還原。

3. CSS 樣式容量警告

這次 auth.css 第一次建置時,超過 Angular 設定的 4KB 樣式警告門檻。

根據開發紀錄,第一次超過約 269 bytes。

後續移除部分重複的 Media Query 與不必要的 CSS 宣告,精簡後仍超過 1 byte。

最後再移除一項全域已經提供的 cursor 宣告,讓 CSS 容量符合原本的設定。

最終建置沒有再出現這項警告。

這次開始了解到,頁面 CSS 不只是要能呈現畫面,也需要注意是否存在重複或不必要的樣式。

4. 手機版儲存按鈕的文字對比不足

這次驗收時發現,手機版「儲存修改」按鈕的白色文字搭配原本的藍色背景,在自動檢查中出現對比不足的問題。

因此調整手機版儲存按鈕的背景色。

目前 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 將註冊欄位分組。
  • 使用 CSS Grid 建立雙欄註冊表單。
  • 使用 grid-column: 1 / -1 建立全寬欄位。
  • 使用 legend::after 製作分隔線。
  • 使用 accent-color 調整 Checkbox 顏色。
  • 使用 aria-describedby 關聯輸入欄位與格式提示。
  • 使用 dl、dt、dd 呈現個人資料。
  • 使用 CSS Grid 對齊欄位名稱與資料值。
  • 學習個人資料查看與編輯畫面的 HTML 差異。
  • 使用 Hover 與 Focus 提供視覺回饋。
  • 使用 Media Query 將表單從雙欄改成單欄。
  • 了解 CSS 配色與文字對比的關係。

二十九、AI 協助

本次主要使用 Codex 協助:

  • 檢查原本登入、註冊與個人資料頁面的結構。
  • 建立登入與註冊共用的 HTML/CSS。
  • 調整登入卡片、欄位與按鈕樣式。
  • 使用 Grid 建立註冊表單雙欄排列。
  • 使用 fieldset 與 legend 組織表單。
  • 完成個人資料查看與編輯畫面。
  • 調整個人資料欄位與按鈕樣式。
  • 協助完成桌面、平板與手機版 RWD。
  • 協助精簡 CSS 容量。
  • 修正手機版儲存按鈕的文字對比問題。
  • 整理既有的測試及開發紀錄。

這次延續之前的方式,先提供 Figma 截圖與需求,再透過 Codex 協助完成畫面。

完成後,我再閱讀實際 HTML/CSS,了解這次使用的表單標籤、CSS Grid 與不同視覺狀態的用途。


三十、今日成果

本次主要完成智慧醫院管理平台的登入、註冊與個人資料頁面 UI。

1. 登入頁面

目前包含:

  • SmartCare Logo。
  • 登入標題與歡迎文字。
  • 帳號欄位。
  • 密碼欄位。
  • 記住我。
  • 忘記密碼入口。
  • 登入按鈕。
  • 註冊入口。
  • RWD。

登入頁面:

https://ithelp.ithome.com.tw/upload/images/20261026/20178845Hd4uGeT7Up.png

2. 註冊頁面

目前包含:

  • 個人基本資料。
  • 帳號設定。
  • 帳號與密碼格式提示。
  • 確認密碼。
  • 隱私權政策及網站使用條款。
  • 建立帳號按鈕。
  • 返回登入入口。
  • 桌面雙欄與手機單欄 RWD。

註冊頁面:

https://ithelp.ithome.com.tw/upload/images/20261026/20178845iJNa86fT3U.png

3. 個人資料查看

目前包含:

  • 個人檔案標題。
  • 會員資料。
  • 聯絡資訊。
  • 編輯資料按鈕。
  • 登出按鈕。

這次使用 dl、dt、dd 呈現欄位名稱與資料內容。

個人資料查看畫面:

https://ithelp.ithome.com.tw/upload/images/20261026/20178845YRODJ3eHkM.png

4. 個人資料編輯

這次將原本的資料文字改成輸入框,並提供取消與儲存修改按鈕。

目前可以暫時更新畫面中的展示資料,但不會永久儲存。

個人資料編輯畫面:

https://ithelp.ithome.com.tw/upload/images/20261026/20178845QqMfFa9DGs.png

5. RWD

本次主要調整:

登入頁面
桌面大卡片 → 手機縮小內距與輸入框

註冊頁面
桌面雙欄 → 手機單欄

個人資料
左側標籤、右側內容
        ↓
手機改成上下排列

登入或註冊手機版:

https://ithelp.ithome.com.tw/upload/images/20261026/20178845lD0VUNUWHb.png

三十二、下一步

目前登入、註冊與個人資料頁面的主要 UI 已經完成。

接下來希望繼續完成尚未開發的前端畫面,並逐步補齊會員相關的 UI。

其中還需要處理:

  • 登出確認 Overlay。
  • Header 使用者選單。
  • 表單錯誤提示樣式。
  • 其他預約掛號流程相關頁面。
  • 各頁面的桌面與手機版 RWD。

等主要頁面完成後,再集中深入學習 Angular TypeScript 的表單處理、狀態切換及資料管理。

最後再逐步串接 ASP.NET Core Web API 與 Oracle Database,將目前的展示畫面擴充成真正可以使用的醫院預約掛號平台。

這次最大的收穫,是開始從單純的圖文與卡片排版,進一步學習 HTML 表單與資料顯示結構,也更清楚了解 UI 完成和正式功能完成之間的差異。


上一篇
Day 17|醫師詳細資訊頁面
下一篇
Day 19|預約掛號與預約成功頁面
系列文
從 Figma 到 Angular:打造智慧醫院預約掛號系統的 30 天實作之旅 共 20 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言