diff --git a/apps/site/src/content/en/changelog.mdx b/apps/site/src/content/en/changelog.mdx
index 9cefbdb88..e5a63d778 100644
--- a/apps/site/src/content/en/changelog.mdx
+++ b/apps/site/src/content/en/changelog.mdx
@@ -15,6 +15,7 @@ Significant changes may continue until v1.0 is released, so all notable changes
- For components added with `lism-cli ui add` before v0.26.0, change `@layer lism-component` to `lism-block` in their `_style.css`.
- **Breaking:** Removed the deprecated component aliases `SideMain` / `FluidCols` / `SwitchCols` and the `Dummy` component from `lism-css/react` and `lism-css/astro`. Migrate to `WithSide` / `AutoColumns` / `SwitchColumns` and `DummyText` from `@lism-css/ui`, respectively (#646).
- **Breaking:** Removed `_propConfig`, which overrode the Lism Props conversion settings per prop, from `getLismProps` and component props. To change the conversion settings, use [`props` in `lism.config.js`](/en/docs/customize/config/) instead (#225).
+- `@lism-css/ui`: Fixed `lism-base` styles taking priority over `b--*` styles when component CSS is output before `lism-css/main.css` (for example, a `Button` rendered as an `a` element kept its underline and link color). Each component's CSS and `style.css` now declare the order of `lism-base` and `lism-block` at the top (#644).
diff --git a/apps/site/src/content/ja/changelog.mdx b/apps/site/src/content/ja/changelog.mdx
index 440d4b1ed..983298186 100644
--- a/apps/site/src/content/ja/changelog.mdx
+++ b/apps/site/src/content/ja/changelog.mdx
@@ -15,6 +15,7 @@ v1.0のリリースまでは大きな変更が続く可能性があるため、
- v0.26.0より前に`lism-cli ui add`で追加したコンポーネントは、`_style.css`の`@layer lism-component`を`lism-block`へ書き換えてください。
- **破壊的変更:** 非推奨だったコンポーネントエイリアス`SideMain` / `FluidCols` / `SwitchCols`と`Dummy`コンポーネントを、`lism-css/react`と`lism-css/astro`から削除しました。それぞれ`WithSide` / `AutoColumns` / `SwitchColumns`と`@lism-css/ui`の`DummyText`へ移行してください(#646)。
- **破壊的変更:** Lism Propsの変換設定をprop単位で上書きする`_propConfig`を、`getLismProps`と各コンポーネントのpropsから削除しました。変換設定を変えたい場合は、[`lism.config.js`の`props`](/docs/customize/config/)で設定してください(#225)。
+- `@lism-css/ui`: コンポーネントのCSSが`lism-css/main.css`より前に出力されると、`lism-base`のスタイルが`b--*`のスタイルより優先される不具合を修正しました(`a`要素の`Button`に下線とリンク色が残るなど)。各コンポーネントのCSSと`style.css`の先頭で、`lism-base`と`lism-block`の順序を宣言します(#644)。
diff --git a/docs/decisions.md b/docs/decisions.md
index e4e19cc10..9037c374d 100644
--- a/docs/decisions.md
+++ b/docs/decisions.md
@@ -1,7 +1,17 @@
-基準日: 2026-09-28・コミットc9321bcec
+基準日: 2026-09-29・コミット4aa2aa5c6
# 意思決定の記録
+## 2026-09-29: `@lism-css/ui`のコンポーネントCSSは先頭で`lism-base, lism-block`の順序だけを宣言する
+
+各コンポーネントは自分の`_style.css`をimportしており、そのCSSの出力位置は利用側のバンドラが決める。`lism-css/main.css`より前に出力されると`lism-block`が最初のレイヤーとして登録され、`lism-base`より弱くなる(#644)。`a`要素の`Button`に下線とリンク色が残った。
+
+- 決定: `packages/lism-ui/src/components/*/_style.css`の各先頭に`@layer lism-base, lism-block;`を置き、全ファイルにあることをテストで検査する。`@layer`文は登録済みのレイヤーの位置を変えず、未登録のレイヤーを宣言順に後ろへ足す。先頭の2層を固定すれば、後から読まれる`main.css`の宣言で残りの層が正しい順に並ぶ。ui側のCSSが使うレイヤーは`lism-block`だけ。
+- 却下: 6層すべてを宣言する案。レイヤーを増減するたびにui側も直すことになる(`lism-component`の削除がその例)。
+- 却下: コンポーネント側のCSSの自動読み込みをやめ、`style.css`に一本化する案。利用者に`style.css`の読み込みを求める破壊的変更になり、使うコンポーネントのCSSだけを読み込む利点も失う。
+- 却下: ビルド時に`dist`のCSSへ宣言を付与する案。Astro版は`src`の`_style.css`を読むため効かない。
+- 決定: `dist/style.css`は全コンポーネントの`_style.css`を結合するため、同じ宣言がコンポーネントの数だけ入る。`packages/lism-ui/build-css.js`がコンパイル後に先頭の1つだけ残し、1つも無ければビルドを失敗させる。共有の`compileCssTree`と`dist/components/*/_style.css`は変えない。
+
## 2026-09-28: 後方互換用の`lism-component`レイヤーを削除する
v0.26.0で`c--`を`b--`へ移行したとき(#546, #559)、旧`c--`の配置先だった`lism-component`は宣言だけ残した。宣言から消すと、利用者CSSの`@layer lism-component`が初出の位置で登録され、優先度が変わるため。空のレイヤーが公開文書の6層の表記と食い違うという報告があり、v1へ持ち越さずに互換を切る。
diff --git a/packages/lism-ui/build-css.js b/packages/lism-ui/build-css.js
index 5f30033c7..d96fa7b46 100644
--- a/packages/lism-ui/build-css.js
+++ b/packages/lism-ui/build-css.js
@@ -1,3 +1,4 @@
+import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
// P1 で bin/build-css.js(compileSCSS)は共有コアへ統合された。
@@ -7,6 +8,21 @@ import { compileCssTree } from '@lism-css/plugin/builder';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
+const LAYER_ORDER_PATTERN = /@layer\s+lism-base\s*,\s*lism-block\s*;/g;
+
+// style.css は全コンポーネントの _style.css を結合するため、同じ順序宣言が重複する。先頭の1つだけ残す。
+function dedupeLayerOrder(cssPath) {
+ const css = fs.readFileSync(cssPath, 'utf8');
+
+ let count = 0;
+ const deduped = css.replace(LAYER_ORDER_PATTERN, (match) => (count++ === 0 ? match : ''));
+ if (count === 0) {
+ throw new Error(`[build-css] ${path.relative(__dirname, cssPath)} にレイヤー順序宣言が見つかりません`);
+ }
+
+ fs.writeFileSync(cssPath, deduped);
+}
+
// デフォルトエクスポート(他から await 可能)
async function buildCSS() {
// パス(絶対パスに変換)
@@ -14,6 +30,7 @@ async function buildCSS() {
const distDir = path.resolve(__dirname, './dist/');
await compileCssTree({ scssDir, distDir });
+ dedupeLayerOrder(path.resolve(distDir, 'style.css'));
}
buildCSS();
diff --git a/packages/lism-ui/src/components/Accordion/_style.css b/packages/lism-ui/src/components/Accordion/_style.css
index db7fbc260..9d2621eb2 100644
--- a/packages/lism-ui/src/components/Accordion/_style.css
+++ b/packages/lism-ui/src/components/Accordion/_style.css
@@ -1,3 +1,4 @@
+@layer lism-base, lism-block;
@layer lism-block {
.b--accordion {
--duration: var(--acc-duration, 0.25s);
diff --git a/packages/lism-ui/src/components/Alert/_style.css b/packages/lism-ui/src/components/Alert/_style.css
index 2959ae1f7..4ccba7845 100644
--- a/packages/lism-ui/src/components/Alert/_style.css
+++ b/packages/lism-ui/src/components/Alert/_style.css
@@ -1,3 +1,4 @@
+@layer lism-base, lism-block;
@layer lism-block {
/* Note: u--cbox との併用を前提としています。layout="withSide" 指定時は l--withSide がレイアウトを上書きします. */
.b--alert {
diff --git a/packages/lism-ui/src/components/Avatar/_style.css b/packages/lism-ui/src/components/Avatar/_style.css
index f77535b9a..ad0164010 100644
--- a/packages/lism-ui/src/components/Avatar/_style.css
+++ b/packages/lism-ui/src/components/Avatar/_style.css
@@ -1,3 +1,4 @@
+@layer lism-base, lism-block;
@layer lism-block {
/* src ありの通常時: l--frame との併用が前提 */
.b--avatar {
diff --git a/packages/lism-ui/src/components/Badge/_style.css b/packages/lism-ui/src/components/Badge/_style.css
index 610468504..dbc594774 100644
--- a/packages/lism-ui/src/components/Badge/_style.css
+++ b/packages/lism-ui/src/components/Badge/_style.css
@@ -1,3 +1,4 @@
+@layer lism-base, lism-block;
@layer lism-block {
.b--badge {
--c: var(--base);
diff --git a/packages/lism-ui/src/components/Button/_style.css b/packages/lism-ui/src/components/Button/_style.css
index bc3ace2d5..80801bcb8 100644
--- a/packages/lism-ui/src/components/Button/_style.css
+++ b/packages/lism-ui/src/components/Button/_style.css
@@ -1,3 +1,4 @@
+@layer lism-base, lism-block;
@layer lism-block {
.b--button {
--c: var(--base);
diff --git a/packages/lism-ui/src/components/Callout/_style.css b/packages/lism-ui/src/components/Callout/_style.css
index 2af086da1..3943ad57b 100644
--- a/packages/lism-ui/src/components/Callout/_style.css
+++ b/packages/lism-ui/src/components/Callout/_style.css
@@ -1,3 +1,4 @@
+@layer lism-base, lism-block;
@layer lism-block {
/* Note: l--stack と u--cbox との併用を前提としています. */
.b--callout {
diff --git a/packages/lism-ui/src/components/Details/_style.css b/packages/lism-ui/src/components/Details/_style.css
index f1658deb1..009d93a08 100644
--- a/packages/lism-ui/src/components/Details/_style.css
+++ b/packages/lism-ui/src/components/Details/_style.css
@@ -1,3 +1,4 @@
+@layer lism-base, lism-block;
/* ::details-content と grid-template-rows: 0fr → 1fr のトランジションでアニメーション */
@layer lism-block {
.b--details {
diff --git a/packages/lism-ui/src/components/Modal/_style.css b/packages/lism-ui/src/components/Modal/_style.css
index 0edbfea98..41f0e19a1 100644
--- a/packages/lism-ui/src/components/Modal/_style.css
+++ b/packages/lism-ui/src/components/Modal/_style.css
@@ -1,3 +1,4 @@
+@layer lism-base, lism-block;
/*
* dialog で実装.
* Memo: ::backdrop のアニメーションはFirefoxで動かない
diff --git a/packages/lism-ui/src/components/NavMenu/_style.css b/packages/lism-ui/src/components/NavMenu/_style.css
index 7b427ed84..1f6b73741 100644
--- a/packages/lism-ui/src/components/NavMenu/_style.css
+++ b/packages/lism-ui/src/components/NavMenu/_style.css
@@ -1,3 +1,4 @@
+@layer lism-base, lism-block;
@layer lism-block {
.b--navMenu {
--link-td: none;
diff --git a/packages/lism-ui/src/components/Popover/_style.css b/packages/lism-ui/src/components/Popover/_style.css
index 808de46f3..66bfb5775 100644
--- a/packages/lism-ui/src/components/Popover/_style.css
+++ b/packages/lism-ui/src/components/Popover/_style.css
@@ -1,3 +1,4 @@
+@layer lism-base, lism-block;
/*
* ネイティブ Popover API(popover 属性)で開閉し、CSS Anchor Positioning で配置する。
* anchor 配置は @supports で囲い、非対応ブラウザ(部分対応の Chrome 128〜130 を含む)には
diff --git a/packages/lism-ui/src/components/ShapeDivider/_style.css b/packages/lism-ui/src/components/ShapeDivider/_style.css
index eb0f38d0a..12031b136 100644
--- a/packages/lism-ui/src/components/ShapeDivider/_style.css
+++ b/packages/lism-ui/src/components/ShapeDivider/_style.css
@@ -1,3 +1,4 @@
+@layer lism-base, lism-block;
/* Note: scale 反転は、__inner に対して行う。shapeDivider自身を反転させると、X方向に隙間ができてしまう。 */
@layer lism-block {
.b--shapeDivider {
diff --git a/packages/lism-ui/src/components/Tabs/_style.css b/packages/lism-ui/src/components/Tabs/_style.css
index 751ead523..f69a66c2d 100644
--- a/packages/lism-ui/src/components/Tabs/_style.css
+++ b/packages/lism-ui/src/components/Tabs/_style.css
@@ -1,3 +1,4 @@
+@layer lism-base, lism-block;
@layer lism-block {
/* l--grid との併用が前提 */
.b--tabs {
diff --git a/packages/lism-ui/src/components/Tooltip/_style.css b/packages/lism-ui/src/components/Tooltip/_style.css
index 9280412b8..b499d88c9 100644
--- a/packages/lism-ui/src/components/Tooltip/_style.css
+++ b/packages/lism-ui/src/components/Tooltip/_style.css
@@ -1,3 +1,4 @@
+@layer lism-base, lism-block;
/*
* 表示は CSS(:hover / :focus-visible)、配置は CSS Anchor Positioning。
* anchor 配置は @supports で囲い、非対応(部分対応の Chrome 128〜130 含む)はルート基準の absolute 配置に落とす。
diff --git a/packages/lism-ui/src/components/styleLayerOrder.test.ts b/packages/lism-ui/src/components/styleLayerOrder.test.ts
new file mode 100644
index 000000000..258aa1a64
--- /dev/null
+++ b/packages/lism-ui/src/components/styleLayerOrder.test.ts
@@ -0,0 +1,25 @@
+import { existsSync, readdirSync, readFileSync } from 'node:fs';
+import { dirname, resolve } from 'node:path';
+import { fileURLToPath } from 'node:url';
+import { describe, expect, it } from 'vitest';
+
+const componentsDir = dirname(fileURLToPath(import.meta.url));
+
+// バンドラがコンポーネントCSSを lism-css/main.css より前に出力しても、lism-block が lism-base より後ろになるよう先頭で順序を固定する
+const LAYER_ORDER = /^@layer lism-base, lism-block;\r?\n/;
+
+const styleFiles = readdirSync(componentsDir, { withFileTypes: true })
+ .filter((entry) => entry.isDirectory())
+ .map((entry) => `${entry.name}/_style.css`)
+ .filter((file) => existsSync(resolve(componentsDir, file)));
+
+describe('コンポーネントCSSのレイヤー順序宣言', () => {
+ it('検査対象の _style.css が見つかる', () => {
+ expect(styleFiles.length).toBeGreaterThan(0);
+ });
+
+ it.each(styleFiles)('%s の先頭に順序宣言がある', (file) => {
+ const css = readFileSync(resolve(componentsDir, file), 'utf8');
+ expect(css).toMatch(LAYER_ORDER);
+ });
+});