Button Hover Swipe 2
On this page
So this is a different way to achieve a sliding in effect on a button background. The first example animated a gradient background. This way is more complicated but understanding how it works opens up lots of possibilities.
How it works
A ::before pseudo-element is added to the button with a different coloured background. This is scaled to zero size and expands up to a size of 1 in the hover state, transform: scaleX(1). You could use the ::after pseudo-element just as easily.
We’ll need to work on 4 elements to do this:
- the
buttonelement - the
button::beforepseudo-element - the
button:hoverpseudo-selector (this is optional: just to addcursor: pointer) - the
button:hover::beforepseudo-selector (but just to addcursor: pointer)
General styles
First add some general styles to the button element such as getting rid of the border, choosing a background-color, the text color and maybe adding some padding. Add a border-radius as this will demonstrate something else.
The pseudo element
Next the button pseudo-element button::before.
First we need to add some empty content. This has to be done to get the pseudo-elements to show up at all:
button::before {
content: '';
}
Our element is created but has no size or colour. We could make it a block level element using display:block but for this we’ll be stretching it across the whole face of the button using position: absolute and inset: 0. But to get position: absolute to work on an element it’s parent must have a position other than the default, static, to work. So first add position: relative to the button element:
button {
position: relative;
}
So now we can use position: absolute on our pseudo-element. Give it a background color so we can see it too:
button::before {
content: '';
position: absolute;
inset: 0;
background-color: green;
}
The inset property is a shorthand for top, left, bottom and right properties. And inset: 0; sets them all to zero, which covers the whole element.
The button is now completely covered with the new pseudo element. Even the round corners have disappeared. As this pseudo-element is the child of the button element it means it is overflowing it’s container. To hide this overflow of the button element we just add overflow: hidden and bring back the rounded corners.
button {
position: relative;
overflow: hidden;
}
Getting the stacking context right
Great we have our round corners but still can’t see the text. When this green background slides across it will hide the text: not what we want. The obvious thing to use is z-index but apply a z-index: -1 to the button::before pseudo-element and you’ll find it disappears completely. That’s because it’s been pushed behind the button element: also not what we want. We want this in front of the button’s blue background but behind the button’s text. To do this we use the CSS property isolation: isolate to create a new stacking context (z-index positions) that’s within the button element.
button {
position: relative;
overflow: hidden;
isolation: isolate;
}
Now z-index values applied to children of the button (including our ::before pseudo-element) will be stacked relative to each other and not go behind the background of the button.
Now if we add a negative z-index to the button::before pseudo-element we get:
The green pseudo-element is behind the text but in front of the button’s background.
The animation
Now we need to add a transform to the pseudo-element. We will scale it down to zero along the X (left / right) axis. We’ll add a transition time for it of 0.4 of a second. Without this it will just appear instantaneously and we won’t see the movement.
button::before {
transform: scaleX(0);
transition: transform 0.4s;
transform-origin: left center;
}
The hover event
Now it’s gone, scaled down to zero, so we need to bring it back on the :hover event.
The order is important. We’re hovering over the button so button:hover and it’s the ::before element we are targeting to change.
button:hover::before {
transform: scaleX(1);
}
The full code
So the whole code should look something like this:
button {
position: relative;
border-radius: 14px;
background-color: #26b;
color: #ddd;
overflow: hidden;
isolation: isolate;
}
button:hover {
cursor: pointer;
}
button::before {
content: '';
position: absolute;
inset: 0;
background-color: #090;
z-index: -5;
transform: scaleX(0);
transition: transform 0.4s;
transform-origin: left center;
}
button:hover::before {
transform: scaleX(1);
}