20 CSS Animated Buttons02 / 20

Pure CSSMIT licensed

CSS Background Slide Hover Button

Four directional background-slide hover buttons — left, right, top, and bottom — where a solid fill sweeps across the button face on hover using CSS pseudo-element transforms.

Published

Live Demo
Try it

The code

<div class="ab-02">
  <p class="ab-02__title">Background Slide Directions</p>
  <div class="ab-02__grid">
    <button class="ab-02__btn ab-02__btn--left"><span>Slide Left</span></button>
    <button class="ab-02__btn ab-02__btn--right"><span>Slide Right</span></button>
    <button class="ab-02__btn ab-02__btn--top"><span>Slide Top</span></button>
    <button class="ab-02__btn ab-02__btn--bottom"><span>Slide Bottom</span></button>
  </div>
</div>
.ab-02,
.ab-02 *,
.ab-02 *::before,
.ab-02 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.ab-02 ::selection {
  background: #6c63ff;
  color: #fff;
}

.ab-02 {
  --fill: #6c63ff;
  --text: #1a1a2e;
  --border: #6c63ff;
  font-family: system-ui,sans-serif;
  background: #f0eeff;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2rem;
  padding: 2rem;
}

.ab-02__title {
  font-size: .8rem;
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: #6c63ff;
  opacity: .7;
}

.ab-02__grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
}

.ab-02__btn {
  position: relative;
  overflow: hidden;
  padding: .8rem 2rem;
  font-size: .95rem;
  font-weight: 700;
  color: var(--fill);
  background: transparent;
  border: 2px solid var(--border);
  border-radius: 8px;
  cursor: pointer;
  outline: none;
  transition: color .35s;
  letter-spacing: .03em;
}

.ab-02__btn span {
  position: relative;
  z-index: 1;
}

.ab-02__btn::before {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--fill);
  transition: transform .35s cubic-bezier(.4,0,.2,1);
  z-index: 0;
}

.ab-02__btn:hover {
  color: #fff;
}

.ab-02__btn--left::before {
  transform: translateX(-100%);
}

.ab-02__btn--left:hover::before {
  transform: translateX(0);
}

.ab-02__btn--right::before {
  transform: translateX(100%);
}

.ab-02__btn--right:hover::before {
  transform: translateX(0);
}

.ab-02__btn--top::before {
  transform: translateY(-100%);
}

.ab-02__btn--top:hover::before {
  transform: translateY(0);
}

.ab-02__btn--bottom::before {
  transform: translateY(100%);
}

.ab-02__btn--bottom:hover::before {
  transform: translateY(0);
}

.ab-02__btn:active {
  transform: scale(.97);
}

@media (prefers-reduced-motion: reduce) {
  .ab-02__btn::before {
    transition: none;
  }

  .ab-02__btn {
    transition: none;
  }
}
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
Here's a working CSS Animated Button from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: CSS Background Slide Hover Button
Source: https://codefronts.com/motion/css-animated-buttons/css-background-slide-hover-button/

Four directional background-slide hover buttons — left, right, top, and bottom — where a solid fill sweeps across the button face on hover using CSS pseudo-element transforms.
## HTML
```html
<div class="ab-02">
  <p class="ab-02__title">Background Slide Directions</p>
  <div class="ab-02__grid">
    <button class="ab-02__btn ab-02__btn--left"><span>Slide Left</span></button>
    <button class="ab-02__btn ab-02__btn--right"><span>Slide Right</span></button>
    <button class="ab-02__btn ab-02__btn--top"><span>Slide Top</span></button>
    <button class="ab-02__btn ab-02__btn--bottom"><span>Slide Bottom</span></button>
  </div>
</div>
```
## CSS
```css
.ab-02,
.ab-02 *,
.ab-02 *::before,
.ab-02 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.ab-02 ::selection {
  background: #6c63ff;
  color: #fff;
}

.ab-02 {
  --fill: #6c63ff;
  --text: #1a1a2e;
  --border: #6c63ff;
  font-family: system-ui,sans-serif;
  background: #f0eeff;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2rem;
  padding: 2rem;
}

.ab-02__title {
  font-size: .8rem;
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: #6c63ff;
  opacity: .7;
}

.ab-02__grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
}

.ab-02__btn {
  position: relative;
  overflow: hidden;
  padding: .8rem 2rem;
  font-size: .95rem;
  font-weight: 700;
  color: var(--fill);
  background: transparent;
  border: 2px solid var(--border);
  border-radius: 8px;
  cursor: pointer;
  outline: none;
  transition: color .35s;
  letter-spacing: .03em;
}

.ab-02__btn span {
  position: relative;
  z-index: 1;
}

.ab-02__btn::before {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--fill);
  transition: transform .35s cubic-bezier(.4,0,.2,1);
  z-index: 0;
}

.ab-02__btn:hover {
  color: #fff;
}

.ab-02__btn--left::before {
  transform: translateX(-100%);
}

.ab-02__btn--left:hover::before {
  transform: translateX(0);
}

.ab-02__btn--right::before {
  transform: translateX(100%);
}

.ab-02__btn--right:hover::before {
  transform: translateX(0);
}

.ab-02__btn--top::before {
  transform: translateY(-100%);
}

.ab-02__btn--top:hover::before {
  transform: translateY(0);
}

.ab-02__btn--bottom::before {
  transform: translateY(100%);
}

.ab-02__btn--bottom:hover::before {
  transform: translateY(0);
}

.ab-02__btn:active {
  transform: scale(.97);
}

@media (prefers-reduced-motion: reduce) {
  .ab-02__btn::before {
    transition: none;
  }

  .ab-02__btn {
    transition: none;
  }
}
```

How this works

Each button contains a ::before pseudo-element that covers the full button area and holds the hover fill colour. By default the pseudo-element is pushed out of view using transform: translateX(-100%) (left variant), translateX(100%) (right), translateY(-100%) (top), or translateY(100%) (bottom). On :hover the transform resets to translate(0) which slides the fill into place over a transition of 0.35 s with a smooth ease curve.

The button text sits in a position: relative; z-index: 1 span so it always renders above the sliding fill layer. overflow: hidden on the button itself clips the pseudo-element as it enters from its starting edge, making the slide feel contained and intentional. Only transform is animated, so the browser compositor handles all motion without repaints.

Make it yours

  • Change the slide direction by swapping the initial transform on ::before — use translateY(-100%) for a top-down sweep.
  • Adjust slide speed by editing the transition duration on .ab-02__btn::before (default .35s; try .2s for snappier feel).
  • Use a gradient fill instead of a solid by replacing the background on ::before with linear-gradient(135deg, #6c63ff, #c471ed).
  • Change text colour on hover by adding a transition: color .35s to the button and setting .ab-02__btn:hover { color: #fff }.
  • Stack two pseudo-elements (::before and ::after) with offset delays to create a two-tone layered slide effect.

Gotchas — read before shipping

  • The overflow: hidden on the button clips box-shadow — move the shadow to a wrapper element if you need both an outer glow and the slide effect.
  • If the button has border-radius, the pseudo-element corners are correctly clipped, but verify on Safari < 15 where overflow clipping with transforms occasionally mis-clips.
  • Avoid width: auto on ::before — always use 100% explicitly, as percentage widths in absolutely-positioned pseudo-elements can calculate incorrectly inside flex or grid containers.

Browser support

ChromeSafariFirefoxEdge
49+9.1+44+49+

Universally supported; relies only on CSS transforms and pseudo-elements.

Techniques used in this demo

Search CodeFronts

Loading…