Skip to content
By Rhiana Heath

CSS transitions for interactive images


Say you have an image that you want to change appearance as the user interacts with it. In my case, I have a 'back to top' button like this:

top button

When the person hovers over it to click, it should look different to let them know it’s interactive, something like this:

top button hover

First solution: Swappable background images

The first way I tried to get this look was to upload the two images, set one as the background image normally and have the other switch out on hover, like this:

/* shared/_header.html.erb */
<a href=“#top” class=“top-button”></a>
/* stylesheets/header.scss */ 

.top-button {
  content: “”;
  display: inline-block;
  width: 50px;
  height: 50px;
  background-image: url(‘top-button.svg’);
  background-position: center;
  background-repeat: no-repeat;
  background-size: 50px 50px;

.top-button:focus {
  background-image: url(‘top-button-hover.svg’);

Now this works fine, the two images switch out and the user can clearly see it is a clickable object. Our transition now looks like this:

no animation

Although this was a great improvement, there are a couple of issues in this solution that bother me:

  1. The transition is a bit sudden, it would be nice to have it smoother
  2. There are now two seperate images that need to load
  • This increases load time
  • There may be a flash between the two states as it loads the second image on hover rather than at page load

Smoother transitions

With CSS3, animations transitions are easier than ever and usually only require a line or two of code to make it look smoother.

The code below has a transition on the background-image, as that’s the property we’re changing, ease is a type of transition and 0.3s is the duration, or how fast the animation is.

/* stylesheets/header.scss */

.top-button {
  transition: background-image ease 0.3s;


OK, so it’s looking a lot nicer now, time to do some cross browser testing. This uncovers two major issues that need to be addressed:

  1. We’re still getting the flash of no image as it changes state for the first time.
  2. It’s doing something strange in Safari: on hover the image looks like it’s getting bigger and going down to the bottom right corner like this:

up-green-circle safari bug

If the image is in SVG format we can solve both these problems by embedding it into the HTML. Otherwise, turning transitions off for Safari can also work for a quick fix (ref: browserhacks).

Note: There are other methods documented for the safari bug; I tried quite a few but this was the only thing that worked for me.

/* stylesheets/header.scss */

:root .top-button {
  transition: none !important;

Second solution: Embedding the SVG using Ruby

This is the solution I found in the end which fixed all the issues I was having. By embedding the SVG file of the image, you only need one version as you can adjust your hover CSS to update the styling of the SVG directly. This means only one image is needed, so no extra load time, no flash and no Safari bug. It also means you have greater control of your image and you can access it’s properties directly with inspect element in the browser.

The code I used for this has been adapted from the guide A more efficient and organized workflow for SVGs.

# app/helpers/application_helper.rb

  def embedded_svg(filename, options = {})
    file = "app", "assets", "images", filename)
    doc  = Nokogiri::HTML::DocumentFragment.parse file
    svg  = doc.at_css "svg"
    if options[:class].present?
      svg["class"] = options[:class]
    raw doc

You can then embed the SVG in your view, just like you would using an image_tag.

/* shared/_header.html.erb */
<a href=“#top” class=“top-button”>
  <%= embedded_svg "top-button.svg", class: "up_arrow" %>

The styling below is a guide only; you will have to inspect your SVG to get the specific id’s and elements.

Note: That instead of background-color and border-color you should try fill and stroke. All of which can be transitioned in the same way as before.

svg labels

/* stylesheets/header.scss */
.top-button .up_arrow svg #circle {
  transition: fill 0.3s ease;

.top-button:hover .up_arrow svg #circle,
.top-button:focus .up_arrow svg #circle {
  fill: #00B293;
  circle {
     stroke: white;
  #arrow {
   fill: white;

Where to next?

SVG’s are very powerful when combined with CSS animations. Don’t stop with here with changing the colours, check out some of these resources with how you can style SVG’s in your project:

Popular Articles by Our Team

Our expert team of designers and developers love what the do and enjoy sharing their knowledge with the world.

We Hire Only the Best

reinteractive is Australia’s largest dedicated Ruby on Rails development company. We don’t cut corners and we know what we are doing.

We are an organisation made up of amazing individuals and we take pride in our team. We are 100% remote work enabling us to choose the best talent no matter which part of the country they live in. reinteractive is dedicated to making it a great place for any developer to work.

Free Community Workshops

We created the Ruby on Rails InstallFest and Ruby on Rails Development Hub to help introduce new people to software development and to help existing developers hone their skills. These workshops provide invaluable mentorship to train developers, addressing key skills shortages in the industry. Software development is a great career choice for all ages and these events help you get started and skilled up.

  • Webinars


    Webinars are our online portal for tips, tricks and lessons learned in everything we do. Make the most of this free resource to help you become a better developer.

    Learn more about webinars

  • Installfest


    The Ruby on Rails Installfest includes a full setup of your development environment and step-by-step instructions on how to build your first app hosted on Heroku. Over 1,800 attendees to date and counting.

    Learn more about Installfest

  • Development Hub

    Development Hub

    The Ruby on Rails Development Hub is a monthly event where you will get the chance to spend time with our team and others in the community to improve and hone your Ruby on Rails skills.

    Learn more about Development Hub

Get the “reinteractive Review” Monthly Email