Home >Web Front-end >CSS Tutorial >4 Cool Hover Effects That Use CSS Text Shadow

4 Cool Hover Effects That Use CSS Text Shadow

Lisa Kudrow
Lisa KudrowOriginal
2025-03-13 10:21:09915browse

4 Cool Hover Effects That Use CSS Text Shadow

In the previous article, we discussed how to use CSS background properties to create cool hover effects. This time, we will focus on the CSS text-shadow property and explore more interesting hover effects. You might be wondering how adding shadows to text can have a cool effect, but the point is: we don't actually create any shadows for these text hover effects.

Cool hover effect series:

  1. Use background properties to achieve cool hover effect
  2. Use CSS text shadow to achieve cool hover effect (your current location!)
  3. Use background cropping, masking and 3D to achieve cool hover effects

text-shadow but no text shadow?

Let me remove confusion by the hover effect we will build in the following demo:

Without looking at the code, many of you will intuitively think that for each hover effect, we copy the text and animate it independently. Now, if you look at the code, you will find that no text in the HTML is actually copied. Have you noticed content: "text" is not used in CSS?

Text layers are created entirely with text-shadow !

Hover effect #1

Let's break down the CSS code:

 .hover-1 {
  line-height: 1.2em;
  color: #0000;
  text-shadow: 
    0 0 #000, 
    0 1.2em #1095c1;
  overflow: hidden;
  transition: .3s;
}
.hover-1:hover {
  text-shadow: 
    0 -1.2em #000, 
    0 0 #1095c1;
}

The first thing to note is that to hide the actual text, I set the color of the actual text to be transparent (using #0000 ). After that, I use text-shadow to create two shadows, each of which only defines two length values. This means there is no blur radius, resulting in a clear and sharp shadow that effectively produces a copy of the text with the specified color.

That's why I claimed in the introduction that there is no shadow here. What we do is not so much a “classic” shadow as an easy way to copy text.

We have two text layers that we move when hovering. If we hide the overflow, the duplicate text will be invisible and moving it makes it look like the actual text has been replaced by other text. This is the main trick to make all the examples in this article work properly.

Let's optimize the code. I used the value 1.2em multiple times to define the height and offset of the shadow, making it an ideal candidate for CSS custom properties (we call it --h ):

 .hover-1 {
  --h: 1.2em;

  line-height: var(--h);
  color: #0000;
  text-shadow: 
    0 0 #000, 
    0 var(--h) #1095c1;
  overflow: hidden;
  transition: .3s;
}
.hover-1:hover {
  text-shadow: 
    0 calc(-1 * var(--h)) #000, 
    0 0 #1095c1;
}

We can also further simplify the code using more calc() calculations so that we only use text-shadow once. (We did the same thing in the previous post.)

 .hover-1 {
  --h: 1.2em;   

  line-height: var(--h);
  color: #0000;
  text-shadow: 
    0 calc(-1*var(--_t, 0em)) #000, 
    0 calc(var(--h) - var(--_t, 0em)) #1095c1;
  overflow: hidden;
  transition: .3s;
}
.hover-1:hover {
  --_t: var(--h);
}

If you're wondering why I'm adding an underscore to the --_t variable, this is just a naming convention I use to distinguish between variables (such as --h ) that users can update from internal variables (such as --_t ) that are only used for optimization purposes and do not need to be changed. In other words, underscores are part of the variable name and have no special meaning.

We can also update the code to get the opposite effect, where duplicate text slides in from the top:

We only made a small update to text-shadow property - we didn't touch anything else!

Hover effect #2

For this effect, we will animate two properties: text-shadow and background . Regarding text-shadow we still have two layers like the previous example, but this time we will move only one of them while setting the color of the other layer to transparent during the swap.

 .hover-2 {
  /* high*/
  --h: 1.2em;

  line-height: var(--h);
  color: #0000;
  text-shadow: 
    0 var(--_t, var(--h)) #fff,
    0 0 var(--_c, #000);
  transition: 0.3s;
}
.hover-2:hover {
  --_t: 0;
  --_c: #0000;
}

On hover, we move the white text layer to the top while changing the color of the other layer to transparent. To do this, we added a background-size animation applied to gradients:

Finally, we add overflow: hidden to make the animation visible only within the boundaries of the element:

 .hover-2 {
  /* high*/
  --h: 1.2em;

  line-height: var(--h);
  color: #0000;
  text-shadow: 
    0 var(--_t,var(--h)) #ffff,
    0 0 var(--_c, #000);
  background: 
    linear-gradient(#1095c1 0 0) 
    bottom/100% var(--_d, 0) no-repeat;
  overflow: hidden;
  transition: 0.3s;
}
.hover-2:hover {
  --_d: 100%;
  --_t: 0;
  --_c: #0000;
}

What we do here is to combine the CSS text-shadow and background properties to create a cool hover effect. Furthermore, we are able to use CSS variables to optimize the code.

If the background grammar looks weird, I highly recommend you read my previous post. The next hover effect also relies on the animation I detailed in that post. Unless you are familiar with CSS background skills, I suggest you read that article for more background information before continuing to read this article.

In previous posts, you showed us how to create a hover effect using only one variable – can you do so here?

Yes, absolutely! We can indeed use the same DRY switching technique so that we only need to handle a CSS custom property that only switches values ​​when hovering:

 .hover-2 {
  /* high*/
  --h: 1.2em;

  line-height: var(--h);
  color: #0000;
  text-shadow: 
    0 var(--_i, var(--h)) #fff,
    0 0 rgb(0 0 0 / calc(var(--_i, 1) * 100%) );
  background: 
    linear-gradient(#1095c1 0 0) 
    bottom/100% calc(100% - var(--_i, 1) * 100%) no-repeat;
  overflow: hidden;
  transition: 0.3s;
}
.hover-2:hover {
  --_i: 0;
}

Hover effect #3

This hover effect is nothing more than a combination of two effects we have made: the second hover effect in the previous post and the first hover effect in this post.

 .hover-3 {
  /* color*/
  --c: #1095c1;
  /* high*/
  --h: 1.2em;

  /* The first hover effect in this article*/
  line-height: var(--h);  
  color: #0000;
  overflow: hidden;
  text-shadow: 
    0 calc(-1 * var(--_t, 0em)) var(--c), 
    0 calc(var(--h) - var(--_t, 0em)) #fff;
  /* The second hover effect in the previous post*/
  background: 
    linear-gradient(var(--c) 0 0) no-repeat 
    calc(200% - var(--_p, 0%)) 100% / 200% var(--_p, .08em);
  transition: .3s var(--_s, 0s), background-position .3s calc(.3s - var(--_s, 0s));
}
.hover-3:hover {
  --_t: var(--h);
  --_p: 100%;
  --_s: .3s
}

All I did was copy and paste the effects from other examples and made some minor tweaks to the variable name. When they are combined, they create a clean hover effect! At first glance, this effect may seem complex and difficult to achieve, but in the end, it simply combines two relatively simple effects into one.

If we consider previous optimizations we have completed, it should also be a simple task to optimize the code using DRY toggle variable technology:

 .hover-3 {
  /* color*/
  --c: #1095c1;
  /* high*/
  --h: 1.2em;

  line-height: var(--h);  
  color: #0000;
  overflow: hidden;
  text-shadow: 
    0 calc(-1 * var(--h) * var(--_i, 0)) var(--c), 
    0 calc(var(--h) * (1 - var(--_i, 0))) #fff;
  background: 
    linear-gradient(var(--c) 0 0) no-repeat
    calc(200% - var(--_i, 0) * 100%) 100% / 200% calc(100% * var(--_i, 0) .08em);
  transition: .3s calc(var(--_i, 0) * .3s), background-position .3s calc(.3s - calc(var(--_i, 0) * .3s));
}
.hover-3:hover {
  --_i: 1;
}

Hover effect #4

This hover effect is an improvement to the second hover effect. First, let's introduce a clip-path animation to display one of the text layers, and then move it:

Here is a better explanation to better understand what is going on:

Initially, we used inset(0 0 0 0) , which is similar to overflow: hidden , because we only see the actual text. On hover, we update the third value (representing the bottom offset) with a negative value equal to the height to display the text layer placed at the bottom.

From there we can add this to the second hover effect we made in this article, and here is what we get:

We are getting closer and closer! Note that we need to run clip-path animation first and then everything else. To do this, we can add a delay to all properties on hover, except clip-path :

 transition: 0.4s 0.4s, clip-path 0.4s;

When the mouse is moved out, we do the opposite:

 transition: 0.4s, clip-path 0.4s 0.4s;

The final touch is to add a box-shadow to create the sliding effect of the blue rectangle. Unfortunately, background does not produce this effect, as the background is cropped to the content area by default. At the same time, box-shadow can go beyond the content area.

 .hover-4 {
  /* color*/
  --c: #1095c1;
  /* high*/
  --h: 1.2em;

  line-height: var(--h);
  color: #0000;
  text-shadow: 
    0 var(--_t, var(--h)) #fff,
    0 0 var(--_c, #000);
  box-shadow: 0 var(--_t, var(--h)) var(--c);
  clip-path: inset(0 0 0 0);
  background: linear-gradient(var(--c) 0 0) 0 var(--_t, var(--h)) no-repeat;
  transition: 0.4s, clip-path 0.4s 0.4s;
}
.hover-4:hover {
  --_t: 0;
  --_c: #0000;
  clip-path: inset(0 0 calc(-1 * var(--h)) 0);
  transition: 0.4s 0.4s, clip-path 0.4s;
}

If you look closely at box-shadow , you will find that it has the same value as the white text layer inside text-shadow . This is logical, because both need to be moved in the same way. Both will slide to the top. box-shadow is then behind the element and text-shadow is at the top.

Here is a demonstration with some modifications to visualize how layers move:

Wait, the background syntax is slightly different from the one used in the second hover effect!

Good eyesight! Yes, we are using different background techniques to produce the same effect. Instead of animateing the size from 0% to 100%, we animate the position.

If we do not specify the size on the gradient, it will occupy the entire width and height by default. Since we know the height of the element ( --h ), we can create a sliding effect by updating the position from 0 var(--h) to 0 0 .

 .hover-4 {
  /* ... */
  background: linear-gradient(var(--c) 0 0) 0 var(--_t, var(--h)) no-repeat;
}
.hover-4:hover {
  --_t: 0;
}

We can use background-size animation to get the same effect, but we just added another trick to our list of tricks!

In the demo, you also used inset(0 0 1px 0) … Why?

I sometimes add or remove some pixels or percentages here to perfect anything that doesn't look very good. In this case, a bad line appears at the bottom, adding 1px will remove it.

How about DRY switching variable optimization?

I'll leave this task to you! After reading these four hover effects and previous articles, you should be able to update the code so that it only uses one variable. I would love to see your attempt in the comments!

now you!

Let me share the last hover effect, which is another version of the previous effect. Can you find out how it is implemented without looking at the code? This is a great exercise, so don't cheat!

Summarize

We looked at many examples that show how using one element and a few lines of CSS is enough to create some rather complex hover effect on text elements – no pseudo-elements are needed! We are even able to combine multiple technologies to achieve more complex animations with smaller efforts.

If you are interested in digging into what’s beyond these four text shadow hover effects in this article, check out my collection of 500 hover effects, where I explore a variety of different techniques.

The above is the detailed content of 4 Cool Hover Effects That Use CSS Text Shadow. For more information, please follow other related articles on the PHP Chinese website!

Statement:
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