From c848a798ef180482db20b98d42e99a3a5b2da0c3 Mon Sep 17 00:00:00 2001 From: ma91n Date: Tue, 8 Sep 2026 10:13:33 +0900 Subject: [PATCH 1/2] =?UTF-8?q?=E3=83=98=E3=83=83=E3=83=80=E3=83=BC?= =?UTF-8?q?=E3=81=AE=E5=B8=AF=E3=82=92=201025px=20=E4=BB=A5=E4=B8=8A?= =?UTF-8?q?=E3=81=A7=E8=BF=BD=E5=BE=93=E3=81=95=E3=81=9B=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #2877 の「追従しない」を PC だけ覆す。読み進めてもロゴが左上に残り、 長いトップページで検索に手が届く。1024px 以下は本文の面を優先して追従しない。 境界は目次が追従し始める幅と同じ。 帯に連動する3箇所: 目次の top と max-height(帯の下から 24px)、 目次のスクロールスパイの基準線(帯の下辺 + 32px。帯の位置を読むので 幅の分岐を持たない)、html の scroll-padding-top(帯 + 16px)。 Co-Authored-By: Claude Opus 5 (1M context) --- CLAUDE.md | 24 +++++++++++++++----- source/specials/styleguide/index.md | 2 +- themes/future/css-src/theme-styles.styl | 27 ++++++++++++++++++----- themes/future/layout/_partial/sidebar.ejs | 13 +++++++---- 4 files changed, 50 insertions(+), 16 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index cecb61c9512..226a378f5e9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1228,12 +1228,26 @@ bootstrap-subset → theme-styles.styl の順で `/css/site.css` に連結する - **ヘッダーの部品の寸法を本文のグリッドに従属させない。** 検索窓の幅を サイドバー列に合わせれば揃うが、サイドバーが縦積みになる幅(1024px以下)で その根拠が消える - - **ヘッダーの帯は追従(sticky)しない。** 64px の帯が全ページで本文の上に - 常に乗ることになり、読んでいる面が狭くなる。写真をやめたぶん - `backdrop-filter` も要らなくなった + - **ヘッダーの帯は 1025px 以上で追従(sticky)する。1024px 以下では追従しない** + (#3220。#2877 の「追従しない」を PC だけ覆した)。読み進めてもロゴが左上に残り + 「どのサイトを読んでいるか」が切り替わるたびに分かる、長いトップページで検索に + 手が届く、が理由。他サイトは固定 3(Qiita 45px・note 65px・dev.to 56px)対 + 非固定 6(Zenn・はてな・Cloudflare・GitHub Blog・Stripe・Medium)で割れていて、 + どちらが通り相場とも言えない + - **モバイルは追従しない。** 64px は 375×667 の画面の 10% で、記事の面を優先する + (Slack の議論でも PC の話に収束した) + - **境界は目次が追従し始める 1025px と同じ。** 新しい境界を足さず、PC の読者は + 既に追従する部品のある画面を見ている + - **見た目は変えない。** 白地・1px の線・影なしのままなので、送っても浮いた箱に + ならない。下へ送ると隠れる型(Medium)は JS が要り、送ると細くなる型は動きが + 増えるので採らない。2段組にして2段目だけ固定する案は、帯が1段なので分ける相手が無い + - **帯を追従させると3箇所が連動する。** 目次の `top`(帯の下から 24px)と + `max-height`、目次のスクロールスパイの基準線(`sidebar.ejs`。帯の下辺 + 32px。 + 帯の `getBoundingClientRect().bottom` を読むので幅の分岐を持たない)、 + `html { scroll-padding-top }`(目次のクリックとアンカーで見出しが帯の下に隠れない) - **サイドバーの目次は追従する**(#2909。以前は「固定サイドバーを置かないのと 同じ理由」と書いていたが、そちらはトライアルで入れた)。目次は - 読んでいる記事の中の移動手段で、帯のように全ページに常駐する部品ではない + 読んでいる記事の中の移動手段で、帯と同じ幅で追従する - **帯の中身は `.container` の内側に置く。** サイト名の左端がパンくず・本文と揃う。 下に開くパネル(ドロップダウン・検索のヒント)の位置の基準も `.header-bar` が持ち、 `top: 100%` が帯の下辺、`right: 0` が本文と同じ右端になる @@ -1333,7 +1347,7 @@ bootstrap-subset → theme-styles.styl の順で `/css/site.css` に連結する カーソルが乗っただけで本文全体がぼけるのは意図しない発火になる - 開いているかは **`:has()`** で拾う。引き金(`:checked` / `:focus-within`)が 帯の中にあるので、兄弟結合子では帯の外の面まで届かない - - **`position: fixed` にしない。** ヘッダーは追従しないので、開いたまま送られると + - **`position: fixed` にしない。** 引き出しが出る幅ではヘッダーは追従しないので、開いたまま送られると 引き出しは一緒に上へ動くのにぼかしだけ残る。帯の下から 100vh 分を 絶対配置で敷く - 出し入れは `display`。`visibility` では隠れている間も 100vh の箱が残り、 diff --git a/source/specials/styleguide/index.md b/source/specials/styleguide/index.md index fd85063a1bf..f28050f8d91 100644 --- a/source/specials/styleguide/index.md +++ b/source/specials/styleguide/index.md @@ -328,7 +328,7 @@ editable: true | 576px | 検索窓が虫眼鏡だけになり、フォーカスされたときだけ帯を覆って広がる。一覧カードのサムネイルが文字の上に積む | [すべての記事](/articles/) | | 768px | サイドバーの探索の枠が消える。2列で並べていた一覧が1列になる。コードと note が画面の端まで伸びる | [カテゴリ一覧](/categories/#categories) | | 992px | ヘッダーのナビが帯から降りて引き出しに入る。フッターが4列から2列になる | [トップページ](/) | -| 1025px | 本文とサイドバーが縦に積む。サイドバーの統計とグラフは消え、目次は本文の上の折りたたみに移る | [記事ページ](/articles/20260804a/) | +| 1025px | 本文とサイドバーが縦に積む。サイドバーの統計とグラフは消え、目次は本文の上の折りたたみに移る。ヘッダーの帯は追従をやめて本文と一緒に送られる | [記事ページ](/articles/20260804a/) | **中間の幅を作りません。** 段階を増やすと、どの幅で確かめた見た目なのかを追えなくなります。2列にするかどうかは列の内寸に中身が入るかで決めていて、たとえばカテゴリ一覧を「列の幅が足りたら自動で2列」にすると、幅 576px の画面でも1列 242px の2列になり、説明文とタグが入りません。列数は幅で決め打ちします。 diff --git a/themes/future/css-src/theme-styles.styl b/themes/future/css-src/theme-styles.styl index dab0cbfdff4..35d69f6bcb8 100644 --- a/themes/future/css-src/theme-styles.styl +++ b/themes/future/css-src/theme-styles.styl @@ -381,8 +381,6 @@ Header and header elements /* ヘッダーは1段・64px の帯 (#2877)。以前は 1500×360 の写真バナーの上に 80px の 中央タイトルを載せた 151px の塊で、全ページの先頭でそれだけ縦を使っていた。 縦に返した約90px のぶん、空いた横にサイト名・ナビ・検索を1行で並べる。 - **追従(sticky)はしない。** 64px の帯が全ページで本文の上に常に乗ることになり、 - 読んでいる面が狭くなる。サイドバーの目次は追従する (#2909)。 影は持たない (#2747)。下辺の 1px の罫線が本文との境目を作る */ .site-header { position: relative; @@ -392,6 +390,23 @@ Header and header elements /* 下に開くドロップダウンと検索のヒントパネルが本文の上に出る */ z-index: 999; } +/* 1025px 以上では帯が追従する (#3220)。読み進めてもロゴが左上に残り、検索が + 手の届く所にある。1024px 以下では追従しない——本文の面を優先する + (64px は 375×667 の画面の 10%)。境界は目次が追従し始める幅と同じで、 + PC の読者は既に追従する部品のある画面を見ている。見た目は変えない + (白地・1px の線・影なし)ので、送っても浮いた箱にはならない。 + scroll-padding は、目次のクリックや見出しのアンカーで見出しが帯の下に + 隠れないためのもの。帯の線に見出しが接すると詰まって見えるので 16px 空ける + (目次のスクロールスパイの線は帯の下から 32px なので、着地した見出しは線の内側) */ +@media (min-width: 1025px) { + .site-header { + position: sticky; + top: 0; + } + html { + scroll-padding-top: header-height + 16px; + } +} /* 帯の中身。左端はページ本文と同じ .container の内側に揃える。 下に開くパネルの位置の基準もここが持つ(top: 100% が帯の下辺になる) */ .header-bar { @@ -3256,16 +3271,16 @@ ul.tag-list { /* 左右の 4px は下の overflow-y: auto のため。スクロールコンテナになると 行のフォーカスの輪郭(2px + outline-offset 2px)が箱の縁で切られる */ padding: 0 4px; - /* スクロールに追従する (#2909)。帯は追従しないので、上端は画面の上から - 少しだけ空ける。サイドバーが本文の下に落ちる幅(1024px以下)では + /* スクロールに追従する (#2909)。帯も追従する幅 (#3220) なので、上端は + 帯の下から少しだけ空ける。サイドバーが本文の下に落ちる幅(1024px以下)では 目次自体を隠しているので、この指定は横並びのときだけ効く。 見出しが多い記事(h2〜h4 の中央値は10、最大62)では画面に収まらないので、 中でスクロールさせる。可視領域 800px で24項目まで入り、溢れるのは 全1,481本のうち68本(5%) */ position: sticky; - top: 24px; - max-height: unquote('calc(100vh - 48px)'); + top: header-height + 24px; + max-height: unquote('calc(100vh - ' + (header-height + 48px) + ')'); overflow-y: auto; } /* 見出しにも行と同じ左パディングを与えて、文字の左端を項目と揃える。 diff --git a/themes/future/layout/_partial/sidebar.ejs b/themes/future/layout/_partial/sidebar.ejs index e2dee0d4194..b230f6845d1 100644 --- a/themes/future/layout/_partial/sidebar.ejs +++ b/themes/future/layout/_partial/sidebar.ejs @@ -136,14 +136,19 @@ return a.compareDocumentPosition(b) & 4 ? -1 : 1; }); - // 画面の上から 32px の線を越えた見出しを「読み始めた」とみなす。 - // 帯は追従しないので、送った後の画面の上端が基準になる。 + // 帯の下辺から 32px の線を越えた見出しを「読み始めた」とみなす。 + // 帯は 1025px 以上で追従する (#3220) ので、基準は画面の上端ではなく帯の下辺。 + // 追従しない幅では送った帯が画面の外へ出るので、下辺は 0 で止める。 // // **線は「見出しから次の見出しまでの最小距離」より浅くする。** 目次の行を // クリックすると見出しが画面の上端(top 0)へ来るので、線が深いと次の見出しも // 線より上に入り、次の節が現在地になってしまう。CSS の値から出した最小距離は // h4 の直後に h4 が来る 46px(h3→h4 が 49px、h2→h3 が 72px) - var LINE = 32; + var header = document.querySelector('.site-header'); + var line = function () { + var bottom = header ? header.getBoundingClientRect().bottom : 0; + return Math.max(0, bottom) + 32; + }; var current = null; var queued = false; @@ -164,7 +169,7 @@ // 文書順に並んでいるので、線より下に出たらそれ以降は全部下にある var found = null; for (var i = 0; i < headings.length; i++) { - if (headings[i].getBoundingClientRect().top >= LINE) break; + if (headings[i].getBoundingClientRect().top >= line()) break; found = headings[i]; } return found; From 924d64d70b07424f8d3800c25b74f2bccf9aa8d0 Mon Sep 17 00:00:00 2001 From: ma91n Date: Tue, 8 Sep 2026 10:36:40 +0900 Subject: [PATCH 2/2] =?UTF-8?q?=E8=BF=BD=E5=BE=93=E3=81=99=E3=82=8B?= =?UTF-8?q?=E5=B8=AF=E3=82=92=E7=A3=A8=E3=82=8A=E3=82=AC=E3=83=A9=E3=82=B9?= =?UTF-8?q?=E3=81=AB=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 地を 90% にして下の本文を 8px ぼかして透かす。90% は帯の下にコードブロック (#2b2b2b)が来ても ink-mute が AA を保つ値(5.15)。ぼかしが効かない ブラウザでは @supports で不透明のまま。 Co-Authored-By: Claude Opus 5 (1M context) --- CLAUDE.md | 11 ++++++++--- themes/future/css-src/theme-styles.styl | 13 +++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 226a378f5e9..b4903221195 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1238,9 +1238,14 @@ bootstrap-subset → theme-styles.styl の順で `/css/site.css` に連結する (Slack の議論でも PC の話に収束した) - **境界は目次が追従し始める 1025px と同じ。** 新しい境界を足さず、PC の読者は 既に追従する部品のある画面を見ている - - **見た目は変えない。** 白地・1px の線・影なしのままなので、送っても浮いた箱に - ならない。下へ送ると隠れる型(Medium)は JS が要り、送ると細くなる型は動きが - 増えるので採らない。2段組にして2段目だけ固定する案は、帯が1段なので分ける相手が無い + - **追従する帯は磨りガラス**(地を 90%、`backdrop-filter: blur(8px)`)。本文の上に + 置かれた箱ではなく本文の一部として読ませる。**90% は帯の下にいちばん暗いもの + (コードブロック `#2b2b2b`)が来ても `ink-mute` が AA を保つ値**(5.15。85% では + 4.65 で余裕が無い)。ぼかしの量は引き出しの背後(#2888)と同じ。`@supports` で + 囲い、ぼかしが効かないブラウザでは不透明のまま——透けるだけだと文字の下に + 本文が見えて読めない。線(1px)と影なしは変えない。下へ送ると隠れる型(Medium)は + JS が要り、送ると細くなる型は動きが増えるので採らない。2段組にして2段目だけ + 固定する案は、帯が1段なので分ける相手が無い - **帯を追従させると3箇所が連動する。** 目次の `top`(帯の下から 24px)と `max-height`、目次のスクロールスパイの基準線(`sidebar.ejs`。帯の下辺 + 32px。 帯の `getBoundingClientRect().bottom` を読むので幅の分岐を持たない)、 diff --git a/themes/future/css-src/theme-styles.styl b/themes/future/css-src/theme-styles.styl index 35d69f6bcb8..6420073b0eb 100644 --- a/themes/future/css-src/theme-styles.styl +++ b/themes/future/css-src/theme-styles.styl @@ -403,6 +403,19 @@ Header and header elements position: sticky; top: 0; } + /* 追従する帯は磨りガラスにする。地を 90% にして下の本文をぼかして透かすと、 + 本文の上に置かれた箱ではなく本文の一部として読める。90% は帯の下にいちばん + 暗いもの(コードブロック #2b2b2b)が来ても ink-mute が AA を保つ値 + (4.5 に対して 5.15。85% では 4.65 で余裕が無い)。ぼかしの量は引き出しの + 背後と同じ 8px。ぼかしが効かないブラウザでは不透明のまま——透けるだけだと + 文字の下に本文が見えて読めない */ + @supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) { + .site-header { + background: unquote('color-mix(in srgb, var(--surface-base) 90%, transparent)'); + -webkit-backdrop-filter: blur(8px); + backdrop-filter: blur(8px); + } + } html { scroll-padding-top: header-height + 16px; }