Define your visual brand

Building a brand for a website can be a time-intensive project, but one that can yield strong audience growth opportunities, especially when paired with a social promotion strategy.

I was recently part of a team that purchased digital science and medical publications. One of my jobs was to fold their technology into our core stack and apply a consistent “look” across the sites. Our technology team used tools like storybook to manage our growing library of cross-site javascript and css components, and our editorial team set standards on the use of illustrations and stock imagery.

But a brand’s visual brand is a strange mix of technology strategy and editorial proposition. Since the editorial team is ultimately responsible for maintaining a consistent look across the assets they add each day, it’s important that developers build technology that not only gets the assets onto the site, but also streamlines the process of working with those assets. Here, then, are some strategies that have worked for me in the past:

Font Pairing

Finding the right font for your site can take hours if you care about that sort of thing (and some of my clients don’t). The key here is not to go overboard. Pick a simple font that is easy on the eyes for the body text of your site, and then find a font that pairs well with it for your headings.

To find the right font:

  1. In Chrome, explore other sites to find a good font.
  2. Control click on the font and select Inspect.
  3. Scroll down to find the name of the font
  4. Search for ‘google font’ and the name of that font to find a performant version
  5. Search for ‘font pairings’ and the name of the google font
  6. Now use your font in the header and the paired font in the body

As you can see, there’s a whole field of study in design on finding the right pairs. My preference is to go a little crazy with the headline font: think BOLD, in all senses of that word.

Find a color scheme that works

Coolers is a fantastic tool for matching swaths to get the perfect hexcode set for your website and visual brand.

As a color-challenged gear-head, I’ve usually deferred to other people on color choices. Fortunately, there’s a tool called coolors that helps designers find what colors go best together. There’s a great tutorial on their site, but basically you start by locking in a single color and then hit the space bar and a program finds several swatches that match well with that color.

Spacing and Alignment

This was always a hard one for me. In my old NPR days, I would present prototypes that always looked a little off, but I never quite knew why. The reason, in most cases, was that I didn’t allow enough space and layout was misaligned. Fortunately there are great tools to simplify spacing and alignment.

For alignment, the key is to do as little tinkering with an original theme as possible and, if you do tinker with it, be sure to look at the desktop, tablet and mobile view of every change to either padding or margin so that you know you’re not introducing misalignment (wordpress has a great toggle tool for this at the lower right corner of the customizer).

For spacing, just remember that more spacing, like alignment, needs to be balanced. That means, for example, that the space under your header should roughly match the spacing on the side margins. The block editor has an excellent tool called spacer blocks which makes it easy to tinker with spacing on a page before you lock it in with your css.

Set consistent aspect ratios to all your images

Step one is to apply a consistent aspect ratio and image compression. There are a number of ways to do this, but I prefer creating a folder action. For a simple folder action, follow these steps:

  1. Create a folder in a somewhat permanent location (i.e., somewhere you can access easily, but don’t mind it not moving).  Give it a name like ImageCrop
  2. From Launchpad, open Automator
  3. Select File > NewSelect Folder Action
  4. Select the folder you just created (ImageCrop) in the dropdown next to ‘Folder action receives files and folders added to:’
  5. On the left side menu of actions, scroll down and double-click Scale Images, decide whether you want to keep originals, and select a standard width, like 1280
  6. On the left side menu of actions, scroll down and double-click Crop Images and select a standard aspect ratio, like 1280 x 720
  7. Now select File > Save and call the script something like Standard Crop
  8. Close automator
  9. Now test it out by finding an image that is at least 1280 wide and then drag that image over to your folder.  It should crop down to 1280 x 720

The above steps will familiarize you with the value of folder actions, but it is fairly limited (it can’t, for instance, handle complex compression algorithms or apply fancy image filters and effects). For that, you’ll need to create an entirely new folder action. This time, double click Run Shell Script and paste in the location of a python file that we’re about to build, along with a few variables.

for f in "$@"
	~/opt/anaconda3/bin/python ~/_notebooks/scripts/ $f 1024 1.61803398875

The above call will tell a script to take every image you drag into the folder, define a maximum width of 1024 and apply an aspect ratio of 1.618 (the golden mean). If you wanted to adjust to a 16:9 aspect ratio, you would change it to 1.7777…

The end result of this process is to create perfectly cropped images that take up 1/10th of the bandwidth of the original image. If you wanted to compress it even more, you could use a line just before the done line that taps into ImageOptim’s command-line compression, but I’ve found it offers little advantage since there’s some compression already in the scaler script, and this line adds time to the process:

/Applications/ "$f"

Here’s the complete code of

from PIL import Image
import sys, os

filename = sys.argv[1]
maxWidth = int(sys.argv[2])
aspect = float(sys.argv[3])

im =
im = im.convert('RGB')

width = im.size[0]
height = im.size[1]
if width<height*aspect: # most images
    left = 0
    right = width
    ratio = width / aspect
    if height>width: # portrait images focus 1/3 way down
        top = height / 3 - ratio / 2
        bottom = height / 3 + ratio / 2
    else: # landscape images focus 1/2 way down
        top = height / 2 - ratio / 2
        bottom = height / 2 + ratio / 2
else: # ultrawide images
    top = 0
    bottom = height
    ratio = height * aspect
    left = width / 2 - ratio / 2
    right = width / 2 + ratio / 2
cropped = im.crop((left, top, right, bottom))
if width>maxWidth: 
    width = cropped.size[0]
    height = cropped.size[1]
    ratio = maxWidth/width; 
    scaled = cropped.resize((int(round(width*ratio)), int(round(height*ratio))), Image.BOX)
    scaled = cropped
base = os.path.splitext(filename)[0]
filename = base + '.jpg', "JPEG", optimize=True, quality=85) #overwrites original

# or use the below, once webp cards are supported by Twitter
#filename = base + '.webp', "WebP", quality=70) #this overwrites the original file.

Note that one other thing the above code does is makes a decision of where to center the image. For landscapes, this is easy: center on the center. Portraits are a little more complex, but focusing about a third of the way down is usually a good assumption for cropping a landscape out of a portrait.

Unfortunately, webp doesn’t play nice with social media shares, at least on WordPress (which you can easily verify with the Twitter card validator). For this reason, I have commented out the webp encoding at the bottom of the file, but this code offers massive compression and is an increasing standard among sites like NPR.

Go further with image processing

Finding images for your site can be expensive and time-intensive. At both The Washington Post and NPR, we employed a team of photographers to cover major news events, but even at those organizations, we often needed to lean heavily on stock photography companies like Getty. Although Getty is too expensive for most small websites, there are plenty of free stock photo services out there (like Pixabay).

The problem with stock photos is that they look, well, like stock photos, and that can cheapen your site. One way to add a little originality to your stock photos is to use automated filters that ‘work’ for your brand.

The WSJ is probably the most famous example of a media company applying a brand filter to their images (though their hedcuts are all done by artists and it’s hard to automate believably).  I talked to the Growth Team at NYT a while back and they confirmed my suspicion that they were applying automated filters to their social promotions whenever they didn’t have an image. 

First, let’s start with a simple image:

You can incorporate image filters into the script above in a number of ways. You can also get a fairly simple artistic effect with the Edge Enhance filter, like so:

#Import required image modules
from PIL import Image, ImageFilter
import os, sys

# Call like: ~/opt/anaconda3/bin/python ~/_notebooks/scripts/ $f 
filename = sys.argv[1]

#Import all the enhancement filter from pillow
from PIL.ImageFilter import (
#Create image object
img =
#Applying the blur filter
img1 = img.filter(EDGE_ENHANCE)

base = os.path.splitext(filename)[0]
filename = base + 'Edge.jpg', "JPEG",optimize=True,quality=85)

That’s a little too artistic for my taste. Here’s a more complex filter, which first converts the image to a PNG with 16 colors in the palette.

#Import required image modules
from PIL import Image, ImageFilter
import os, sys

# Call like: ~/opt/anaconda3/bin/python ~/_notebooks/scripts/ $f 
filename = sys.argv[1]

#Create image object
img =

#convert to a PNG and shrink the palette down to 16 colors
img1 = img.convert("P", palette=Image.ADAPTIVE, colors=16)

#convert it back to jpg
img1 = img1.convert('RGB')

from PIL.ImageFilter import (SMOOTH_MORE)
img1 = img1.filter(SMOOTH_MORE)

base = os.path.splitext(filename)[0]
filename = base + 'Palette.jpg', "JPEG",optimize=True,quality=85)

Next, it smooths the image down and converts it back to jpg:

Palette conversion: this is close to the filter we’re using for stock images at Hidden Brain

Here are a few more Pillow (python library) filters to explore: composite / blend, palate changes, contrast stretching, color depth, edge enhancement, negative, sharpen, smoothing, thresholding

Imagemagick also offers some more complex filters that take a bit more time to code but might be worth it if you like the effect.  My pick from that group would be a subtle paint effect, like so:

ImageMagick Paint Effect

How do you create these effects? I recommend starting with some of the command line filters developed by other folks in this space. Here are a few: trace to vector, paint effect, sketch, cartoon

“Future Proof” your site with a Media Server

One note on images: they offer a lot of bloat that can make managing a site difficult (particularly if you’re relying on staging and version control. One simple, elegant way to fix this issue is to decouple your images from your site, which is fairly simple in wordpress. tldr; Set up a media subdomain on your host, copy your uploads folder from wordpress into the media subdomain, and then, in phpmyadmin, go to the …_options table for that wordpress db and change upload_url_path to something like (no trailing slash) and change upload_path to something like /home/yourhostusername/

Then flush the cache. If you’ve done everything right, you should see your new paths in settings > media and the images should just work all over the site.