Table of Contents
Create a basic
Add fill
Add directional awareness
Combine together
Accessibility
that's all!
Home Web Front-end CSS Tutorial Ghost Buttons with Directional Awareness in CSS

Ghost Buttons with Directional Awareness in CSS

Apr 16, 2025 am 11:32 AM

Ghost Buttons with Directional Awareness in CSS

You may have seen ghost buttons? They are characterized by transparent backgrounds and the background is filled with solid color when the mouse hovers. Smashing Magazine has an article on this topic. This article will build a ghost button, but this part is relatively simple. Interestingly and tricky, we're going to have the fill animation of the ghost button start at the mouse hover.

Here is a basic ghost button example:

In most cases, the background color transitions to the solid color. Some designs will fill the buttons from left to right, top to bottom, etc. to increase the visual effect. For example, fill from left to right:

Here is a small user experience problem. If the mouse hovers over the edge of the filled area, it will feel something is wrong. Consider this example, the button fills from the left, while you hover from the right.

It is best to have the button fill from the initial hover point.

So, how do we give button direction perception ? Your initial intuition might be to use JavaScript, but we can do it with CSS and some extra tags.

For those who want to get a quick look at the results, here are some direction-aware ghost buttons implemented in pure CSS!

Let's build it step by step. All code can be found in this CodePen collection.

Create a basic

Let's start with the basics of creating the ghost button. The marking is simple.

 <button>Boo!</button>
Copy after login

Our CSS implementation will utilize CSS custom properties. This makes maintenance easier and also facilitates customization through inline properties.

 button {
  --borderWidth: 5;
  --boxShadowDepth: 8;
  --buttonColor: #f00;
  --fontSize: 3;
  --horizontalPadding: 16;
  --verticalPadding: 8;

  background: transparent;
  border: calc(var(--borderWidth) * 1px) solid var(--buttonColor);
  box-shadow: calc(var(--boxShadowDepth) * 1px) calc(var(--boxShadowDepth) * 1px) 0 #888;
  color: var(--buttonColor);
  cursor: pointer;
  font-size: calc(var(--fontSize) * 1rem);
  font-weight: bold;
  outline: transparent;
  padding: calc(var(--verticalPadding) * 1px) calc(var(--horizontalPadding) * 1px);
  transition: box-shadow 0.15s ease;
}

button:hover {
  box-shadow: calc(var(--boxShadowDepth) / 2 * 1px) calc(var(--boxShadowDepth) / 2 * 1px) 0 #888;
}

button:active {
  box-shadow: 0 0 0 #888;
}
Copy after login

Put it together and we get:

very good! We have a button and hover effect, but there is no fill effect yet. Next let's add the fill effect.

Add fill

To do this, we create some elements to display the fill state of the ghost button. The trick is to use clip-path to crop these elements and hide them. We can display them on hover by converting clip-path .

They must be aligned with the parent button. Our CSS variables will be of great help here.

At first, we might consider using pseudo-elements. However, for each direction, the number of pseudo-elements is not enough. They also affect accessibility…more on that later.

Let's start by adding a basic left-to-right padding. First, let's add one<span></span> element. Should<span></span> The element needs to have the same text content as the button.

<button>
  <span>Boo!</span>
  Boo!
</button>
Copy after login

Now we need to<span></span> Elements are aligned with buttons. Our CSS variables will do most of the work.

 button span {
  background: var(--buttonColor);
  border: calc(var(--borderWidth) * 1px) solid var(--buttonColor);
  bottom: calc(var(--borderWidth) * -1px);
  color: var(--bg, #fafafa);
  left: calc(var(--borderWidth) * -1px);
  padding: calc(var(--verticalPadding) * 1px) calc(var(--horizontalPadding) * 1px);
  position: absolute;
  right: calc(var(--borderWidth) * -1px);
  top: calc(var(--borderWidth) * -1px);
}
Copy after login

Finally, we will<span></span> The element is cropped outside the view and adds a rule to display it on hover by updating the crop. Defining a transition will add icing on the cake.

 button span {
  --clip: inset(0 100% 0 0);
  -webkit-clip-path: var(--clip);
  clip-path: var(--clip);
  transition: clip-path 0.25s ease, -webkit-clip-path 0.25s ease;
  /* ...Remaining div styles */
}

button:hover span {
  --clip: inset(0 0 0 0);
}
Copy after login

Add directional awareness

So, how do we add directional awareness? We need four elements. Each element will be responsible for detecting the hover entry point. Using clip-path , we can divide the button area into four parts.

Let's add four to the button<span></span> elements and position them to fill the buttons.

<button>
  <span></span>
  <span></span>
  <span></span>
  <span></span>
  Boo!
</button>
Copy after login
button span {
  background: var(--bg);
  bottom: calc(var(--borderWidth) * -1px);
  -webkit-clip-path: var(--clip);
  clip-path: var(--clip);
  left: calc(var(--borderWidth) * -1px);
  opacity: 0.5;
  position: absolute;
  right: calc(var(--borderWidth) * -1px);
  top: calc(var(--borderWidth) * -1px);
  z-index: 1;
}
Copy after login

We can locate each element and assign crops and colors using CSS variables.

 button span:nth-of-type(1) {
  --bg: #00f;
  --clip: polygon(0 0, 100% 0, 50% 50%, 50% 50%);
}
button span:nth-of-type(2) {
  --bg: #f00;
  --clip: polygon(100% 0, 100% 100%, 50% 50%);
}
button span:nth-of-type(3) {
  --bg: #008000;
  --clip: polygon(0 100%, 100% 100%, 50% 50%);
}
button span:nth-of-type(4) {
  --bg: #800080;
  --clip: polygon(0 0, 0 100%, 50% 50%);
}
Copy after login

Very cool. To test this, let's change the opacity while hovering.

 button span:nth-of-type(1):hover,
button span:nth-of-type(2):hover,
button span:nth-of-type(3):hover,
button span:nth-of-type(4):hover {
  opacity: 1;
}
Copy after login

Oh, there is a question here. If we go in and hover over one section and then hover over another, the filling direction will change. This doesn't seem right. To solve this problem, we can set z-index and clip-path on hover so that a part of the space is filled.

 button span:nth-of-type(1):hover,
button span:nth-of-type(2):hover,
button span:nth-of-type(3):hover,
button span:nth-of-type(4):hover {
  --clip: polygon(0 0, 100% 0, 100% 100%, 0 100%);
  opacity: 1;
  z-index: 2;
}
Copy after login

Combine together

We know how to create fill animations, and we know how to detect directions. How do we combine the two? Use a combo at the same level!

Doing this means that when we hover a segment, we can display a specific fill element.

First, let's update the tag.

<button>
  <span></span>
  <span></span>
  <span></span>
  <span></span>
  <b>Boo!</b>
  <b>Boo!</b>
  <b>Boo!</b>
  <b>Boo!</b>
  Boo!
</button>
Copy after login

Now, we can update the CSS. Referring to our left-to-right padding, we can reuse styles. We just need to set a specific clip-path for each element. I handled it in the same order as some attribute values. The first child element is the top, the second is the right, and so on.

 button b:nth-of-type(1) {
  --clip: inset(0 0 100% 0);
}
button b:nth-of-type(2) {
  --clip: inset(0 0 0 100%);
}
button b:nth-of-type(3) {
  --clip: inset(100% 0 0 0);
}
button b:nth-of-type(4) {
  --clip: inset(0 100% 0 0);
}
Copy after login

The last step is to update clip-path of the relevant element when hovering the pairing segment.

 button span:nth-of-type(1):hover ~ b:nth-of-type(1),
button span:nth-of-type(2):hover ~ b:nth-of-type(2),
button span:nth-of-type(3):hover ~ b:nth-of-type(3),
button span:nth-of-type(4):hover ~ b:nth-of-type(4) {
  --clip: inset(0 0 0 0);
}
Copy after login

alright! We get a pure CSS ghost button with directional awareness.

Accessibility

In the current state, the button is inaccessible.

These extra elements don't help much, as the screen reader repeats the content four times. We need to hide these elements from the screen reader.

<button>
  <span></span>
  <span></span>
  <span></span>
  <span></span>
  <b aria-hidden="true">Boo!</b>
  <b aria-hidden="true">Boo!</b>
  <b aria-hidden="true">Boo!</b>
  <b aria-hidden="true">Boo!</b>
  Boo!
</button>
Copy after login

No more duplicate content.

that's all!

With just some extra marking and some CSS tricks, we can create ghost buttons with directional awareness. Using a preprocessor or combining a component in your application, you don't need to write out all the HTML.

This is a demonstration of using inline CSS variables to control button color.

This revised output maintains the original image and uses more concise and varied phrasing while preserving the core meaning of the original text. It also addresses the accessibility issue mentioned in the original article.

The above is the detailed content of Ghost Buttons with Directional Awareness in CSS. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Vue 3 Vue 3 Apr 02, 2025 pm 06:32 PM

It&#039;s out! Congrats to the Vue team for getting it done, I know it was a massive effort and a long time coming. All new docs, as well.

Building an Ethereum app using Redwood.js and Fauna Building an Ethereum app using Redwood.js and Fauna Mar 28, 2025 am 09:18 AM

With the recent climb of Bitcoin’s price over 20k $USD, and to it recently breaking 30k, I thought it’s worth taking a deep dive back into creating Ethereum

Can you get valid CSS property values from the browser? Can you get valid CSS property values from the browser? Apr 02, 2025 pm 06:17 PM

I had someone write in with this very legit question. Lea just blogged about how you can get valid CSS properties themselves from the browser. That&#039;s like this.

Stacked Cards with Sticky Positioning and a Dash of Sass Stacked Cards with Sticky Positioning and a Dash of Sass Apr 03, 2025 am 10:30 AM

The other day, I spotted this particularly lovely bit from Corey Ginnivan’s website where a collection of cards stack on top of one another as you scroll.

A bit on ci/cd A bit on ci/cd Apr 02, 2025 pm 06:21 PM

I&#039;d say "website" fits better than "mobile app" but I like this framing from Max Lynch:

Comparing Browsers for Responsive Design Comparing Browsers for Responsive Design Apr 02, 2025 pm 06:25 PM

There are a number of these desktop apps where the goal is showing your site at different dimensions all at the same time. So you can, for example, be writing

Using Markdown and Localization in the WordPress Block Editor Using Markdown and Localization in the WordPress Block Editor Apr 02, 2025 am 04:27 AM

If we need to show documentation to the user directly in the WordPress editor, what is the best way to do it?

Why are the purple slashed areas in the Flex layout mistakenly considered 'overflow space'? Why are the purple slashed areas in the Flex layout mistakenly considered 'overflow space'? Apr 05, 2025 pm 05:51 PM

Questions about purple slash areas in Flex layouts When using Flex layouts, you may encounter some confusing phenomena, such as in the developer tools (d...

See all articles