CSS
Note: All the below is a much more condensed version of the CSS methodology we use called ECSS. For full insight into the methodology, you can read more here: https://ecss.benfrain.com/
Separate structure from aesthetics
The way we approach HTML & CSS is to split styling into 2 main functions. Structural styling & aesthetic styling. This allows us to compose more robust layouts not overloading elements and components with responsibilities.
With the example below we control all the vertical spacing in the section with the _Header, _Body and _Footer classes. This allows us to put whatever we want inside these elements and the vertical spacing remains consistent. This means we can put carousels, cards, accordions, etc. inside the _Body and re-use the sec-Section in multiple places to keep a consistent section layout.
When it comes to deciding what class should be holding the margin we should apply the "what if" mentality. What this means in practice is asking yourself, of these 3 elements, _Header, _Body & _Footer which ones should ultimately be responsible for the spacing?
Should it be the _Body because you can then do the top & bottom margin on 1 element thus writing less CSS? Should it be the _Header and _Body so we can keep a consistent margin-bottom spacing?
The correct answer is it should be on the elements that have the potential to go away. What we don't want to end up with is a "hangover" margin. i.e. margin-top on a _Body when a _Header doesn't exist. So, for that reason, we should have margin-bottom (margin-block-end) on the _Header and margin-top (margin-block-start) on the _Footer. That means if either of these elements weren't needed then the
spacing of the section isn't affected.
Bad
<!-- bad -->
<div class="sec-Section">
<div class="sec-Section_Inner">
<h2 class="sec-Section_Title"></h2>
<div class="nws-CardList"></div>
<div class="sec-Section_Links">
<a class="sec-Section_Link sec-Section_Link-primary"></a>
<a class="sec-Section_Link sec-Section_Link-secondary"></a>
</div>
</div>
</div>
Good
<!-- good -->
<div class="sec-Section">
<div class="sec-Section_Inner">
<header class="sec-Section_Header">
<h2 class="sec-Section_Title"></h2>
</header>
<div class="sec-Section_Body">
<div class="prd-List"></div>
</div>
<footer class="sec-Section_Footer">
<div class="sec-Section_Links">
<a class="sec-Section_Link sec-Section_Link-primary"></a>
<a class="sec-Section_Link sec-Section_Link-secondary"></a>
</div>
</footer>
</div>
</div>
This doesn't just apply to sections. Lists of cards are also a great example of this. The "Good" example may seem overly verbose but each element plays an important role in separating layout and style.
The prd-List allows us to vertically space the list based on its context.
The prd-List_Items acts as our container to hold items
The prd-List_Item acts as our item placer
The prd-Card is the module we can use to start the context to style our cards
Again, this allows us to be able to use the prd-Card in multiple places because we aren’t adding a margin to this to control the spacing when in a list.
Bad
<!-- bad -->
<div class="prd-List">
<a class="prd-Card" href="#">
...
</a>
</div>
Good
<!-- good -->
<div class="prd-List">
<ul class="prd-List_Items">
<li class="prd-List_Item">
<a class="prd-Card" href="#">
...
</a>
</li>
</ul>
</div>
One place where we could forego the structural elements is when using display: grid. Because grid offers gap on the parent we don’t need the structural children to implement the spacing. However, we stick with the "good" example because it allows us to future-proof any further structural changes without having to change the whole HTML structure as well.
Semantics
HTML5 provides us with lots of semantic elements aimed to describe precisely the content. Make sure you benefit from its rich vocabulary.
Bad
<!-- bad -->
<div id="main">
<div class="article">
<div class="header">
<h1>Blog post</h1>
<p>Published:
<span>21st Feb, 2015</span>
</p>
</div>
<p>…</p>
</div>
</div>
Good
<!-- good -->
<main>
<article>
<header>
<h1>Blog post</h1>
<p>Published:
<time datetime="2015-02-21">21st Feb, 2015</time>
</p>
</header>
<p>…</p>
</article>
</main>
Make sure you understand the semantics of the elements you're using. It's worse to use a semantic element in the wrong way than to stay neutral.
Bad
<!-- bad -->
<h1>
<figure>
<img alt="Company" src="logo.png">
</figure>
</h1>
Good
<!-- good -->
<h1>
<img alt="Company" src="logo.png">
<span class="util-ScreenReaderOnly">{{ site.name }}</span>
</h1>
Brevity
Keep your code terse.
Bad
<!-- bad -->
<!doctype html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;" charset="utf-8" />
<title>Contact</title>
<link rel="stylesheet" href="style.css" type="text/css" />
</head>
<body>
<h1>Contact me</h1>
<label>
Email address:
<input type="email" placeholder="you@email.com" required="required" />
</label>
<script src="main.js" type="text/javascript"></script>
</body>
</html>
Good
<!-- good -->
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Contact</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>Contact me</h1>
<label>
Email address:
<input type="email" placeholder="you@email.com" required />
</label>
<script src="main.js"></script>
</body>
</html>
Fonts
Fonts are 1 of the few places where we use utility classes.
The purpose behind the font classes is to effectively create “tokens” with which we style all of our text. You can think of these along the lines of “heading 1”, “heading 2”, etc. The reason we don’t call them this is that they offer no context. Seeing .fz-14_130 immediately allows you to mentally connect with what this font looks like and corresponds to in the design. If you're coming to a project and find a font in the design you've absolutely no idea if this is .fnt-Heading1, .fnt-Heading2, etc. You'd need to go to the fonts file and look through each class name to see if the size & line height correspond. The use of fz-14_130 tells us exactly where to look in the fonts
file to see if it already exists.
All styling related to that token should be on the class. Don’t just do font-size, font-weight & line-height.
The syntax for the class names are: .fz-[desktopFontSize]_[desktopLineHeight]
.fz-14_130 {
font-size: 14px;
font-weight: 500px;
letter-spacing: 0.3px;
line-height: 130%;
text-transform: uppercase;
}
When it comes to the approach for mobile, where possible, we should be using media queries to alter the fz-14_130 token as opposed to providing different mobile, tablet & desktop font sizes.
There may be circumstances where you have a class like fz-42_130 which has a different mobile size. In these instances, you should just do a local override instead of creating a 1 off token. This is why you'll see font sizes always paired with a relevant child node. <h1 class="sec-Section_Title fz-42_130">...</h1>
.sec-Section_Title {
font-size: ...
}
Obviously, there are exceptions to this rule but for most typographic elements on the site, this is the preferred method.