同方向失敗 ≥ 2 次時的轉折協議 — 停下來驗證底層假設、不沿同方向加碼到第 3 次。

適用:debug 反覆失敗、CSS 規則不生效、JS 改完元素還原、layout 怎麼調都不對。 不適用:第 1 次失敗(修細節即可);不同方向各自失敗 1 次(不算同方向累積)。

自包含聲明:閱讀本文件不需要先讀其他 reference。本文件涵蓋失敗計數、假設驗證、換方向決策、對外回報模板。


何時參閱本文件

訊號該做的第一件事
同方向第 2 次失敗停 — 用工具驗證底層假設
內心 OS:「再試一次更小心應該就過」停 — 這是沉沒成本綁住的訊號
即將加 !important 解 specificity停 — 切到 CSS layers 思路
即將加第 2 條 polyfill 補跨瀏覽器停 — 先回報成本、問使用者意願
即將用 imperative JS 補宣告式 layout停 — 切到 CSS-first 思路

為什麼第 2 次是轉折點

第 1 次失敗常是執行細節(typo、cache、syntax)— 修了再試通常會過。

第 2 次失敗、用同樣的方法但更小心、還是失敗 — 訊號的重量遠大於兩次相加。它說的是:「我以為的問題不在這層、根本問題在別處」

第 3 次以上、沉沒成本綁住、加碼產生的副作用會超過解決的問題:

嘗試次數心理狀態行動模式副作用
1信心足直接做
2信心動搖加碼(更複雜的 selector / important)可控
3焦慮全面反擊(layers + important + polyfill)大 — 改動範圍擴張
4+沉沒成本綁住不肯放棄已寫的嚴重 — 為前面的錯買單

第 2 次是還能優雅切換方向的最後機會。


失敗計數的協議

失敗次數行動
第 1 次修細節(typo、cache、syntax)再試
第 2 次停下來 — 用工具驗證底層假設(DOM tree、computed style、framework 行為)
第 2 次驗證後假設對 → 繼續修;假設錯 → 換方向、不為前面買單

關鍵動作是第 2 次的「停」 — 把行動從「執行更努力」切換到「驗證假設」。


假設驗證的具體方法

方法 1:用工具讀真實狀態

假設類型驗證工具
DOM 結構playwright browser_evaluate 讀 ancestor chain
Computed styleplaywright + getComputedStyle()
元素位置playwright + getBoundingClientRect()
Framework 行為讀框架 source、看 reconciliation 條件
Event 觸發DevTools Event Listeners panel + console.count()

方法 2:反問「如果假設錯了會怎樣」

這個反思能在沒有工具的情況下測試假設。

假設如果錯了會發生什麼
Drawer 是 form 的 sibling那 grid-row 完全無效(drawer 跟 form 共用 grid cell)
Specificity 30 是上限那 layers 才是解、不是雙寫 selector
元素永遠存在於 DOM那 framework 重渲染後 querySelector 會回 null

「如果錯了會發生什麼」的答案 = 你正在看的失敗現象 → 假設可能錯。

方法 3:對外回報模板

1我嘗試了 [方向 X]:
2- 第 1 次:[做法 A] → [現象]
3- 第 2 次:[做法 B] → [一樣的現象]
4
5我的底層假設是「[假設 Z]」、但 [方法 1 / 方法 2 的驗證] 顯示 Z 似乎不成立。
6
7要不要換 [方向 W]、或您看到我沒看到的訊息嗎?

對外回報 = 把卡關放到使用者視野、避免繼續單方面加碼。


假設錯了之後:換方向 ≠ 全部重寫

換方向不是「之前的全部丟掉」、是「對抗錯假設的部分丟掉、其他保留」。

範例:search scope UI 放在「form 與 results 之間」。

  • 嘗試 1-4:基於假設「drawer 是 form 的 sibling」、用 grid + display:contents + grid-row 排序 → 全失敗
  • 第 5 次(用 playwright 驗證):drawer 是 form 的 child、跟 form 共用 grid cell
  • 換方向:不用 grid-row 控制位置(被假設綁住的部分)、改用 absolute + drawer margin-top(不被假設綁住)→ 一次成功

換方向後保留:CSS variable 命名、scope 命名、HTML 結構。丟掉:grid-row 規則。只丟跟錯假設綁定的代碼、不丟所有東西


Wrong vs Right 對照

範例 1:specificity 戰

1/* 第 1 次:規則沒生效 */
2.target { color: red; }
3/* 第 2 次:加 specificity */
4.parent .target { color: red; }
5/* 第 3 次:再加 */
6.parent .container .target { color: red; }
7/* 第 4 次:放大絕招 */
8.parent .container .target { color: red !important; }

四次同方向加碼、根本問題(vendor CSS 用了更高 specificity 或更晚 cascade)沒解。

 1/* 第 1 次:規則沒生效 */
 2.target { color: red; }
 3
 4/* 第 2 次失敗 → 停下來驗證假設 */
 5/* DevTools Computed → 看到 vendor 的 .pagefind .target { color: blue } 贏了 */
 6/* 假設「我的規則該贏」錯 → 換方向:CSS layers */
 7
 8@layer vendor { /* @import vendor css here */ }
 9/* 我的規則 unlayered → 自動贏所有 layered 規則 */
10.target { color: red; }

範例 2:JS 改完元素被還原

1// 第 1 次:改完被還原
2el.textContent = 'custom';
3// 第 2 次:加保護
4setTimeout(() => { el.textContent = 'custom'; }, 100);
5// 第 3 次:再加
6setInterval(() => { el.textContent = 'custom'; }, 50);  // CPU 100%

 1// 第 1 次:改完被還原
 2el.textContent = 'custom';
 3
 4// 第 2 次失敗 → 停、驗證假設
 5// playwright: 看到 framework 每次 state change 重渲染整個子樹
 6// 假設「我的修改會 stick」錯 → 換方向:把客製 UI 放到 framework 邊界外
 7
 8const customEl = document.createElement('div');
 9customEl.textContent = 'custom';
10container.appendChild(customEl);  // 不在 framework 子樹內、不會被 reconcile

自檢清單(dogfooding)

第 2 次失敗時、用這份清單檢查:

  • 我有沒有列出「底層假設是什麼」?
  • 我有沒有用工具或反問驗證假設?
  • 如果假設錯了、有沒有列出替代方向?
  • 對外回報訊息有沒有寫「驗證 X、似乎不成立、要不要換 W」這種句式?
  • 我有沒有避免「再試一次更小心」這種同方向加碼的衝動?

任一項打勾失敗 → 停下來補上、再決定下一步。


延伸閱讀

對應的事後檢討(在 content/report/):


Last Updated: 2026-04-26 Version: 0.1.0