Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 49 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,54 @@ bootstrap-subset → theme-styles.styl の順で `/css/site.css` に連結する
生まれない。以前は 2 / 3 / 5 / 6 / 10 / 14 / 25px が混ざっており、多くは
「円の直径の半分」のようにその場で計算した値で、隣の部品と揃える理由が無いまま
1px ずつ違っていた
- **ページの最大幅は種類で変えない。幅で切り替わる点は4つだけ**(#3222)。
記事・一覧・トップ・特設はすべて同じ `.container`(540 / 720 / 960 / 1140 / 1320px)に
入る。左右の空きは全幅で 12px、列の溝は 24px、本文とサイドバーの間は 44px
(本文側 24px + サイドバー側 20px)で、**いずれも間隔の 4px 刻みの上にある**
(幅の側だけ別の単位を持たない)
- 切り替わるのは **576 / 768 / 992 / 1025px** の4つ。どれも「その列に何が入るか」で
決まる。576px = 検索窓が虫眼鏡だけになる・一覧カードのサムネが縦積み、
768px = サイドバーの探索の枠が消える・2列の一覧が1列・コードと note が全幅、
992px = ナビが引き出しに入る・フッターが4列から2列、
1025px = 本文とサイドバーが縦積み・サイドバーの統計とグラフが消える・
目次がモバイルの折りたたみへ
- **`max-width` の側は 767 / 991 / 1024、`min-width` の側は 576 / 768 / 992 / 1025 で書く。**
同じ境界を 767 と 768 の両方で書くと、768px ちょうどで両側が同時に当たる
(サイドバーの枠だけ 768px になっていて、2列化と重なっていた #3222)
- **992px と 1025px は別の境界で、片方に寄せない。** 992px は帯に何本並ぶかで、
1025px は2列にしたときの列の内寸で決まる(1025px 未満で2列にすると本文 684px・
サイドバー 208px より狭くなる #2044)。**幅で囲む規則はどちらの境界に属するかを
決めてから書く**——ドロップダウンを畳む規則が 1025px 側に付いていて、
992〜1024px では帯にナビが並ぶのに効かず、開いたパネルが残っていた(#3222)
- **中間の幅を作らない。** 2列にするかは列の内寸に中身が入るかで決めるが、
`column-width` で自動に落とすと幅 576px の端末でも2列(1列 242px)になる。
**列数は幅で決め打ちする**(#3180 と同じ判断)
- はみ出してよいのは3つだけ。**記事の中の画像**(列いっぱいを上限に、`img-width-middle`
520px と `img-width-small` 360px の2段)・**横に溢れる表**(`.scroll` の中で横スクロール)・
**767px 以下のコードと note**(`margin-inline: calc(50% - 50vw)` で画面端まで。
`.article-entry` 直下のものだけ #2568)。記事末の帯(#2874)は全幅だが、
中の `.container` が他ページと同じ左右を持つ
- **時間の段は2つ+例外1つ**(#3222)。`_variables.styl` が持つ。**役で選ぶ**

| 段 | 値 | 使うところ |
| --- | --- | --- |
| `hover-speed` | 0.05s | 反応。色・面・下線が変わるところすべて |
| `state-speed` | 0.18s | 状態の変化。タブの切り替え・ドロップダウンと引き出しの開閉・検索窓の伸縮・折りたたみの開閉 |
| `footer-underline-speed` | 0.25s | 例外。フッターのリンクの下線(#2839) |

- **状態の変化の側も1つだけ。** 以前は 0.12 / 0.15 / 0.18 / 0.2s が部品ごとに散っていて、
役が4つあるのではなく別々に決めた値が残っていただけだった。0.02〜0.05s の差は
見分けられない(#2534 の「見分けの付かない差に2つの役を割り当てない」と同じ理屈)
- **同じ操作の中で2つの段を混ぜない。** ヘッダーのカレットの回転が `hover-speed`、
指しているパネル本体が `state-speed` で、同じ「開く」が2つの速さで動いていた(#3222)
- **イージングは触らない**(#2693)。体感を決めているのは秒数だけ
- **`prefers-reduced-motion: reduce` では状態の変化を止め、反応は残す。** 開閉も
切り替えも結果だけを出す(`transition: none`)。0.05秒の色・面・下線は動きではなく
押せることの合図なので止めない(#2686 と同じ線引き)
- **打ち消しは対象と同じ詳細度で、対象より後ろに置く**(メディアクエリは詳細度を
上げない)。基底と開いた側の両方に `transition` があるなら両方を打ち消す
- **例外はドロップダウンと検索ヒントの `visibility 0s 0.3s`。** あれは動きではなく、
消えるまでに click を届かせるための待ち時間(Safari 対策)なので残す
- **サムネイルの寸法は5つしかない。新しい値を作らず、器の形で選ぶ**(#2790)。
いずれも `object-fit: cover` で切り抜き、角丸は `radius-small`。サムネの実寸は
幅300px・高さがばらばら(比 1.0〜3.2)なので、寸法はこちら側の枠が決める
Expand Down Expand Up @@ -1531,7 +1579,7 @@ bootstrap-subset → theme-styles.styl の順で `/css/site.css` に連結する
GA4 の値が 100 単位に丸められていて(全1,499件が100の倍数)、窓の中の合計では
同点が構造的に出ていたため(Business と Culture が 10,000PV でちょうど上限の線に
並んだ)。経過年で割ると値がばらけるので、実測で同点は0件になった(#3038)
- **768px 以下では3枠とも消える**(`display: none`)。サイドバーは本文の下に落ちるので、
- **767px 以下では3枠とも消える**(`display: none`)。サイドバーは本文の下に落ちるので、
一覧25本とページャの後ろに出しても読者は辿り着かない(目次を `.toc-mobile` に
移したのと同じ理由 #2452)。モバイルの行き先はヘッダーの引き出しが持つ
- 連載をここに入れたのは、646本(全記事の44%)を束ねる軸だから(#2892)。
Expand Down
56 changes: 52 additions & 4 deletions source/specials/styleguide/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,37 @@ editable: true

段階を数え上げないのは、使う値が並びの間隔だけでも 4〜48px と幅広く、どこで打ち切る理由も無いからです。刻みを4pxに揃えておけば隣の段階が必ず 4px 差になり、5px と 6px のように**見分けの付かない差**が生まれません。色を3段階に絞ったのと狙いは同じで、迷う余地を減らすためです。

## 幅

**ページの最大幅は種類で変えません。** 記事も一覧もトップも同じ枠に入ります。読む対象が変わってもページの左端と右端が動かないので、どのページでも同じ場所を見に行けます。

左右の空きは全幅で 12px です。間隔の刻み(4px)の3つぶんで、幅の側だけ別の単位を持ちません。列の溝は 24px、本文とサイドバーの間は 44px(本文側 24px とサイドバー側 20px)で、どちらも同じ刻みに乗っています。

| 画面幅 | ページの最大幅 | 本文列の内寸 | サイドバー |
| --- | --- | --- | --- |
| 〜575px | 画面いっぱい | 画面幅 − 24px | 本文の下 |
| 576〜767px | 540px | 516px | 本文の下 |
| 768〜991px | 720px | 696px | 本文の下 |
| 992〜1024px | 960px | 936px | 本文の下 |
| 1025〜1199px | 960px | 684px | 208px |
| 1200〜1399px | 1140px | 819px | 253px |
| 1400px〜 | 1320px | 954px | 298px |

**幅で切り替わる点は4つだけです。** どれも「その列に何が入るか」で決めていて、端末の呼び名では決めていません。

| 幅 | 狭い側で変わるもの | 実物 |
| --- | --- | --- |
| 576px | 検索窓が虫眼鏡だけになり、フォーカスされたときだけ帯を覆って広がる。一覧カードのサムネイルが文字の上に積む | [すべての記事](/articles/) |
| 768px | サイドバーの探索の枠が消える。2列で並べていた一覧が1列になる。コードと note が画面の端まで伸びる | [カテゴリ一覧](/categories/#categories) |
| 992px | ヘッダーのナビが帯から降りて引き出しに入る。フッターが4列から2列になる | [トップページ](/) |
| 1025px | 本文とサイドバーが縦に積む。サイドバーの統計とグラフは消え、目次は本文の上の折りたたみに移る | [記事ページ](/articles/20260804a/) |

**中間の幅を作りません。** 段階を増やすと、どの幅で確かめた見た目なのかを追えなくなります。2列にするかどうかは列の内寸に中身が入るかで決めていて、たとえばカテゴリ一覧を「列の幅が足りたら自動で2列」にすると、幅 576px の画面でも1列 242px の2列になり、説明文とタグが入りません。列数は幅で決め打ちします。

はみ出してよいものは3つあります。**記事の中の画像**は列いっぱいを上限に、縮めたいときは 520px と 360px の2段階から選びます(3段階目は置きません。狙った大きさがどちらとも違うなら、画像そのものを加工します)。**横に溢れる表**は受け皿の中で横スクロールし、ページ全体は横に動きません。**コードと note は、狭い画面でだけ画面の端まで伸びます。** 幅375pxでコードの1行に入る字数が 39.9 字から 45.0 字になり、横スクロールの要るブロックが 71.8% から 64.0% に下がります。文字の位置は段落の左端に揃うので、読者から見ると背景の帯だけが端まで伸びた形になります。本文末の帯(関連記事・We're hiring)も全幅ですが、中の左右は本文と同じ位置に揃えます。

**幅の決まりは単位ではなく構造です。** 12px・24px・44px は間隔のスケールから借りているだけで、幅そのものが持つ決まりは「ページの種類で最大幅を変えない」「切り替わる点は4つ」「はみ出すのは画像・表・コードと note だけ」の3つです。値を覚える必要はなく、どの構造に当てはまるかだけを選びます。

## 形と反応

### 角丸は3段階
Expand All @@ -327,9 +358,7 @@ editable: true

### hover は1部品1反応

同じ「押せる」の合図なので、速さは 0.05 秒の1つだけです。反応は待たせるものではないので短い側に寄せています。0.1 秒だと変化が半分進むのに 29ms かかり、カーソルを乗せて 20ms の時点でまだ3割しか動いていません。0.05 秒なら 15ms で7割動くので、ほぼ即時に見えます。

イージングは触りません。体感を決めているのは秒数だけで、20ms 時点の進捗は ease 30% 対 ease-out 31% とほぼ同じでした。
同じ「押せる」の合図なので、速さも1つだけです。秒数の決まりは下の「時間」がまとめて持ちます。

反応は入れ子のうち**外側だけ**が返します。

Expand Down Expand Up @@ -358,7 +387,7 @@ editable: true

ヘッダーの帯の中だけは、下線も背景も動かさず文字色を1段階濃くします(帯から下がるドロップダウンの行は背景が変わります)。

フッターのリンクだけは例外で、下線が左から 0.25 秒で伸びます。読者がわざわざ辿り着いた先なので動きを持たせても認知負荷にならない、という判断です。**開閉・展開は反応ではなく状態の変化**なので、別の時間を持ちます。タブの切り替え、ドロップダウンと引き出しの開閉、検索窓の拡張、折りたたみの開閉がこれで、いずれも hover より長い側(0.12〜0.2 秒)に置きます。変わったことが読み取れるまで動きが続く必要があるからです
フッターのリンクだけは例外で、下線が左から伸びます。**開閉・展開は反応ではなく状態の変化**なので、別の時間を持ちます。タブの切り替え、ドロップダウンと引き出しの開閉、検索窓の拡張、折りたたみの開閉がこれです

### フォーカスリング

Expand All @@ -368,6 +397,25 @@ editable: true

暗い背景(フッターとヘッダーの帯)ではネイビーが見えないので、`on-dark-strong` に替えます。白背景の入力欄のように背景が明るいまま暗い場所に置かれる部品は、色ではなく `outline-offset: -2px` で内側に逃がします。

## 時間

役割は2つです。**押せることの合図(反応)と、開いたり切り替わったりしたこと(状態の変化)**で、前者は待たせるものではないので短い側、後者は変わったと読み取れるまで続く必要があるので長い側に置きます。

| 役割 | 時間 | 使うところ |
| --- | --- | --- |
| 反応 | 0.05 秒 | 色・面・下線が変わるところすべて |
| 状態の変化 | 0.18 秒 | タブの切り替え、ドロップダウンと引き出しの開閉、検索窓の拡張、折りたたみの開閉 |

**どちらの役割も値は1つです。** 反応が 0.05 秒なのは、0.1 秒だと変化が半分進むのに 29ms かかり、カーソルを乗せて 20ms の時点でまだ3割しか動いていないからです。0.05 秒なら 15ms で7割動くので、ほぼ即時に見えます。0 にはしません。タグのチップのように面の広いところでは、ハードカットだと切り替わる瞬間が硬く出ます。

**イージングは触りません。** 体感を決めているのは秒数だけで、20ms 時点の進捗は ease 30% 対 ease-out 31% とほぼ同じでした。

フッターのリンクの下線だけは例外で、左から 0.25 秒で伸びます。読者がわざわざ辿り着いた先なので動きを持たせても認知負荷にならない、という判断です。**この1つだけをスケールの外に置きます。** 反応の側に混ぜると「押せることの合図は1つの速さ」が言えなくなり、状態の変化の側に混ぜると開閉と同じ役割に見えます。

**位置や大きさが動くのは、開いたことを示す部品だけです。** 折りたたみの三角・ドロップダウンの矢印・引き出しの三本線が回り、検索窓が横に伸びます。読む対象そのもの(記事のカードや行、本文)は動きません。反応で動くのは下線と背景だけです。

**動きを減らす設定では、状態の変化を瞬時にします。** 開閉も切り替えも結果だけが出て、途中の動きは出ません。反応の 0.05 秒は止めません。あれは動きではなく、押せることの合図そのものだからです。

## 状態

部品が「今どうなっているか」は、**新しい色を足さずに、すでにあるスケールの中で1つだけ動かして**表します。動かすのは太さか面のどちらか一方で、両方は動かしません。
Expand Down
37 changes: 9 additions & 28 deletions themes/future/css-src/_variables.styl
Original file line number Diff line number Diff line change
Expand Up @@ -307,9 +307,8 @@ img-width-small = 360px
// hover / focus の反応の速さ。1つだけ置く(#2686)。
// 以前は 0.1 / 0.15 / 0.2 / 0.3 秒が部品ごとに散っていて、同じ「押せる」の
// 合図なのに速さが違っていた。反応は待たせるものではないので短い側に寄せる。
// 対象は色・面・下線・カードの持ち上がりまで。開閉のアニメーション
// (details の高さ・三角の回転)と検索欄の伸縮は状態の変化であって
// 反応ではないので、それぞれの時間を持つ。
// 対象は色・面・下線。開閉のアニメーション(details の高さ・三角の回転)と
// 検索欄の伸縮は状態の変化であって反応ではないので、state-speed が持つ。
//
// 0.1s では「もっさり」と感じられたので詰めた(#2693)。0.1s だと変化が半分
// 進むのに 29ms 掛かり、カーソルを乗せて 20ms 経った時点でまだ3割しか動いて
Expand All @@ -336,32 +335,14 @@ footer-underline-speed = 0.25s
// 間隔の 4px 刻みとは別の系統なので、space-step からは導かない
link-underline-offset = 2px

// タブの切り替え(#2728)。反応ではなく状態の変化なので hover-speed とは別に持つ。
// details の開閉(0.18s)に合わせた。中身が入れ替わったことが分かる程度で、
// 待たされない長さ
tab-speed = 0.18s
// 状態が変わったことを見せる速さ。反応(hover-speed)とは役が違うので別に持つが、
// **状態の変化の側も1つだけ**。タブの切り替え・ドロップダウンと引き出しの開閉・
// 検索窓の伸縮・折りたたみの開閉が対象で、中身が入れ替わったことが分かる程度で
// 待たされない長さ。
// 以前は 0.12 / 0.15 / 0.18 / 0.2s が部品ごとに散っていた。役が4つあるのではなく
// 別々に決めた値が残っていただけで、0.02〜0.05s の差は見分けられない
state-speed = 0.18s

// Layout
block-margin = 50px
article-padding = 20px
mobile-nav-width = 280px
main-column = 9
sidebar-column = 3

if sidebar and sidebar isnt bottom
_sidebar-column = sidebar-column
else
_sidebar-column = 0

// Grids
column-width = 80px
gutter-width = 20px
columns = main-column + _sidebar-column

// Media queries
mq-mobile = "screen and (max-width: 479px)"
mq-tablet = "screen and (min-width: 480px) and (max-width: 767px)"
mq-normal = "screen and (min-width: 768px)"
// 色の付いた地の上に置くインラインコードの背景を返す (#2487)。
// 「地より一段濃い同じ色」という関係を1箇所で定義し、note の4色でも
// テーブルヘッダでも同じ規則が効くようにする。個別に値を決めていた頃は
Expand Down
Loading
Loading