Posted on • Originally published atcoryrylan.com on
Resilient CSS APIs and Design Systems
Design Systems and UI libraries help companies and product teams align visual design consistency and speed up UI development. As much as we hope to make our UIs pixel perfect, many aspects of the Web actively work against pixel perfection. Not only do we have to deal with browser inconsistencies but also other code running in the application unintentionally breaking or changing our expected visual output.
Many Design Systems and UI libraries use global CSS to apply the website’s desired look and feel. Global CSS can be good and bad in different use cases. Global styles can help easily make things consistent but also cause conflicts. Let’s walk through a seemingly simple scenario.
Our Design System needs consistent styles for ourh1
headings. We define something like this in our code:
h1{color:#2d2d2d;font-size:24px;}
Great, now everyh1
heading will look the same. Quickly we run into issues at scale. What if we want to use anh1
style but can’t due to anh1
existing already on the page? Duplicate headings are bad for SEO and accessibility. Well, we could make anh1
class.
h1,.h1{color:#2d2d2d;font-size:24px;}
This additional selector is a step in the right direction. We can now use any semantically correct element to style it like our system’sh1
style. But this is still at risk of other issues. First, if we are building a Design System to support multiple apps or teams, they may be already using another library to style their app. By applying styles to native element selectors, we have a high risk of causing style collisions.
.h1{color:#2d2d2d;font-size:24px;}
So if we remove the native element selector, now we eliminate the risk of the Design System colliding with other styles. This now leaves the question of why call it anh1
? Why not name it to something semantic that makes it easy to understand its purpose?
.heading{color:#2d2d2d;font-size:24px;}
That’s better, but the class name is a bit generic and still could be more specific. We can prefix with some standard name for our system.
.ds-heading{color:#2d2d2d;font-size:24px;}
The prefix could be a shorthand name for the product or company. Here I haveds
for Design System. So now, we have a scoped isolated and consistent way to style headings in our design system. Something as simple as a class name can be more complicated than it seems. Thoughtful API design can save teams significant amounts of time when trying to adopt, use, or upgrade to your Design System/UI Library.
Often I think CSS selector types are often not used to their potential. While CSS class names are the most common style hook, we can use HTML attributes to provide a more expressive CSS API.
[ds-text*='heading']{...}[ds-text*='subheading']{...}[ds-text*='body']{...}
<h2ds-text="heading">A cool heading</h2><h2ds-text="subheading">A cool subheading</h2><pds-text="body">A cool paragraph</p>
By leveraging attribute selectors, we can may our CSS much more expressive. Not only is the style selector specific and scoped but also easily conveys its intent in the HTML.
CSS libraries and Design Systems can leverage more expressive selectors and Shadow DOM to create resilient CSS that works in more predictable and reliable ways. Check out theClarity Design System Typography utilities, as well asblueprintcss.dev which both leverage similar attribute-based APIs.
Top comments(0)
For further actions, you may consider blocking this person and/orreporting abuse