Buttons with Background Wipe on Hover
What we’re building today is a button whose background and text colour wipe from one colour to another on mouse hover.
The concept of a background wipe isn’t new, and has been done many times before, including in this collection by Mary Lou from 2013. But as the background animates, the text simply fades between its start and end colours; we’d like it to wipe along with the background.
User zFunx later demonstrated the technique we’re after in a CodePen, by using background-clip: text
, a non-standard property added to WebKit in 2008 to fill the button text with its own background gradient, which can also be animated.
Their solution involved an extra <span>
and an ::after
pseudo-element for the effect to work. This updated method works with no additional elements.
Basic Styling
To begin, we style the button in its default state—in this case, with a transparent background, red text, and a rounded red border:
<a href="#" class="button button--wipe">Button</a>
.button {
display: inline-block;
margin: 0;
border: 2px solid #cc3359;
border-radius: 4px;
padding: 0.75em 1em;
background: none;
font: 1em/1 sans-serif;
text-decoration: none;
color: #cc3359;
cursor: pointer;
}
Wiping the Background
Next we add the wipe effect on hover for the main background:
.button--wipe {
background-image:
linear-gradient(135deg, #cc3359 50%, transparent 50%);
background-position: bottom right;
background-size: 200% 200%;
transition: 0.3s;
}
.button--wipe:hover {
background-position: top left;
color: white;
}
The principle is simple: the background is a linear gradient with a sharp colour change from transparent to red. The total size of the background is twice the size of the button in both directions; this allows it to show only the transparent portion when the background is aligned bottom-right, and only the coloured portion when it is aligned top-left.
By transitioning the background position, the diagonal edge wipes across the button.
For other angles of gradient, the background during the default and hover states will need to be changed accordingly:
Angle | Default Position | Hover Position |
---|---|---|
0°–90° | top right | bottom left |
90°–180° | bottom right | top left |
180°–270° | bottom left | top right |
270°–360° | top left | bottom right |
Wiping the Text
With the code so far, the background wipes across the button, but the text only fades between its colours. We can improve on this with some progressive enhancement:
@supports(-webkit-background-clip: text) {
.button--wipe {
background-image:
linear-gradient(135deg, white 50%, #cc3359 50%),
linear-gradient(135deg, #cc3359 50%, transparent 50%);
-webkit-background-clip: text, border-box;
-webkit-text-fill-color: transparent;
}
}
We give the button two backgrounds. The second is the same as for the un-enhanced version, but the new first background is clipped to paint over just the text. That’s all that is necessary. It will work in browsers that support it, and browsers that don’t fall back gracefully to fading the text in and out.
Demo
Here is the completed button in action; hover over it to reveal the effect.
Note: there is a bug in Safari where <button>
elements don’t support gradient backgrounds, so this demo uses an <a>
element instead. If you require a <button>
, you can wrap its contents in an extra <span>
and apply the button styles to that.