Adaptive Design Systems
White Labeling, Rebranding, and re-UXing web applications #
Changing requirements, fast deployments, large-scale applications, rapid changes… These words describe the modern web application’s / saas’ lifecycle.
TLDR;
Enterprise-size front-end. A tech giant buys our company and requires rebranding the application to be aligned with the rest of the corporates style guide.
TLDR.2;
Our product (or service) is purchased by one or more companies. They have requirements for changing the look and feel of the UI. We are now in a need to deploy the same application with different flavors.
Creating a design system that is both clear and flexible is not an easy task, but after a few successful implementations of such systems, I would like to share the knowledge and lessons learned from this experience.
The ingredients of an adaptive design system #
Let’s define some terms first
Design system #
A list of rules, describing which components are part of the UI, and their initial look. In the designer’s software, it might be referenced as “symbols”.
Typically it represents the sizes, borders, and base colors. It can also define the interactivity and visual effects for those elements (animations, drop-shadows, etc.).
A well-defined system covers all the technical details of the “atomic” parts of the UI (i.e. button, slider, tooltip…) and more complicated elements, such as grids, layouts, and forms. In many cases, it should describe how they combine (A button in the header is different from a button in a form).
Variable Ruleset #
The naming convention of the design system. The list of variables describes the meaning or the reason the element is there. A button[primary]
is quite different from a button [role="cancel"]
. They are both buttons but they serve a different purpose. Probably the design would reflect that.
A good ruleset never relies on a naming convention that you can visualize. It means that variable names like “red”, “darker” or “heavy” should never be used. Prefer using reasonable names that describe the purpose. Words like “primary”, “emphasize”, “highlight”, “selected” have a clear intention and reason for their existence. If you can’t find a reasonable functional name, it’s probably a rule you can scrape out from the list.
As the first set of rules contains a very “stripped” look and feel, the initial values of the rules should provide the most minimalistic appearance of the application.
The second set of values will apply a theme that modifies the way the UI appears: a simple 3x3 grid can be transformed into an asymmetric layout. A button would be wide and have a subtle background. The hover effect will suddenly have a border, etc.
If the design can separate between the functional and the theme, you’re on the fast lane to reaching an Adaptive Design System.
Adaptive Design System - Implementation #
An adaptive design system is an implementation of a variable ruleset on top of a well-defined design system. The final product of this implementation is actually 3 layers of replaceable parts. The functional, the app theme, and the brand. Where did that third layer come from? I’ll explain that later.
The first layer, the functional layer, represents a list of rules, without actual meaning. Only declarations.
The second layer applies the “default” or “app theme” values on top of the previous rule-set. It should attempt to focus on UX and be at least tied to the brand as possible.
The third layer overrides the second layer. It contains a subset (up to 100%) of the possible rules and an enhancement of the values. It will override, but not add anything to the design. A simple unskinned button would become a red one with a bolder font, just like the logo (how original).
It is important to distinguish between the brand and the theme. They might look similar, but they serve different purposes.
Cut the bulls*t, show me some code! #
First layer (the functional layer): acme-design-system-functional.css #
/* Our buttons are designed */
button, input[type="button"] {
background: white;
border: 1px solid black;
}
/* We can learn that the designer want's the same base ruleset
across the page */
body {
font-weight: 100;
text-color: darkgray;
}
/* We now know that there is more types of buttons */
button[primary], button[aria-role="apply"], input[type="submit"] {
background: black;
color: white; /* inverted effect */
font-weight: 400;
}
/* The login form deserves a different treatment */
form.login {
background: white;
}
In the example above we can see that the designer clearly defines a difference between the common button and the “submit”. It tells us that the login form looks different for a reason.
Second layer (the theme layer): acme-theme.css #
:root {
--color-text: #333;
--color-primary: orange;
--fontweight-emphasized: 800;
--fontweight-default: 400;
--brand-color: aquamarine;
--button-background-color: var(--default-background-color); /* where's that? */
--fontweight-default: 100;
--default-background-color: white; /* here! */
}
body {
font-weight: var(--fontweight-default); /* intention of look and feel */
}
/* A subset of the rules, and overrides */
button[primary] {
/* though it's inverted in the first layer,
the theme uses a different set of rules */
background-color: var(--default-background-color);
}
In the second layer, the number of rules is lesser or equal to the number of rules presented in the first layer, but the number of variables is increasing. Note that actual rule values may point to other variables. All rules use variables with a meaningful and functional name, providing a set of values that makes our app what it is.
The third layer (the brand): our-brand.css
/* ha! nothing here */
An EMPTY FILE?!
Why? Because we’re not bought yet. Or not sold anything yet.
But when the time comes to be adaptive, the third layer becomes the-other-company-brand.css
:root {
--button-background-color: var(--default-background-color);
--brand-color: orange;
--fontweight-default: 100;
--default-background-color: white;
}
The third layer, the branding layer, contains overrides for the second layer. This layer will be changed most frequently compared to the other layers.
In case of a re-branding, most likely you will replace this file only with another one. There is a difference between theming an app and branding it. A brand is tied to constraints related to larger picture than the usage of the application. The theme provides decisions of positions, interactions: strategic decisions for this exact application.
If you have to deploy multiple flavors of the same app (white-labeled app) then you hit the jackpot. At this point, maintenance is simple, flexible and you can simply deploy different files for different flavors. You already have the rules that define how the application will look and behave, now you just need the tweaks for each label. Colors, backgrounds, image URLs.
Is this better for runtime or compile time? It’s for both! #
If you are basing your bundling using SASS/LESS, the concept remains the same. Your preprocessor should remove duplicates and provide a clean file(s). Choosing which file to use as the third layer is a simple configuration file for your app’s bundler.
If you are taking the runtime approach, the order of loading the CSS files is important. Deploy to correct files and ensure the HTML loads them by the correct order (hint: first, second, third…).
Case Study #
Fortinet, a large cyber company purchased a relatively small but established startup, called “enSilo”. enSilo already had a working product distributed among its clients. The UI of the product was fully branded.
The first requirement, obviously, came from the purchasing company. They requested “few” changes. Among replacing logos and some of the icons, they wanted to change colors, some sizes, etc. Not anything special or unexpected.
Before the re-branding was completed, another request came. White-labeling the product. But it was a special case of white-labeling. The requested feature was to let an administrator user at any client site change the looks of the application. This way Fortinet could sell a product that can be re-branded without large efforts, by a non-technical person, somewhere.
Given an Adaptive Design System implemented in the product, a very simple download link with a single CSS file was added to the product and a single “upload” button to replace it. Anyone could download that file, edit it and upload it back again. If you opened the file, it contained a list of… css variables. That’s it.
The admin user, which had NO background in web development, could easily understand what can be changed, and how. He could easily decide that --brand-color: #ccc;
can be replaced with --brand-color: #bff;
. She could just ask the dev team on the next floor what are the css color values. Within a few minutes, anyone could rebrand portions of the site.
The clients simply loved this feature. It was both accessible, easy to use, and fun.
The dev team was grateful that any further change request was relatively easy to deliver, mostly within minutes. Large buttons? You got it. Hover effect? Simple. The product manager played with this tool and started delivering CSS files with changes - if only he knew how to use git.
Side note: It’s true that if you have the understanding of how CSS works you could add your own rules and start breaking anything you like. But that’s not the point, the point was that it was adaptive to changes.
Conclusion #
User experience, like user interfaces, is software. And software design practices can apply here too. The Adaptive Design System method consists of the separation of concerns, code abstraction, and reusability. Looking at style sheets files equal among the javascript files is crucial. They are an important part of the software just as much as controllers, services, and template engines.
The author is a full-stack developer, speaker, and OSS developer.
Feel free to reach out @eavichay
https://github.com/eavichay
eavichay@gmail.com
https://twitter.com/eavichay