How we built the new Paparazzi site

The underlying philosophy behind the new site was to keep things as simple as possible code-wise by utilising the best of HTML5 and CSS3. It's remarkable what you can do in the front end these days without having to write a line of Javascript. Keeping things lean brings a multitude of benefits: less dependencies to manage and keep up to date, less code to maintain and debug, and less code to remember in our feeble brains! Amazingly, we only used two javascript libraries for the front end: jQuery, and DropzoneJS.

In the Node powered backend we also tried to keep things as lean as possible. Zappa.js together with Coffeescript, a Mongo DB and Handlebars templates helped us build things rapidly, whilst benefiting from the raw speed of Node.

Responsive web design

The old site was not responsive at all: it was only designed with desktop users in mind. On the new site we optimized the layout with 6 different types of device in mind:

  1. High resolution laptops/desktops
  2. Standard resolutions laptops/desktops
  3. Landscape tablets
  4. Portrait tablets
  5. Large smart phones and landscape smart phones
  6. Standard smart phones

Not only is the site still wonderful to use on smaller devices , it will also load quickly because the site serves smaller images. Using Stylus to generate the CSS helped us keep the CSS manageable, even with multitudes of media queries.

It's much easier to see the RWD in action via screenshots:

Browse models on mobile

This is what the site used to look like on the iPhone. Not very usable at all, with the footer taking up almost half the page.

Now it looks something like this:

Or even nicer in landscape:

And of course people don't only use Apple products, Android is increasingly popular these days:

Browse models on portrait iPad

This is what the site used to look like on the iPad. More usable than the iPhone, but still a ridiculous amount of unused screen space.

The new site on a portrait iPad brings the models to the forefront, utilizing all available screen space:

Browse models on laptop/desktop

The old site was designed for desktop, so works as expected here. But the new version is a great improvement, especially for larger screens,
where we can take advantage of all that extra space.


The new site has separate English and Finnish versions, rather than the mish-mash of both that was found in the old site:

Easy to use image uploads

For models wanting to apply to join Paparazzi, we used the brilliant DropzoneJS library so people could easily
upload their images from any device. Here it is in action after one successful upload on the Galaxy S3:

Minified assets

All stylesheets and javascript files have been minified so they download in an instant: this helps the page load as quickly as possible. Combining this technique with our minimal use of javascript allowed us to make the files downloaded almost 50 times smaller to what they were before (Tested on the home pages on 23rd June 2013).

Asset type New Old Improvement
Javascript 2.5KB 121.1KB ~48X
Stylesheets 8.7KB 16.5KB ~2X

Retina CSS sprites

We used CSS sprite technology on the new site, allowing us to minimize the number of image assets downloaded by the browser. Using CSS sprites also
made it simple to swap out site images for retina versions when the site is viewed by retina devices. Thanks to this, even with the huge image on the home page, we were able to keep the image downloads to a minimum, as you can see in the table below.
All in all, the home page is almost a 1/4 of the size of the old site, even with the massive image.

Site image resources (buttons, backgrounds, logos etc)

New Old Improvement
~22KB ~116KB ~5X

Home page images:

New Old Improvement
~152KB ~584KB ~4X

Total download size of home page

New Old Improvement
230KB 794KB ~3.5X


We've used lots of the latest HTML5 goodness on the site, which means we can minimize the amount of code we use, and has great support from all modern

HTML5 history

Each model's main image and polaroids page uses the HTML5 history API to keep track of the current image being browsed. The implementation is fairly simple: whenever someone skips to the next image, we update the image index by setting the URL via replaceState(). So if you are browsing Anna's 5th image the URL will be /model/anna/5, and when you swipe to the 6th, will update to /model/anna/6

This brings us two big benefits: firstly, when the user navigates back, we know exactly which picture they were browsing, so can take them back to where they were; secondly, if they reload the page later their position will also be remembered. The big win of using replaceState is that we don't clutter the users history with useless history states, which is what would happen if this was implemented with hash fragments (/models/anna#5). Then if the user tried to navigate back they would be taken to /models/anna#4, which wouldn't be the expected behaviour (we would expect to go the page we came from).

HTML5 forms

The support for forms in HTML5 is still developing, but already we can save ourselves a lot of code by using some of the new additions.

Little things like using email input boxes instead of text input boxes may not seem that important at first, but on mobile devices you clearly see the usability benefit straight away: on iOS the users keyboard will adapt to make it easier to type an email, showing the @ symbol in an easy to reach location. Another small touch is that iOS no longer tries to capitalise the start of the input, which is the default behaviour in standard input boxes.

Form validation is made super simple with HTML5, although not all browsers support it to the same level. We can gracefully add some simple validation javascript which just checks for the form elements with the error css pseudo class, for browsers that don't also handle flagging the errors to the user. This has very good support by modern browsers.

HTML5 local storage

HTML5 local storage is used to store the users shortlist of models. The support is so good now with modern browsers that we don't need to revert to cookies. The best thing about local storage is that the native API is so simple we don't need to use any external libraries, helping keep our codebase lean.

Asset fingerprinting

We have used fingerprinting for all image, stylesheet and javascript files which allows us to aggressively cache these assets.
This means the browser will only re-download these assets if they have been modified. The previous site used Etag headers, which means the browser still had to submit a conditional request to check if the files had been modified or not since the last retrieval. With asset fingerprinting, if the asset is in the browser cache, and the asset hasn't been modified, the browser will simply re-use its cached asset without needing to check if it's still valid.