線上課程觀課進度管理小工具開發日誌
Day 6:JavaScript 程式碼執行排序:遞迴函數、Call Stack、Task Queue
Call Stack;遞迴函數與 call stack 的關係;Task Queue(非同步的概念再釐清)
Day 9:「修煉圈圈 Practice Rings」Web app 開發日誌 - 2025 六角 AI Vibe Coding 體驗營期末大魔王作業
這份筆記旨在記錄 2025 六角 Vibe Coding 體驗營每日作業 Day 21 的期末專案成果,從一個簡單的個人痛點出發,透過與 AI(在我這個情境中是 Perplexity)協作,在一天內完成了一個包含前後端的全端網頁小工具:「修煉圈圈 Practice Rings」。
記錄雞蛋糕的每一步前端煉成過程,從小白到(也許是)前端工程師的學習與分享。
線上課程觀課進度管理小工具開發日誌
Day 6:JavaScript 程式碼執行排序:遞迴函數、Call Stack、Task Queue
Call Stack;遞迴函數與 call stack 的關係;Task Queue(非同步的概念再釐清)
Day 9:「修煉圈圈 Practice Rings」Web app 開發日誌 - 2025 六角 AI Vibe Coding 體驗營期末大魔王作業
這份筆記旨在記錄 2025 六角 Vibe Coding 體驗營每日作業 Day 21 的期末專案成果,從一個簡單的個人痛點出發,透過與 AI(在我這個情境中是 Perplexity)協作,在一天內完成了一個包含前後端的全端網頁小工具:「修煉圈圈 Practice Rings」。
記錄雞蛋糕的每一步前端煉成過程,從小白到(也許是)前端工程師的學習與分享。

Subscribe to 雞蛋糕的前端修煉屋

Subscribe to 雞蛋糕的前端修煉屋
<100 subscribers
<100 subscribers
今日閱讀:《單元測試的藝術》3/e 2.6 p.56 ~ 2.8 p.64
書中示範用 Jest beforeEach API 把不同測試條件共同需要初始化的程式碼抽出來,Vitest 也有相對應完全相容的 API
API | 執行時機 | 適用情境 | 潛在問題 |
|---|---|---|---|
| 每個測試前 | • 初始化測試資料<br>• 建立新的物件實例<br>• 重置狀態 | ⚠️ 如果初始化成本高,會拖慢測試速度 |
| 每個測試後 | • 清理資源<br>• 關閉連線<br>• 刪除測試檔案 | ⚠️ 如果忘記清理,可能影響其他測試 |
| 所有測試前一次 | • 建立昂貴的資源(DB連線)<br>• 載入大型設定檔 | ⚠️ 測試間可能共享狀態,導致互相影響 |
| 所有測試後一次 | • 關閉資料庫連線<br>• 清理共享資源 | ⚠️ 如果測試失敗可能不會執行 |
需要在測試前做初始化?
↓
能用 beforeEach 嗎?
↓ 是
✅ 用 beforeEach(預設選擇)
↓ 否(速度真的太慢)
↓
能重構程式碼避免依賴嗎?
↓ 是
✅ 重構(最佳解法)
↓ 否(物理限制)
↓
⚠️ 用 beforeAll(最後手段)
+ 寫清楚的註解說明為什麼
+ 確保狀態真的不會被修改
+ 加上 afterAll 清理
// password-verifier1.test.js
import { describe, it, expect, beforeEach } from "vitest";
import { PasswordVerifier1 } from "./password-verifier1";
describe("Password Verifier", () => {
// 以 USE 原則為測試命名
describe("with a failing rule", () => {
let verifier;
let fakeRule;
beforeEach(() => {
// 設定測試的輸入
verifier = new PasswordVerifier1();
fakeRule = (input) => ({ passed: false, reason: "fake reason" });
verifier.addRule(fakeRule);
});
it("has an error message based on the rule.reason", () => {
// 用輸入來呼叫進入點
const errors = verifier.verify("any value");
// 檢查退出點
expect(errors[0]).toMatch("fake reason");
});
// 在同一個退出點檢查額外的最終結果,解決斷言輪盤問題
it("has exactly one error message", () => {
// 用輸入來呼叫進入點
const errors = verifier.verify("any value");
// 檢查退出點
expect(errors.length).toBe(1);
});
});
});
describe("with a failing rule")
→ let verifier; let fakeRule; (變數宣告)
→ beforeEach 執行 (第1次) - 賦值給 verifier, fakeRule
→ it("has an error message...") 執行
→ beforeEach 執行 (第2次) - **重新賦值**
→ it("has exactly one error") 執行
按照範例寫完覺得上下捲動閱讀似乎降低了可讀性,聯想到之前看過的工廠函式概念,嘗試重構改寫:
// password-verifier1.test.js
import { describe, it, expect, beforeEach } from "vitest";
import { PasswordVerifier1 } from "./password-verifier1";
describe("Password Verifier", () => {
// 以 USE 原則為測試命名
describe("with a failing rule", () => {
// 用工廠函式取代 beforeEach 初始化每個測試條件需要的輸入參數
function createVerifierWithFakeRule() {
const verifier = new PasswordVerifier1();
const fakeRule = (input) => ({ passed: false, reason: "fake reason" });
verifier.addRule(fakeRule);
return verifier;
}
it("has an error message based on the rule.reason", () => {
// 用輸入來呼叫進入點
const verifier = createVerifierWithFakeRule();
const errors = verifier.verify("any value");
// 檢查退出點
expect(errors[0]).toMatch("fake reason");
});
// 在同一個退出點檢查額外的最終結果,解決斷言輪盤問題
it("has exactly one error message", () => {
// 用輸入來呼叫進入點
const verifier = createVerifierWithFakeRule();
const errors = verifier.verify("any value");
// 檢查退出點
expect(errors.length).toBe(1);
});
});
});
比較三種方案:
方案 | 可讀性 | 彈性 | 複雜度 |
|---|---|---|---|
重複代碼 | ⭐⭐⭐ 完整獨立 | ⭐⭐⭐ 每個測試都能客製化 | ⭐ 最簡單 |
beforeEach | ⭐ 需要跳轉閱讀 | ⭐ 難以客製化 | ⭐⭐ 中等 |
工廠函式 | ⭐⭐ 語意清楚 | ⭐⭐⭐ 可以傳參數客製化 | ⭐⭐ 中等 |
註:自己做完工廠函式版本才發現這就是作者緊接著在 2.7 安排的內容,專有名詞是避免「捲動疲勞」,2.7 略讀帶過
如果確認測試程式已封裝完整且不再需要 describe 結構,可以考慮移除,作者似乎是比較喜歡最後保留 test...expect 簡潔風格,跟 describe...it...expect 的結構化風格各有好處,實作時要拿捏可維護性和可讀性的平衡點
今日閱讀: MDN Getting Started Modules 文件 目前進度到 Learn > Getting started modules > Web standards > The web standards model
HTML 是標記語言,告訴瀏覽器該如何呈現畫面
由起始標籤、內容、結束標籤組成,可以增加一或多個屬性以利設定元素色彩、對齊方式、格線等視覺特性
包在起始標籤內,與元素名稱或其他屬性間有空格,屬性名稱後接 =
img 是一種沒有內容的空元素,因為圖片元素是直接把圖檔嵌在 HTML 上,以下列範例程式碼來說,它有開始標籤、兩個屬性、沒有內容、沒有結束標籤
<img src="images/firefox-icon.png" alt="My test image" />
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>My test page</title>
</head>
<body>
<img src="images/firefox-icon.png" alt="My test image" />
</body>
</html>
用元素的概念階層式閱讀,可以找到的元素:
<!doctype html> 文件類型
<html> 根元素
<head> 元素,包含 metadata,預設樣式不會顯示
<meta charset="utf-8" /> 指定字元編碼為 UTF-8
<title> 瀏覽器標題列會顯示的標題
<body> 元素,包含所有網頁瀏覽器會顯示的內容
img 圖片元素,是一種沒有內容和結尾標籤的空元素
屬性
src :source,圖片來源,可以是本地或遠端路徑
alt :alternative,替代說明文字,可以讓報讀軟體說明圖片內容給視覺障礙者
有 <h1> - <h6> 六個階層標題可以使用,<p> 用來表示文字段落
無排序清單 unordered list:<ul>...<li>
排序清單 ordered list:<ol>...<li>
<a> anchor,用 href 屬性加上網址
CSS 是一種風格頁面語言,讓 HTML 元素呈現不同樣式
p {
color: red;
width: 500px;
border: 1px solid black;
}
選擇器1,
選擇器2,
選擇器3 {
屬性1: 屬性值1;
屬性2: 屬性值2;
屬性3: 屬性值3;
}
選擇器有非常多不同類型,分別選取不同元素、屬性、類別 class、id …… 等 HTML 元素
CSS 佈局主要基於「box 模型」。在頁面空間的每個 box 都有下列屬性:
padding:內容周圍的空格
border: 位於矩形內容外部的實線
margin: 元素外部的空間
用 display 控制元素是 box 或 inline 顯示
每個瀏覽器都有一套內建的預設樣式表,當 HTML 沒有套用任何 CSS 時,瀏覽器會自動套用這套樣式讓網頁有基本排版 。 geeksforgeeks
本質:
<head> 只是普通 HTML 元素,透過 display: none; 隱藏 stackoverflow
所有元素的「預設長相」都來自 CSS,不是寫死在瀏覽器中
瀏覽器廠商可以自行決定預設樣式細節 reddit
元素 | 可能的差異 |
|---|---|
| Chrome/Firefox/Safari 的 |
|
|
| 圓角、內距、邊框樣式在 Safari 和 Chrome 有差異 stackoverflow |
表單元素 | 輸入框、下拉選單外觀差異最明顯 geeksforgeeks |
<!-- 在不同瀏覽器看起來會有細微差異 -->
<h1>歡迎來到我的網站</h1>
<p>這是一段文字</p>
Chrome DevTools 檢查方式:
打開開發者工具(F12)
選取元素
找到標註「user agent stylesheet」的樣式 stackoverflow
不像以前那麼必要,但仍有實務價值 youtube
現代瀏覽器(Chrome、Firefox、Safari、Edge)預設樣式已非常接近
不像 IE6 時代需要大量調整 dev
減少重複工作:避免每個專案都寫一次相同的覆寫
團隊一致性:確保所有開發者從相同基準線開始 mui
細微差異仍存在:表單元素在不同瀏覽器還是有差異 geeksforgeeks
誤解:「CSS 後面覆蓋前面,所以不需要 Reset」
正確觀念:
覆蓋只能蓋住「你有寫的屬性」
沒寫的屬性仍會使用瀏覽器預設值
不同瀏覽器的預設值可能不同
/* 情境 1:沒有 Reset */
h1 {
font-size: 24px; /* 只覆蓋 font-size */
}
/* 問題: margin 沒寫,各瀏覽器可能不同 */
/* 情境 2:有 Reset */
* {
margin: 0; /* 先清空所有 margin */
}
h1 {
font-size: 24px;
margin-bottom: 16px; /* 明確定義需要的間距 */
}
/* 結果: 完全掌控,各瀏覽器一致 */
/* 現代最小化 Reset */
*, *::before, *::after {
box-sizing: border-box;
}
body {
margin: 0;
line-height: 1.5;
}
img, picture, video {
max-width: 100%;
display: block;
}
button, input, select, textarea {
font: inherit;
}
<!-- 保留有用的預設樣式,只修正不一致的部分 -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css">
適用場景: youtube
不想完全清空預設樣式
希望保留瀏覽器有意義的預設值(如 <b> 的粗體)
Material UI、Bootstrap 等框架已內建 Reset,使用框架時不需額外引入 。 mui
誤解:「Reset 只影響 <body> 元素」
正確觀念:
CSS Reset 的萬用選擇器 * 會選中所有元素,包括 <html>、<head>、<meta> youtube
<head> 隱藏是因為瀏覽器預設 display: none;,不是因為它特殊
Reset 通常不會改變 display 屬性,所以 <head> 仍然不顯示
/* 實驗 1:證明 <head> 是普通元素 */
head {
display: block !important;
background: yellow;
padding: 10px;
}
/* 結果: <head> 會顯示在頁面上 */
/* 實驗 2:Reset 不會影響 display */
* {
margin: 0;
padding: 0;
}
/* 結果: <head> 仍然隱藏,因為 display: none 沒被覆蓋 */
當多個樣式來源同時存在時:
瀏覽器預設: head { display: none; margin: 8px; }
你的 Reset: * { margin: 0; }
─────────────────────────────────────────────
合併結果: head { display: none; margin: 0; }
關鍵:屬性會合併,不是完全取代 。 stackoverflow
只在 Chrome 測試就上線
至少在 Chrome、Firefox、Safari 測試
盲目複製 2010 年的完全清空式 Reset
使用現代輕量級 Reset,只重置必要項目 news.ycombinator
以為「自己的 CSS」會完全取代「瀏覽器預設」
理解「只有寫到的屬性會覆蓋」
以為 <head> 有特殊的「永遠不顯示」機制
理解它只是透過 display: none; 隱藏的普通元素 stackoverflow
建立空白 HTML 檔案,只放 <h1> 和 <p>
在 Chrome DevTools 檢查它們的 margin 值
加上 * { margin: 0; },觀察變化
/* 執行這段 CSS,觀察結果 */
* {
border: 1px solid red;
}
head {
display: block;
}
思考:為什麼 <head> 會顯示並有紅色邊框?
在 Chrome 和 Firefox 分別測試同一個按鈕的外觀差異。
MDN - CSS Cascade - 理解層疊原理 developer.mozilla
W3C HTML 預設樣式參考 - 官方建議的預設樣式 blog.csdn
問題 | 答案 |
|---|---|
不同瀏覽器預設樣式有差異嗎? | 有,但現代瀏覽器差異已很小 dev |
2026 年還需要 CSS Reset 嗎? | 不是必須,但有討論仍建議使用輕量版 news.ycombinator |
CSS 能覆蓋預設樣式,為何要 Reset? | 只能覆蓋「有寫的屬性」,沒寫的仍有差異 |
Reset 會影響 | 會選中,但不會改變其 |
核心原則:從統一的起點開始,明確定義所有需要的樣式,不依賴瀏覽器預設值。
今日閱讀:《單元測試的藝術》3/e 2.6 p.56 ~ 2.8 p.64
書中示範用 Jest beforeEach API 把不同測試條件共同需要初始化的程式碼抽出來,Vitest 也有相對應完全相容的 API
API | 執行時機 | 適用情境 | 潛在問題 |
|---|---|---|---|
| 每個測試前 | • 初始化測試資料<br>• 建立新的物件實例<br>• 重置狀態 | ⚠️ 如果初始化成本高,會拖慢測試速度 |
| 每個測試後 | • 清理資源<br>• 關閉連線<br>• 刪除測試檔案 | ⚠️ 如果忘記清理,可能影響其他測試 |
| 所有測試前一次 | • 建立昂貴的資源(DB連線)<br>• 載入大型設定檔 | ⚠️ 測試間可能共享狀態,導致互相影響 |
| 所有測試後一次 | • 關閉資料庫連線<br>• 清理共享資源 | ⚠️ 如果測試失敗可能不會執行 |
需要在測試前做初始化?
↓
能用 beforeEach 嗎?
↓ 是
✅ 用 beforeEach(預設選擇)
↓ 否(速度真的太慢)
↓
能重構程式碼避免依賴嗎?
↓ 是
✅ 重構(最佳解法)
↓ 否(物理限制)
↓
⚠️ 用 beforeAll(最後手段)
+ 寫清楚的註解說明為什麼
+ 確保狀態真的不會被修改
+ 加上 afterAll 清理
// password-verifier1.test.js
import { describe, it, expect, beforeEach } from "vitest";
import { PasswordVerifier1 } from "./password-verifier1";
describe("Password Verifier", () => {
// 以 USE 原則為測試命名
describe("with a failing rule", () => {
let verifier;
let fakeRule;
beforeEach(() => {
// 設定測試的輸入
verifier = new PasswordVerifier1();
fakeRule = (input) => ({ passed: false, reason: "fake reason" });
verifier.addRule(fakeRule);
});
it("has an error message based on the rule.reason", () => {
// 用輸入來呼叫進入點
const errors = verifier.verify("any value");
// 檢查退出點
expect(errors[0]).toMatch("fake reason");
});
// 在同一個退出點檢查額外的最終結果,解決斷言輪盤問題
it("has exactly one error message", () => {
// 用輸入來呼叫進入點
const errors = verifier.verify("any value");
// 檢查退出點
expect(errors.length).toBe(1);
});
});
});
describe("with a failing rule")
→ let verifier; let fakeRule; (變數宣告)
→ beforeEach 執行 (第1次) - 賦值給 verifier, fakeRule
→ it("has an error message...") 執行
→ beforeEach 執行 (第2次) - **重新賦值**
→ it("has exactly one error") 執行
按照範例寫完覺得上下捲動閱讀似乎降低了可讀性,聯想到之前看過的工廠函式概念,嘗試重構改寫:
// password-verifier1.test.js
import { describe, it, expect, beforeEach } from "vitest";
import { PasswordVerifier1 } from "./password-verifier1";
describe("Password Verifier", () => {
// 以 USE 原則為測試命名
describe("with a failing rule", () => {
// 用工廠函式取代 beforeEach 初始化每個測試條件需要的輸入參數
function createVerifierWithFakeRule() {
const verifier = new PasswordVerifier1();
const fakeRule = (input) => ({ passed: false, reason: "fake reason" });
verifier.addRule(fakeRule);
return verifier;
}
it("has an error message based on the rule.reason", () => {
// 用輸入來呼叫進入點
const verifier = createVerifierWithFakeRule();
const errors = verifier.verify("any value");
// 檢查退出點
expect(errors[0]).toMatch("fake reason");
});
// 在同一個退出點檢查額外的最終結果,解決斷言輪盤問題
it("has exactly one error message", () => {
// 用輸入來呼叫進入點
const verifier = createVerifierWithFakeRule();
const errors = verifier.verify("any value");
// 檢查退出點
expect(errors.length).toBe(1);
});
});
});
比較三種方案:
方案 | 可讀性 | 彈性 | 複雜度 |
|---|---|---|---|
重複代碼 | ⭐⭐⭐ 完整獨立 | ⭐⭐⭐ 每個測試都能客製化 | ⭐ 最簡單 |
beforeEach | ⭐ 需要跳轉閱讀 | ⭐ 難以客製化 | ⭐⭐ 中等 |
工廠函式 | ⭐⭐ 語意清楚 | ⭐⭐⭐ 可以傳參數客製化 | ⭐⭐ 中等 |
註:自己做完工廠函式版本才發現這就是作者緊接著在 2.7 安排的內容,專有名詞是避免「捲動疲勞」,2.7 略讀帶過
如果確認測試程式已封裝完整且不再需要 describe 結構,可以考慮移除,作者似乎是比較喜歡最後保留 test...expect 簡潔風格,跟 describe...it...expect 的結構化風格各有好處,實作時要拿捏可維護性和可讀性的平衡點
今日閱讀: MDN Getting Started Modules 文件 目前進度到 Learn > Getting started modules > Web standards > The web standards model
HTML 是標記語言,告訴瀏覽器該如何呈現畫面
由起始標籤、內容、結束標籤組成,可以增加一或多個屬性以利設定元素色彩、對齊方式、格線等視覺特性
包在起始標籤內,與元素名稱或其他屬性間有空格,屬性名稱後接 =
img 是一種沒有內容的空元素,因為圖片元素是直接把圖檔嵌在 HTML 上,以下列範例程式碼來說,它有開始標籤、兩個屬性、沒有內容、沒有結束標籤
<img src="images/firefox-icon.png" alt="My test image" />
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>My test page</title>
</head>
<body>
<img src="images/firefox-icon.png" alt="My test image" />
</body>
</html>
用元素的概念階層式閱讀,可以找到的元素:
<!doctype html> 文件類型
<html> 根元素
<head> 元素,包含 metadata,預設樣式不會顯示
<meta charset="utf-8" /> 指定字元編碼為 UTF-8
<title> 瀏覽器標題列會顯示的標題
<body> 元素,包含所有網頁瀏覽器會顯示的內容
img 圖片元素,是一種沒有內容和結尾標籤的空元素
屬性
src :source,圖片來源,可以是本地或遠端路徑
alt :alternative,替代說明文字,可以讓報讀軟體說明圖片內容給視覺障礙者
有 <h1> - <h6> 六個階層標題可以使用,<p> 用來表示文字段落
無排序清單 unordered list:<ul>...<li>
排序清單 ordered list:<ol>...<li>
<a> anchor,用 href 屬性加上網址
CSS 是一種風格頁面語言,讓 HTML 元素呈現不同樣式
p {
color: red;
width: 500px;
border: 1px solid black;
}
選擇器1,
選擇器2,
選擇器3 {
屬性1: 屬性值1;
屬性2: 屬性值2;
屬性3: 屬性值3;
}
選擇器有非常多不同類型,分別選取不同元素、屬性、類別 class、id …… 等 HTML 元素
CSS 佈局主要基於「box 模型」。在頁面空間的每個 box 都有下列屬性:
padding:內容周圍的空格
border: 位於矩形內容外部的實線
margin: 元素外部的空間
用 display 控制元素是 box 或 inline 顯示
每個瀏覽器都有一套內建的預設樣式表,當 HTML 沒有套用任何 CSS 時,瀏覽器會自動套用這套樣式讓網頁有基本排版 。 geeksforgeeks
本質:
<head> 只是普通 HTML 元素,透過 display: none; 隱藏 stackoverflow
所有元素的「預設長相」都來自 CSS,不是寫死在瀏覽器中
瀏覽器廠商可以自行決定預設樣式細節 reddit
元素 | 可能的差異 |
|---|---|
| Chrome/Firefox/Safari 的 |
|
|
| 圓角、內距、邊框樣式在 Safari 和 Chrome 有差異 stackoverflow |
表單元素 | 輸入框、下拉選單外觀差異最明顯 geeksforgeeks |
<!-- 在不同瀏覽器看起來會有細微差異 -->
<h1>歡迎來到我的網站</h1>
<p>這是一段文字</p>
Chrome DevTools 檢查方式:
打開開發者工具(F12)
選取元素
找到標註「user agent stylesheet」的樣式 stackoverflow
不像以前那麼必要,但仍有實務價值 youtube
現代瀏覽器(Chrome、Firefox、Safari、Edge)預設樣式已非常接近
不像 IE6 時代需要大量調整 dev
減少重複工作:避免每個專案都寫一次相同的覆寫
團隊一致性:確保所有開發者從相同基準線開始 mui
細微差異仍存在:表單元素在不同瀏覽器還是有差異 geeksforgeeks
誤解:「CSS 後面覆蓋前面,所以不需要 Reset」
正確觀念:
覆蓋只能蓋住「你有寫的屬性」
沒寫的屬性仍會使用瀏覽器預設值
不同瀏覽器的預設值可能不同
/* 情境 1:沒有 Reset */
h1 {
font-size: 24px; /* 只覆蓋 font-size */
}
/* 問題: margin 沒寫,各瀏覽器可能不同 */
/* 情境 2:有 Reset */
* {
margin: 0; /* 先清空所有 margin */
}
h1 {
font-size: 24px;
margin-bottom: 16px; /* 明確定義需要的間距 */
}
/* 結果: 完全掌控,各瀏覽器一致 */
/* 現代最小化 Reset */
*, *::before, *::after {
box-sizing: border-box;
}
body {
margin: 0;
line-height: 1.5;
}
img, picture, video {
max-width: 100%;
display: block;
}
button, input, select, textarea {
font: inherit;
}
<!-- 保留有用的預設樣式,只修正不一致的部分 -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css">
適用場景: youtube
不想完全清空預設樣式
希望保留瀏覽器有意義的預設值(如 <b> 的粗體)
Material UI、Bootstrap 等框架已內建 Reset,使用框架時不需額外引入 。 mui
誤解:「Reset 只影響 <body> 元素」
正確觀念:
CSS Reset 的萬用選擇器 * 會選中所有元素,包括 <html>、<head>、<meta> youtube
<head> 隱藏是因為瀏覽器預設 display: none;,不是因為它特殊
Reset 通常不會改變 display 屬性,所以 <head> 仍然不顯示
/* 實驗 1:證明 <head> 是普通元素 */
head {
display: block !important;
background: yellow;
padding: 10px;
}
/* 結果: <head> 會顯示在頁面上 */
/* 實驗 2:Reset 不會影響 display */
* {
margin: 0;
padding: 0;
}
/* 結果: <head> 仍然隱藏,因為 display: none 沒被覆蓋 */
當多個樣式來源同時存在時:
瀏覽器預設: head { display: none; margin: 8px; }
你的 Reset: * { margin: 0; }
─────────────────────────────────────────────
合併結果: head { display: none; margin: 0; }
關鍵:屬性會合併,不是完全取代 。 stackoverflow
只在 Chrome 測試就上線
至少在 Chrome、Firefox、Safari 測試
盲目複製 2010 年的完全清空式 Reset
使用現代輕量級 Reset,只重置必要項目 news.ycombinator
以為「自己的 CSS」會完全取代「瀏覽器預設」
理解「只有寫到的屬性會覆蓋」
以為 <head> 有特殊的「永遠不顯示」機制
理解它只是透過 display: none; 隱藏的普通元素 stackoverflow
建立空白 HTML 檔案,只放 <h1> 和 <p>
在 Chrome DevTools 檢查它們的 margin 值
加上 * { margin: 0; },觀察變化
/* 執行這段 CSS,觀察結果 */
* {
border: 1px solid red;
}
head {
display: block;
}
思考:為什麼 <head> 會顯示並有紅色邊框?
在 Chrome 和 Firefox 分別測試同一個按鈕的外觀差異。
MDN - CSS Cascade - 理解層疊原理 developer.mozilla
W3C HTML 預設樣式參考 - 官方建議的預設樣式 blog.csdn
問題 | 答案 |
|---|---|
不同瀏覽器預設樣式有差異嗎? | 有,但現代瀏覽器差異已很小 dev |
2026 年還需要 CSS Reset 嗎? | 不是必須,但有討論仍建議使用輕量版 news.ycombinator |
CSS 能覆蓋預設樣式,為何要 Reset? | 只能覆蓋「有寫的屬性」,沒寫的仍有差異 |
Reset 會影響 | 會選中,但不會改變其 |
核心原則:從統一的起點開始,明確定義所有需要的樣式,不依賴瀏覽器預設值。
Share Dialog
Share Dialog
No activity yet