Github's CSS

[Note trans.]: I’m bringing to your attention a translation of an article by Mark Otto, GitHub developer, former Twitter developer, creator of the most famous Bootstrap CSS framework. In this article, he talks about the internal structure of CSS GitHub projects.


I have always been interested in the details of the development process of other products, especially their guidelines and the approach to using CSS. Given my penchant for the details of someone else's CSS code, I decided to write about the CSS approach on GitHub.

Some facts


Overview of our current CSS state:

  • As a preprocessor, we use SCSS.
  • We have over 100 separate style source files that we compile before rolling out into production.
  • Sources are compiled into 2 separate CSS files (to avoid the problem with the maximum number of selectors for IE <10).
  • These 2 files weigh about 90 kb in total.
  • We do not use any special “CSS architecture”.
  • We chose pixels to determine the size, but still we have a few "ems".
  • We use Normalize.css mixed with several of our own styles to reset properties.


Preprocessor


As mentioned above, we use SCSS. This choice was made even before I began to take part in the development, but I agree with it (despite the fact that Bootstrap is written in LESS). Our SCSS is compiled and connected using the Rails asset pipeline and Sprockets (for now). Details will be described below.

What about LESS, or Stylus, or ...? I don't think GitHub will ever switch to LESS. We would not want to change anything in this regard, since there are no obvious advantages.

Why a preprocessor? Our internal framework includes a set of variables (such as fonts and corporate colors) and impurities (mainly for prefixes) that make the process of writing code faster and easier. We are not currently using Autoprefixerbut we should do it. So we could nullify all our existing impurities. I hope we will do this soon.

We also do not use source maps, but that will change soon. (For those who don’t know, source maps allow you to see in the debugger which of the source SCSS files a specific set of styles belongs to, unlike compiled and minified files. They are awesome.)

We use SCSS tools quite limitedly. We have variables for defining colors, impurities, functions for working with color, mathematical functions and nesting levels. We do not need to iterate over classes, create global settings, or anything like that. I like the simplicity that we have.

Architecture


Typically, CSS architecture is BEM or OOCSS. We are inclined towards OOCSS, but we do not have any holistic approach. Our basic rules are:

  • Avoid optional attachments
  • Use (single) dashes when naming classes
  • Write as little as possible so as not to confuse
  • I will write about my preferred CSS architecture in another article. Right now I am describing a GitHub approach that, although not perfect, serves its purpose quite well.


Code analysis


A few weeks ago we did not use code analyzers. We had several common agreements, but each developer had his own style, and the formatting of each of us was somewhat unique. At the moment, each assembly goes through the process of analyzing SCSS code and crashes if:

CSS describes a class that is not used in app / views / templates.
The same selector is used several times (since they must always be combined).
The basic formatting rules have been violated (maximum nesting, line breaks between rule sets, etc.)

In general, there are several rules that allow us to keep our code base neat enough. They do not account for differences in commenting style or architecture, but this is exactly what every team needs. And each of us can offer and improve something.

Two packages


The CSS of the GitHub project consists of 2 files: github and github2. This separation was added several years ago to solve the problem of working with IE, which limits the number of selectors to 4.095 per 1 file. This restriction applies to IE 9 and below. Due to the fact that the requirement of GitHub is a minimum of IE9, we have to split the files.

As of today, our 2 files consist of approximately 7000 selectors. How does this compare with other sites?

  • Bootstrap v3.2.0 - less than 1,900 selectors
  • Twitter - less than 8,900 selectors
  • NY Times - Less than 2,100 Selectors
  • SoundCloud - only for 1,100 selectors (Edited: I previously spoke about 7,400, but it was an old SoundCloud)


This data was collected using cssstats.com. This is a small tool that looks at your CSS from an angle that most people, including me, usually don't. We also have charts on GitHub that we use for our own purposes.

Connection via Sprockets


In GitHub, CSS and JavaScript are enabled using Sprockets and require. We store both our CSS packages in separate directories inside app / assets / stylesheets. This is how it looks:

/ *
 = require primer / basecoat / normalize
 = require primer / basecoat / base
 = require primer / basecoat / forms
 = require primer / basecoat / type
 = require primer / basecoat / utility
 = require_directory ./shared
 = require_directory ./_plugins
 = require_directory ./graphs
 = require primer-user-content / components / markdown
 = require primer-user-content / components / syntax-pygments
 = require primer / components / buttons
 = require primer / components / navigation
 = require primer / components / behavior
 = require primer / components / alerts
 = require primer / components / tooltips
 = require primer / components / counter
 = require primer-select-menu
 = require octicons
 = require_directory.
* /

We connect our dependencies (Primer is our internal framework) and then download all the files from the scss directory. The connection order will be decided by Sprockets (it seems to me that it is alphabetical). The ease with which we can connect our style sheets (by simply writing require_directory) is amazing. But this approach has its drawbacks.

The order in which styles are applied plays an important role. Due to the use of Sprockets, we sometimes have specific problems. This is because new files can be added to any package at any time. Depending on the file name, new styles may appear in different places in compiled CSS.

In addition, using Sprocket, you do not have immediate and automatic access to global variables and impurities in your SCSS files. This means that you will have to import them explicitly at the beginning of each file that refers to a variable or impurity.

Performance


We have a huge number of graphs for monitoring the operation of sites and our API. Including we track some interesting statistics on the frontend. For example, the size of our two CSS packages in the last 3 months:
image
We also track the number of selectors on the page. We are still faced with the task of reducing the number of selectors by tag.
image
Since we regularly update our CSS and do it many times every day, we have to constantly reset the caching of our rather large files. So far, we have not made much progress in optimizing the size of these files and limiting the dumping of the cache, but we have already begun to think about it more seriously. It would be nice to have a main package that rarely changes, and a minor, honestly changeable one.

When I worked on Twitter, we had 2 packages (not sure if this is still the case), primary and secondary. Basically, all the styles that were required to display the first tweet as quickly as possible were described. Everything else was stored in an extra. Given the love of GitHub for everything fast, this is exactly what we plan to consider in the near future. File sharing is currently random.

As a rule, we do not deal with the performance of selectors. We know about bad practices - a lot of nesting, the use of selectors by id and element, etc., but we are not trying to optimize it a bit. The one exception is the diff page. Due to the extensive markup required to render diffs, we avoid attribute selectors such as [class ^ = "octicon"]. If used too often, such attribute selectors can put the browser (and did).

For the curious, Jon Rohan, the developer of GitHub, made an excellent report on CSS performance on GitHub that addresses these issues.

Documentation


image
Speaking of documentation, we did a great job on it, but are still working on making improvements to it. We have made publicly available our CSS guide and all our basic rules for writing CSS. We also posted examples of most of our components. It is built using KSS, a style guide generator.

Our documentation is not perfect, but it helps people find and use what they want. In addition, this is a great way to show recruits how we work in order to speed up their flow into the development process (as it was with me about 2 years ago).

Primer


image
I referred to Primer earlier, but for those who don’t know, Primer is our internal framework that contains styles and components used both in public and in our internal projects. It includes:

  • Normalize
  • Global styles for box-sizing, typography, links, etc.
  • Navigation items
  • Forms
  • Nets
  • Custom select element

We use it on GitHub.com, Gist and several internal applications. As a rule, if something can be used in another application, we include it in Primer. Most Primer components are documented in our guide.

Refactoring


Our projects have some Legacy code, and CSS is included. Unlike opera projects with strict versioning rules, we often hammer on this. We decide to remove part of the code in two cases:

  1. Manually we find places that look similar, but are described by different HTML or CSS code. In this case, we simply combine them.
  2. Run a script that looks for classes in CSS code that are not in the views. (Now we have automated this process by including it in our tests).

The CSS refactoring process itself on GitHub is not unique. We find the bad code, delete it and roll it out as quickly as possible. Any team member can delete the code. Many cool developers join our team, but we also have nerds that monitor what can be removed and what not.

Questions?


If you have questions about this article, Bootstrap, GitHub, or anything else, ask Twitter or my repository for feedback.

Also popular now: