A good looking and well functioning front end is what makes most web applications good. In fact, an app might have an incredibly smart back end, where things seem to magically happen, but if it's user interface is counter-intuitive, or if it breaks on different devices, then it is very easy to overlook the greatness of the actual product.
As web developers, we spend hundreds of hours working with designers, gathering requirements, going through wireframes or finished designs, and then carefully crafting a clean looking, functional and responsive front end that just works on any device, on any browser and in anyone's hands. Now that's good UX. But in our efforts initially to nail that pixel perfect design we sometimes overlook an important factor - The front end's evolution.
It is completely natural for companies to go through different iterations of their brand, and therefore of their look and feel. We have all seen many web sites or applications, such as Netflix, Spotify, Facebook, Reddit, etc. go through various changes. These changes might be small such as changing the way posts are displayed on Reddit or big like completely remaking the look of the site.
A ready-to-evolve front end should always be ready for any kind of change. It should be ready to very quickly and consistently update how certain parts of it look, or even how the entire interface looks. The main characteristics of a ready-to-evolve front end are:
- It is scalable
- Easy to maintain
- New developers joining the team find code clear and easy to work with
- Changes and complete redesigns are done in a short time period
How to achieve ready-to-evolve front end code
Start with the CSS
Most companies use CSS pre-processors to write code and compile it to pure CSS. In this article, I'll be using SASS as an example. If you're not using a pre-processor to write CSS, I highly recommend moving to SASS and it's SCSS syntax - it is easy to write and it supports full vanilla CSS syntax.
Variables
Pre-processors support creating variables in your code, which can point to absolutely anything - they could be colours, sizes in any supported unit (px, em, rem, cm, etc), font names and pretty much anything you can think of. If you can write it as a CSS value, you could write it as a variable.
If you have any values that are likely to be used in multiple places in your code, I strongly recommend assigning these to variables and using them everywhere in your code. A huge benefit that this provides is that let's say if your site has a main colour, you can write something like this:
$main-color: #BADA55;
h1 {
color: $main-color;
}
Now imagine if you didn't assign that colour value to a variable. It certainly isn't a disaster, but if your design changed and suddenly your main colour is changed from blue to pink, you would have to go through every css file that points to blue and update the value in multiple places. This is error-prone, as you might accidentally miss a certain file or line. If you use variables, the only thing you need to worry about is changing the initial variable's value and you can be confident that when you compile down to pure CSS you'll have a consistent colour change.
I recommend putting every colour inside a variable, even colours like black and white. You never know what direction your brand might go in, and perhaps you might need your white to be slightly darker, or your black slightly lighter.
$white: #fff;
// white might change from #fff to #f8fcff
$black: #000;
// black might change from #000 to #282828
Another neat trick to using variables is that you can utilise math operators for widths and sizes. You can have a perfectly scalable font size like so:
$base-font-size: 10px;
$font-size-large: $base-font-size * 3;
$font-size-medium: $base-font-size * 2;
$font-size-extra-small: $base-font-size / 1.5;
So if you need to change font sizes in your brand, you can simply update the base font size value and the rest will scale accordingly.
In conclusion - variables are good and you should aim to use them as much as you can, while avoiding having a file with thousands of variables that are difficult to manage. If you do end up in a situation with more variables than you can manage, it is worth going through the structure of your code and checking for duplication or for variables that are not being used and refactoring them.
The benefits that variables provide are that they are consistent and easy to update, you can update the value of a variable and ensure that it is updated across your codebase, resulting in very speedy and virtually no bug inducing changes.
Mixins
CSS pre-processors such as SASS provide these great things called "mixins". A mixin essentially is a a function that can take arguments and output SCSS code. If you are familiar with functions in programming in general, then mixins should be easy to grasp. If you're not - no worries, they'll become clear in just a minute.
Let's create a basic mixin that we will use to style buttons:
@mixin btnStyler ($background, $color, $border-radius, $font-size) {
background-color: $background;
color: $color;
border-radius: $border-radius;
font-size: $font-size;
}
.danger-btn {
@include btnStyler(red, white, 5px, 1.5rem);
}
.success-btn {
@include btnStyler(green, white, 10px, 1rem);
}
So what is happening behind the scenes?
We declare a mixin called btnStyler
, which takes some parameters for a background colour, the text content colour, border radius and the font size.
Inside the btnStyler
mixin we assign regular CSS values to point to the parameters.
We then call that mixin with the @include
keyword and we provide some arguments.
The mixin will generate CSS based on its logic and arguments provided and apply said CSS to the selector. Easy!
Mixins are my favourite feature in SASS, as they are reusable and flexible. If I use mixins throughout my code, I can guarantee a single source of truth and if I need to make changes to how certain elements look or behave, or maybe enhance existing functionality I can simply update the mixin, which when compiled will be called and my changes will be reflected throughout the codebase.
Utilising the usage of mixins in your code will give you the flexibility to make changes quickly, and you can store commonly used styles within them, and if you need to change style slightly - just update the arguments in your mixin call.
General tips
Avoid specificity in your stylesheets.
While it may be tempting to do something like:
div.widget > button {
background: teal;
}
It will result into painful to refactor code later on, should you decide to do any changes to your CSS. Sometimes in a hurry, it is common for developers to write code like this and specify certain elements in order to get the UI out quickly, so a feature can make it to production, but this level of specificity can make your code
- Hard to maintain
- Hard to debug
- Hard for other people to work with
My general tip for specificity is to avoid it as much as you can. Be specific with nicely named class names:
.button.success {
// style
}
.button.danger {
// style
}
p.important {
// style
}
Instead of being specific with where your elements are located, be specific with their class names and give your elements easy to distinguish class names. When you need to make changes to said elements, you can rely more on a global class name that will affect your UI on multiple levels, rather targeting a specific element, nested 3 levels deep inside a div.
Create reusable classes and components
My final tip is to think about reusable code. That's right, components and reusable blocks of code are not reserved only for programming languages, but also CSS. Does your web site have lots of pages that have a full width hero section with a CTA and a heading? Turn that into a component in your HTML!
<section class="hero">
<h1 class="hero-header">Join our awesome website now</h1>
<button class="button hero-cta">register</button>
</section>
Identify what would the common look of all of these hero sections would be and add them to your style:
.hero {
background-size: cover;
background-position: center center;
background-repeat: no-repeat;
// more and more code
}
This approach allows you to create reusable classes and style each one of them. The only thing you'd need to worry about is what background image or colour you want your heroes to have, and the rest of the style is taken care of by the base class styling we've already applied!
I strongly recommend introducing this style of component based styling throughout your stylesheets. While it might be a slight effort at first, it will allow you to quickly update components and debug code.
Summary (TLDR;)
- Orientate towards using a CSS pre-processor
- Store your brand colours / font sizes / screen sizes and everything that makes the core of your design in variables
- Use the power of mixins and pre-processor functions to re-use code and change once, affect everywhere
- Avoid being too specific about styling your elements
- Prioritise well-defined class names
- Build components by combining HTML and class names
I hope these tips are useful for you. Using them for work and for personal projects (I even built my dissertation based on a similar approach) has proven them to be valuable both for code quality and for achieving best practices.
Want to change the world, while being surrounded by smart people and dogs? We're hiring - https://tails.com/careers/