The World of Styling for the Web
CSS Methodologies, Preprocessors, Frameworks, and Beyond. An Overview of Everything You Need to Know About Styling.
Introduction
Should you use a framework? Should you write pure CSS? What about LESS and SASS? Styled components?
Styling for the web is constantly evolving. I've looked through dozens of different approaches to styling and summarised it up here so you can get to building that site you've been thinking about.
If you have some experience with styling using CSS, and you want to learn more about the wide variety of options to approach styling your websites and webapps, this is the right article for you.
Contents
CSS
CSS separates content from its presentation. CSS controls layouts, colors, and fonts. This is what every other styling technique will end up as - the browser only understands your styling in terms of pure CSS (or inline styles).
In CSS you use a selector to declare which part of the markup a set of style rules apply to. Selectors can match the element type such as an <h1>
or an <article>
, or by an elements attributes such as it's class
or id
, and selectors can be used to match elements that are placed relative to other elements, such as siblings or children.
Some standard CSS might look like this:
h1 {
color: white;
text-align: center;
}
.center {
text-align: center;
color: red;
}
Once your project starts growing in complexity, you need methodologies to keep your CSS in order. You need a set of rules on how to organize your CSS, when to use different types of selectors, and so on. All of these methodologies work with preprocessors as well, which I'll get into in a later chapter of this post.
CSS Design Methodologies
There are many CSS methodologies out there, here's a few of the most popular ones. I'll talk a bit about each.
- BEM
- SMACSS
- OOCSS
- ACSS
- ITCSS
BEM
BEM stands for Block
Element
Modifier
. BEM is a naming convention for your CSS.
- Block - Standalone entity that is meaningful on its own; a component.
- Element - A part of a block that has no standalone meaning and is semantically tied to its block; an element inside a component.
- Modifier - A flag on a block or element; a variation is signified by a modifier.
The BEM naming convention would look like this if all three are used:
[block]__[element]--[modifier]
Block with an element
In the example below, there is a block with an element inside. The block, or main component is photo
, and the elements are photo__img
, photo__caption
, and photo__quote
Elements are children of blocks, but the classes shouldn't communicate structural depth. In the example below you have a nested <blockquote>
in the <figcaption>
, but you can see the classes don't reflect the nesting. You may be tempted to write the class for the <blockquote>
as "photo__caption__quote"
because of the nesting, but this would be incorrect according to BEM.
<figure class="photo">
<img class="photo__img" src="me.jpg">
<figcaption class="photo__caption">
<blockquote class="photo__quote">
Look at me!
</blockquote>
</figcaption>
</figure>
.photo { }
.photo__img { }
.photo__caption { }
.photo__quote { }
Block with a modifier
Modifiers aren't used on their own, they should always be used along with a block or element. The modifier augments the block, therefore we use both button
and button--secondary
.
<button class="button button--secondary">click me</button>
.button {
display: inline-block;
color: blue;
}
.button--secondary {
color: grey;
}
Element with a modifier
Elements can also have modifiers. In this example you see photo__img
as the element, and photo_img--framed
modifying that specific element.
<figure class="photo">
<img class="photo__img photo__img--framed" src="me.jpg">
<figcaption class="...">Look at me!</figcaption>
</figure>
.photo__img--framed {
/* incremental style changes */
}
Resources to learn BEM
- The official BEM site
- A guide to BEM with examples (most of the examples I use are borrowed from this)
SMACSS
SMACSS stands for Scalable and Modular Architecture for CSS. It's best understood as a CSS style guide.
SMACSS is about the categorization of CSS rules. There are five categories:
- Base
- Layout
- Module
- State
- Theme (optional)
For each category, you'll create a separate folder to hold the CSS for that category.
Base styles are applied to element selectors:
In the base styles, you'd include a CSS reset. Base styles are default sizes, margins, colors, border, and anything else that will ensure consistency across your website. Typography and form inputs would fall into base styles.
body, form {
margin: 0;
padding: 0;
}
a {
color: #039;
}
a:hover {
color: #03F;
}
Layout styles are the major sections of the site such as header, article, and footer:
These are the largest sections of your site that all of your modules would live inside. Usually you will name the layout sections with an id
to ensure uniqueness.
#header, #article, #footer {
width: 960px;
margin: auto;
}
#article {
border: solid #CCC;
border-width: 1px 0 0;
}
Modules are the meat of the website, navigation bars, carousels, and so on.
For each module, it's best to create a separate CSS file to house the styles for it.
.module > h2 {
padding: 5px;
}
.module span {
padding: 5px;
}
State rules modify other style rules. They are applied to layouts and/or modules, and usually indicate a JavaScript dependency.
In the example, is-collapsed
and is-hidden
are state rules; they modify the elements they are attached to.
<div id="header" class="is-collapsed">
<form>
<div class="msg is-error">
There is an error!
</div>
<label for="searchbox" class="is-hidden">Search</label>
<input type="search" id="searchbox">
</form>
</div>
Theme can affect any of the previous base styles (base, layout, module, and state), and is stored in a separate theme.css
file.
Themes define colors, backgrounds, typography, etc. They are rarely used, but they give you some freedom to change the theme of your website if need be.
// in module-name.css
.mod {
border: 1px solid;
}
// in theme.css
.mod {
border-color: blue;
}
OOCSS
OOCSS stands for Object Oriented CSS. It applies object oriented programming concepts to CSS. A dynamic bottom-up approach is used rather than a procedural top-down one.
The "object" in OOCSS can be any repeating pattern that can be specified in a separate piece of code.
There are two rules in OOCSS:
- Separate Structure and Skin
- Separate Container and Content
Separate Structure and Skin
Structure - things that are "invisible" to the user:
- Height
- Width
- Margins
- Padding
- Overflow
Skin - the visual properties of an element:
- Colors
- Fonts
- Shadows
- Gradients
/* Structure */
.side-widget {
width: 100%;
padding: 10px 5px;
}
/* Skinning */
.recent-posts {
font-family: Helvetica, Arial, sans-serif;
color: #2b2b2b;
font-size:1.45em;
}
Separate Container and Content
Content are elements that are nested inside other elements called Containers.
Styles for Content should be independent from the Container.
Essentially, avoid using child selectors whenever possible. Give unique elements unique classes rather than using descendant selectors.
ACSS
ACSS means Atomic CSS, or Functional CSS.
In ACSS you define classes with a single attribute inside:
.relative {
position: relative;
}
.mt10 {
margin-top: 10px;
}
.pb10 {
padding-bottom: 10px;
}
There is also a programatic variation of ACSS that utilizes Atomizer to programatically generate styles. This can be categorized as a preprocessing step.
With programatic ACSS, styles are generated based what's in the HTML, using a function style syntax in the element's class:
<div class="Bgc(#0280ae) C(#fff) P(20px)">Lorem ipsum</div>
The above HTML will generate the following CSS:
.Bgc\(#0280ae\) { background-color: #0280ae; }
.C\(#fff\) { color: #fff; }
.P\(20px\) { padding: 20px; }
ITCSS
ITCSS stands for Inverted Triangle CSS. It helps you organize your CSS files in a way that makes it easier to deal with global namespaces, cascade, and selector specificity. ITCSS is meant to be used in conjunction with most of the previously mentioned methodologies (BEM, SMACSS, OOCSS).
Your styles will be separated into the following folders:
- Settings
- Tools
- Generic
- Elements
- Objects
- Components
- Utilities
ITCSS works best with preprocessing languages like SCSS or LESS, etc. The examples below use SCSS syntax.
- Settings – fonts, colors definitions, etc
@font-face {
font-family: 'Source Sans Pro';
src: url(../../font/Source_Sans_Pro/SourceSansPro-Regular.ttf);
}
$fontType: 'Source Sans Pro',
sans-serif;
$colorPrimary: #ff9617;
$colorSecondary: #4078c0;
- Tools – globally used mixins and functions
@mixin box-size($width:100%, $height:100%) {
width: $width;
height: $height;
}
- Generic – reset and/or normalize styles
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: $fontType;
}
- Elements – styling for bare HTML elements, redefining the browser's default styling
body,
html {
@include box-size();
background-color: $colorDark;
scroll-behavior: smooth;
overflow-y: hidden;
}
header {
@include box-size(100%, 60px);
background-color: $colorDark;
}
- Objects – abstract elements, the same as "structure" in OOCSS
Objects are "non-styling" elements: border
, padding
, text-align
, cursor
etc.
.button {
display: inline-block;
padding: 8px;
}
- Components – specific UI components. The bulk of the styling
.button {
color: $colorLight;
background-color: $colorDark;
}
- Utilities – utilities and helper classes
It's best to think of this in terms of atomic CSS.
.mt10 {
margin-top: 10px;
}
.pb10 {
padding-bottom: 10px;
}
An example of ITCSS in use can be found here: github.com/csswizardry/frcss
Preprocessors
CSS preprocessors are programs that generate CSS using the preprocessor's own unique syntax.
Preprocessors add an extra build step to your programs, and might generate larger CSS files than plain CSS.
There are a few flavors of preprocessors that will generate CSS for you:
- Preprocessing languages
- CSS in JS
Preprocessing Languages
Preprocessing languages add useful features such as variables, loops, conditional statements, nested styles, mixins, inheritance, and more.
The most popular preprocessing languages are:
- SASS / SCSS
- LESS
- Stylus
- PostCSS
The following examples use the SCSS syntax. Most preprocessing languages have a similar syntax.
Variables
$primary-color: #4D926F;
#header {
color: $primary-color;
}
Nesting
nav {
ul {
margin: 0;
padding: 0;
list-style: none;
}
}
Mixins
@mixin important-text {
color: red;
font-size: 25px;
}
.danger {
@include important-text;
}
Modules
@use 'base';
.inverse {
background-color: base.$primary-color;
color: white;
}
Inheritance
%message-shared {
border: 1px solid #ccc;
padding: 10px;
color: #333;
}
.success {
@extend %message-shared;
border-color: green;
}
Operators
article {
width: 600px / 960px * 100%;
}
CSS in JS
CSS in JS is just as it sounds, it allows you to control CSS from within your JavaScript files. Typically these solutions are used with JavaScript frameworks such as Vue, Angular, React, and so on, but work with vanilla JavaScript as well.
Dynamic functionality, scoping, and portability are some of the limitations of CSS that are tackled by CSS in JS.
Within the umbrella of CSS in JS, you have a few options:
- CSS modules
- Styled components
Modules In CSS modules, your styles are written in separate files, and referenced in your JS.
import styles from './Button.module.css';
render(
<button className={styles.error}>Err Button</button>;
);
Styled Components Styled components have your styles written next to your JS.
const Title = styled.h1`
font-size: 1.5em;
text-align: center;
color: palevioletred;
`;
render(
<Title>
Hello World!
</Title>
);
CSS Frameworks
A CSS framework is a collection of stylesheets that allows you to quickly add styling to your projects. Frameworks utilize many of the CSS methodologies from the previous chapters and build up a set of styles that you can quickly apply to your project.
CSS frameworks commonly have the following features:
- Semantics
- Design Systems
- Customization
- Components
- Responsiveness
- Utilities
- Grid system
- JavaScript Integration
- Browser Support
- Integration with JavaScript Frameworks
- Reset stylesheet
- Typography Support
- Icons
- Interactions (hover, focus, etc)
Generally CSS frameworks fall somewhere between a utility framework and a component framework.
Utility frameworks utilize features in line with atomic CSS, providing static utility classes that you can use to build up your styles:
<h3 class="h1 pad-3-vert text-blue">Lorem ipsum</h3>
Component frameworks have predefined components that can be used to build up your application, typically following naming conventions similar to BEM:
<div class="card">
<div class="card-body">
This is some text within a card body.
</div>
</div>
A combination of both of these types is the most common - providing both utilities and components.
Conclusion
The most important takeaway is that you should choose a method and stick with it for the project. Depending on you and your teams skillset, the tools and frameworks you're using, and how much time you are able to invest will determine which method you should choose.
Whether you're bootstrapping an MVP or creating a large-scale application, choose the methodology or framework that aligns best with the scope of the application. Keep in mind the maintainability and scalability of the method you choose.
You may even consider creating your own styling library or system tailored exactly to your needs.