Creating a Dark Theme for Stack Overflow

On March 30, 2020, Stack Overflow developers gave website visitors the opportunity to use a beta version of the dark theme. The material, the translation of which we publish, is dedicated to the story of how the dark theme of Stack Overflow was created.


Banner on Stack Overflow, which allows you to include a dark theme

My name is Aaron Sheki. I am the head of design at Stack Overflow. I participate in the design of the interface components that underlie the new features of the project.

To begin with, a little irony. Personally, I am not a fan of dark interface themes.

I often see that the contrast level of dark interfaces is too low. The design of such interfaces is difficult to use a full range of colors. The same applies to simulating volume using shadows, and to applying other visual effects. When I read a light text, located on a dark background, my eyes get tired. It’s difficult to deal with phenomena like simultaneous contrast when using light themes, and if a dark theme is used, then everything becomes more complicated.

But I'm the person whose efforts brought up a dark theme on Stack Overflow.

The work that I want to talk about has never been aimed specifically at developing a dark topic, despite the fact that many users have long asked to equip the resource with such a topic. But in the course of moving towards a dark topic, we had to solve many problems. In particular, the Stack Overflow front-end code has been upgraded, content accessibility has been improved. Working on a dark topic, we got an incentive to use our design system more widely in the project .

Can we give users a dark theme, and simultaneously open the way to improving the accessibility of the project? We answered this question in the affirmative, having done everything that I will tell about now.

Color research


When creating the original color scales for the project, we, probably a little naive, took a certain color value and modified it using transformations implemented using Less . So, for example, we could declare a Less-variable @redand make the color darker several times using the design darken(@red, 10%). The same goes for multiple color clarification using tint(@red, 10%). This can give a color scale in which colors are in the range from @red-050to @red-900in increments of 10%.

When I first tried to understand how the Stack Overflow resource might look in dark mode, I decided to just try changing the white background to black and “flip” the color scales. With this approach, color @red-050becomes color@red-900, colors correspondingly change between the initial and final colors of the scale. But these colors themselves remain the same as those used before.


Light and dark color scales for red.

With this approach, the contrast of elements has suffered. What happened turned out to contain something that, in general, I did not like about dark topics. For example, if you look closely at the darkest version of red, located on a dark background, you will see that the color is almost indistinguishable. We will talk more about this below.


We definitely need to come up with something better.

â–ŤGetting started: layout design


Just trying to draw the color scales, I actually did not achieve anything. This step cannot be called the real start of work on a dark topic. Therefore, I decided to start developing a layout and manually selecting colors in Figma . I selected the colors, focusing on how, in my opinion, Stack Overflow should look, and not thinking about how the new colors will relate to existing ones. Reducing the overall contrast was the key to preserving the depth effect in the interface, to supporting the shadows of the elements, to applying the full spectrum of colors.


Getting started with the design of the layout allowed us, first of all, to understand what aesthetic effect we are striving for, while not paying attention to the technical requirements for the project

â–ŤSelection of an improved algorithm for working with colors


After I picked up a lighter background for the dark theme, I got the opportunity to more deeply explore the color scales. First, I needed to deal with some of the color problems of the existing design system, which appeared when applying the light theme. At the bright end of the spectrum, the red and yellow colors did not look the way I would like. Some colors had the lightest values, too close to white. There were colors, the lightest values ​​of which were too dark.


The lightest version of yellow was indistinguishable from white, and the darkest was indistinguishable from black

. We had problems at the dark end of the spectrum. Using, as background, colors@red-900and@blue-900, we noticed that these colors are indistinguishable from black and from each other. We needed an algorithm that would give us colors whose main tone is distinguishable for both the lightest and the darkest versions. This would allow the creation of components using these color values.


The darkest variations of our colors were indistinguishable from black and from each other.

Creating components that implement notifications, we could not use the colors from our design system. Instead, we needed to pick our own colors on the eye.


These colors are beautiful, but they are not based on the color values ​​from our color scales.

I used the wonderful ColorBox toolfrom Lyft Designto normalize the colors. Instead of changing colors in the simplest way, linearly, in 10% increments, I applied Bezier curves. This allowed us to achieve significant improvements in the extreme positions of the color scales.


After normalizing the colors in the bright part of the spectrum, I was able to create notifications whose colors are taken from the colors of our design system

â–Ť Dark colors


After we put in order the light version of the site, it's time to try out new colors against a dark background. As a result, I resorted to manual settings of what the color matching algorithm produced, doing this to preserve the corporate colors that have been used for a very long time. This allowed me to use new colors in production and at the same time do without too drastic changes in the appearance of the project.


Full normalized color gamut

Implementing a dark theme in the Stacks interface


If I somehow hoped to equip Stack Overflow with a dark theme, I would first need to implement a dark theme in our Stacks design system , using it as a testing ground for testing new technology.

â–ŤVariables


I needed to convert static Less compiled hexadecimal color values ​​into custom CSS properties that were designed to be used while the program was running. The point is that color values ​​should be stored using view structures var(--red-500), rather than using static view structures @red-500. It was an interesting task - both within our system design, and within the entire site. We usually took a single color value, like @red-500, and made it lighter or darker to highlight different states of the elements (like the states that the elements take when they hover over them, or when they get focus), to use as the background color or the color of the borders of the elements.

If we talk about the colors of each of the buttons, which we have a lot, about the colors of each state of each button, then we can say that these colors were obtained in the course of a set of transformations of a single compiled color value. It reminded me of one scene from the movie "The game for a fall." There they talked about the possibility of turning a ten millionth investment into billions of dollars. It is not surprising that such “transformations” led to the financial crisis.

The problem with regular CSS variables is that you cannot apply Less transforms to them. CSS variable values ​​are computed at runtime, so a construct like this darken(var(--red-500), 5%)leads to a compilation error.

All this meant that I needed to rework the code responsible, for example, for styling buttons. At first he looked like this:

.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%);
    }
}

I needed to go on to indicate the exact color values ​​described in our color system. As a result, I needed to come to this version of the code:

.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);
    }
}

At the same time, it was clear that everything was not limited to buttons. Therefore, I needed to rework the styles of all components available in Stacks. The same was true for notifications, pop-up menus, modal windows, links, and many other components.

â–Ť Browser Compatibility


If we talk about CSS variables, their application meant the need to consider their support by browsers. In particular, they are not supported by Internet Explorer 11 - a browser that we have never forgotten about. As a result, we decided to abandon IE11 support, getting rid of all those CSS hacks that we added to the system over the years of its development, taking into account the features of this browser. In addition, we decided to send notifications to IE11 users with a proposal to install a new browser. This decision was not easy for us. Its implementation required weeks of refactoring.

â–ŤConditional classes


IE11 didn't limit me anymore and I was able to work with colors in Stacks. I decided to add a bodyclass to the element .theme-system. Having done this, I was able to replace light colors with their dark equivalents using the appropriate media query. In addition, we could completely refuse the media request by simply adding to the bodyclass .theme-dark. This would allow users to use the dark theme of the site regardless of their system settings. Here is what I got as a result:

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

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

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

To achieve full flexibility, Stacks makes it possible to work with atomic color classes, which apply only when a dark theme is enabled. Details on CSS support in Stacks can be found here . For example, adding a class to an element. d:bg-green-100, the designer expresses the following thought: "In dark mode, you need to use green for the background bg-green-100." Additional conditional classes designed for dark mode allow us to remove the borders of elements, change backgrounds, and adjust the color of the text. In this tweet you can see an interesting example of color adjustment. Such a setting is sometimes necessary in dark mode. I want to note that one of the sources of inspiration when working on the dark mode of the site for me was the Tailwind CSS framework .

â–ŤUse a dark theme in Stacks


After the dark theme was implemented in Stacks, we decided to add a button to the top of the system interface that allows you to switch between themes. The employees of the company should have had a quick and convenient ability to switch between different color themes of the site.


Switch between light and dark themes in Stacks

Implementing a dark theme on the Stack Overflow main site


I solved the tasks related to the implementation of the dark theme in the interface of the Stacks design system relatively easily. Refactoring, which takes into account considerations of the future development of the system, makes it easier for Stacks to be smaller than the main site from the consequences of erroneous decisions made in the past. In order to equip Stack Overflow with a dark theme, I needed to provide support for Less variables for the sake of backward compatibility of the solution. This allowed us to organize the application of the dark theme incrementally, in separate parts of the interface.

Since most of our interface, created after 2018, is based on Stacks, this part of the interface receives, without additional efforts on our part, a dark theme and responsive layouts. What about the main part of the interface? Everything here is far from so simple.

â–ŤMain colors of the site


To begin with, I needed to make the biggest changes to the site that could be made without violating the standard light theme Stack Overflow. The tasks that I had to solve were mainly to replace static Less variables with CSS variables equivalent to them. First, I applied the style background-color: var(--white)to the background of the site, replacing it with the style background-color: @white. Thanks to this, the main area of ​​the villages could now easily be repainted in the background dark color. Then I did the same operation with the colors of the fonts and some other elements. This work mainly consisted in removing a large amount of CSS code, since, for example, we were often fond of overly detailed styles, setting the font colors of child elements, although we could well get by with color values ​​inherited from parent elements.

â–Ť Demonstration of a new design for the company employees


After I worked on large blocks of the site, I asked our programmers Adam Lear and Nick Craver to help me find a way to show a preliminary version of the dark theme to the Stack Overflow staff. This would allow employees to include a dark topic, which is still very far from being ready to see which areas of the site still need improvement. This, I thought, would encourage them to help refine parts of the site with the most traffic. This would allow me to overcome the main barrier to a new design. Namely, it would help integrate the new design into the existing code base.

â–ŤButtons


If the area of ​​the site that I was working on was created using Stacks, then in order to prepare it for using the dark mode, it was necessary to solve not very many problems. Say, during the course of the work, it was possible to decide that somewhere the border was not needed, or - that somewhere, a special shade of gray was needed as the background color. This preparation for the use of the dark regime could be limited. Unfortunately, most of the site was created without using Stacks.

This was most clearly manifested when it came to the buttons. Over the years of working on the site, many button implementations have been used in it. This was especially frustrating as we stylized the elements themselves button. This means that any element button, or element, decorated asinput type=«button», was assigned the default style. This style has a very high level of specificity and is based on an outdated set of rules.

The above fact has led to the need for a lot of refactoring, which is still ongoing. It aims to remove element-level CSS styles buttonand replace them with equivalents from Stacks. In particular, we are talking about the fact that hundreds of elements input type=«submit»need to be replaced with <button type="submit" class="s-btn s-btn__primary">. In addition to adding work, I note that we often linked JavaScript functionality to visual selectors. If you change the classes that affect the appearance of the element, this can break the functionality of the button. As a result, during the processing of thousands of buttons, I needed to add classes to them firstjs-, connect handlers to them, and then get rid of old styles that define the appearance of buttons.

This ultimately led me to remove most of the old button classes, which allowed the buttons to change colors correctly when turning on a dark theme.

â–Ť Website Title


To complicate the task, the header used on the entire site can work in different modes. We are talking about light and dark modes, and about the support mode for a special topic. The site option for teams (Stack Overflow for Teams) and for corporate systems forcibly uses a dark header theme. In addition, the command version uses the color specified by the color of the team avatar. Like many of our other components, CSS for the site title provides for a single color, which determines whether the title is light or dark. This color then, using complex Less instructions, is transformed, which allows you to get its different options. However, we could not do what we did when we processed the code of the design system. That is, they couldn’t just throw away all the old CSS and replace it with code,which uses CSS variables. The fact is that our corporate clients, in fact, completely, with the help of themes, customize the appearance of the header. In this case, color options are generated based on a single color.


Light heading


Dark title


Command heading

In the case of the bright Stack Overflow heading, we needed to find a mechanism to find out if a certain color was set using a CSS variable, or using a static hex value. If the color was set using a CSS variable, then we could completely skip its Less transformation, creating a heading that could change colors based on the parameters of the dark theme. If a static Less variable was used instead, you had to evaluate the color to see if it is light or dark, and create an appropriate heading.

As a result, we came to this approach:

& 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;
 }

Then, based on the received value ( automatic, lightor dark), the correct header is created.

â–ŤTags


If I could give just one piece of advice to those involved in the design of components, then it would read: "Do not describe in components what affects their location on the page." In other words, what kind of space separates the components should determine the context in which they are applied. No need to set such things in the component itself. In earlier versions of Stack Overflow, it was decided that post-tagexternal padding should be applied to components . At the same time, tags, like buttons, turned out to be subject to a JavaScript-related problem. To make things even harder, most tags were generated using a single helper method.

Tag refactoring involved replacing post-tag-components withs-tag-components designed to use different topics. This work also included changes to JavaScript, taking into account the use js-tag. In addition, it was necessary to change the method responsible for generating tags, making it so that it would accept arbitrary classes that affect the placement of elements. The fact is that in certain contexts, tags may need to be placed in the flex layout by doing this instead of relying on predefined external indents (or instead of fighting against such indents).

â–Ť Styling publications


The bulk of Stack Overflow is made up of user publications. These publications, namely questions, answers, comments, are made out with the help of Markdown markup. During the launch of Stack Overflow, Markdown Markup was a relatively new technology.

Over the years, the web has developed some standard ways to display something like headings and quotes. The introduction of the dark topic was an excellent moment to review our approach to formatting publications. The most controversial issue in this matter was the formatting of quotes.

Initially, quotes were framed using a powerful yellow background color, which reduced the contrast of the quote itself. The yellow color, in addition, causes certain problems when it is displayed on a dark background. As a result, we moved on to the generally accepted method of displaying quotes, using a narrow gray vertical bar to highlight them.

â–Ť Code styling


On the pages of Stack Overflow, which is quite understandable, many pieces of code are displayed. The colors we used to highlight syntax had nothing to do with our signature colors. I have a strong suspicion that these colors are the legacy of the first library used in the project for syntax highlighting. Having analyzed these colors, I decided to subject the syntax highlight to a deep redesign. As a result, the backlight colors were replaced with colors from our design system. This applies to both light and dark topics. And this is done so that what happened does not differ radically from what it was before.

results



The bright theme and the beta version of the dark theme, released on March 30.

Due to the volume of refactoring that we did while moving to the dark topic, we were able to make quite large changes to the look of the project without too much difficulty. Based on what we now have, we can, for example, develop a high-contrast website theme that increases its accessibility.

The creation of the dark theme was the result of a fundamental shift in the approach to Stack Overflow design. In particular, we are talking about the use of a design system , which I have been promoting for a year now. And creating a dark theme was an excellent opportunity for me to rebuild many parts of the site. This is the first of many projects that will increase the availability of Stack Overflow.

If you do not take into account the rejection of support for IE11, work on the dark topic began in July 2019 with this PR, aimed at researching the situation. Prior to this, in April 2019, there were discussions regarding a dark topic. In October 2019, an experimental version of a dark theme went into production. And then, after at least 60 PRs were made, a beta version of the dark theme was presented to users. It happened on March 30, 2020.

Dear readers! Do you use Stack Overflow? Do you like their new dark theme?


All Articles