Base64 encoding and embedding images in CSS

By on

One problem I always have with mobile development is making images load faster. Having lots of images can make the page extremely slow, and with the iphone 4 using double rez images, its even slower.

Theres a couple steps to take to optimize the images.

First I recommend using no image tags, and only using the url() property in CSS to display your images.

.img-social-facebook {
  background: url(/assets/images/gurgo/social-icon-facebook.png) no-repeat;
  background-size: 100%;
  width: 32px;
  height: 32px;
}

Second, encode all your url entries using base64 encode. This allows each image to be inside your main css.

.img-social-facebook {
  background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABBCAYAAABhNaJ7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NUVBQ0RBQ0YxQjY0MTFFMDk0Q0RDQThBQ0E4QkZCQjAiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NUVBQ0RBRDAxQjY0MTFFMDk0Q0RDQThBQ0E4QkZCQjAiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo1RUFDREFDRDFCNjQxMUUwOTRDRENBOEFDQThCRkJCMCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo1RUFDREFDRTFCNjQxMUUwOTRDRENBOEFDQThCRkJCMCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Puxf/AUAAAioSURBVHja3JxdaCPX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) no-repeat;
  background-size: 100%;
  width: 32px;
  height: 32px;
}



The problem with this is encoding all the images into a css file can be hella time consuming. The solution: write a script to do it for you!

./cssbuild.php gurgo.src.css gurgo.css


Thats all you need to convert a css any time you modify it. This script will read though the css for whatever regex you want, encode the images, and output it to the second file. Source:



#!/usr/bin/php
<?php

$file = dirname(__FILE__).'/../public_html/assets/css/'.$argv[1];

$lines = file($file);
foreach ($lines as $key => $line) {

  if (preg_match('/url\(\/assets\/images.*\)/i',$line)) {
    $css = preg_replace('/^.*url\(\/assets\/images\/(.*)\).*$/','\\1',$line);
    $file = new Caffeine_View_Helper_ImageBase64(dirname(__FILE__).'/../public_html/assets/images/'.trim($css));
    $lines[$key] = preg_replace('/url\((.*)\)/','url('.$file.')',$lines[$key]);
  }
}

$writefile = dirname(__FILE__).'/../public_html/assets/css/'.$argv[2];
file_put_contents($writefile, $lines);
echo "done\n";

class Caffeine_View_Helper_ImageBase64 {
  public function __construct($image) {
    $this->_file = $image;
    $fp = fopen($this->_file,'rb', 0);
    if (!$fp) throw new Exception('Could not open '.$this->_file.' for reading');
    $picture = fread($fp,filesize($this->_file));
    fclose($fp);
    $this->_encoded = base64_encode($picture);
  }
  
  public function output() {
    return 'data:'.mime_content_type($this->_file).';base64,'.$this->_encoded;
  }
  
  public function __toString() {
    return $this->output();
  }
}


Reasons NOT to use this method: If you have a page that has images only used on a single page, I instead recommend using a base64 encoded img tag on that page. If that image is going to be reused, using a normal image is most likely your best bet.