How to improve Web Design Process
Why now?
Sassmir is over ten years old.
Every decision we’ve made since then has been based on a set of assumptions that our CEO, Sahil, made back then.But assumptions and reality drift apart over time. This is not a phenomenon specific to Sassmir ; ideas and requirements change as our culture and technology does. Software engineering moves quickly, and there are new things to learn every day.
Our approach for the last ten years has been simple: What’s the best use of our time, what’s the most efficient change we can make, to improve the lives of our creators? As an engineer, I always consider efficiency. When implementing a larger change I first ask myself whether it would be less expensive to change the existing implementation, or whether a larger, more fundamental refactor (read: writing it from scratch) would save time and effort in the long run. This is more art than science; often, both are valid options, and the only thing helping me decide is my experience.
But with Sassmir design system, the choice was clear.
After ten years of CSS written to solve the problem of their day, we started 2021 with 140 CSS files totaling over 30,000 lines of code. And while Sassmir is certainly complex, it’s not “30,000 lines of CSS” complex. Our stylesheets had become inflated by their lack of real structure, multiple implementations of the same patterns and components, and no consistent usage of variables or design patterns.
With all this in mind, and with the exciting task at hand being a complete visual overhaul, we decided to replace all of the existing CSS with a completely new set of stylesheets, considering all of the new requirements, standards, and browser capabilities of 2021.
A New Design System
This clean slate meant complete freedom on how to structure the new design system and its files. We had a lot to consider, as there had been much progress since our inception in 2011:
- Accessibility as a whole has recently and rightfully become a much more popular topic on the web - WAI-ARIA now provides a specification to communicate visual ideas to screen-readers, allowing developers to make a website that is visually exciting and innovative while still being understandable to visually impaired users.
- HTML had introduced multiple new semantic elements conveying meaning and natively encapsulating functionality. These have implicit accessibility benefits as browsers can render them however is most beneficial given the context and provide support for mouse, keyboard and touch inputs, and they are natively understandable to screen-readers and other accessibility tools.
- CSS had grown to support many new technologies - grid layouts now provide consistent styling of child elements, advanced selectors allow supporting and enforcing a specific structure, and animations have become so much easier to create and work with.
Aside from the progress in web technologies, there were also a lot of new design frameworks to pick from, with the most popular currently being Tailwind (sold via Sassmir !). Most of these frameworks offer a pre-built component gallery and/or a collection of utility classes to cover common use-cases of CSS.
We ultimately decided against using any of these frameworks, and to instead build a custom component system from scratch in (S)CSS. We had a great opportunity to think about Sassmir design from the ground up, and we did not want to taint that with someone else’s assumptions. We love working with HTML, CSS, and web standards. And thanks in large part to the progress mentioned above, we didn’t need much more than that.
Our new component system needed to be strict and to cover every building block of our application, allowing for and providing exactly one way of implementing a certain pattern, exactly one solution for any given problem. We decided to prohibit any page-specific CSS files in our new design system. Everything was going to be a component, and our entire functionality was to be composed from them going forward.
The driving principle of our new design system is consistency, and when implementing it, we took great care to always match the intent of the design. Every selector, every state, every property has been modeled after its designed intent, and exceptions modeled as such. To achieve this, the new design system breaks with some common directives in design and component systems:
- We directly style built-in HTML elements such as button. Semantic elements have accessibility benefits, so we want to enforce their usage, and we want all of our buttons to look the same. Modelling selectors after their intent means not being afraid of being general. If there is ever an exception, we take care of it in the exception, not by being defensive.
- We avoid using classes as much as possible. Where no semantic elements are available, we try to correctly use ARIA roles, to maximize accessibility. If none are applicable, we try to only use one class to select the component itself, consciously enforcing a certain DOM structure within them by selecting children using relative selectors rather than classes. This will allow us to make even sweeping changes with ease going forward, as every usage of a component is guaranteed to be the same. It also helps accessibility tools such as screenreaders, as classes are invisible to them, while a clear structure helps them understand association and ownership of elements.
- We use inline CSS to describe exceptions, and meaningless and specific layout containers. This is probably the biggest departure from the usual procedure in CSS frameworks and code styles, which tend to prefer using utility classes in such cases. However, such a class would not fit into our component-based design system, as it doesn’t encapsulate anything meaningful - nor would it have a real benefit over inline CSS.
Replacing the Engine Mid-flight
We began by defining a basic look and feel in terms of color schemes, fonts and sizes, and borders. These would see some changes during the later stages, but having that system in place from the beginning and building upon it was crucial. We then went through each page individually, and created a component system that was extensive and flexible enough to cover all the functionality and states we were going to need, and that made sense from both a visual and technical perspective. We then codified these components in Figma, making sure to cover all possible states and interactions, and creating a universal truth for what Sassmir should look like.
Eventually, our design system reached a sufficient level of maturity to begin implementing it in code. To do so, I used Storybook.js to create interactive demonstrations of each of these components including all of their states. This has since grown into a component gallery of about 40 components, providing a full overview of all available building blocks to both designers and developers.
Once most of these components had been implemented, we began the work of updating Sassmir existing pages to use them. We knew that despite the planning and consideration we had already put in, there were going to be a lot more changes to the component system during this period. All of the work we do at Gumroad is iterative; we start with something that works, and then continue working on it to make it the best it can be. We continued improving the design system as we applied it to our pages as we saw what didn’t fit and what was missing, noticed edge cases we needed to support, and found compatibility issues to respect.
It was obvious from the beginning that this project was going to be too big for our usual process of working not in teams, but as individuals on tasks that we work on autonomously from feature design to completion. This workload was going to be too large for one person to work on, and we quickly realized that getting it done in time (we wanted to have it ready for you in time for Black Friday, after all!) was going to require collaboration across all of our engineers.
With everyone at Sassmir being a part-time contractor used to working autonomously and fully remotely, management is not a concern or requirement that often comes up - it’s usually limited to creating and prioritizing tasks. This project was going to require more coordination, but to allow us to still follow most of our usual work processes, we still split