CSS makes it really easy to add styles that tie you down – so you can’t make changes without breaking things. This post shows some examples of how we are fixing these problems in our codebase.
When something is “brittle” it means it is easy to break. Brittle code means code you can’t change easily without breaking something. CSS is a language that is prone to a lot of brittleness. There are some things we can do to make working with CSS better though! Let’s look at some examples from our codebase.
We have text inputs that let users at-mention social media accounts. They should look like this:
One day, we noticed the alignment had broken and they looked like this:
The problem was that the CSS for our @mention tag was brittle. Making an “unrelated” change in the codebase had caused the styles to break here unintentionally.
Here are some of the styles we had:
.mention {
position: relative;
padding: 1px 2px 1px 8px;
...
}
.socialIconContainer {
position: absolute;
top: 0.06em;
left: 0.24em;
...
}
Here are the same styles after refactoring:
.mention {
display: inline-flex;
align-items: center;
padding: 2px;
...
}
.socialIconContainer {
display: flex;
align-items: center;
justify-content: center;
padding: 2px;
margin-right: 2px;
}
We replaced the absolute positioning and hard-coded numbers with fluid self-calculating values. This means that now we can change other styles without breaking this code. Hard-coded positioning can almost always be replaced with fluid self-calculating values like this.
Sidebar layouts are really common in CSS. We had one in our app that looked like this:
This worked well on desktop, but not on smaller screens:
The styles were hard-coded for desktop:
.root {
padding: 20px;
width: 1000px;
margin: 0 auto;
}
.aside {
float: left;
width: 310px;
margin-right: 20px;
}
.main {
width: 670px;
}
After refactoring the styles look like this:
.root {
padding: 10px;
max-width: 1000px;
margin: 0 auto;
}
.aside {
max-width: 400px;
}
@media (min-width: 600px) {
.root {
padding: 20px;
}
}
@media (min-width: 1000px) {
.root {
display: flex;
}
.aside {
flex: 1;
margin-right: 20px;
}
.main {
flex: 2;
}
}
Now we use “additive” media queries like this so the styles work on any screen size (mobile, tablet, desktop, TV…whatever); we start with the base styles that should apply always, then only add changes on top for explicit overrides. We replaced width
with max-width
to ensure items are 100% width on mobile so they don’t overflow. Also, as with the first example, we replaced hard-coded values with fluid self-calculating values using flexbox.
width
values can usually be replaced with max-width
so that they don’t overflow on smaller screens.translate
etc.).max-width
undo media queries can usually be replaced with min-width
additive media queries (or container queries, element queries etc.).important!
and other “undo” rules are usually a symptom of bad cascading/inheritance that should be broken up into explicit styles.Although there are legitimate uses for these, they are usually a code smell.
If CSS is “hacky”, there is probably a cleaner way! Using clean, flexible styles will keep styles self-contained so they don’t break randomly.
Send this to a friend
1 Comment
I never use !important, it is evil. I’m sure there are some edge cases for it but it’s usually a sign that you could do things better