
Dynamic Full Page Background Images in Rails
rails css helpers
Note (Updated 2025): This post was originally written in 2020. The CSS approach using
background-size: cover
is still valid. For modern projects, you can also use CSS variables, utility frameworks (TailwindCSS), or inline style bindings (via Stimulus/React/Vue) to dynamically manage backgrounds more flexibly.
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 its size using background-size: cover
.
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
You can use a view helper to conditionally set the background per layout:
module ApplicationHelper
def html_background
# Add logic here if some layouts shouldn’t have a background
"background-image: url('background.png');"
end
end
And then in your layout:
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'
title = t('.meta_title')
= csrf_meta_tags
= stylesheet_link_tag 'application', media: 'all'
= javascript_include_tag 'application'
body
= yield
Randomizing Backgrounds
You can also cycle background images automatically (e.g., one per day). First define a helper:
def background_images
Array.new(7) { |i| "backgrounds/background-#{i}.png" }
end
To avoid randomness on every re-render, base the selection on today’s date:
def randomized_background_image
background_images[Date.today.day % 7]
end
Full Example
module ApplicationHelper
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 the Helpers
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 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 eq(expected_image_path)
end
end
end
Modern Alternatives (2025)
- TailwindCSS utilities: apply dynamic backgrounds with bg-[url(‘/path/to/image’)].
- CSS variables: set
--bg-url
dynamically and use it in your CSS. - Stimulus/React/Vue: bind styles to state for runtime control.
- Randomization: use JS (
Math.random
) if you want different images per refresh, instead of per day.
Wrap-up
- In 2020, CSS3’s
background-size: cover
combined with Rails helpers was a clean solution for full-page backgrounds. - Today, frameworks and modern CSS features make it easier to apply and rotate dynamic backgrounds with less custom code.
- The idea of date-based cycling remains a neat trick if you want predictable but changing visuals.
Quick Comparison
Approach | Where it Shines | Pros | Cons |
---|---|---|---|
Rails Helper (this post) | Simple, works server-side | No JS required, predictable, testable | Limited flexibility, page reload needed |
Stimulus Controller | Rails 7+ apps using Hotwire/Turbo | Declarative, client-side updates, reusable | Slightly more setup, JS knowledge needed |
TailwindCSS Utilities | Apps already using Tailwind | One-liner backgrounds, responsive utilities | Static unless paired with JS/variables |
CSS Variables | Modern CSS-driven design systems | Easy theming, works with any framework | Requires careful setup and browser support |
React/Vue/JS Binding | SPA or component-driven UIs | Full dynamic control at runtime | Overkill for simple Rails views |