In my first three years at Genius, I introduced lots of software, templates, and guides to improve the design, handoff, and implementation processes.

Design Process

I introduced Sketch and Origami, and created a library of components, plugins, and data files to make rote tasks easier. This transformed mockups at Genius from rough illustrator files with lots of cropped screenshots and duplication, to high fidelity mockups and prototypes that take less time to make.

Using a plugin to quickly populate a list of real songs into a mockup.

Using Sketch templates and a library of symbols decreased project startup time, gave us more fine-grained control over every element, improved each mockup’s consistency with the real product, and made it easy to hand off a project to another designer.

As the engineering and mobile teams grew, the design team was less and less likely to implement its designs. I introduced Zeplin and Origami to improve the way we communicated our design choices to other teams.

Even the simplest Origami prototype is a whole level above a static mockup from Sketch.

Zeplin saved us a ton of time and gave app developers better specs than we ever did manually.

Origami allowed us to spend more time in the design phase figuring out how things should behave, and gave us a great preview tool on iOS so interactive prototypes could be passed around at meetings, before implementation ever began.

Implementation Process

A few months after I started, we released a new brand and design. Behind the scenes, we also overhauled the song page front-end with Angular and a new approach to CSS.

I introduced a variant of BEM syntax and wrote a styleguide detailing how to do everything from order properties to organize files. When I started, Genius’ CSS was hard to reuse, nested under body classes, and used to enforce permissions by showing or hiding page elements. I pushed to move logic and high-level states out of CSS and into JS, and now Genius’ CSS is highly componentized and reusable.

Styleguide Excerpts

Rules Of Thumb

  • Avoid using extends: they change the order of rendered CSS selectors in an unintuitive way, and there are caveats when using them inside media queries and mixins.
  • Avoid using ids in selectors: they have different specificity rules than class selectors, which forces you to use unnecessarily specific selectors to override them.
  • Avoid using element selectors: these are the least efficient selector — especially at the end of long selector strings like `.class .class .class.class element`, which forces the browser to search for every `element` and then filter that list.
  • Avoid nesting more than three levels deep with SCSS.

What Is A Component

  • When adding new HTML/CSS or editing existing elements on the site, always think of how parts of the element can be extracted into their own discrete units.
  • A component should be the smallest possible unit that still makes sense: this often means a component will represent a tiny element, like the user badge, but it can also mean a component will represent an element which is large, and contains many other components, like a layout.
  • A component should contain *just enough* css such that it can be included anywhere without having to override any default styles.

Component Naming Conventions

  • Names should be based on the component’s visual role, not its content e.g. text_label, not song_lyrics_label.
  • The syntax of naming:
    • component_name
      component_name-descendant
      component_name-descendant-descendant
      component_name--modifier
      component_name-descendant--modifier
  • Words within a component name are separated by underscores.
  • Descendant components are separated by dashes.
  • You can continue to stack descendants to whatever reasonable length — more than three is probably too many, and you should reconsider your component or break its children into separate components.
  • Modifier classes use two dashes — modifiers can’t be used alone, they must always be paired with a root class.

Using SCSS Variables

  • Name a variable after its role, not its value e.g. primary_color, not brand_yellow.
  • Use underscores to separate words.
  • Use a name which is specific to the variable’s current use.
  • Only use the same variables across items which make sense to change as a group i.e. not items that incidentally use the same value, but items that on principle must use the same value.

Using z-index

  • Add a layer name and corresponding z-index value to the master list in imports/z_index_variables.scss.
  • Access the layer via the z_index() mixin.
  • If the layer to which you want to add a z-index is within a z-index context, create a nested map inside the master list in z_index_variables and end its name with _context.
  • If you’re not sure whether your layer is in an explicit or implicit context, or what a z-index context is at all, read this — it explains how z-index contexts are created.

Organizing SCSS Files

  • All component and import filenames should start with an underscore and separate words with an underscore.
  • All import filenames should end with their type e.g. _x_variables.scss or _y_mixins.scss.
  • Imports can only contain non-rendering scss e.g. @mixins, %extends, or $variables, otherwise they’ll render their contents as many times as they’re imported.
  • Import filenames shouldn’t be too specific or too broad e.g. imports/_helper_mixins.scss doesn’t indicate the role of its contents very clearly, and imports/_song_page_padding_variables.scss is too specific and can’t be reused.
  • Components should be named after the main class they style e.g. _leaderboard.scss should style the .leaderboard component and all its modifiers and descendants.
  • Components should not include the title of their folder e.g. prefer mobile/_leaderboard.scss to mobile/_mobile_leaderboard.scss.
  • Cross-platform components which have some platform-specific features should be named the same thing in all three folders e.g. mobile/_leaderboard.scss, desktop/_leaderboard.scss, and shared/_leaderboard.scss — in these cases, the shared version should be the master reference, with the platform-specific overrides/additions being as small as possible.