Run CSS transition in one direction but not the other - html

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;
}
Test link
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.

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;
}
<span>Test link</span>
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;
}
<span>Test link</span>

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;
}
Test link
Test link

Related

Why transition is applying to active state despite only being specified on normal state

The transition that I applied to the normal state is being applied to the arrow on the active state. Notice that when the button is clicked, it takes the arrow .3s to turn from white to the same color as the rest of the active state. How can I remove this transition from the arrow's active state while keeping the transition of the button background on hover?
I tried removing transition: all .3s from .btn but this removes the hover state background color delay as well. I want to keep this.
body {
background: #00b894;
}
.btn {
color: #fff;
padding: 0 60px;
height: 64px;
border: 3px solid #fff;
line-height: 58px;
background: none;
display: inline-block;
position: relative;
overflow: hidden;
outline: none;
transition: all .3s;
/* This is causing a transition on the arrow's active state */
}
.btn:hover {
background: #009E7E;
}
.btn:active {
border-color: #008066;
color: #008066;
}
.btn:before {
position: absolute;
transition: all 0.3s;
top: 50%;
transform: translateY(-50%);
}
.btn--continue:before {
left: 130%;
}
.btn--continue:hover:before {
left: 80%;
}
.icon-arrow-right:before {
content: "→";
}
<button class="btn btn--continue icon-arrow-right">Continue</button>
I want the white arrow to immediately turn into the same color as the rest of the active state. Basically, remove the .3s transition. However, I want to keep the hover button background delay.
Set your transition to: transition: background .3s;

Make nav underline animate based on class

I have a .nav-link
When .active is added to it, it gets text-decoration: underline. How do i make this text decoration animate by sliding in from the left?
You can create and animate custom underline like this. As you cannot animate the text-decordation: underline;
.nav-link:after{
content: '';
position: absolute;
width: 0; height: 3px;
display: block;
margin-top: 5px;
right: 0;
background: #fff;
transition: width .2s ease; // this will add animation from left to right.
-webkit-transition: width .2s ease;
}
.nav-link:active:after{
width: 100%;
left: 0;
background: #fff;
}

Is there a more efficient way to make background position change from left to right on hover?

This is the code I currently have to make it seem as though the left border expands on hover, even though it's just the background changing. Is there a more efficient way to write this code?
edit: Efficient meaning a better way to write it.
span {
padding: 5px;
text-align: center;
border-left: 5px solid black;
background: linear-gradient(to left, yellow 50%, black 50%);
background-size: 200%, 100%;
background-position: right;
transition: .5s ease;
}
span:hover {
background-position: left;
color: white;
}
<span>This is some example text.</span>
I prefer using pseudo elements for this stuff, as you can then add transforms and such to the pseudo element for better performance.
Only problem with this is that you need to wrap your span in another element, so that you can position the text over the pseudo element with z-index. Otherwise it will just cover your text.
span {
color: black;
transition: color .5s ease;
z-index: 2;
position: relative;
}
p {
padding: 5px;
text-align: center;
border-left: 5px solid black;
background-color: yellow;
position: relative;
overflow: hidden;
display: inline-block;
}
p::after {
content: '';
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-color: black;
transition: transform .5s ease;
transform: translateX(-100%);
will-change: transform;
z-index: 1;
}
p:hover::after {
transform: translateX(0);
}
p:hover span {
color: white;
}
<p><span>This is some example text.</span></p>

How to remove glitchy color transitions?

I am in the process of designing an animated menu. I tried to get the text in the boxes to change color and they do so, but it's rather glitchy. The text flashes after the transition, and when you hover over it. Here's the JsFiddle with the glitch.
I also noticed it works fine without the hover transition, except of course the text doesn't change color. Here's that one: Less glitchy one.
Please suggest a fix.
Glitchy code [I removed webkit]
/* CSS */
#keyframes box {
0% {
left: 0px;
width: 30px;
}
50% {
left: 30px;
width: 0px;
}
100% {
left: 30px;
width: 70px;
color: #FFF;
}
}
h1 {
position: relative;
left: 30px;
color: cyan;
font-family: 'Agency FB';
}
div {
position: relative;
height: 30px;
width: 0px;
left: 0px;
background-color: cyan;
color: transparent;
animation: box 1.0s forwards;
transition: all 0.5s ease;
}
div:hover {
background-color: #FFF;
border: 1px solid cyan;
}
div:hover label {
color: cyan;
}
label {
position: absolute;
left: 5px;
font-family: 'Agency FB';
transition: all 0.5s ease;
}
<!-- HTML -->
<h1>
Test
</h1>
<div id="1">
<label>Hello</label>
</div>
<br>
<div id="1">
<label>World</label>
</div>
<br>
<div id="1">
<label>Foobar</label>
</div>
I can see the glitch, but probably is because of this:
transition: all 0.5s ease;
maybe you have other color fot the text in the parent, if you only want the transition on the background-color useit only there
transition: background-color 0.5s ease;
andto avoid the change of height you can use this
box-sizing: border-box;
I don't know what exactly you mean by "glitchy".
First of all I would change:
border: 1px solid cyan;
To:
outline: 1px solid cyan;
Border made this div move a little bit when hover works.

Add line transition above and below text

this question is a follow on from my previous question.
I have some style used from this website, to create a slide in underline effect, please see example on this jsfiddle.
My previous question was asking how to adapt this so the line came in from right to left, and on top of the text, please see example on this jsfiddle.
My next step is to add both of these to one element, so one line slides in from left to right on the bottom, and the other right to left on top.
When I tried to add both of these together, it seems to only display the top one, please see this jsfiddle.
My question is how do I add both the top slide in line and the bottom slide in line to an element?
.cmn-t-underline {
position: relative;
color: #ff3296;
}
.cmn-t-underline:after {
display: block;
position: absolute;
left: 0;
bottom: -10px;
width: 0;
height: 10px;
background-color: #2E9AFE;
content: "";
-webkit-transition: all 0.3s;
-moz-transition: all 0.3s;
-o-transition: all 0.3s;
transition: all 0.3s;
height:2px;
}
.cmn-t-underline:hover {
color: #98004a;
}
.cmn-t-underline:hover:after {
width: 100%;
height:2px;
}
.cmn-t-overline {
position: relative;
color: #ff3296;
}
.cmn-t-overline:after {
display: block;
position: absolute;
right: 0;
top: -10px;
width: 0;
height: 10px;
background-color: #2E9AFE;
content: "";
-webkit-transition: all 0.3s;
-moz-transition: all 0.3s;
-o-transition: all 0.3s;
transition: all 0.3s;
height:2px;
}
.cmn-t-overline:hover {
color: #98004a;
}
.cmn-t-overline:hover:after {
width: 100%;
height:2px;
}
<h1 class="cmn-t-underline cmn-t-overline">Test</h1>
You have to make use of :before for your top line, and :after for your bottom line.
The way you are doing it the second ":after" overrides the first so you end up with only one line.
I have edited your jsFiddle :
http://jsfiddle.net/7k4rLdno/
I only changed the second :after with :before and everything works well.
You can't have two :after or two :before the the exact same element.
use
:before - top line
:after - bottom line
h1{
position: relative;
color: #ff3296;
}
h1:before,
h1:after {
display: block;
position: absolute;
width: 0;
height: 10px;
background-color: #2E9AFE;
content:"";
-webkit-transition: all 0.3s;
-moz-transition: all 0.3s;
-o-transition: all 0.3s;
transition: all 0.3s;
height:2px;
}
h1:before {
left: 0;
top: -10px;
}
h1:after {
right: 0;
bottom: -10px;
}
h1:hover {
color: #98004a;
}
h1:hover:after,
h1:hover:before {
width: 100%;
height:2px;
}
<h1>Test</h1>
Fiddle