demosthenes.info

I’m Dudley Storey, the author of Pro CSS3 Animation. This is my blog, where I talk about web design and development with , and . To receive more information, including news, updates, and tips, you should follow me on Twitter or add me on Google+.

web developer guide

my books

Book cover of Pro CSS3 AnimationPro CSS3 Animation, Apress, 2013

my projects

CSSslidy: an auto-generated #RWD image slider. 3.8K of JS, no JQuery. Drop in images, add a line of CSS. Done.

tipster.ioAutomatically provides local tipping customs and percentages for services anywhere.

Animated CSS3 Navigation With Overlapping Elements

css / navigation

Estimated reading time: 3 minutes, 49 seconds

One of the benefits of being a web development teacher is that I can be inspired by the work of students. That was the case recently in the site of Kalina Whyte, a student in my 2nd year Web Communications class. The navigation she created for the first revision of her portfolio was well-designed, and inspired me to push it further, creating the result you can see here. All of the photographs shown are by Kalina, and used with her permission, with the exception of the “Contact” mail image, which is  by Peter Lee and licensed under Creative Commons.

Kalina’s navigation bar was essentially what you see in the default state: static and unchanging. I thought it could be brought to life with a little CSS.  The approach I used has a lot of similarities to the basic CSS image gallery I’ve demonstrated earlier, with a few differences: I’ve simplified the markup to just a plain series of links with images inside them, within a nav element:

<nav id="k-nav">
<a href="#">Home
<img src="watch.jpg" alt="Photograph of a watch"></a>
<a href="#">About
<img src="kalina-whyte.jpg" alt="Photograph of Kalina Whyte"></a>
<a href="#">Portfolio
<img src="rocks.jpg" alt="Photographs of rocks"></a>
<a href="#">Contact
<img src="mail.jpg" alt="Photograph of air mail envelopes"></a>
</nav>

I wanted the navigation to do two things: have the blue bar to the left of every link grow during a hover, and have the image at the top change with a fade-in. The initial is:

nav#k-nav { border-radius: 20px;
background: #3F3935; float: left;
padding-top: 300px; padding-bottom: 40px;
width: 300px; position: relative;
}
nav#k-nav a { display: block;
color: #CFCECE; text-decoration: none;
border-left: 8px solid #356374;
text-transform: uppercase;
padding: 8px; padding-left: 20px;
border-bottom: 1px dashed #000;
text-shadow: 2px 2px 2px rgba(0,0,0,0.6);
transition: .7s all linear;}

The bar on the left side of each link is created by changing the left border; animating it on hover is therefore pretty easy. We already have the set up in the declaration for the links (to which you’d have to add vendor prefixes for browsers that require them), so all we need to do is indicate the change:

nav#k-nav a:hover { border-left-width: 20px; }

The tricky part is the images. The first thing to do is get them into the correct place: you’ll notice that I placed position: relative on the nav itself, in order to achieve this next step:

nav#k-nav a img { width: 250px; border-radius: 50%;
overflow: hidden; position: absolute;
top: 25px; left: 25px;  opacity: 0; }

That stacks the linked images at the top of the nav element. They’re invisible, due to the fact that opacity is set to 0, and circular, due to the border-radius and overflow: hidden.

Next, I want to make the associated image show up when the user hovers over the correct link, which is also very easy:

nav#k-nav a:hover img { opacity: 1; }

The complication comes from the fact that I want to have one image show by default, to indicate what page the user is on. For example, let’s say we were on the home page: in that case, I want to have the first image visible by default. I have an additional issue: because absolute positioning stacks overlapping elements like playing cards dealt onto a table, the image of the watch is at the bottom of the pile. I need to raise that to the foreground:

nav#k-nav a:first-child img { z-index: 1; opacity: 1; }

(Typically this would be done in an embedded style sheet, as you’d wish different images to be visible on different pages.)

That works, but immediately makes the other navigational images invisible, as they are now underneath the watch image. We’ll change the hover declaration above to compensate:

nav#k-nav a:hover img { opacity: 1; z-index: 2; }

Finally, we need to animate the transition of the fresh images and place a border around their outside edge. You’ll find that simply setting a border doesn’t have the visual quality you might want: the photograph may appear to be “pinched” in the browser, with black gaps on its edges. Instead, we’ll use a special derivation of box-shadow: one with no offset, no blur, only a spread value and a color:

nav#k-nav a img {
width: 250px; border-radius: 50%;
overflow: hidden; position: absolute;
top: 25px; left: 25px;  opacity: 0;
transition: .7s all linear;
box-shadow: 0 0 0 3px #000; }

That’s it! It’s my intention to take this idea much further in future articles: I’d like to thank Kalina for the original inspiration. CodePenPlay with live code for this UI

comments powered by Disqus

This site helps millions of visitors while remaining ad-free. For less than the price of a cup of coffee, you can help pay for bandwidth and server costs while encouraging further articles.