Speaking the Same Language
May 6, 2016
Ever since the dawn of the first graphical user interface, designers and engineers have been collaborating to build software. Now that Graphics Processing Units (GPUs) on computing devices support nearly infinite colors, textures, shapes, and animations—not to mention a growing array of input and output methods—the collaboration between those that design user interfaces and those that build them has become more important than ever. Facilitating that dialogue between hundreds of designers and engineers can be challenging at best and fraught with frustration at worst. So at LinkedIn, we set out to bridge that gap with a set of tools built by a unified team of designers and engineers, with the goal of empowering other designers and engineers around the company. This is the story of our journey through the creation and evolution of our design language and pattern library.
In the Beginning … a Design Language
Back in 2012, LinkedIn developed its first design language, called Katy, which was inspired by musician Katy Perry and focused primarily around the web as a user interface. In 2015, the design team sought to create a new design language that would both modernize the web experience and introduce the language for the mobile platform as well. The newest design language, called Art Deco, was established in early 2015 and receives revisions every two weeks. The architecture-inspired name symbolizes the relationship between design and engineering.
The Art Deco language has two primary goals: consistency of end user experience, and empowering designers to make decisions faster. Having every design team in the company work from a single library of building blocks means the resulting user experiences should have a similar look and feel, in addition to demonstrating interaction best practices. Designers have access to these building blocks as pieces that can be easily incorporated into their design tools, empowering them to focus on the details of the product problem they are trying to solve rather than focusing on the minutiae of the building blocks. Users experience consistency in design and an interface that bakes in elements like sufficient color contrast, which is important for accessibility.
From the Design Language … a Pattern Library is Formed
In 2015, the same engineering team began to do bi-weekly releases to match the cadence of updates to the design specification, and subsequently released a new version of the library for Art Deco to support our existing tech stack and newest front-end frameworks. In late 2015, the developer team expanded to include mobile developers, who began investigating how to build out the patterns for iOS and Android platforms, in addition to the web platform. The team is currently in early implementation of the library’s native mobile versions.
To Build the Patterns … Distributions are Born
Beyond the living website, which demonstrates and documents the code patterns, we needed to ensure that the shared code could be easily consumed from all our current and prior generation web frameworks. We therefore implemented the Play-NPM pipeline to allow easy build and dependency management with modern Pemberly (Play + Ember), Flyer (Python/Flask + Ember), and Play/Dust ecosystems. You can read more about that project here.
For mobile, we are just beginning our distribution strategy. The first phase is the creation of a library for iOS that contains patterns we can version. The second phase will involve building the patterns into a reference app that developers can model their code on. Android will take a similar approach later this year.
From the Code … Abstractions Emerge
With our continued investment in a concrete pattern library with its own design language, we had to figure out an abstraction for this language that would allow us to deliver a reusable and flexible solution for development. We wanted to mirror the Katy design language that had already been established, so that’s where we started. For example, the visual design pattern might specify a “button in a container.” We took that idea and created a simple CSS abstraction to handle this for us:
Leveraging the design vernacular, this abstraction makes obvious the intent (hint: this will look like a “button in a container”). At the same time, using such abstractions introduced a powerful convention: composability. You could now begin to compose visual elements based on a flexible design language. Composable definitions for “small button in a container” or a “large secondary button in a modal” allowed the abstraction to evolve with and accommodate the growing design demands.
The first technical iteration on this solution was Archetype, which was a Sass extension built atop Compass and Sass.
For the Art Deco initiative, we did an overhaul of the CSS abstraction stack, in addition to a new version of the library. We swapped out our Ruby Sass and Compass tools and adopted a modern Sass pipeline leveraging node-sass, LibSass, and Eyeglass. This pipeline enabled better integration into our node asset pipeline, and Eyeglass allowed us to deliver and consume Art Deco as a library via npm. Many of the natural language patterns pioneered in Archetype were revamped in reSTYLE, an Eyeglass plug-in.
Art Deco provides a clean abstraction atop reSTYLE to enable a composable UI pattern API, leveraging the same vocabulary found in its design language:
The ecosystem introduced here makes it incredibly easy to share, consume, and contribute to the UI patterns as they grow and expand. reSTYLE’s composable nature allows for highly customizable UI pattern definitions. The Art Deco library defines the UI patterns to adhere to our design specifications. Eyeglass allows us to easily distribute Art Deco across multiple products through a simple npm install.
For the Library … Contribution Evolves
After debuting the Art Deco library for use in production, we turned our attention to encouraging and enabling grassroots contributions from engineers outside the core team. We wanted app developers who create new UI patterns or bug fixes to be able to contribute to the library's codebase. This way, we can aim for the kind of rigorous development that powers successful open source projects by leveraging LinkedIn's entire engineering population, exceeding what the group responsible for the library could do alone.
The first step in opening up the project was to establish guidelines and instructions for contribution. We assembled a document that lives alongside the pattern documentation for developers to refer to when using our patterns. The goal of this document is to:
- Codify a feature proposal process so that a contributor with an idea can get feedback on feasibility and appropriateness before starting to code an implementation;
- Provide an overview of the library and documentation app codebases to quickly get new contributors up-to-speed on each project's file structure and feature set;
- Outline the optimal development workflow, explaining how to run, develop in, and test out changes to the projects on the contributor’s computer;
- Specify the code review and check-in steps required for a contributor to submit changes.
Contribution guidelines like these are important for any project to efficiently onboard new contributors and make the process of receiving their contributions a smooth one.
Let's explore a subset of this process in a little more depth by writing a hypothetical contribution. To start, here's a closer look at what the Art Deco library provides:
- Pattern Styles: The implementation of the design patterns' aesthetics written as reSTYLE definitions, this part of the codebase is Art Deco's core offering, allowing consuming apps to pull in complex styling with simple invocations of the artdeco() mixin as described earlier. It consists of:
- Resets: styles that normalize the appearance of pages and markup across browsers;
- Primitives: styling for core design fundamentals like our color palette, typography, and grid system;
- Elements: atomic patterns that are the smallest units of our design language and are the building blocks for other patterns; they include buttons, containers, and dividers;
- Components: compositions of elements that comprise our more complex interface patterns, such as modals, entities, and alerts.
- Reusable Assets: These include the web fonts, icons, and illustrations we use across products.
Now that we've looked at the various areas for potential contribution, let's explore a hypothetical addition. To keep things simple, we'll create an easy style pattern for modifying the look and feel of images. We'll write a reSTYLE definition to express the following:
- Give images a 100 percent max width by default so they're sized to fit their containers;
- Have images scale up in size slightly on hover (probably not something we'd do in the real world, but fun for our example);
- Add a round modifier for optionally styling images as circles;
- Add a grayscale modifier for optionally filtering images to grayscale, with a reset to return them to full color on hover.
First, let’s add our contribution to the Art Deco library:
We use the restyle-define() mixin to define a pattern definition. It takes a Sass map of CSS properties. Representing our styles in maps allows reSTYLE to perform some impressive and useful transformations, one of which we'll see momentarily. The first entries are the default styles we apply to all images. Then we add a nested restyle-states map to define our hover-specific styles. After that, we define a restyle-modifiers entry to indicate the styles that our round and grayscale modifiers should apply.
Notice in the grayscale modifier we define additional hover styles in a more deeply nested restyle-states map. reSTYLE will merge the grayscale-specific hover styles with the default hover styles defined earlier when the grayscale modifier is applied. This is just a simple example of how delivering our styles to reSTYLE in maps allows it to handle the details of producing the correct CSS output so we can write our pattern definitions in a declarative fashion. For more on all the features reSTYLE offers, see the reSTYLE documentation.
Now that we have a pattern to use, let's add it to our documentation app. It's built with Ember, so we'll define a router entry, a template, and a Sass partial.
First, the router update:
Next, the template. We'll simplify it a bit and exclude the example code snippets we usually provide for each pattern.
The template documents the styles available to the image pattern and details how to call our artdeco() mixin (which proxies to reSTYLE) to apply the pattern.
Finally, let's utilize our image pattern definition to apply styles to the examples in our new documentation page:
Notice how we use the abstraction reSTYLE provides to invoke styling using design language. Also note the ability to compose modifiers to produce complex styling, as our round grayscale image invocation exemplifies.
Here's our new documentation page in all its glory:
(Kitten image copyright 2006 Paul Reynolds under the Creative Commons Attribution 2.0 license)
And here's the demo with the hover state triggered on all the examples:
We hope this walkthrough of the Art Deco library codebase and the example, albeit simplified, of contributing a new pattern illustrate how useful it is to take a design language and implement a reusable library of code.
We’ve seen tremendous improvements in both the speed of bringing product designs to market and the consistency of user experience in the years since we started the pattern library and code documentation. As the library grows, we plan to extend the visual language to our native mobile platforms. Additionally, we want to capture richer interactions for developers in the Ember ecosystem.