Reworking styling for over 2,000 buttons, labels and screens

We love a good design overhaul. Here's how we reworked our typeface to keep it consistent for more than 2,000 buttons, labels and screens.
By Team member, 27/03/2019
8 minutes read

We're pretty proud of our mobile apps here at Cuvva. After all they're the public face of our ambition and culture, and they embody our mission to make a new, better kind of insurance. That's one of the reasons we're constantly working to improve them. Sometimes it's little things like clearer instructions and minor visual tweaks, other times new features or ... now and again ... a complete design overhaul!

However, constant and rapid improvement can lead to problems unexpected and enjoyable opportunities to improve our processes.

Changing our typeface

About 6 months ago, we re-evaluated the typeface we use in the apps. At the time, the house style was to use variations of the Avenir font, but as design trends evolve and preferences change, we decided it was time to replace all the text with a font better suited to our needs.

Both of the major platform companies have spent countless hours crafting fonts that work well on a variety of devices for a wide range of uses and users. We absorbed all the reasoning and arguments and decided to use Apple's San Francisco for iOS and Roboto for Android.

And here's the this point both our apps had many, many, many screens, labels and buttons¹, all carefully and lovingly crafted in what was now the wrong font. 🙁

Someone was going to have to go back through everything and change it all.

One solution would be to grab an intern, a box of doughnuts and a fresh pot of coffee and let them at it. 🍩But that would've been mean, boring and mundane.

Another would be a great big automated "search and replace" on everything. Risky, as automated search and replace doesn't always change the things you want, and some poor intern would still have to check it all manually.

So instead we thought it was a great opportunity to look with fresh eyes at how we use typeface to talk to our audience. We had a deeper dive into the issue, looking at the weight, style, size and position of our type.

On the whole, our use of typography and style was on-point, although there were a few "Why the hell is that button bright blue with bold black text when nothing else in the app looks like that?" moments, and even a few "Awww do you remember when we thought it would be cute to do that? 🤢" ones.

The result of all this navel-gazing was quite interesting. A lot of the screens had very similar font styles and colours - thank the gods and design team! - but others, particularly the ones created early on in the app's history, were a little bit different. Not by much, but enough to make them look odd compared to the other screens (things like the text colour being a shade or two darker, or the font size being 1 or 2 points smaller).

This is kind of understandable - different people, working at different times with different priorities, will implement things in different ways, leading to some barely-perceptible but odd discrepancies.

>Making things consistent

Working with the design team, we decided these outliers could be considered "wrong". We could bring them back into the fold by changing them to meet the majority of the existing styles.

Initially we had a LONG list of different styles and colours in use throughout the app, but by grouping them into "intention" or "purpose" we could cut it down.

It soon became clear that we could reduce all the different styles to:

  • 2 styles for navigation text
  • 2 styles for titles
  • 6 styles for absolutely-everything-else text

Each style had a defined purpose and reason to exist.

We did the same with the colour palette and settled on 9 main colours for text and backgrounds, plus the usual red, amber and green for signposting.

(I pushed for fewer but had to concede in the end that there is a deep and meaningful psychological difference between #F3F3FF . and #F9F9FF .)

Making the changes... intelligently

So, now we had the start of a style guide and a bit of a plan for moving forward (no new colours or styles from the design team unless there is a really good use case for it!) and a list of "approved" styles and colours.

And we still needed to change everything in the app. (Where is that intern hiding?)

But, because we're engineers (and therefore cynical and lazy by nature) we just knew that by the time we'd finished implementing the agreed styles and colour scheme some bright spark (usually from marketing or growth management) would suddenly wake up and say ">Can you make it a bit more toupe? It's the in thing right now and trending well". [Marketing edit: toupe is so2018.]

So we needed a system where the next poor sap wouldn't have to go through 2-year-old code and tweak 3 labels to be "toupe-i-er".

On the web this is easy(er) - there are these things called "style sheets" that define everything. They even cascade (allowing a newer one to undo an older one and mess with the first person's plan).

There are similar libraries available for native mobile development but there are a couple of drawbacks. They:

  • Usually want you to do things in a certain way
  • Are bad at being retrofitted into code that didn't start out the way they wanted
  • Can be over-specified or too complicated for what you want to do
  • Don't tend to work well across multiple platforms

All we want is to control the fonts and colours in our app in a nice semantic² way.

So, in true Cuvva style, we rolled our own. 👍

Style File

We took the style and colour information we distilled from our investigation and encapsulated it in a common data format called JSON.

JSON is platform-agnostic (which means it will work on any operating system) and both iOS and Android have got good support for processing it. Here's an example of what it looks like:

{ "fonts": { "navigationTitle": { "fileName": "", "postScriptName": "System", "weight": "UIFontWeightBold", "size": 15 }, "exampleShadowStyle": { "fileName": "Lato-Semibold.ttf", "postScriptName": "Lato-Semibold", "size": 20, "shadow": { "dx": 0, "dy": 2, "blurRadius": 7, "color": { "r": 51, "g": 51, "b": 153, "a": 1 } } } }, "colors": { "clear": { "r": 0, "g": 0, "b": 0, "a": 0 }, "primary": { "r": 51, "g": 51, "b": 153, "a": 1 } } }

We then wrote our own custom versions of the apps views, labels and buttons that exposed some extra "properties"3 for font and colour that would "automagically" convert "largeNavigation" and "primaryBright" into the correct fonts and colours as defined in our JSON file. We exposed these properties to the screen designer so the programmers can set them in a nice friendly way:

Now when our friend from marketing wanders up and tells us that toupe is out but fuschia is in, and that all the cool apps have gone back to Comic Sans (I kid you not), we just need to change one file and our iOS and Android apps both look completely different!

Never again (?)

We still had to go through every screen, label and button in the app to do this. But at least we knew it was the last time we'd ever have to! (And hey, it kept the intern busy.)


If you want to see, in detail, how we made all this work, there are some technical bits and an example project below.

Technical bits...

If you've read this far I'm guessing you're eager for the juicy technical and programmer-type-stuff huh?

Well, it's not rocket science, it's just what engineers do: be presented with a problem, instantly think of a solution, have a cup of coffee and a mooch around, think of a better and much more fun solution that will make your life easier in the long run, implement it. 🙂

I'll keep things simple and high-level so you won't need too much tech knowledge to follow along.

Theme Manager

Once we defined our JSON file of fonts and colours, we needed a way to manage this throughout the app. So we created a "theme manager" object that did the following:

  • consume the JSON file

  • validate it

  • convert the JSON to iOS / Android objects

  • create a default set of iOS / Android objects if anything went wrong

  • expose some helper functions

Then we needed to subclass the UI elements that would take advantage of these themes.

UI Elements

The most common elements we wanted to target are UIView, UILabel, UIButton and UITextView. Each of these elements have slightly different requirements, so they need different implementations. For example, a UIView only really needs a background colour, whereas a UILabel needs the font, font colour and background colours.

We exposed these requirements to the interface builder using the @IBDesignable directive. This meant we could assign the right values directly in the screen designer:

Or programmatically in the code:

self.backgroundColor = [CuvvaThemeManager.sharedManager.currentTheme colorFromString:@"lightGrey"];
self.font = [CuvvaThemeManager.sharedManager.currentTheme styleFromString:@"primary"].font;

Each element implemented a new method called "loadTheme", which accepts a theme object and applies the fonts and colours to the display appropriately.

It's boxes all the way down

So now we had a way of interpreting the JSON theme file, exposing the right stuff throughout the apps, and UI elements that knew what to do with the theme... but we needed a way to quickly apply the theme to all these elements on the screen without too much extra work for us (we are lazy after all).

So we took advantage of the way app screens are created and a couple of events that happen when the screen gets displayed.

All app screens start with a "view". This is basically a box that can contain other elements like labels, buttons and other views. These are called "subviews". Each of these elements is also like a "view", so they too can contain even more subviews - and so on and so on. An app screen is basically a big box of boxes of boxes.

We needed to look in each box and see if it contained something we wanted to apply a theme to. AND if it contained any other boxes we might be interested in.

Luckily there's an event that happens when the mobile device has sorted out all the boxes. On iOS it's (handily) called "viewDidLoad". We rewrote this bit of code so, when all the boxes are ready, we can loop through and see if each one is interested in the theme. If they are, we give it to them so they can set their colours and fonts. (In iOS we created a protocol that the theme-able elements implement, to make it quick and easy to identify them).

Here's a picture of one of the app screens and all its boxes:

(look at all the lovely boxes!)

If you want to have a look at a sample app that demonstrates these principles, we've put together a demo.

And a little demo gif here:

GIF demonstrating the principles


1How many things?

  • 174 screens or bits of screen
  • 1,145 labels
  • 766 buttons

2 Semantic.

What the dictionary says: "Of or relating to meaning or arising from distinctions between the meanings of different words or symbols."

What we mean: "It's not a sodding Green button, it's an Action button! What if your whole colour scheme was green and you wanted to highlight the action button by making it orange!? Then your 'GreenButton' is actually orange and your 'OrangeButton' is now purple, and the whole universe will implode!"

3 "Properties" is just an engineer's way of saying "settings" whilst remaining smug and aloof

4 No interns were harmed in the making of this blog post.

Team member