Written by Daniel Schwarz✏️
A CSS boilerplate is a set of unoriginal and unspecific CSS rules designed for inherent use in web projects. Using one can help you to get your CSS up and running in seconds.
You can find CSS boilerplate templates online, or you can create and maintain your own one, to make 1rem = 10px
, reset various CSS properties, enforce your preferences on raw HTML elements, and so on. I’m certain that there are many CSS rules that you habitually include in all of your projects (some of which might do things that you believe CSS should do out of the box), so even if you don’t use a CSS boilerplate consciously, you almost certainly have the makings of one.
The problem with using popular CSS boilerplates is that they tend to be overzealous, making way too many assumptions about what the average website needs and resetting every CSS property known to exist. In fact, it wouldn’t be totally inaccurate to refer to some of them as bloatware. That being said, many custom CSS boilerplates are more extravagant than they need to be, contain a lot of redundant code, and become larger over time without much thought.
In this article, I’ll show you what I believe are the must-haves of a modern CSS boilerplate. The result? Hopefully, something more minimal, predictable, and easier to maintain going forward. We’ll also discuss some helpful but not essential CSS rules.
Jump ahead:
- Don’t reset margins
- Definitely reset the box model
- What you do with borders is up to you
- Force images to behave
- Reset (most) lists
- Enhance link underlines
- Change the root font size
- Disable the text inflation algorithm
- Enable smooth scrolling
- Rethink how focus works
- Provide interactive elements with a cursor
Don’t reset margins
There are quite a few HTML elements that web browsers automatically apply margins to, and although it’s very common to reset them (i.e., margin: 0;
), you shouldn’t because web browsers do this for legitimate reasons. The <body>
element uses margins to ensure that webpages remain readable and that touch targets don’t fall to the edges of mobile screens in the event that the CSS doesn’t load. Content elements (e.g. <h1>
, <p>
, and <figure>
) apply margins for the same reason — accessibility. The <dialog>
element uses margins to center itself in the middle of the screen.
I’m not saying that we should let web browsers decide everything for us, but since you’ll certainly be defining your own margins according to a design spec (right?), why reset them only to redefine them later? This is how I feel about CSS resets in general, which is why I won’t be talking about them that much.
Definitely reset the box model
Imagine you set the width
of an element to 700px
, the border
to 1px
, and the padding
to 1px
too — what’s the physical width of the element now? Is it still 700px
with the border and padding forming on the inside, or is it now 704px
with the border and padding added on? Most people would agree that if you set the width
to 700px
then that’s what the physical width should be, but ordinarily, it will, in fact, be 704px
. To understand why you’ll want to read about the CSS box model.
To make a selector’s box model act in what most consider a more logical way, you’ll want to reset it with this CSS rule:
box-sizing: border-box;
With this CSS rule in place, 700px
means 700px
, and any borders and padding will form on the inside, reducing the content area's width instead of being added onto the outside of the element.
Although, since there’s no telling what exactly you’ll be adding the borders and padding to, you’ll just want to apply the rule to everything using the universal selector (*)
:
* {
box-sizing: border-box;
}
Writing *
is quicker than writing a list of specific selectors to target. Also, the universal selector’s impact on performance is negligible these days and doesn’t impact the specificity weight value.
However, it doesn’t target pseudo-elements, so considering how common it is to use ::before
and ::after
, you’ll probably prefer the following snippet instead:
*,
*::before,
*::after {
box-sizing: border-box;
}
But why doesn’t the box model work more logically right out of the box? The reason is that the box-sizing
property is a relatively new one, and having web browsers change the way they render layouts would completely break the layouts that already exist.
So even though box-sizing: border-box;
It isn’t the default; I imagine most developers believe it to be the best approach.
What you do with borders is up to you
border: none;
is a CSS rule that features in a lot of CSS resets. Buttons, dialogs, form-related elements, and images on Firefox all have borders by default. This is great for usability because borders can increase the affordance of interactive elements, but if you’d rather address affordance differently, use the following code snippet to remove all borders altogether:
* {
border: none;
}
Force images to behave
<img>
elements are inline, so they’ll often have that annoying little space underneath them. You can fix this by tinkering with vertical-align
, but there’s no value that works in every scenario, and it’s very unlikely that you’ll want your images to be inline, anyway. You’re better off fixing the issue with display: block;
.
I’ve also thrown in max-width: 100;
, which prevents images from blowing up their containers for absolutely no reason at all. Why? Because containers should contain!
img {
display: block;
max-width: 100;
}
Of course, there are many other inline elements, but they’re either uncommon, or making them block-level might be a little presumptuous.
Reset (most) lists
Whether you’re using ordered lists (ol
), unordered lists (ul
), or menus (<menu>
), it’s unlikely that you’ll want the list markers (i.e., bullets, numbers, etc.,) that come with them since they look rather unsightly on user interfaces. The following snippet removes them, but not from those used in articles where it makes sense to use them in their natural form:
menu:not(article menu),
ol:not(article ol),
ul:not(article ul) {
list-style: none;
}
Annoyingly, they also have some padding on the left side, which you’ll want to remove inherently:
>menu,
ol,
ul {
padding-left: 0;
}
Additionally, since list markers appear on the outside of lists, removing the padding using the snippet above can cause the list markers (the ones used in articles that we’re not resetting) to overlap neighboring content or overflow the viewport, so you’ll want to switch them to the inside
instead:
article ol,
article ul {
list-style-position: inside;
}
Tip: Add the
role="list"
attribute-value to all lists that you’d like screen readers to announce as such, becauselist-style: none;
disables this ability in some web browsers.
Enhance link underlines
As a designer, I believe that typography is the most important part of a design’s aesthetic. I also believe that buttons are overused, although this makes sense since underlinked links aren’t pleasant to look at. However, there’s now a way to make underlines thicker (to match the size and weight of the font) and spacier. It only requires two CSS properties:
a {
/* Places underlines below the descenders */
text-underline-position: under;
/* Sets the thickness as a percentage of the font size */
text-decoration-thickness: 8;
}
Change the root font size
If you prefer using rem
units (which are better for accessibility), 1rem
is equal to 16px
(the default root font size). Naturally, it’s much easier to convert px
to rem
when 1rem
is equal to 10px
, but to do that, you’ll need to change the root font size to 62.5
, like so:
/* <html> = the root */
html {
font-size: 62.5; /* (62.5/100) * 16px = 10px */
}
Disable the text inflation algorithm
On smartphones and tablets, web browsers inflate the font sizes of text elements that use 100 percent of the viewport’s width using a text inflation algorithm. This is done with the best intentions (to enhance readability), but it can be quite unpredictable, with some elements being hit by the algorithm and some not.
Besides, I’m certain you wouldn’t want web browsers deciding your font sizes for you — because I wouldn’t want it either. Any good designer or developer knows that text should be readable on all devices, and invests time and energy into making websites responsive. To disable this algorithm, you’ll want to apply text-size-adjust: none;
to the root/<html>
:
html {
-webkit-text-size-adjust: none; /* for iOS Safari */
text-size-adjust: none; /* for other mobile browsers */
}
Enable smooth scrolling
Pretty simple — instead of instantly snapping to same-page anchors and text fragments, scroll-behavior: smooth;
enables users to scroll to them smoothly. Also, to cater to those that prefer reduced motion for accessibility reasons, the rule is wrapped in a prefers-reduced-motion: no-preference
media query:
@media (prefers-reduced-motion: no-preference) {
html {
scroll-behavior: smooth;
}
}
Rethink how focus works
The :focus-visible
pseudo-class provides a less aggressive approach to styling interactive elements that are currently being focused on. More specifically, using the snippet below, you can use it to remove the outline for mouse users but keep it for keyboard users. With just one selector, no less!
:focus:not(:focus-visible) {
outline: none;
}
Provide interactive elements with a cursor
Many interactive elements, such as buttons, don’t have pointer (hand) cursors when hovered as anchor tags do. I’ve always found this odd, especially for interactive elements without clearly defined regions, such as most labels. The cursor just doesn’t change at all, which in my opinion, shows that the spec gets it wrong sometimes. It’s a small caveat that only affects desktop users, but it’s one that I believe is worth fixing.
The following snippet adds pointer
cursors to interactive elements that don’t already have an alternative cursor, for example, text inputs
, textareas
, and more:
label,
button,
select,
summary,
[type=radio],
[type=submit],
[type=checkbox] {
cursor: pointer;
}
Closing thoughts
It’s important to think about your CSS boilerplate carefully. After all, it is the foundation of every website you'll work on. This includes reviewing it regularly as well as reviewing any changes you make to it over time. If you’ve ever worked on a design system before (or even just design versioning), you might find the concept of reviewing changes quite familiar, as well as the outcome of changes feeling purposeful and minimal.
I look forward to hearing about the CSS rules that feature in your CSS boilerplate and whether you plan on making changes to it after reading this article. Drop a comment in the box below!
Is your frontend hogging your users' CPU?
As web frontends get increasingly complex, resource-greedy features demand more and more from the browser. If you’re interested in monitoring and tracking client-side CPU usage, memory usage, and more for all of your users in production, try LogRocket.
LogRocket is like a DVR for web apps, recording everything that happens in your web app or site. Instead of guessing why problems happen, you can aggregate and report on key frontend performance metrics, replay user sessions along with application state, log network requests, and automatically surface all errors.
Modernize how you debug web apps — Start monitoring for free.
Top comments (2)
You're missing "%" on some values in the article - max-width, font-size & text-decoration-thickness.
Сongratulations 🥳! Your article hit the top posts for the week - dev.to/fruntend/top-10-posts-for-f...
Keep it up 👍