Skip to content

chore: 設定 stylelint(支援 libsass)並導入 husky 提交前自動 lint#76

Open
ross-nics wants to merge 2 commits into
mainfrom
chore/lint-css-style
Open

chore: 設定 stylelint(支援 libsass)並導入 husky 提交前自動 lint#76
ross-nics wants to merge 2 commits into
mainfrom
chore/lint-css-style

Conversation

@ross-nics

Copy link
Copy Markdown

概述

導入 stylelint 對 CSS/SCSS 的 lint 與自動修正,並透過 husky + lint-staged 在 commit 前自動處理。針對專案使用的 libsass(Hugo 內建轉譯器)調整規則,確保 lint 規範與實際編譯環境一致。

Lint 設定變更(.stylelintrc.json)

既有規則

規則 說明
extends stylelint-config-standard-scss SCSS 標準規則集
plugins stylelint-order 屬性排序
order/order custom-properties, declarations 自訂屬性置前
order/properties-alphabetical-order true 屬性字母排序

本次新增規則

規則 用途
selector-class-pattern BEM 正規式 放寬命名規範,允許 BEM block__element--modifier,避免誤判既有命名
no-descending-specificity null 關閉;對既有大型樣式易誤報且無法自動修正
scss/no-global-function-names null 允許 unquote / unitless 等全域函式(libsass 不支援 Dart Sass module)
media-feature-range-notation "prefix" 強制 @media (max-width: …)(libsass 不支援 (width <= …) range 語法)
color-function-notation "legacy" 強制 rgba(…)(libsass 不支援 rgb(0 0 0 / .5) 現代語法)

⚠️ 後三項為 libsass 相容性關鍵:stylelint-config-standard-scss 預設輸出 Dart Sass / 現代 CSS 語法,會導致 Hugo 編譯失敗,故需明確指定 legacy 行為。

npm scripts 變更(package.json)

  • lint:styles / lint:fix:styles 的 glob 由 **/*.css 擴充為 **/*.{css,scss},使 SCSS 一併納入檢查。

提交前自動化(husky + lint-staged)

  • 新增 huskylint-staged devDependencies。
  • 新增 .husky/pre-commit:commit 時對 staged 的 .css / .scss 執行 stylelint --fix 並重新 stage。
"lint-staged": {
  "*.{css,scss}": "stylelint --fix"
}

樣式修正

  • 套用 stylelint --fix 的屬性排序等安全變更(多檔案)。
  • 手動修正無法自動處理的問題:
    • table.scss:合併重複選擇器(no-duplicate-selectors)
    • guide.scss:移除重複的 clip-path
    • warning-text.scss:拆開同行宣告並修正屬性排序
    • accordion.scss:SCSS 變數改為 kebab-case(含使用處)
    • form.scss:@extend .list 加上 inline disable 註解
    • breadcrumb.scss:數字精度修正
    • main.scss:// 註解後補空白

驗證

  • npm run lint:styles 零錯誤
  • hugo --gc --minify 成功編譯全部 91 頁
  • ✅ pre-commit hook 實測可對 staged 樣式自動修正

變更範圍

涵蓋 31 個檔案(.stylelintrc.jsonpackage.jsonpackage-lock.json.husky/,以及 CSS/SCSS 樣式檔)。

- add husky and lint-staged dev dependencies
- run stylelint --fix on staged .css/.scss files via pre-commit hook
- include .scss in lint:styles and lint:fix:styles globs
- adjust .stylelintrc.json for libsass compatibility (legacy color notation, prefix media-feature range, allow global sass functions)
- relax selector-class-pattern to allow BEM naming; disable no-descending-specificity
- fix remaining lint errors: duplicate selectors/properties, property order, variable kebab-case, extend placeholder, number precision, comment spacing
- apply stylelint --fix property ordering across css/scss files
@github-actions

Copy link
Copy Markdown

@ross-nics ross-nics requested review from nonumpa and tony140407 June 10, 2026 10:00

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request configures Husky and lint-staged for pre-commit linting, updates Stylelint rules, and formats various CSS and SCSS files. The review feedback highlights several compatibility and code quality improvements, such as enforcing numeric alpha values in Stylelint to avoid compilation errors in older environments, reverting Selector Level 4 :not() lists to chained selectors, renaming variables to proper kebab-case, restoring -webkit-clip-path for older Safari support, and correcting a multi-declaration line formatting issue.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread .stylelintrc.json
Comment on lines +12 to +13
"media-feature-range-notation": "prefix",
"color-function-notation": "legacy",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

在相容舊版編譯器(如 libsass)與舊版瀏覽器的情境下,rgba() 中的百分比不透明度(例如 rgba(0, 0, 0, 18%))可能會導致編譯錯誤或解析失敗。\n\n建議在 .stylelintrc.json 中加入 \"alpha-value-notation\": \"number\" 規則,強制使用小數格式(例如 0.18),並還原各樣式檔案中被自動修正為百分比的 alpha 值。

    "media-feature-range-notation": "prefix",
    "color-function-notation": "legacy",
    "alpha-value-notation": "number",

padding: 0.6rem 1.2rem;

&:hover:not(.button-disabled):not(:disabled), &:focus {
&:hover:not(.button-disabled, :disabled), &:focus {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

:not() 內使用選擇器列表(例如 :not(.button-disabled, :disabled))是 CSS Selectors Level 4 的新特性,在 Internet Explorer 以及舊版 Safari/Chrome/Firefox 中完全不支援。\n\n由於此專案需要相容舊版環境(libsass),建議在 .stylelintrc.json 中設定 \"selector-not-notation\": \"double\",並將此處還原為多個 :not() 連接的寫法(:not(.button-disabled):not(:disabled)),以確保相容性。

Suggested change
&:hover:not(.button-disabled, :disabled), &:focus {
&:hover:not(.button-disabled):not(:disabled), &:focus {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

應為 "selector-not-notation": "simple"
selector-not-notation 在這個 Stylelint 版本只有兩種值:simple 和 complex。沒有 double。

Comment on lines +5 to +6
$accordion-header-fontcolor: var(--textColor);
$accordion-header-active-fontcolor: var(--backgroundColor);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

PR 說明中提到「SCSS 變數改為 kebab-case」,但此處將 fontColor 改為 fontcolor 僅是全小寫,並非標準的 kebab-case。\n\n為了與同檔案中的其他變數(如 $accordion-header-active-bg)保持一致,建議命名為 $accordion-header-font-color$accordion-header-active-font-color。\n\n> ⚠️ 修改後請記得一併更新第 24 行與第 65 行的使用處。

$accordion-header-font-color: var(--textColor); 
$accordion-header-active-font-color: var(--backgroundColor); 

Comment thread assets/css/guide.scss
Comment on lines +52 to +54
border: 0;
clip: rect(0,0,0,0);
clip-path: inset(50%);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

在 Safari 15.3 以前以及 iOS Safari 15.3 以前的版本中,HTML 元素上的 clip-path 仍需要 -webkit- 前綴。\n\n為了確保舊版 Apple 裝置上的相容性,避免 .sr-only 的內容意外顯露,建議保留 -webkit-clip-path: inset(50%);

Suggested change
border: 0;
clip: rect(0,0,0,0);
clip-path: inset(50%);
border: 0;
clip: rect(0,0,0,0);
-webkit-clip-path: inset(50%);
clip-path: inset(50%);

Comment on lines +6 to 8
left: 0;
position: absolute; right: 0;
top: 0;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

第 7 行在同一行中包含了多個宣告(position: absolute; right: 0;),這違反了標準的 CSS 排版規範,且降低了程式碼的可讀性。建議將其拆分至獨立行。

  left: 0;
  position: absolute;
  right: 0;
  top: 0;

@nonumpa nonumpa left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

補充兩個建議

Comment thread assets/css/color.css
Comment on lines +107 to +109
--gov-font-sans-serif: system-ui, -apple-system, "Segoe UI", roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--gov-font-monospace: sfmono-regular, menlo, monaco, consolas, "Liberation Mono", "Courier New", monospace;
--gov-gradient: linear-gradient(180deg, rgba(255, 255, 255, 15%), rgba(255, 255, 255, 0%));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stylelint --fix 目前會把 custom property 裡未加引號的字體名稱轉成小寫,例如 RobotorobotoSFMono-Regularsfmono-regular。雖然多數瀏覽器比對 font family 時通常不區分大小寫,但 Linux fontconfig 在某些設定下可能是 case-sensitive,因此這類大小寫變更仍可能影響字體匹配結果。

建議把非 generic 的字體名稱加上引號,並保留 system-ui-apple-systemsans-serifmonospace 這類 generic/system keyword 不加引號,例如:

--gov-font-sans-serif: system-ui, -apple-system, "Segoe UI", "Roboto", "Helvetica Neue", "Noto Sans", "Liberation Sans", "Arial", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--gov-font-monospace: "SFMono-Regular", "Menlo", "Monaco", "Consolas", "Liberation Mono", "Courier New", monospace;

Comment thread package.json
"lint:fix:styles": "npx stylelint '**/*.css' --ignore-path .gitignore --fix"
"lint:styles": "npx stylelint '**/*.{css,scss}' --ignore-path .gitignore",
"lint:fix:styles": "npx stylelint '**/*.{css,scss}' --ignore-path .gitignore --fix",
"prepare": "husky"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

建議在 readme 補充開發前要先 npm install

開發

安裝前端開發工具與 Git hooks:

npm install

在本機啟動網站:

hugo server

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants