In today’s tutorial, we’re going to create 7 different CSS hover effects. We’ll learn loads along the way, including how to animate font icons, borders, and SVG paths. You’ll be able to apply these CSS hover effects to all kinds of situations. Let’s dive in!
Just to give you an idea of what you’ll learn during this tutorial, check out one of the demos we’ll be building:
Let’s start with this one, see you in the first step..
1. Revealing Icon CSS Hover Effect
In this first example, we’ll explore the demo you’ve already seen: a hover effect where text is replaced by an icon with a slide animation.
Start with the Page Markup
We’ll start with a plain unordered list which will represent a typical page menu. Each menu link will include two span
elements. The first span
will contain the anchor text, while the second one will hold a Font Awesome icon:
<ul class="menu"> <li> <a href="#0"> <span>About</span> <span> <i class="fas fa-address-card" aria-hidden="true"></i> </span> </a> </li> <li> <a href="#0"> <span>Projects</span> <span> <i class="fas fa-tasks" aria-hidden="true"></i> </span> </a> </li> ... </ul>
Specify Some Styles
The list will be a flex container with horizontally centered content:
.menu { display: flex; justify-content: center; }
Note: This basis style will be added to all the demos we build, so we won’t discuss it again. The demo also has some aesthetic styles we’ll reuse every time (such as the dark background etc.) which you can copy from the CodePen demo.
The first span
in each item will have some padding around it:
.menu a span:first-child { display: inline-block; padding: 10px; }
Then the second span
will be absolutely positioned and hidden by default. Plus, its icon will be horizontally and vertically centered:
.menu a { display: block; position: relative; overflow: hidden; } .menu a span:last-child { position: absolute; top: 0; right: 0; bottom: 0; left: 0; display: flex; align-items: center; justify-content: center; transform: translateY(-100%); }
Each time we hover over a link, its text will disappear. On the other hand, at that point the associated icon will become visible:
.menu a span { transition: transform 0.2s ease-out; } .menu a:hover span:first-child { transform: translateY(100%); } .menu a:hover span:last-child { transform: none; }
Happily enough, there’s the option to modify the direction of the slide animations according to our needs. By default during the hover animation, the icon will appear from top to bottom, while the text will be moved to the bottom. To change that behavior, we have to pass the data-animation
attribute to the target list. Possible values are to-top
, to-right
, and to-left
.
The corresponding styles are shown below:
.menu[data-animation="to-top"] a span:last-child { transform: translateY(100%); } .menu[data-animation="to-top"] a:hover span:first-child { transform: translateY(-100%); } .menu[data-animation="to-right"] a span:last-child { transform: translateX(-100%); } .menu[data-animation="to-right"] a:hover span:first-child { transform: translateX(100%); } .menu[data-animation="to-left"] a span:last-child { transform: translateX(100%); } .menu[data-animation="to-left"] a:hover span:first-child { transform: translateX(-100%); }
Here’s the full CodePen demo that summarizes the aforementioned cases:
2. Revealing Swipe CSS Hover Effect
In this second example we’ll continue with another hover effect where text is replaced by a Font Awesome icon. But, this time, the replacement will happen in the background and won’t be visible to us, thanks to a “swipe” which happens in the foreground:
Specify the Page Markup
As ever, we’ll start with an unordered list which will contain the page links. In this case though, each of our links will have a data-icon
attribute. The value of this attribute will match the Unicode respresentation of a Font Awesome icon:
<ul class="menu"> <li> <a href="#0" data-icon=""> About </a> </li> <li> <a href="#0" data-icon=""> Projects </a> </li> ... </ul>
Specify the Styles
We’ll then define the ::before
and ::after
pseudo-elements of all links.
- The
::before
pseudo-element will be positioned in the center of the link, though it will initially be invisible. - The
::after
pseudo-element will cover the full link dimensions, but it will also be hidden by default. Its content will hold a Font Awesome icon stored in the relevantdata-icon
attribute:
:root { ... --text-color: #aaaebc; --timing-function: cubic-bezier(0.82, 0.2, 0.42, 1); } .menu a { position: relative; overflow: hidden; } .menu a::before, .menu a::after { position: absolute; left: 0; width: 100%; } .menu a::before { content: ’’; top: 50%; transform: translate(-101%, -50%); height: 50%; z-index: 1; background: var(--text-color); } .menu a::after { content: attr(data-icon); font-family: "Font Awesome 5 Free"; font-weight: 900; top: 0; display: flex; align-items: center; justify-content: center; height: 100%; color: var(--text-color); opacity: 0; }
Each time we hover over a link, first the ::before
pseudo-element will quickly appear. Then, it will be moved to the right and the icon will appear. During that time, the anchor text color will set to transparent.
To achieve this precise timing synchronization, we have to customize the transitions speed. For instance, we’ll add delays to the links as well as their ::after
pseudo-element:
/*CUSTOM VARIABLES HERE*/ .menu a { transition: color 0s 0.25s var(--timing-function); } .menu a::before { transition: transform 0.5s var(--timing-function); } .menu a::after { transition: opacity 0s 0.25s var(--timing-function); } .menu a:hover { color: transparent; } .menu a:hover::before { transform: translate(101%, -50%); } .menu a:hover::after { opacity: 1; }
If you prefer a reversed animation, just add the data-animation="to-left"
attribute to the corresponding list:
Here’s the Codepen demo that covers both cases:
3. Animated Underline CSS Hover Effect
In our third example we’ll look at a common hover effect where an underline is revealed with a slide animation:
Specify the Page Markup
We’ll start with an unordered list which will store the page links:
<ul class="menu"> <li> <a href="#0"> About </a> </li> <li> <a href="#0"> Projects </a> </li> ... </ul>
Specify the CSS Styles
We’ll then define the ::before
pseudo-element for all the links. We’ll place it to the bottom of its container and give it translate: scaleX(0)
, so it will initially be hidden.
In addition, we’ll apply transform-origin: left
to it because we want the animation to start from left to right:
.menu a { position: relative; } .menu a::before { content: ’’; position: absolute; bottom: 0; left: 0; width: 100%; height: 2px; background: linear-gradient(to right, #b47dcd, #e878a2, #eb85ab); z-index: 1; transform: scaleX(0); transform-origin: left; transition: transform 0.5s ease-in-out; }
Each time we hover over a link, its pseudo-element will appear:
.menu a:hover::before { transform: scaleX(1); }
Similarly to the previous example, we have the option to change the direction of the slide animation. The line will appear from left to right by default, but to change that behavior, we have to pass the data-animation
attribute to the target list. Possible values are to-left
and center
.
The corresponding styles are as follows:
.menu[data-animation="to-left"] a::before { transform-origin: right; } .menu[data-animation="center"] a::before { transform-origin: center; }
Bonus!
We can go things one step further and change the transform-origin
property value of the pseudo-element depending on its state. This makes the underline appear from one side, and disappear from the other:
Here are the rules that implement this functionality:
.menu[data-animation="bonus"] a::before { transform-origin: right; transition: transform 0.5s ease-in-out; } .menu[data-animation="bonus"] a:hover::before { transform-origin: left; transform: scaleX(1); transition-timing-function: cubic-bezier(0.2, 1, 0.82, 0.94); }
Here’s the CodePen demo for the scenarios we discussed:
4. Multiline Animation CSS Hover Effect
Moving on, in this fourth example we’ll cover a hover effect where multiple lines will be revealed sequentially. The beauty of this technique is that it will give us the impression that the border of the hovered element is being painted. How cool is that!
Specify the Page Markup
Again, our markup will consist of an unordered list. Each of the menu links will contain four empty span
elements:
<ul class="menu"> <li> <a href="#0"> About <span class="border border-top"></span> <span class="border border-right"></span> <span class="border border-bottom"></span> <span class="border border-left"></span> </a> </li> ... </ul>
Specify the Styles
The span
elements will be absolutely positioned and hidden by default. However, their position
and transform-origin
will be different:
.menu .border { position: absolute; left: 0; background: currentColor; } .menu .border-top, .menu .border-bottom { width: 100%; height: 1px; transform: scaleX(0); } .menu .border-left, .menu .border-right { width: 1px; height: 100%; transform: scaleY(0); } .menu .border-top, .menu .border-left, .menu .border-right { top: 0; } .menu .border-bottom { bottom: 0; transform-origin: bottom right; } .menu .border-top { transform-origin: top left; } .menu .border-left { transform-origin: bottom left; } .menu .border-right { left: auto; right: 0; transform-origin: top right; }
As we hover over a link, its spans will become visible sequentially, following a clockwise rotation. To do so, we’ll control when the second, third, and fourth spans become visible:
:root { ... --transition-duration: 0.2s; --transition-delay: 0.2s; } .menu .border { transition: transform var(--transition-duration) ease-in-out; } .menu a:hover .border-top, .menu a:hover .border-bottom { transform: scaleX(1); } .menu a:hover .border-left, .menu a:hover .border-right { transform: scaleY(1); } .menu a:hover .border-right { transition-delay: var(--transition-delay); } .menu a:hover .border-bottom { transition-delay: calc(var(--transition-delay) * 2); } .menu a:hover .border-left { transition-delay: calc(var(--transition-delay) * 3); }
By modifying the transform-origin
property value and canceling the delays of our elements, we can easily generate another nice effect:
To incorporate this effect in our menu, we have to append the data-animation="diagonal"
attribute to it. This will result in the following CSS styles:
.menu[data-animation="diagonal"] .border-left { transform-origin: top left; } .menu[data-animation="diagonal"] .border-right, .menu[data-animation="diagonal"] .border-bottom { transform-origin: bottom right; } .menu[data-animation="diagonal"] a:hover [class^=border]{ transition-delay: 0s; }
Take a look at the CodePen demo that gives us those effects:
5. Animated Circle SVG Hover Effect
In this fifth example, we’ll walk through a hover effect where an SVG path is animated, encircling our link. The technique we’re going to use isn’t something new; in actual fact, Jake Archibald wrote about it some years ago.
Specify the Page Markup
Once more, we’ll start with an unordered list, but this time we’ll include an SVG nested inside each link:
<ul class="menu"> <li> <a href="#0"> About <svg preserveAspectRatio="none" viewBox="0 0 546.714 178.143"><path d="M546.214 89.072c0 48.917-122.162 88.571-272.857 88.571C122.662 177.643.5 137.988.5 89.072.5 40.155 122.662.5 273.357.5c150.695 0 272.857 39.655 272.857 88.572z"/></svg> </a> </li> ... </ul>
The SVG will be an ellipse and is represented via the path
element. We’ll give it preserveAspectRatio="none"
because, as we’ll see in a moment, it should cover the full parent dimensions, even if it’s stretched.
Specify the Styles
The SVG will be absolutely positioned and centered within its container. Plus, as mentioned above, it will be big enough to cover the anchor text:
.menu a { position: relative; } .menu a svg { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 120%; height: 120%; z-index: -1; }
The path
element will have a stroke and its fill color will be transparent:
.menu a svg path { fill: transparent; stroke-width: 5px; stroke: currentColor; }
To animate the path, we’ll need two additional properties. Specifically, the stroke-dasharray
and stroke-dashoffset
properties.
The stroke-dasharray
property is responsible for creating dashes/gaps in our stroke. For example, by setting stroke-dasharray: 50
to the path, it will look as follows:
The stroke-dashoffset
property is responsible for changing the position (offsetting) of those dashes.
So here’s the trick:
- First, the value of the
stroke-dasharray
property should match the length of the path. Instead of guessing it, JavaScript provides a handy way for grabbing it through thegetTotalLength()
method. - Next, we’ll also assign the resulting value (or its negative one for a reversed effect) to the
stroke-dashoffset
property. This neat combination will hide the SVG. - Then, each time we hover over a link, we’ll run an animation which will move the
stroke-dashoffset
property value to 0. As a result of that, the path will be gradually “drawn”.
With all the above in mind, let’s first retrieve the path’s length (just for the first path) via JavaScript:
document.querySelector("li:nth-child(1) path").getTotalLength(); //1210.709716796875; // you might see slightly different values depending on your browser
Then, we’ll assign this value to the corresponding properties:
.menu a svg path { stroke-dasharray: 1210.709716796875; stroke-dashoffset: -1210.709716796875; /*or the positive one*/ transition: stroke-dashoffset .5s cubic-bezier(.29,.68,.74,1.02); } .menu a:hover svg path { stroke-dashoffset: 0; }
Lastly, as an improvement, instead of hard coding the stroke-dasharray
and stroke-dashoffset
values, we could have specified them dynamically through JavaScript (see if you can do that bit yourself!).
Here’s the final demo, which gives us a cool chalkboard hover effect:
6. SVG Wavy UnderLine Hover Effect
Now that we know the basic principles behind the SVG path animation, let’s have a quick look at two other very similar examples. In both examples, there won’t be any need to stretch the SVGs, so we won’t make use of the preserveAspectRatio="none"
attribute.
The first one will reveal a wavy underline.
Here’s the demo:
7. Pointing SVG Arrow Hover Effect
The third SVG demo will reveal an Iconmonstr icon (a pointing arrow).
Here’s the demo for you to reverse engineer:
Conclusion
That concludes another tutorial, folks! It was quite a long journey, but I hope that you enjoyed it and have learned some new things which you will include in your front-end toolkit.
Last but not least, I have added all the demos of this tutorial to a CodePen collection. Be sure to check it out and give it some love!
I’d love to see your favorite CSS hover effects. They can come from CodePen, an inspirational website, or somewhere else. Don’t forget to share them with us in the comments section.
As always, thanks a lot for reading!
More CSS and JS Hover Effect Tutorials
Learn how to create even more interesting CSS hover effects with these Tuts+ tutorials:
-
CSSCSS Hover Effects: Techniques for Creating a Text “Wipe Fill”
-
HTMLQuick Tip: How to Build a MouseOver Navigation Slide Effect
-
HTMLHow to Make Multi-Preview Thumbnails With JavaScript Mouse Events
-
CSS Grid LayoutCreate a CSS Grid Image Gallery (With Blur Effect and Interaction Media Queries)
No comments:
Post a Comment