2 min read

Dynamic Full Page Background Images in Rails

Syed Aslam

You can set a background image purely through CSS thanks to the background-size property in CSS3. Using the html element is better than body as it's always at least the height of the browser window. You set a fixed and centered background on it, then adjust it's size using background-size set to the cover keyword.

html { 
  background: asset-url('background.png') no-repeat center center fixed; 
  -webkit-background-size: cover;
  -moz-background-size: cover;
  -o-background-size: cover;
  background-size: cover;
}

Background Image Per Layout

A view helper could be used to control and set or not set the background per layout:

module ApplicationHelper
  def html_background
    # Conditions can be added here to determine
    # whether there is a background or not
    'background-image: url('background.png');'
  end
end

and then use this helper in the layout to set the background image style:

doctype html
html style=html_background
  head
    meta http-equiv='X-UA-Compatible' content='IE=edge'
    meta name='viewport' content='width=device-width, initial-scale=1'
    meta content='text/html; charset=UTF-8' http-equiv='Content-Type'
    title = t('.meta_title')
    = csrf_meta_tags
    = stylesheet_link_tag    'application', media: 'all'
    = javascript_include_tag 'application'
  body
    = yield

You can also randamize by using one background image for a layout for each day of the week using the same idea as above. Say, there are 7 images, each for the day in the week to be used as the background. First keep a list of images to be used background by defining a helper:

def background_images
  Array.new(7) { |i| "backgrounds/background-#{i}.png" }
end

With % (mod) operator you can limit the result within a range. Here, we need to select one image from the array of 7 images for this day. We can't use rand here since the number will be different when the helper runs again upon re-rendering the page. We could use todays' date to select the background image to use for this day, something like Date.today.day % 7.

def randomized_background_image
  background_images[Date.today.day % 7]
end

With this, one image is used as background for each day of the week. Full listing:

module ApplicationHelper
  # Defining the constant here since this is not used anywhere else
  # instead of in an initializer.
  RANDOM_BACKGROUND_IMAGES_COUNT = 7

  def html_background
    "background-image: url('assets/#{randomized_background_image}');"
  end

  def randomized_background_image
    background_images[Date.today.day % RANDOM_BACKGROUND_IMAGES_COUNT]
  end

  def background_images
    Array.new(RANDOM_BACKGROUND_IMAGES_COUNT) { |i| "backgrounds/background-#{i}.png" }
  end
end

Testing these helpers methods:

require 'spec_helper'

describe ApplicationHelper do
  describe '#background_images' do
    it 'returns an array of 7 image paths' do
      images = helper.background_images

      expect(images).to be_a(Array)
      expect(images.size).to eq(7)
    end

    it 'returns images in sequence with path' do
      image = helper.background_images.first

      expect(image).to be_a(String)
      expect(image).to match('backgrounds/background-0.png')
    end
  end

  describe '#randomized_background_image' do
    it 'returns expected image path' do
      image = helper.randomized_background_image
      expected_image_path = "backgrounds/background-#{Date.today.day % 7}.png"

      expect(image).to satisfy('is of expected format') { |p| expected_image_path.match?(p) }
    end
  end
end