変数を使ったDiscourseのスタイリング:よりシンプルなセマンティクスのための事例

Styling Discourse with variables: Show & Tell の議論を続けます。

Discourse のテーマ設定エクスペリエンスを改善するための取り組みは非常に高く評価していますが、上記のトピックで共有されているような多数の CSS 変数を追加するアプローチが最適な解決策であるとは確信が持てません。その理由について、いくつか考えを共有したいと思います。

このアプローチは、Canvas Theme Template を通じて自分で実験してきました。これは、基本的にベーステーマを構築するための調整可能な変数のコレクションを提供します。

:root {
  /* Layout */
  --d-max-width: 1110px;
  --canvas-nav-space: 0.75rem;
  --canvas-content-padding: 1.5rem;
  --canvas-topic-list-padding: 0.8em;

  /* Base Styles */
  --canvas-background: var(--secondary);
  --canvas-surface: var(--secondary);
  --canvas-border: 1px solid var(--primary-500);
  --canvas-border-light: 1px solid var(--primary-200);

  /* Border Radius */
  --d-border-radius: 2px;
  --d-border-radius-large: 2px;
  --d-button-border-radius: 2px;
  --d-input-border-radius: var(--d-button-border-radius);
  --d-nav-pill-border-radius: var(--d-button-border-radius);

  /* Button Styles */
  --canvas-button-padding: 0.5em 0.65em;
  --canvas-button-primary-padding: 0.5em 0.65em;

  /* Header */
  --canvas-header-height: 4rem;
  --canvas-header-background: var(--header_background);
  --canvas-header-border: none;
  --canvas-header-shadow: var(--shadow-header);

  /* Sidebar */
  --d-sidebar-width: 17em;
  --d-sidebar-background: var(--secondary);
  --canvas-sidebar-border: 1px solid var(--primary-low);
  --canvas-sidebar-scrollbar: var(--scrollbarWidth);
  --d-sidebar-row-height: 2.2em;
  --d-sidebar-highlight-background: var(--primary-low);

  /* And several more... */
}

これは単純な調整にはかなりうまく機能しますが、このアプローチをスケーリングする際にはいくつかの制限に直面しました。

認知負荷と検出可能性

変数の広範なリストは、基本的にルックアップテーブルを必要とします。これは、コンポーネントベースのフレームワークで通常作業する方法とはかけ離れているように感じます。コンポーネントを実際にスタイル設定することを期待するでしょう。そして、それは私だけかもしれませんが、メンタルモデルが「このコンポーネントをスタイル設定したい」から「適切な変数名を見つける必要がある」にシフトしているように感じます。

カスケードロジックの欠如

現在の実装では、適切なカスケード階層を確立せずに、ハードコーディングされた値を直接変数に割り当てています。

--d-sidebar-link-color: var(--primary-high);
--d-nav-background-color--active: transparent;
--table-border-width: 1px;

これは、--link-color--border-width のようなより一般的な変数からの継承がないことを意味します。体系的な変更を行いたい場合、1 つの基本的な値を変更する代わりに、複数の特定の変数を更新する必要があります。

デザインから開発へのギャップ

このアプローチは、デザインツール(Figma など)と実装の間で作業する際に摩擦を生み出すと思います。デザインシステムは通常、これらの非常に実装固有の変数と 1 対 1 でマッピングされないセマンティック変数を使用します。

コンポーネントアーキテクチャを採用した代替アプローチ

基本的なセマンティック変数と信頼性の高いコンポーネントターゲティングを組み合わせることで、同じ目標をより自然に達成できると思います。特定の変数の長いリストを持つ代わりに、Discourse 全体で一意で一貫した名前のコンポーネントクラスを確実に利用できるとしたらどうでしょうか? .d-sidebar.d-topic-list.d-header のようなものです。

次に、CSS が本来機能するように、実際にカスケードする小規模な基本的な変数のセットとペアにします。

/* Set the design foundation */
:root {
  --d-border-width: 2px;
  --d-surface-color: #3498db;
  --d-space-1: 1rem;
}

/* Override at the component level when you need to */
.d-topic-list,
.d-sidebar {
  --d-border-width: 1px;
}

私にとっては、これは CSS が自然に機能する方法に近いです。グローバルスタイルを設定し、必要に応じて調整します。アプリ全体で境界線の表示方法を変更したい場合は、1 つの変数を変更します。サイドバーを変更したい場合は、サイドバーを具体的にターゲットにします。

「いいね!」 3

CSSが自然に機能する方法は、変数をスキップして次のようにすることだと思います。

/* デザインの基礎を設定 */
body {
  border-width: 2px;
  background-color: #3498db;
  margin: 1rem;
}

/* 必要に応じてコンポーネントレベルでオーバーライドする */
.d-topic-list,
.d-sidebar {
  border-width: 1px;
}

もしかしたら私は古いだけかもしれません。

本当の問題はこれです

例:単に.btnまたはbuttonをターゲットにする場合:

.btn {
    border: 1px solid red;
}

投稿ボタンは見逃しますが、「表示」リンクとハンバーガーメニューはターゲットにします。

「いいね!」 1

変数を使用するのにはもっともな理由があります。ここでは触れないでおきましょう。CSSの性質について議論しないというのは良い点です。もっとうまく表現すべきでした。CSSの性質ではなく、コンポーネントベースのフレームワークのスタイリングに関するベストプラクティスについてです。そして、ボタンがこれらを適切に適用できない良い例であることにも完全に同意します。

より大きな視野で見ると、フロントエンドフレームワークのJavaScript側を近代化するための組織的な努力がありました。そしてそれは大成功だったと思います。クリーンな標準とよく構造化されたクラスで作業することは、今では本当に楽しいです。デザイナーとしても、新しいフロントエンドコンポーネントをより簡単かつ効率的に構築する機会が開かれました。

しかし、デザインシステムを同じ基準に引き上げるための同様のコミットメントがないという感覚を拭えません。CSS変数にあらゆる側面で追加することは、現在の方法よりも確かにパフォーマンスが高く、クリーンですが、依然としてより深いアーキテクチャの問題を回避しているように感じます。過度に具体的な宣言でいっぱいのコードベースであり、明確なコンポーネントスコープのスタイルがありません。これは、より困難な問題であるスタイリングアーキテクチャをフレームワークのモジュラーデザインと完全に整合させることを回避する「簡単な」解決策のように思えます。

これには多くの作業と後方互換性の問題が発生することは理解しています。しかし、チームはJavaScript側でこれらの課題にうまく対処してきました。JavaScriptがスタイルよりも大幅に多くのリソースを受け取り続ける場合、その格差は最終的なデザインに現れます。ユーザーは、理由を明確に説明できなくても、その違いを感じるでしょう。

開発者とユーザーエクスペリエンスの両方にとって長期的なメリットが変革的であると確信しているので、CSSアーキテクチャにも同じ近代化のエネルギーが適用されるのを見たいだけです。

「いいね!」 5

私たちが採用したアプローチは、あなたが説明しているものに近いと感じており、そのため、あなたがどのように異なる実装をしたのかを理解するのが難しいです。もちろん、フィードバックはいつでも歓迎しますし、あなたがもたらしてくれる視点に感謝しています。

例えば、--space のようなものの場合、これを変更するとアプリ全体のすべてのスペーシングが変更されます。あなたが説明したのと同様のアプローチで、トピックリストやサイドバーのスペーシングのみに影響するようにターゲットすることもできます。

これは一部の項目には当てはまりますが、他の項目には当てはまりません。他に共有できる例があれば、ぜひ教えてください!

これは確かに問題です。私たちが考えているアプローチ(少なくとも現時点では実験的なもの)は、shadcn がここで行っているようなエディタです。

完璧なアプローチではありませんが、インスペクタの使い方 / ドキュメント用のメタへのアクセス方法 / CSS の使い方を知らない人にとって、より簡単に使えるように近づけることができると感じています。

よりコンポーネント化されたアプローチに関しては、最終的にはそうしたいと考えていますが、Discourse はコンポーネント化されたデザインを念頭に置いて構築されておらず、使いやすい変数を追加する前にそこまで待つことは選択肢にありませんでした。

これらのためのクラスを追加して、特定のセクションで実装しやすくすることは、ユーザビリティにおける良い前進の道のように思えます。


あなたに同意します :+1:

「いいね!」 2

短い答えは、これを行わないでください :sweat_smile:

btn-defaultbtn-primarybtn-flat のようなセカンダリボタンクラスをターゲットにする方がはるかに良いでしょう。これらのセカンダリクラスは、ボタンのビジュアルタイプを表します。

.btn および button は、特定の外観というよりも、「これはボタンである」というより広範な意味合いを持ちます。

「いいね!」 4

まさにその通りです。現在、Emberのアップデートという数年がかりの旅が終わっていないことを考えると、HTMLとCSS、そして私たちが維持しているすべてのテーマの数年がかりの書き直しに着手するだけの帯域幅がありません。

「いいね!」 5