CSS3 Hover Link Effects

• 4 minutes READ

One of the essential parts of a website is a text link. By clicking an anchor tag you can go anywhere from the site as it points to a specific page.

Typical links contain simple hover effects such as use of a simple color change when the mouse is pointed or clicked. But there are ways to make this effect even better.

Today, I am going to show you how to create awesome links using new features of CSS3: transition and transform. At the end of this tutorial you’ll have cool link hover effect that will surely rock your navigation.

Preview

Resources you need to complete this tutorial:

  • Font-Awesome
  • Knowledge about CSS3 transitions and transform
  • Time and Patience

Demo 1

The first demo will have a simple effect so that when you hover your mouse, a three-pixel border will come out from the back of the box container of the link text.

No-Code Email Template Builder

With Postcards Email Builder you can create and edit email templates online without any coding skills! Includes more than 100 components to help you create custom emails templates faster than ever before.

Free Email BuilderFree Email Templates

The HTML

Our markup will simply contain an HTML5 nav tag which holds all of the links on our demo. On each anchor tag there is class box and demo-1. We will also place font-awesome icons before the link to make a cool design.

<nav>
  <a href="demo1.html" class="box demo-1">
    <i class="fa fa-hand-o-right"></i> <span>Demo 1</span>
  </a>
  <a href="demo2.html" class="box demo-1">
    <i class="fa fa-hand-o-up"></i> <span>Demo 2</span>
  </a>
  <a href="demo3.html" class="box demo-1">
    <i class="fa fa-hand-o-left"></i> <span>Demo 3</span>
  </a>
  <a href="demo4.html" class="box demo-1">
    <i class="fa fa-thumbs-o-up"></i> <span>Demo 4</span>
  </a>
</nav>

The CSS

For our CSS, we will use the ::before and ::after selector to insert a 3 pixel border when the mouse was hovered to the anchor tag element. To make the effect smooth, we will use CSS3 transition.

.box{
  color: #fff;
  padding: 10px;
}

.box:hover{
  background: #fff;
  color: #26425E;
}

.demo-1 {
  position: relative;
}

.demo-1:before {
  content: '';
  position: absolute;
  bottom: 0;
  left: 0;
  top: 0;
  right: 0;

  -webkit-transition-duration: 0.3s;
  -moz-transition-duration: 0.3s;
  -ms-transition-duration: 0.3s;
  -o-transition-duration: 0.3s;
  transition-duration: 0.2s;

  -webkit-transition-property: top, left, right, bottom;
  -moz-transition-property: top, left, right, bottom;
  -ms-transition-property: top, left, right, bottom;
  -o-transition-property: top, left, right, bottom;
  transition-property: top, left, right, bottom;
}

.demo-1:hover:before, .demo-1:focus:before{
  -webkit-transition-delay: .1s;
  -moz-transition-delay: .1s;
  -ms-transition-delay: .1s;
  -o-transition-delay: .1s;
  transition-delay: .1s; 

  border: #fff solid 3px;
  bottom: -7px;
  left: -7px;
  top: -7px;
  right: -7px;
}

Demo 2

The second demo will have a smooth highlight effect wherein when you hover your mouse to it; it will highlight the text and add a dashed border on the top and bottom of the text.

The HTML

Our markup is almost the same as the first demo, however this time we will be using demo-2 as the class on each anchor tag. I’ll use the HTML5 data attribute to manipulate the hover effects via CSS later on. Notice that I added &nbps; on the data-text attribute. Since data attribute won’t take a non-breaking space, I need to use an escape string to put some space between the word Demo and the number of the demo. Aside from this escape string you can also use the code &#160 to create similar output.

<nav>
    <a href="demo1.html" class="demo-2" data-text="Demo&nbsp;1">Demo 1</a>
    <a href="demo2.html" class="demo-2" data-text="Demo&nbsp;2">Demo 2</a>
    <a href="demo3.html" class="demo-2" data-text="Demo&nbsp;3">Demo 3</a>
    <a href="demo4.html" class="demo-2" data-text="Demo&nbsp;4">Demo 4</a>
</nav>

The CSS

Now for our CSS, we will set a dashed border on the top and bottom and set the width of the data-text attribute to zero. Using the :hover and :focus selector we will transition the width of the data attribute as well as the 2 dashed border to 100% to create a smooth highlight effect.

.demo-2{
  color: #314559;
  padding: 10px 0;
}

.demo-2::before {
  color: #fff;
  max-width: 0;
  padding: 10px 0;
  border-top: 1px dashed #fff;
  border-bottom: 1px dashed #fff;
  position: absolute;
  top: 0;
  left: 0;
  overflow: hidden;
  content: attr(data-text);
  -webkit-transition: all 0.3s;
  -moz-transition: all 0.3s;
  -ms-transition: all 0.3s;
  -o-transition: all 0.3s;
  transition: all 0.3s;
}

.demo-2:hover::before,
.demo-2:focus::before {
  max-width: 100%;
  outline: none;
  text-shadow: none;
}

Demo 3

Our third demo is inspired by Sebastian Ekström’s 3D link hover effect. This will have a 3D background box flipping effect when the mouse is hovered.

The HTML

Our markup is almost identical like the first two demos however to create some awesome effects we need to use a data attribute for repeating the link text in the pseudo-element.

<nav>
    <a href="demo1.html" class="demo-3">
        <span data-text="Demo 1">Demo 1</span>
    </a>
    <a href="demo2.html" class="demo-3">
        <span data-text="Demo 2">Demo 2</span>
    </a>
    <a href="demo3.html" class="demo-3">
        <span data-text="Demo 3">Demo 3</span>
    </a>
    <a href="demo4.html" class="demo-3">
        <span data-text="Demo 4">Demo 4</span>
    </a>
</nav>

The CSS

Now let’s add some magic to our markup. The basic idea for this effect is that we will translate3d and perspective to create an illusion of spinning upward and backward box. We will use overflow: hidden to clip the box, and the rest of the content will be invisible.

Low-Code Website Builders

With Startup App and Slides App you can build unlimited websites using the online website editor which includes ready-made designed and coded elements, templates and themes.

Try Startup App Try Slides AppOther Products
 .demo-3 {
  color: #fff;
  display: inline-block;
  text-decoration: none;
  overflow: hidden;
  vertical-align: top;
   background: #1C3044;
  -webkit-perspective: 600px;
  -moz-perspective: 600px;
  -ms-perspective: 600px;
  perspective: 600px;
  -webkit-perspective-origin: 50% 50%;
  -moz-perspective-origin: 50% 50%;
  -ms-perspective-origin: 50% 50%;
  perspective-origin: 50% 50%;
}
 .demo-3:hover span {
  background: #314559;
  -webkit-transform: translate3d(0px, 0px, -30px) rotateX(90deg);
  -moz-transform: translate3d(0px, 0px, -30px) rotateX(90deg);
  -ms-transform: translate3d(0px, 0px, -30px) rotateX(90deg);
  transform: translate3d(0px, 0px, -30px) rotateX(90deg);
}
  .demo-3 span {
  display: block;
  position: relative;
  padding: 10px 20px;
  -webkit-transition: all 0.3s ease;
  -moz-transition: all 0.3s ease;
  -ms-transition: all 0.3s ease;
  transition: all 0.3s ease;
  -webkit-transform-origin: 50% 0%;
  -moz-transform-origin: 50% 0%;
  -ms-transform-origin: 50% 0%;
  transform-origin: 50% 0%;
  -webkit-transform-style: preserve-3d;
  -moz-transform-style: preserve-3d;
  -ms-transform-style: preserve-3d;
  transform-style: preserve-3d;
}

 .demo-3 span:after {
  content: attr(data-text);
  -webkit-font-smoothing: antialiased;
  padding: 10px 20px;
  color: #fff;
  background: #0e6957;
  display: block;
  position: absolute;

  left: 0;
  top: 0;
  -webkit-transform-origin: 50% 0%;
  -moz-transform-origin: 50% 0%;
  -ms-transform-origin: 50% 0%;
  transform-origin: 50% 0%;
  -webkit-transform: translate3d(0px, 105%, 0px) rotateX(-90deg);
  -moz-transform: translate3d(0px, 105%, 0px) rotateX(-90deg);
  -ms-transform: translate3d(0px, 105%, 0px) rotateX(-90deg);
  transform: translate3d(0px, 105%, 0px) rotateX(-90deg);
}

Notice that we also use the rotateX property along with the translate3D. This will create an effect of translating and rotating the box when the text was hovered.

Demo 4

The fourth demo will be different. This time we will a flashing border animation using CSS3’s @keyframes property.

The HTML

Our markup for this demo will be different. Inside our nav tag we will add four anchor tags and put two span tags inside of each anchor tags. The first span tag will contain our text for normal state and the second one for the hover state. We will also add the class demo-4 on each anchor tag.

<nav>
    <a href="demo1.html" class="demo-4">
        <span>
            <span>Demo 1</span>
            <span>Hover</span>
            <span></span>
        </span>
    </a>

    <a href="demo2.html" class="demo-4">
        <span>
            <span>Demo 2</span>
            <span>Hover</span>
            <span></span>
        </span>
    </a>

    <a href="demo3.html" class="demo-4">
        <span>
            <span>Demo 3</span>
            <span>Hover</span>
            <span></span>
        </span>
    </a>

    <a href="demo4.html" class="demo-4">
        <span>
            <span>Demo 4</span>
            <span>Hover</span>
            <span></span>
        </span>
    </a>
</nav>

The CSS

Now it’s time to bring some life to our links. To create a flashing border effect, we will use the CSS3 new feature, @keyframes property to create the animation. First, we need to specify the width container of the anchor tags as well as the span borders.

.demo-4 {
  width: 210px;
  background-color: transparent;
  cursor: pointer;
  border-color: #bdc3c7;
}

.demo-4:hover {
  border-color: #C672E9;
}

.demo-4 span:nth-child(1) {
  color: #FCFCFC;
}

.demo-4 span:nth-child(2) {
  color: #C672E9;
}

.demo-4 span {
  font-family: 'Lato', sans-serif;
  font-size: 28px;
  letter-spacing: 3px;
}

.demo-4 {
  position: relative;
  box-sizing: border-box;
  padding: 0;
  border-style: none;
  height: 65px;
  display: inline-block;
}

.demo-4 span {
  position: absolute;
  box-sizing: border-box;
  display: block;
}

Next, we need to specify position and properties of the contents using the :before and :after selector. It will also include the position of borders and text on hover state.

.demo-4 > span > span:nth-child(3), .demo-4:before, .demo-4:after, .demo-4 > :first-child, .demo-4 > :first-child:before, .demo-4 > :first-child:after {
  border-color: inherit;
  display: block;
  -moz-transition: border-color 0.3s ease;
  -webkit-transition: border-color 0.3s ease;
  transition: border-color 0.3s ease;
}

.demo-4:before, .demo-4:after, .demo-4 > :first-child:before, .demo-4 > :first-child:after {
  -webkit-animation-duration: 0.3s;
  animation-duration: 0.3s;
  position: absolute;
  box-sizing: border-box;
  content: ' ';
}

.demo-4 > span > span:nth-child(3), .demo-4:before, .demo-4:after, .demo-4 > :first-child:before, .demo-4 > :first-child:after {
  border-width: 3px;
}

.demo-4 > span > span:nth-child(3) {
  border-radius: 3px;
}

.demo-4:before {
  border-radius: 3px 0 0 3px;
}

.demo-4:after {
  border-radius: 0 3px 3px 0;
}

.demo-4 > :first-child:before {
  border-radius: 3px 3px 0 0;
}

.demo-4 > :first-child:after {
  border-radius: 0 0 3px 3px;
}

.demo-4 > :first-child {
  top: 0;
  left: 0;
  width: inherit;
  height: inherit;
}

.demo-4 > span span {
  width: inherit;
  text-align: center;
  -moz-transition: opacity 0.6s ease, top 0.5s ease;
  -webkit-transition: opacity 0.6s ease, top 0.5s ease;
  transition: opacity 0.6s ease, top 0.5s ease;
}

.demo-4 > span > span:nth-child(1) {
  opacity: 1;
  top: 18px;
}

.demo-4 > span > span:nth-child(2) {
  top: 37px;
  opacity: 0;
}

.demo-4:hover > span > span:nth-child(1) {
  opacity: 0;
  top: 2px;
}

.demo-4:hover > span > span:nth-child(2) {
  opacity: 1;
  top: 18px;
}

.demo-4 > span > span:nth-child(3) {
  top: 28%;
  height: 44%;
  width: inherit;
  border-style: none solid none solid;
}

.demo-4:before, .demo-4:after {
  top: 0;
  width: 0;
  height: inherit;
  border-style: solid none solid none;
}

.demo-4 > :first-child:before, .demo-4 > :first-child:after {
  left: 0;
  height: 0;
  width: inherit;
  border-style: none solid none solid;
}

.demo-4:before {
  -webkit-animation-name: left-center;
  animation-name: left-center;
}

.demo-4:after {
  -webkit-animation-name: right-center;
  animation-name: right-center;
}

.demo-4 > :first-child:before {
  -webkit-animation-name: center-top;
  animation-name: center-top;
}

.demo-4 > :first-child:after {
  -webkit-animation-name: center-bottom;
  animation-name: center-bottom;
}

.demo-4:hover:before {
  -webkit-animation-name: center-left;
  animation-name: center-left;
}

.demo-4:hover:after {
  -webkit-animation-name: center-right;
  animation-name: center-right;
}

.demo-4:hover > :first-child:before {
  -webkit-animation-name: top-center;
  animation-name: top-center;
}

.demo-4:hover > :first-child:after {
  -webkit-animation-name: bottom-center;
  animation-name: bottom-center;
}

Notice that I also put the animation-name on each hover selector. This time we need to work on the animation. Below is the @keyframes animation set up for Chrome, Safari, IE and Firefox.

@-webkit-keyframes center-left {
    0%   {left: 40%; width: 8%; opacity: 0.2;}
    25%  {left: 25%; width: 15%;}
    50%  {left: 0%; width: 30%;}
    80%  {left: 0%; width: 0%;}
    100% {left: 0%; width: 0%; opacity: 1;}
}

@-webkit-keyframes left-center {
    0%   {left: 0%; width: 0%; opacity: 1;}
    20%  {left: 0%; width: 0%;}
    50%  {left: 0%; width: 30%;}
    55%  {left: 40%; width: 11%;}
    100% {left: 43%; width: 8%; opacity: 0.2;}
}

@-webkit-keyframes center-right {
    0%   {left: 52%; width: 8%; opacity: 0.2;}
    25%  {left: 60%; width: 15%;}
    50%  {left: 70%; width: 30%;}
    80%  {left: 100%; width: 0%;}
    100% {left: 100%; width: 0%; opacity: 1;}
}

@-webkit-keyframes right-center {
    0%   {left: 100%; width: 0%; opacity: 1;}
    20%  {left: 100%; width: 0%;}
    50%  {left: 70%; width: 30%;}
    55%  {left: 49%; width: 11%;}
    100% {left: 49%; width: 8%; opacity: 0.2;}
}

@-webkit-keyframes top-center {
    0%   {top: 0%; height: 0%; opacity: 0.2;}
    50%  {top: 0%; height: 0%;}
    60%  {top: 0%; height: 20%;}
    80%  {top: 0%; height: 50%;}
    90%  {top: 25%; height: 25%;}
    100% {top: 50%; height: 0%; opacity: 1;}
}

@-webkit-keyframes center-top {
    0%   {top: 50%; height: 0%; opacity: 1;}
    10%  {top: 25%; height: 25%;}
    20%  {top: 0%; height: 50%;}
    40%  {top: 0%; height: 20%;}
    50%  {top: 0%; height: 0%;}
    100% {top: 0%; height: 0%; opacity: 0.2;}
}

@-webkit-keyframes bottom-center {
    0%   {top: 100%; height: 0%; opacity: 0.2;}
    50%  {top: 100%; height: 0%;}
    60%  {top: 80%; height: 20%;}
    80%  {top: 50%; height: 50%;}
    90%  {top: 50%; height: 25%;}
    100% {top: 50%; height: 0%; opacity: 1;}
}

@-webkit-keyframes center-bottom {
    0%   {top: 50%; height: 0%; opacity: 1;}
    10%  {top: 50%; height: 25%;}
    20%  {top: 50%; height: 50%;}
    40%  {top: 80%; height: 20%;}
    50%  {top: 100%; height: 0%;}
    100% {top: 100%; height: 0%; opacity: 0.2;}
}

@keyframes center-left {
    0%   {left: 40%; width: 8%; opacity: 0.2;}
    25%  {left: 25%; width: 15%;}
    50%  {left: 0%; width: 30%;}
    80%  {left: 0%; width: 0%;}
    100% {left: 0%; width: 0%; opacity: 1;}
}

@keyframes left-center {
    0%   {left: 0%; width: 0%; opacity: 1;}
    20%  {left: 0%; width: 0%;}
    50%  {left: 0%; width: 30%;}
    55%  {left: 40%; width: 11%;}
    100% {left: 43%; width: 8%; opacity: 0.2;}
}

@keyframes center-right {
    0%   {left: 52%; width: 8%; opacity: 0.2;}
    25%  {left: 60%; width: 15%;}
    50%  {left: 70%; width: 30%;}
    80%  {left: 100%; width: 0%;}
    100% {left: 100%; width: 0%; opacity: 1;}
}

@keyframes right-center {
    0%   {left: 100%; width: 0%; opacity: 1;}
    20%  {left: 100%; width: 0%;}
    50%  {left: 70%; width: 30%;}
    55%  {left: 49%; width: 11%;}
    100% {left: 49%; width: 8%; opacity: 0.2;}
}

@keyframes top-center {
    0%   {top: 0%; height: 0%; opacity: 0.2;}
    50%  {top: 0%; height: 0%;}
    60%  {top: 0%; height: 20%;}
    80%  {top: 0%; height: 50%;}
    90%  {top: 25%; height: 25%;}
    100% {top: 50%; height: 0%; opacity: 1;}
}

@keyframes center-top {
    0%   {top: 50%; height: 0%; opacity: 1;}
    10%  {top: 25%; height: 25%;}
    20%  {top: 0%; height: 50%;}
    40%  {top: 0%; height: 20%;}
    50%  {top: 0%; height: 0%;}
    100% {top: 0%; height: 0%; opacity: 0.2;}
}

@keyframes bottom-center {
    0%   {top: 100%; height: 0%; opacity: 0.2;}
    50%  {top: 100%; height: 0%;}
    60%  {top: 80%; height: 20%;}
    80%  {top: 50%; height: 50%;}
    90%  {top: 50%; height: 25%;}
    100% {top: 50%; height: 0%; opacity: 1;}
}

@keyframes center-bottom {
    0%   {top: 50%; height: 0%; opacity: 1;}
    10%  {top: 50%; height: 25%;}
    20%  {top: 50%; height: 50%;}
    40%  {top: 80%; height: 20%;}
    50%  {top: 100%; height: 0%;}
    100% {top: 100%; height: 0%; opacity: 0.2;}
}

Wrapping Up

There you have it! You just created awesome hover link text.

Feel free to experiment with effects from here. There are endless possibilities and I believe you can improve them yourself.

I hope that you learned something from this tutorial; please drop a line on the comment section if you create something using this demo.

Just a reminder: Although CSS3 had come a long way some new features such as transform-style are not working on IE10 but you can always create a fallback effect using JavaScript.

Sam Norton

Sam is an expert Full Stack Developer who loves making digital solutions that are meaningful and new. Sam is an expert in web design and development. He uses his knowledge of HTML/CSS, JavaScript, jQuery, Ruby, Ruby on Rails, WordPress, Node.js, React, Express.js, Gatsby.js, GraphQL, and Strapi.js to make custom websites that reflect clients' unique brands and serve their business niches. Committed to staying ahead of the curve, Sam harnesses the power of the latest technologies, CMS, and platforms to build cutting-edge websites that outperform competitors.

Posts by Sam Norton