Fixed positioning
Now we have got to the final part of the chapter, covering fixed positioning. position: fixed; positions elements in a similar way to position: absolute; taking them out of the document flow. The difference is that instead of positioning them relative to the nearest positioned ancestor, it positions them relative to the browser window, so they will always stay in the same position inside the window regardless of how much you scroll the page (Figure 21.10).
Figure 21.10: Fixed positioning fixes the position of an element relative to the browser window, so now.img02 will always stay in the same place, no matter how much you scroll the content.
Figure 21.11 shows a good use of fixed position—this is a screenshot of http://www.hicksdesign.co.uk/journal, the blog of designers Jon and Leigh Hicks. The right-hand navigation has been positioned using position: fixed;, so it will always stay in the same position. Check the page out yourself, and subscribe to the Hicks’s RSS feed—there’s some great content on it.
Figure 21.11: A good use of position: fixed;—http://www.hicksdesign.co.uk/journal.
Let’s try to create something similar. I will take the last example and add a navigation menu on the right hand side that always stays in the same position when the page is scrolled. I will also fix the position of the header so it does the same thing. You can see the finished example by loading up fixed_positioning1.html from the code download at http://interactwithwebstandards.com.
Making initial changes to the HTML
To make this design work, I had to make a few changes to the HTML. I first put the header inside its own <div>, outside of the main content wrapper:
<div id="header"> <h1>Simple fixed positioning</h1> </div>
It needs to go outside as I want to scroll the rest of the content underneath this, and I want to stretch it over the whole width of the <body>. CSS is then used to get this the way I want it looking:
h1 { font-family: Futura, Helvetica, Arial, sans-serif; margin-top: 0; padding-top: 0.6em; padding-left: 0.6em; text-shadow: 2px 2px 2px #94d7e3; } #header { height: 100px; background-color: #00A6B9; width: 110%; margin-top: 0; }
The next thing to do is add in the navigation menu, at the top of the main content:
<div id="navigation_menu"> <ul> <li><a href="#">Home</a></li> <li><a href="#">Articles</a></li> <li><a href="#">Tour map</a></li> <li><a href="#">Photos</a></li> <li><a href="#">Contact</a></li> </ul> </div>
Figure 21.12 shows how this currently looks.
Figure 21.12: Our new additions, near the beginning of the project.
I also added some extra content at the end of the page, to give you some more space to play with the scrolling effect.
Fixing the header and menu position
The next step is to fix the positions of the header and menu. This was done via the following rules:
#header { height: 100px; background-color: #00A6B9; width: 110%; margin-top: 0; position: fixed; } #navigation_menu { position: fixed; top: 5.5em; left: 36.5em; }
There is not much to explain with the first rule—the #header rule has simply had a position: fixed; declaration added to it; we don’t want to change the position of it at all—we just want it to be fixed in place.
With the #navigation_menu, things are a bit more complicated. I’ve added position: fixed; to it, but I’ve also used top and left to make sure that it is positioned in the right-hand column.
This gets the elements in the position we want them, but there are a couple of problems (Figure 21.13). For a start, setting the header and navigation to have position: fixed; takes them out of the document flow, so the top of the content starts off hidden underneath the header! Second, when you start to scroll the content upwards, you’ll see that the images actually go over the top of the header!
Figure 21.13a: Our content starts off hidden.
Figure 21.13b: Now the images scroll over the top of the heading.
To start off, let’s tackle the content overlapping problem. This is easy to solve—I’ve added an ID of #first to the first paragraph of the content, and given it top padding to shift it downwards so it starts below the header:
#first { padding-top: 100px; }
Now we’ll address the image problem. This brings us nicely on to the subject of z-index. “What on earth is z-index?” I hear you cry. Read on, brothers; read on, sisters...
Understanding z-index—the third dimension
As this is a pretty advanced topic that you’ll only really run into when dealing with positioning, it is only natural to cover it near the end of the book. If you thought that HTML and CSS web pages were two-dimensional, then you wouldn’t be completely accurate. In fact, different elements sit at different depths to one another, closer and farther away from your nose as you look at the screen; the z-axis, as it were. We are still talking about flat bits of content, but the order in which they’re put on the screen (the source order in the HTML) determines which overlaps which by default.
To explain this in a bit more detail, positioned elements (including relatively positioned elements) are rendered within something known as a stacking context. Elements within a stacking context have the same point of reference along the z-axis. You can change the position along the z-axis—also known as z-position or stack level—of a positioned element using the z-index property.
z-index takes a positive or negative integer as a value—the higher the integer, the closer the element to your nose. The default value is auto, which means the element will have the same stack level as its parent. You should note that you can only specify an index position along the z-axis—you can’t make one element appear 19 pixels behind or 5 centimetres in front of another! Think of it like a deck of cards: you can stack the cards and decide that the ace of spades should be on top of the three of diamonds.
Setting a really high z-index value will not cause your web pages to poke your site visitors in the eye.
If you specify the z-index as a positive integer, you assign it a stack level in front of other elements within the same stacking context that have a lower stack level. A negative integer value for z-index assigns a stack level behind the parent’s stack level. When two elements in the same stacking context have the same stack level, the one that occurs later in the source code will appear on top of its preceding siblings. The browser draws the elements on the page starting from the one with the lowest z-index, going up to the one with the highest z-index.
There can in fact be up to seven layers in one stacking context, and as many different z-indices in those layers as you want, but don’t worry—you are unlikely to have to deal with seven layers in a stacking context. The order in which the elements (all elements, not only the positioned ones) within one stacking context are rendered, from back to front, is as follows:
- The background and borders of the elements that form the stacking context.
- Positioned descendants with negative stack levels.
- Block level descendants in the normal flow.
- Floated descendants.
- Inline level descendants in the normal flow.
- Positioned descendants with the stack level set as auto or 0 (zero).
- Positioned descendants with positive stack levels.
The bold entries are the elements whose stack level we can change using the z-index property.
Going back to our example, to cause our images to behave and stay behind the header, we just need to set a higher z-index value on the header:
#header { height: 100px; background-color: #00a6b9; width: 110%; margin-top: 0; position: fixed; z-index: 3; }
This has solved our problems (Figure 21.14).
Figure 21.14: Now our example is behaving itself.
Adding extra refinements
There are a couple of other features in the code that I haven’t yet covered, so let’s go over these now. First, I have given two of the navigation menu list items a class of shifted:
<ul> <li><a href="#">Home</a></li> <li class="shifted"><a href="#">Articles</a></li> <li><a href="#">Tour map</a></li> <li class="shifted"><a href="#">Photos</a></li> <li><a href="#">Contact</a></li> </ul>
I then apply a rule to these to slightly displace them to the left, using relative positioning:
.shifted { position: relative; right: 10px; }
I’ve also decided to style the menu items a bit more by removing the bullets and colouring them a silvery-gray colour:
#navigation_menu li a { color: gray; } #navigation_menu li { list-style-type: none; }
This creates the effect seen in Figure 21.15. As I’ve mentioned a couple of times now in the chapter, this combination of positioning inside positioning can be used to create some very precise irregular layout/design features. As always, the best way to find out what is possible is to experiment with these techniques!
Figure 21.15: A jaunty navigation.
The second is somewhat of a hidden treasure. To find it, try narrowing the browser window slowly but surely. If you are using Firefox, Opera or Safari, eventually you’ll see the change documented in Figure 21.16.
Figure 21.16: Magic shifting menu action.
This is due to the fact that I have implemented a CSS3 media query at the bottom of my CSS:
@media all and (max-width: 760px) { #navigation_menu { top: 2.6em; left: 0em; z-index: 4; min-width: 600px; } #header { min-width: 600px; } #navigation_menu li { display: inline; } #navigation_menu li a { color: grey; } .shifted { right: 0px; } }
This is a CSS3 feature that allows you to selectively apply CSS rules depending on whether a certain criterion is met. In this case, the above block says “If the browser width goes below 760 pixels, apply the rules inside the @media block.”