ygoe
ygoe

Reputation: 20364

Run CSS transition in one direction but not the other

I'm using a CSS transition on my hyperlink elements to make their interaction appear smoother. But I also want immediate feedback when the user is waiting for it. Hence I want the new state to appear immediately, but let it fade out when the user moves away.

Here's some CSS that I'm currently using:

a
{
  display: inline-block;
  padding: 20px;
  background: #eeeeee;
  color: black;
  text-decoration: none;
  transition: background 1s;
}
a:hover
{
  background: #bbbbbb;
  transition: background 0s;
}
a:active
{
  background: #888888;
  transition: background 0s;
}
<a href="javascript:void(0)">Test link</a>

As you can see the colour fade is in effect when leaving the element with the mouse cursor, but not when entering it.

When pressing a mouse button on the hovered link, the colour again changes immediately.

Now comes the interesting part: When the mouse button is released, I'd like the colour to fade back to the hover state. But I can't manage to do so because the :hover state doesn't know from which state direction it's coming and always disables the transition.

Whatever is changed, there must be no transition when first hovering the link.

Again in a simple state diagram:

State:          normal   <---------->   hover   <---------->   active
Transition:             yes         no         yes?        no
                                          (currently no)

Is this possible with CSS? I know I could add custom JavaScript but that would need to go to a great number of elements.

Upvotes: 6

Views: 690

Answers (2)

ygoe
ygoe

Reputation: 20364

Here's what I did based on Temani Afif's answer. It doesn't need the additional <span> inside the link but instead an additional data-text attribute on it, and it only works for plain text content (no images etc.).

The example has two test links, one with and one without the attribute, to show the fallback behaviour that's basically what I have in the question.

Not sure which is "better". It probably depends on the circumstances. I just wanted to add this solution as well.

a
{
  display: inline-block;
  padding: 20px;
  background: #eeeeee;
  color: black;
  text-decoration: none;
  transition: background 1s;
  position: relative;
}

a:hover
{
  background: red;
  transition: background 0s;
}

a[data-text]::before
{
  content: attr(data-text);
  color: transparent;
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  padding: 20px;
  background: transparent;
  transition: background 1s, color 1s;
}

a[data-text]:active::before,
a:not([data-text]):active
{
  color: white;
  background: blue;
  transition: background 0s;
}
<a href="javascript:void(0)" data-text="Test link">Test link</a>

<a href="javascript:void(0)">Test link</a>

Upvotes: 0

Temani Afif
Temani Afif

Reputation: 272723

An idea is tu use pseudo-element to create your backgrounds and you can easily create the effect you want. The drawbacks is that you will have more CSS and you have to add your content inside a span in order to correctly set z-index values.

Using 2 pseudo-elements:

a {
  display: inline-block;
  padding: 20px;
  background: #eeeeee;
  color: black;
  text-decoration: none;
  transition: background 1s;
  position: relative;
}

a span {
  position: relative;
  z-index: 3;
}

a:before,
a:after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  background: transparent;
  z-index: 1;
  transition: background 1s;
}

a:after {
  z-index: 2;
}

a:hover::before {
  background: red;
  transition: background 0s;
}

a:active::after {
  background: blue;
  transition: background 0s;
}
<a href="javascript:void(0)"><span>Test link</span></a>

Using only one pseudo element:

a {
  display: inline-block;
  padding: 20px;
  background: #eeeeee;
  color: black;
  text-decoration: none;
  transition: background 1s;
  position: relative;
}

a span {
  position: relative;
  z-index: 1;
}

a:before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  background: transparent;
  z-index: 0;
  transition: background 1s;
}

a:hover {
  background: red;
  transition: background 0s;
}

a:active::before {
  background: blue;
  transition: background 0s;
}
<a href="javascript:void(0)"><span>Test link</span></a>

Upvotes: 3

Related Questions