How to create a large CCS3 menu with transitions

While playing around with some CSS3 transitions for an image gallery representation, I ended up creating a menu that I really liked, so I decided to write a tutorial around it. Have a look at the demo (or this pen) to see what we’re going to create. After building the horizontal version, it’s very easy to create a vertical menu as well. But we’ll get to that.

Note: All versions should work properly in the latest versions of Chrome, Firefox, Opera, Safari, and Internet Explorer, as well as work without transitions in IE8 & IE9.

So, first of all…

The HTML code

We are going to create our menu as an unordered list of links and images, and place it inside a nav element with the class menu-container, as follows:

<nav class="menu-container">
<ul>
    <li>
        <a href="#">Home sweet <strong>home</strong></a>
        <img src="home.jpg" alt="Home sweet home" />
    </li>
    <li>
        <a href="#">Some cool quote about <strong>movies</strong></a>
        <img src="movies.jpg" alt="Some cool quote about movies" />
    </li>
    <li>
        <a href="#">Some cool quote about <strong>music</strong></a>
        <img src="music.jpg" alt="Some cool quote about music" />
    </li>
    <li>
        <a href="#">Some cool quote about <strong>games</strong></a>
        <img src="games.jpg" alt="Some cool quote about games" />
    </li>
    <li>
        <a href="#">Some cool quote about <strong>books</strong></a>
        <img src="books.jpg" alt="Some cool quote about books" />
    </li>
    <li>
        <a href="#">Some cool quote about <strong>art</strong></a>
        <img src="art.jpg" alt="Some cool quote about art" />
    </li>
</ul>
</nav>

Note: In the demo, there is more HTML & CSS code, but since it’s irrelevant of the actual menu, I’m not explaining it in the tutorial. You can find the whole code in the [download id=”18″ format=”1″].

The CSS code

The idea is that the images are going to be visible, and the anchor tags are going to sit on top of them with an opacity value of 0, until there is a hover state. When this happens, the anchor will become visible, and will be expanded a little bit over the image.

To begin with, we will reset some styles of our ul and li elements, and we will set the width of our menu to 100%.

.menu-container ul, .menu-container li
{
    margin: 0;
    padding: 0;
    list-style: none;
    position: relative;
}

.menu-container
{
    width: 100%;
}

The next step is to set the width of the list items, which will hold the images. We want to use 6 images, so since 100 / 6 = 16.66666666666667, we’ll set the width to that. We’ll also specify that the width of each image will expand to the 100% of its container (i.e. the li element).

.menu-container li
{
    float: left;
    width: 16.66666666666667%;
}

.menu-container li img
{
    width: 100%;
}

That was the simple part. Now, let’s move to the anchors. I broke the whole CSS code for the anchor tag in 2 blocks, just to explain it easier.

Starting with the first block, the important part is to specify the element’s position as absolute (that’s why we earlier set the li element’s position as relative), and its width and height values to 100%, to make sure it will cover the image. The box-sizing values are there to make calculations (e.g. with padding) easier.

.menu-container li a
{
    position: absolute;
    width: 100%;
    height: 100%;

    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
    padding: 10%;

    line-height: 1.4em;
    font-size: 1.5em;
    background-color: #000;
    color: #fff;
}

We also have to specify that the initial opacity of the element is zero, and the appropriate values for the transitions.

.menu-container li a
{
    filter: alpha(opacity=0);
    -moz-opacity: 0;
    -khtml-opacity: 0;
    opacity: 0;

    -webkit-transition: all 0.2s ease-in-out;
    -moz-transition: all 0.2s ease-in-out;
    -o-transition: all 0.2s ease-in-out;
    transition: all 0.2s ease-in-out;
}

Finally, let’s style the hover state. We’ll expand a little bit the width and height of the element (10% larger than the image), and use some margin values to center it. We’ll also set its opacity value to 0.8. Remember that this process will be animated due to the transition value we set before.

.menu-container li a:hover
{
    width: 110%;
    height: 110%;
    margin-top: -5%;
    margin-left: -5%;
    padding: 14%;
    text-decoration: none;

    filter: alpha(opacity=80);
    -moz-opacity: 0.8;
    -khtml-opacity: 0.8;
    opacity: 0.8;
}

Have a look at the demo (or this pen) to see what we’ve just created. You can also download the [download id=”18″ format=”1″].

But, let’s not stop here. Let’s build a…

Vertical version

Transforming the menu to work vertically is extremely easy. The HTML code remains the same. We will only have to set the .menu-container to something smaller than 100%, and set the li element’s width to 100% (adding a small margin fix if it’s required).

.menu-container
{
    width: 13%;
}

.menu-container li
{
    width: 100%;
    float: left;
    margin-top: -2%;
}

Here you go (pen). You can find this version as well in the [download id=”18″ format=”1″].

Removing opacity from text

If you notice, the opacity value is inherited to the text as well, making it a little transparent. I quite like it that way, but since it’s highly likely that someone will want the text to be completely opaque, let’s create a workaround.

We will add the following before setting the anchor element’s opacity values (which are still zero).

.menu-container li a
{
    background-color: rgba(0, 0, 0, 0);
    filter: progid:DXImageTransform.Microsoft.
gradient(startColorStr='#80000000', EndColorStr='#80000000');
    -ms-filter: "progid:DXImageTransform.Microsoft.
gradient(startColorStr='#80000000', EndColorStr='#80000000')";
}

And we will replace the opacity values of the hover state with the following:

.menu-container li a:hover
{
    filter: alpha(opacity=100);
    -moz-opacity: 1;
    -khtml-opacity: 1;
    opacity: 1;

    background-color: rgba(0, 0, 0, 0.7);
    filter:  progid:DXImageTransform.Microsoft.
gradient(startColorStr='#80000000', EndColorStr='#80000000');
    -ms-filter: "progid:DXImageTransform.Microsoft.
gradient(startColorStr='#80000000', EndColorStr='#80000000')";
}

That’s all! This version’s demo is here (pen). As you probably already figured out, you can find this version as well in the [download id=”18″ format=”1″].

For any issues or questions, feel free to post a comment.