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
button
element - the
button::before
pseudo-element - the
button:hover
pseudo-selector (this is optional: just to addcursor: pointer
) - the
button:hover::before
pseudo-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);
}