为堆栈溢出创建黑暗主题

2020年3月30日,Stack Overflow开发人员为网站访问者提供了使用Beta版深色主题的机会。该材料(我们翻译的译本)致力于讲述如何创建Stack Overflow黑暗主题的故事。


Stack Overflow上的Banner,它允许您包含深色主题。

我叫Aaron Sheki。我是Stack Overflow的设计主管。我参与了构成项目新功能的接口组件的设计。

首先,有点讽刺意味。我个人不喜欢深色界面主题。

我经常看到深色界面的对比度太低。这种界面的设计很难使用所有颜色。这同样适用于使用阴影模拟体积以及应用其他视觉效果。当我阅读深色背景上的浅色文字时,我的眼睛会疲倦。使用浅色主题时,很难同时处理对比度等现象,如果使用深色主题,则一切都会变得更加复杂。

但是我是在Stack Overflow上提出黑暗主题的人。

我想谈论的工作从来没有专门针对开发一个黑暗的主题,尽管许多用户长期以来一直要求为资源配备这样的主题。但是在迈向一个黑暗的话题的过程中,我们不得不解决许多问题。特别是,堆栈溢出前端代码已升级,内容可访问性已得到改善。在讨论一个黑暗的话题时,我们有动机在项目中更广泛地使用我们的设计系统

我们可以给用户一个黑暗的主题,同时为改善项目的可访问性开辟道路吗?我们已经做了我将要讲的一切,我们肯定地回答了这个问题。

色彩研究


在为项目创建原始色标时,我们可能有点天真,我们采用了某个色值,并使用使用Less实现的转换对其进行了修改。因此,例如,我们可以声明一个Less-variable @red并使用design将颜色变暗几次darken(@red, 10%)。使用进行多种颜色澄清也是如此tint(@red, 10%)。这可以给出一个色标,其中颜色的范围是从@red-050@red-90010%。

当我第一次尝试了解Stack Overflow资源在黑暗模式下的外观时,我决定只是尝试将白色背景更改为黑色,然后“翻转”色标。通过这种方法,颜色@red-050变成了颜色@red-900,颜色会在刻度的初始和最终颜色之间相应地变化。但是这些颜色本身与以前使用的颜色相同。


浅色和深色代表红色,

使用这种方法会损害元素的对比度。总的来说,发生的事情包含了一些我不喜欢黑暗话题的东西。例如,如果您仔细观察位于深色背景上的最暗的红色,您会发现颜色几乎无法区分。我们将在下面讨论更多。


我们绝对需要提出更好的建议。

▍入门:布局设计


只是试图绘制色阶,我实际上并没有取得任何成就。这个步骤不能称为真正的黑暗工作开始。因此,我决定开始开发布局并在Figma中手动选择颜色我选择了颜色,重点是我认为Stack Overflow的外观,而不是在考虑新颜色与现有颜色的关系。降低整体对比度是在界面中保留深度效果,支持元素阴影,应用所有颜色光谱的关键。


首先,通过布局设计入门,我们可以了解我们正在努力追求的美学效果,而无需关注项目的技术要求

▍选择一种改进的颜色处理算法


在为深色主题选择了较浅的背景后,我有机会更深入地探索了色阶。首先,我需要处理现有设计系统在应用浅色主题时出现的一些颜色问题。在光谱的最亮处,红色和黄色看起来并不像我想要的那样。一些颜色的值最浅,太接近白色。有颜色,最浅的值太暗了。


黄色的最

浅色与白色没有区别,最暗的与黑色没有区别,我们在光谱的暗端遇到了问题。使用,作为背景,颜色@red-900@blue-900,我们注意到,这些颜色从黑色和相互区分。我们需要一种算法,该算法可以为我们提供主色调在最亮和最暗版本中都可以区分的颜色。这将允许使用这些颜色值创建组件。


我们的颜色最深的变化与黑色以及彼此之间没有区别,

创建能够实现通知的组件时,我们将无法使用设计系统中的颜色。相反,我们需要在眼睛上选择自己的颜色。


这些颜色很漂亮,但它们不是基于我们色标中的颜色值。

我使用了Lyft Design出色的 ColorBox工具对颜色进行归一化我没有以10%的增量线性地以最简单的方式更改颜色,而是应用了Bezier曲线。这使我们能够在色标的极端位置上实现显着的改进。


在将光谱的明亮部分的颜色归一化之后,我能够创建通知,这些通知的颜色来自我们设计系统的颜色

▍深色


在订购网站的浅色版本之后,是时候在深色背景上尝试新的颜色了。结果,我采取了手动设置颜色匹配算法的方法,从而保留了已经使用了很长时间的公司色彩。这使我可以在生产中使用新的颜色,同时又不必在项目外观上进行太大的改动。


完全归一化的色域

在Stacks界面中实现深色主题


如果我以某种方式希望为Stack Overflow配备深色主题,那么我首先需要在Stacks设计系统中实现深色主题,并将其用作测试新技术的试验场。

▍变量


我需要将静态的较少编译的十六进制颜色值转换为旨在在程序运行时使用的自定义CSS属性。关键是颜色值应该使用视图结构var(--red-500)而不是静态视图结构存储@red-500。这是一项有趣的任务-在我们的系统设计中以及在整个站点中。我们通常采用单一的颜色值(例如)@red-500,然后将其变亮或变暗以突出显示元素的不同状态(例如当元素悬停在元素上或获得焦点时元素所处的状态),以用作背景色或元素边框的颜色。

如果我们谈论每个按钮的颜色(我们有很多关于每个按钮的每种状态的颜色),那么我们可以说这些颜色是在对单个编译的颜色值进行一组转换的过程中获得的。这让我想起了电影《秋天的游戏》中的一个场景。在那里,他们谈到了将十分之一的投资变成数十亿美元的可能性。这种“转变”导致了金融危机也就不足为奇了。

常规CSS变量的问题在于您无法对它们应用Less变换。 CSS变量值是在运行时计算的,因此像这样的构造darken(var(--red-500), 5%)会导致编译错误。

所有这些意味着我需要重新编写负责样式设置按钮的代码。起初他看起来像这样:

.s-btn {
    color: @white;
    background-color: @blue-600;
    border: 1px solid darken(@blue-600, 5%);
    
    &:hover {
        background-color: darken(@blue-600, 5%);
        border-color: darken(@blue-600, 10%);
    }
}

我需要继续指出我们的色彩系统中描述的确切色彩值。结果,我需要使用以下版本的代码:

.s-btn {
    color: var(--white);
    background-color: var(--blue-600);
    border: 1px solid var(--blue-700);
    
    &:hover {
        background-color: var(--blue-700);
        border-color: var(--blue-800);
    }
}

同时,很明显,所有内容都不仅限于按钮。因此,我需要重做Stacks中所有可用组件的样式。通知,弹出菜单,模式窗口,链接和许多其他组件也是如此。

▍浏览器兼容性


如果我们谈论CSS变量,则它们的应用意味着需要考虑浏览器的支持。特别是Internet Explorer 11(我们从未忘记的浏览器)不支持它们。结果,我们决定放弃对IE11的支持,考虑到该浏览器的功能,摆脱了多年来在系统中添加到系统中的所有CSS hack。此外,我们决定向IE11用户发送通知,建议安装新的浏览器。这个决定对我们来说并不容易。它的实施需要数周的重构。

▍条件班


IE11不再限制我了,我能够使用Stacks中的颜色。我决定为元素添加一个body.theme-system。完成此操作后,我可以使用适当的媒体查询将浅色替换为深色。另外,我们只需添加到bodyclass 即可完全​​拒绝媒体请求.theme-dark。这将使用户无论其系统设置如何都可以使用网站的深色主题。结果是我得到的:

body {
    --red-600: #c02d2e;
}

body.theme-system {
    @media (prefers-color-scheme: dark) {
        --red-600: #d25d5d;
    }
}

body.theme-dark {
    --red-600: #d25d5d;
}

为了获得完全的灵活性,堆栈使使用原子颜色类成为可能,原子颜色类仅在启用深色主题时才适用。可在此处找到有关Stacks中CSS支持的详细信息。例如,将一个类添加到元素。d:bg-green-100,设计师表示以下想法:“在黑暗模式下,您需要使用绿色作为背景bg-green-100。”为黑暗模式设计的其他条件类使我们能够删除元素的边框,更改背景并调整文本的颜色。在推文中,您可以看到一个有趣的颜色调整示例。在黑暗模式下,有时需要进行这样的设置。我想指出,对我来说,在网站的黑暗模式中工作时,灵感来源之一是Tailwind CSS框架

▍在Stacks中使用深色主题


在Stacks中实现了深色主题之后,我们决定在系统界面顶部添加一个按钮,使您可以在主题之间进行切换。公司的员工应该具有快速便捷的能力,可以在网站的不同颜色主题之间进行切换。


在堆栈中的浅色和深色主题之间切换

在Stack Overflow主站点上实现深色主题


我相对容易地在Stacks设计系统的界面中解决了与深色主题的实现相关的任务。重构考虑了系统的未来发展,使得过去由于错误决策而导致的Stacks比主站点更小。为了使Stack Overflow具有深色主题,我需要为Less变量提供支持,以实现解决方案的向后兼容性。这使我们能够在界面的不同部分中逐步组织深色主题的应用。

由于我们在2018年之后创建的大部分界面都是基于Stacks的,因此界面的这一部分无需任何额外的工作即可获得深色主题和响应式布局。界面的主要部分呢?这里的一切远非如此简单。

the网站的主要颜色


首先,我需要在不违反标准轻量主题Stack Overflow的前提下,对网站进行最大的更改。我要解决的任务主要是用与它们等效的CSS变量替换静态Less变量。首先,我将样式应用于background-color: var(--white)网站的背景,然后将其替换为样式background-color: @white由于这个原因,现在可以轻松地将村庄的主要区域重新涂成背景深色。然后,我对字体和其他元素的颜色进行了相同的操作。这项工作主要包括删除大量CSS代码,因为例如我们经常喜欢过于详细的样式,设置子元素的字体颜色,尽管我们很可能会从父元素继承来的颜色值获得满意的结果。

▍为公司员工演示新设计


当我在大型站点上工作后,我请我们的程序员Adam LearNick Craver帮助我找到一种方法来向Stack Overflow员工展示黑暗主题的初步版本。这将使员工可以包含一个黑暗的主题,而这个主题离准备查看站点的哪些区域仍需要改进还很遥远。我认为,这将鼓励他们帮助改进网站中流量最多的部分。这将使我克服新设计的主要障碍。即,它将有助于将新设计集成到现有代码库中。

▍按钮


如果我正在使用的站点区域是使用Stacks创建的,那么为了准备使用暗模式,就需要解决很多问题。说,在工作过程中,可以决定不需要边框的地方,或者-某个地方需要特殊的灰色阴影作为背景色。使用暗区的准备工作可能会受到限制。不幸的是,大多数站点是在不使用堆栈的情况下创建的。

当谈到按钮时,这一点最为明显。在网站上工作多年以来,已在其中使用了许多按钮实现。当我们对元素本身进行样式化时,这尤其令人沮丧button。这意味着任何元素button或元素装饰为input type=«button»,被分配了默认样式。这种样式具有很高的特异性,并且基于一组过时的规则。

上述事实导致需要大量重构,这一重构仍在进行中。它旨在删除元素级CSS样式,button并用Stacks中的等效样式替换它们。特别是,我们谈论的事实是数百个元素input type=«submit»需要替换为<button type="submit" class="s-btn s-btn__primary">。除了添加工作,我注意到我们经常将JavaScript功能链接到可视选择器。如果更改影响元素外观的类,则可能会破坏按钮的功能。结果,在处理数千个按钮的过程中,我需要先向它们添加类js-,将处理程序连接到它们,然后摆脱定义按钮外观的旧样式。

最终,这使我删除了大多数旧的按钮类,这些类使打开深色主题时按钮可以正确更改颜色。

▍网站标题


为了使任务复杂化,整个站点上使用的标题可以在不同的模式下工作。我们正在谈论明暗模式,以及特殊主题的支持模式。团队的站点选项(团队的Stack Overflow)和公司系统的站点选项强制使用深色标题主题。另外,命令版本使用由团队化身的颜色指定的颜色。与我们的许多其他组件一样,网站标题的CSS提供了一种颜色,该颜色确定标题是浅色还是深色。然后,使用复杂的Less指令对该颜色进行转换,从而使您能够获得其不同的选择。但是,当我们处理设计系统的代码时,我们做不到。也就是说,他们不能只是丢弃所有旧的CSS并用代码代替它,使用CSS变量。事实上,实际上,我们的公司客户完全是在主题的帮助下自定义标题的外观。在这种情况下,颜色选项是基于单一颜色生成的。


浅标题


深色标题


命令标题

对于明亮的Stack Overflow标题,我们需要找到一种机制来确定是否使用CSS变量或静态十六进制值设置了某种颜色。如果颜色是使用CSS变量设置的,那么我们可以完全跳过其Less转换,创建一个可以根据深色主题的参数更改颜色的标题。如果改为使用静态的Less变量,则必须评估颜色以查看其是浅色还是深色,并创建适当的标题。

结果,我们来到了这种方法:

& when ( iscolor(@theme-topbar-background-color) ) {
     @theme-topbar-style: if(luma(@theme-topbar-background-color) >= 50%, light, dark);
 }
 & when not ( iscolor(@theme-topbar-background-color) ) {
     @theme-topbar-style: automatic;
 }

然后,基于所接收到的值(automaticlightdark),创建正确的标题。

▍标签


如果我只对涉及组件设计的人员提供建议,那么它将显示为:“不要在组件中描述影响它们在页面上位置的因素。”换句话说,将组件分隔开什么类型的空间应该确定应用它们的上下文。无需在组件本身中设置此类内容。在早期版本的Stack Overflow中,决定将post-tag外部填充应用于组件。同时,诸如按钮之类的标签也受到了JavaScript相关问题的困扰。为了使事情变得更加困难,大多数标记都是使用单个辅助方法生成的。

标签重构涉及将post-tag-components 替换s-tag-旨在使用不同主题的组件。考虑到的使用,这项工作还包括对JavaScript的更改js-tag另外,有必要更改负责生成标签的方法,使其可以接受影响元素放置的任意类。事实是,在某些情况下,可能需要将标签放置在flex布局中,而不是依赖于预定义的外部缩进(或代替处理此类缩进)。

▍出版物样式


堆栈溢出的大部分由用户出版物组成。这些出版物(即问题,答案,评论)是在Markdown标记的帮助下完成的。在Stack Overflow推出期间,Markdown标记是一项相对较新的技术。

多年来,网络已经开发出一些显示标题和引号之类的标准方法。引入深色主题是回顾我们格式化出版物的绝佳时机。在这个问题上最有争议的问题是引号的格式。

最初,报价使用强大的黄色背景框起来,这降低了报价本身的对比度。此外,黄色在深色背景上显示时会引起某些问题。结果,我们继续使用公认的显示报价的方法,即使用狭窄的灰色垂直条突出显示报价。

▍代码样式


在相当容易理解的Stack Overflow页面上,显示了许多代码。我们用来突出显示语法的颜色与我们的签名颜色无关。我非常怀疑这些颜色是该项目中用于语法高亮显示的第一个库的遗留物。分析了这些颜色之后,我决定对语法突出显示进行深刻的重新设计。结果,背光颜色被我们设计系统中的颜色所取代。这适用于浅色和深色主题。这样做是为了使发生的事情与以前没有太大的不同。

结果



明亮主题和黑暗主题的Beta版本于3月30日发布。

由于在转向黑暗主题时我们进行了大量的重构工作,因此我们能够对项目的外观进行相当大的更改而没有任何困难。例如,根据现有信息,我们可以开发一个高对比度的网站主题,以增加其可访问性。

黑暗主题的创建是Stack Overflow设计方法发生根本转变的结果。特别是,我们谈论的是设计系统的使用,我已经推广了一年。对我来说,创建一个黑暗的主题是一个绝佳的机会,可以重建网站的许多部分。这是许多将提高Stack Overflow可用性的项目中的第一个。

如果您没有考虑到对IE11的支持遭到拒绝,则 PR计划于2019年7月开始针对黑暗主题开展工作,旨在研究情况。在此之前,在四月2019年,有讨论关于黑暗的话题。2019年10月,一个黑暗主题的实验版投入生产。然后,至少制作了60个PR,然后向用户展示了深色主题的Beta版本。它发生在2020年3月30日。

亲爱的读者们!您是否使用堆栈溢出?你喜欢他们的新黑暗主题吗?


All Articles