Grolsch 400: Building a graphic-shifting hover state with SVG

At Nation we were asked to display the artworks of 400 artists to celebrate 400 years of Grolsch. You can see the mini site over here - Grolsch 400. Sadly this site is no longer live, it was quite a long time ago now.

During this build, a few things stood out as โ€˜nicetiesโ€™ to me which I will go through in a bit of detail; one of them being the "Explore the art gallery" button.

It looks like an obvious choice to go through exactly how the artwork grid works, but half way through building that grid, there were some unexpected bumps in the road and some of those bumps I didnโ€™t have time to fully get my head around. Something something transform scale / transform translate something something. That part of the site ended up needing some extra attention to meet the 400-year deadline ๐Ÿ˜ฐ

Hover me โ˜๏ธ

This had to work in Internet Explorer 9, so it was important to find a solution that would work cross-browser. Above is the SVG solution I went with, and here is the code for that:

<div class="explore">
  <a href="#">
    <svg version="1.1" xmlns="" class="button">
        <pattern id="background" patternUnits="userSpaceOnUse" width="469" height="1991" >
          <image xlink:href="explore-cta.jpg" class="image" width="469" height="1991"></image>
      <text fill="#6ec049" x="35" y="50">Explore the art gallery</text>
    <svg class="border border-top">
      <rect fill="#6ec049" width="100%" height="100%"></rect>
    <svg class="border border-right">
      <rect fill="#6ec049" width="100%" height="100%"></rect>
    <svg class="border border-bottom">
      <rect fill="#6ec049" width="100%" height="100%"></rect>
    <svg class="border border-left">
      <rect fill="#6ec049" width="100%" height="100%"></rect>

Each element inside our button (borders and text) has a starting fill of #6ec049, then on 'mouseover', this fill is set to use our <pattern> we have defined inside the <defs> tag.

The <pattern> we defined contains the image that we will be flicking through on hover. This is essentially a sprite sheet. Here is it slowed down and animated so we can see what is actually happening ๐Ÿ‘‡

At the same time the new fill is set on 'mouseover', we start an interval to display each frame. I think what you can also see in the animation is a miscalculation of frame heights on the jpg, you didn't see that ๐Ÿ˜ฌ

Here is the interval code:

__LINK.addEventListener('mouseover', function(e) { startCtaEffect(e); });

function startCtaEffect() {
  ctaFrameInterval = setInterval(function() {
    // Increment ctaCurrentFrame
    // Move to the next frame based on
    // the ctaCurrentFrame index
  }, ctaFrameRate);

function setCtaFill() {
  // Only store one of the elements' fill, these colours 
  // should always stay the same
  originalFill = __LINK.querySelector('text').getAttribute('fill');
  // Set new fill, which is the svg pattern #background id
  var i = 0, borders = __LINK.querySelectorAll('svg rect');
  for (; i < borders.length; i++) {
    borders[i].setAttribute('fill', 'url(#background)');
  __LINK.querySelector('svg text').setAttribute('fill', 'url(#background)');

...then finally we move the image:

function ctaMoveFrame() {
  // Set top to 0
  var newTop = 0;
  // If we are at the end of the frames
  // set the current frame back to the beginning
  if (ctaCurrentFrame === ctaTotalFrames) {
    ctaCurrentFrame = 0;
    // ...otherwise, continue by multiplying the
    // ctaCurrentFrame index with the frameHeight
  } else {
    newTop = ctaCurrentFrame * ctaFrameHeight;
  // Set newTop at each interval
  var value = ' translate(0, -' +newTop+ ')';
  __LINK.querySelector('.image').setAttribute('transform', value);

The transform attribute is being set on the svg image tag, not a CSS transform. Just something to note, super nice article about SVG transforms over here.

Want to tell me how much you hate my solution and that you want me to stop doing front-end as a full-time job โ€“ @tomsansome โœ‹๐Ÿค–