使用变量样式化Discourse:支持更简单语义的案例

继续关于 使用变量为 Discourse 设置样式:展示与交流 的讨论:

我非常赞赏为改善 Discourse 的主题化体验所做的努力!但是,我并不完全相信如上主题中所述添加大量 CSS 变量的方法是最佳解决方案。我想分享一些关于原因的看法。

我一直在通过 Canvas 主题模板 试验这种方法,该模板本质上提供了一组可调变量,用于构建基础主题:

: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)的继承。如果我想进行系统性更改,我需要更新多个特定变量,而不是更改一个基础值。

设计到开发差距

我认为这种方法在设计工具(如 Figma)和实现之间工作时会产生摩擦。设计系统通常使用语义变量,这些变量与这些非常具体的实现变量不一一对应。

一种拥抱组件架构的替代方法

我认为我们可以通过结合基本的语义变量和可靠的组件定位来实现相同的目标,而且更加自然。与其拥有一个长长的特定变量列表,不如如果我们能够依赖 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 的自然工作方式。我设置全局样式,然后在需要的地方进行细化。当我想更改应用程序中边框的外观时,我更改一个变量。当我想让侧边栏有所不同时,我专门定位侧边栏。

3 个赞

嗯,我认为 CSS 的自然工作方式就是跳过变量,然后这样做

/* 设置设计基础 */
body {
  border-width: 2px;
  background-color: #3498db;
  margin: 1rem;
}

/* 在组件级别需要时覆盖 */
.d-topic-list,
.d-sidebar {
  border-width: 1px;
}

也许我太老了。

真正的问题是这个

例如,简单地定位 .btnbutton

.btn {
    border: 1px solid red;
}

会错过帖子按钮,但会定位“views”链接和汉堡菜单。

1 个赞

使用变量有充分的理由,也许我们在此不深入探讨。不过,不争论 CSS 的本质是一个好观点。我应该更好地表述:这不是关于它的本质,而是关于组件化框架的样式设计最佳实践。我完全同意按钮是另一个很好的例子,说明这些(最佳实践)无法正确应用。

从更宏观的角度来看,前端框架的 JavaScript 部分一直在进行一项协同努力来实现现代化。我认为这是一次巨大的成功。现在,使用干净的标准和结构良好的类确实令人愉悦。对我这个设计师来说,这也为我提供了更轻松、更高效地构建新前端组件的机会。

然而,我总觉得在将设计系统提升到相同标准方面,并没有类似的承诺。虽然为每个方面添加 CSS 变量比当前的方法更具性能和更干净,但这仍然感觉像是回避了更深层次的架构问题:代码库充斥着过于具体的声明,并且没有清晰的组件作用域样式。这感觉像是一个“更容易”的解决方案,回避了更棘手的问题:将样式架构与框架的模块化设计完全对齐。

我明白这会带来大量工作和向后兼容性问题。但是,团队已经在 JavaScript 方面成功地解决了这些挑战。如果 JavaScript 获得的资源持续远超样式,这种差距最终会在设计中显现出来。用户会感受到这种差异,即使他们无法明确说出原因。

我只是希望看到同样的现代化精力应用到 CSS 架构上,因为我坚信这会对开发人员和用户体验产生变革性的长期效益。

5 个赞

我们采取的方法感觉与您所描述的类似,因此我很难理解您将如何以不同的方式实现它们。当然,我很乐意听取反馈,并感谢您带来的视角。

例如,对于像--space这样的东西,更改它将改变应用程序中的所有间距。您也可以将其定位为仅影响主题列表或侧边栏中的间距,方法与您描述的类似。

这对于某些项目来说是真的,但对于其他项目来说则不然。如果您能分享其他例子,那就太好了!

这确实是一个问题。我们考虑的一种方法(至少目前是实验性的)是采用类似于 shadcn 在这里所做的编辑器:

虽然它不是一种完美的方法,但我认为它能让我们更接近于让那些不知道如何使用检查器/访问文档元数据/使用 CSS 的人更容易上手。

至于更组件化的方法,这是我们最终想要实现的,但 Discourse 目前的构建方式并非为组件化设计而考虑,而且在添加可用变量之前等待实现这一点是不可能的。

添加一些类来使在特定部分实现这一点更容易,这听起来是一个改进可用性的好方法。


我同意你 :+1:

2 个赞

简短的回答是不要这样做 :sweat_smile:

你最好定位一个辅助按钮类,如 btn-defaultbtn-primarybtn-flat —— 这些辅助类代表了按钮的视觉类型。

.btnbutton 更广泛地表示“这是一个按钮”,而不是任何特定的外观。

4 个赞

这正是它。我们目前没有精力着手进行一项为期数年的 HTML 和 CSS 重写以及我们维护的每个主题,尤其考虑到我们尚未完成多年的 Ember 更新之旅。

5 个赞