March 26th, 2008 - by Paul OB

Keep scrollin’, scrollin’, scrollin’,
Though the streams are swollen,
Keep them images scrollin’, rawhide.

No, I haven’t gone mad yet – it’s just been a long day and I couldn’t think of a suitable tag line so I just burst into song. As you may have guessed I’ve got a bad case of the scrolls today but the doctor says I’ll be fine.

Let’s get to the point before you run for the door. This week we will look at how to create an element where the inner content is larger than the parent. We’ll also look at how by using the overflow property on the parent we can arrange for scrollbars to appear so that the inner content can be viewed.

This may seem like a very simple task. However, there’s more to this than may be anticipated so bear with me and I think we can all learn something along the way. As usual let’s start by viewing the finished result so that you have a good idea of what we are going to achieve. Here is a screenshot of the finished result.

Figure 1
scroll-fig0.png

Overflow

Most of you probably know how to do this already, but what makes the demo slightly more interesting is that the width of the inner element is undefined and therefore can accommodate any number of images that may, for example, be drawn from a database. Although at first sight you may think that this will be easy to accomplish, the truth of the matter is that if you don’t specify a width for the inner element then the inner elements will just wrap at the end of the line as per normal and no scrollbar will appear even if we have set overflow to auto.

The usual way to make a container produce scrollbars when the inner content is greater than the parent is to specify overflow:auto or overflow:scroll. This usually means that both elements should have widths defined otherwise there will be nothing to trigger an overflow. (The value “auto” means apply scrollbars when necessary and the value “scroll” means stick them on the element now so that we can see them right away.)

In our example we will define a width for the outer but we want the inner elements to be width auto so that we can have as many images as required because as stated above they may be coming from our database and we just don’t know how wide our inner container needs to be.

Let’s start at the beginning and work our way through this one step at a time.

Draw the box and place some images inside.

The first thing we need is a box to hold our images and then we’ll drop our images inside the box. As images are inline elements they should line up horizontally quite nicely. To keep things semantic we will use a list to hold all the images, but since a list is display:block by default we will set it to display:inline instead and that will allow the images to line up horizontally as we wanted.

  1. * {margin:0;padding:0}
  2. img{border:none}
  3. #outer{
  4.     width:760px;
  5.     margin:auto;
  6. }
  7. ul{list-style:none;padding:5px;}
  8. .wrap {
  9.     border:5px solid #ccc;
  10.     width: 520px;
  11.     overflow: auto;
  12.     padding-bottom:14px;
  13. }
  14. .wrap li {
  15.     margin:0 10px;
  16.     display:inline;
  17. }
  1. <div id="outer">
  2.     <h1>Sideways Scroll</h1>
  3.     <div class="wrap">
  4.         <ul>
  5.             <li><a href="#"><img src="images/zimg7-small.jpg" width="100" height="100" alt="example image" /></a></li>
  6.             <li><a href="#"><img src="images/zimg7-small.jpg" width="100" height="100" alt="example image" /></a></li>
  7.             <li><a href="#"><img src="images/zimg7-small.jpg" width="100" height="100" alt="example image" /></a></li>
  8.             <li><a href="#"><img src="images/zimg7-small.jpg" width="100" height="100" alt="example image" /></a></li>
  9.             <li><a href="#"><img src="images/zimg7-small.jpg" width="100" height="100" alt="example image" /></a></li>
  10.             <li><a href="#"><img src="images/zimg7-small.jpg" width="100" height="100" alt="example image" /></a></li>
  11.             <li><a href="#"><img src="images/zimg7-small.jpg" width="100" height="100" alt="example image" /></a></li>
  12.             <li><a href="#"><img src="images/zimg7-small.jpg" width="100" height="100" alt="example image" /></a></li>
  13.         </ul>
  14.     </div>
  15. </div>

So to start with we have set a width on our outer container (.wrap) and set the overflow to auto. That should allow scrollbars to appear when the inner content exceeds the dimensions of the parent. (I have used the same image in the demo because I was lazy but of course you would use different images, although for this demo you should keep the thumbnails the same size to make it look nice.)

If we run the above code we come across the first problem which is that as soon as the image meets the edge of the container it wraps to another line. This is shown in Figure 2 below.

Figure 2
scroll-fig1.jpg

To make all the images stay on the same horizontal line we could set a width for the parent UL, but this only works if you know how many images you’ll have. We want to be more fluid (dynamic) and have it work with an unknown amount of images. A simple solution for the demo so far would be to use the white-space property and set it to a value of nowrap which will hold the inline elements all on one line without wrapping as the value suggests.

We add it to .wrap as shown below:

  1. .wrap {
  2.     border:5px solid #ccc;
  3.     width: 520px;
  4.     overflow: auto;
  5.     padding-bottom:14px;
  6.     white-space:nowrap;
  7. }

The result of this change gets us closer to what we are looking for as shown in Firefox 2.0 in Figure 3 below:

Figure 3
scroll-fig2.jpg

However if we look in IE we see that we get a horrible vertical scrollbar which we don’t want.

Figure 4

scroll-fig3.jpg

This spoils the effect slightly so we are going to use some CSS3 (which was previously proprietary IE only code) and hide the vertical scrollbar. We will use conditional comments to apply this style for IE only so as not to upset anyone else.

  1. <!--[if IE ]>
  2. <style type="text/css">
  3. .wrap{overflow-x:auto;overflow-y:hidden}
  4. </style>
  5. <![endif]-->

We use overflow-y:hidden to remove the vertical scrollbar. Of course this means that we will have to make sure there is always enough vertical room for our content or it will stay hidden when it does go below the fold.

That cures IE and we now get the result as seen in Figure 3 for both Firefox and IE (and other browsers).

Captions

So far in a few simple lines of CSS and HTML we have managed to create a fluid width gallery that can hold as many images as needed and they can be scrolled left and right all along the same horizontal line. However, most times when you have this type of effect you will also want to have an image caption under the image as well. Therefore let’s add a caption under the image and see what happens.

  1. <li><a href="#"><img src="images/zimg7-small.jpg" width="100" height="100" alt="example image" /><br />Image Name</a></li>

I have just inserted a break after the image so that the caption is underneath the image. This immediately has the effect of destroying the layout as seen in Figure 5 below.

Figure 5
scroll-fig5.jpg

Of course you knew this was going to happen didn’t you?

The break we inserted obviously creates a new line so the text starts on the line below and then appears to refer to the wrong image as the next image in line lines up alongside the text. We need some way to have the image and the text treated as one block and for each block to still remain horizontal. “Ahaa” I hear you say, “we can simply float the blocks”.

If we add the following CSS to our stylesheet we can have the image and the text float nicely across the screen.

  1. .wrap li {
  2.     margin:0 10px;
  3.     display:inline;
  4.     float:left;
  5. }

Although this works well we seem to be back at square one because the floats will not honor the white-space:nowrap as that only applies to inline elements and the floats simply wrap at the end of each line and we loseWeight Exercise our horizontal scrollbar.

Figure 6
scroll-fig6.jpg

We could address this by setting a width on the UL and then everything would be fine.

  1. ul{
  2.     list-style:none;
  3.     padding:5px;
  4.     width:980px;/* width added */
  5. }

Figure 7
scroll-fig7.jpg

But we don’t want to set a width on the UL because that won’t allow for a variable number of images to be used so we need another approach.

The first method I am going to show is one that we have used before and involves using display:inline-block. As Firefox 2.0 doesn’t understand display:inline-block we are going to use display:-moz-inline-box which is a Vendor Specific Extension for gecko browsers and performs much the same as display:inline-block for our purposes.

Although I generally don’t like using these extensions there is no avoiding the fact that they can be useful at times. Therefore you must always weigh the risks yourself when using proprietary code.

I should also mention at this point that IE doesn’t understand display:inline-block when used on block elements but there is a fix also for IE which is effectively setting “haslayout” to be true while also setting the element to display:inline. We do this strangely enough by using firstly display:inline-block (which is a haslayout trigger) and then setting the element to display:inline in the next rule. (Read the full explanation in this previous article as to how this works.)

Here is the extra code needed for Firefox, Opera Safari etc.

  1. .wrap li {
  2.     margin:0 10px;
  3.     text-align:center;
  4.     display:-moz-inline-box; /* gecko*/  
  5.         display:inline-block;/* opera and safari*/            
  6.     padding:5px;
  7.     margin:5px;
  8. }

And here follows the IE fix which we’ll place in the conditional comments along with the scrollbar fix from earlier.

  1. <!--[if IE ]>
  2. <style type="text/css">
  3. .wrap{overflow-x:auto;overflow-y:hidden}
  4. .wrap li{display:inline}
  5. </style>
  6. <![endif]-->

If you refer to Figure 7 above you will see that the images have underlines underneath them because they are anchors. We want the underline underneath the text but not under the images. We can cure this simply by setting the image to display:block and the underline will only appear at the bottom under the text. At the same time we should also avoid the horrible blue border around images that browsers put on linked images by default.

  1. img{border:none;display:block}

As I don’t like using multiple breaks in the HTML because they are hard to control I am going to wrap the text in a span instead — we can then keep complete control from the stylesheet. To set the text on a new line we set the span to display:block and then align the text to the center as follows.

  1. .wrap li a,.wrap li a span{
  2.     display:block;
  3.     text-align:center;
  4. }
  1. <li><a href="#"><img src="images/zimg7-small.jpg" width="100" height="100" alt="example image" /><span>Image Name</span></a></li>

The result of all the above changes can be seen in the following demo. Just view source for the full code.

Rollover

You may notice that the demo shows a rollover effect — this is accomplished with a few lines of CSS as follows:

  1. .wrap li a{
  2.     background:url(images/zimg7-small-over.jpg) no-repeat 0 0;
  3. }
  4. .wrap li a:hover{visibility:visible}
  5. .wrap li a:hover img{visibility:hidden}

We create a background image of the correct size that is placed in the anchor and then on hover we simply set the image’s visibility property to the value “hidden” and that allows the anchors background to show through. The visibility:visible style is an IE6 fix as it needs a little helping hand to effect the change on the image. Obviously if all your images were coming from a database then you wouldn’t want to do a background rollover like this as it would be far too complicated and would not be worthwhile.

Take Two

As mentioned earlier there is another way of getting this horizontal effect and instead of using display:-moz-inline-box we can use display:table and display:table-cell which is valid CSS and not a Vendor Specific Extension. IE7 and under will still need the old method though as they don’t understand display:table (but IE8 will be able to as it has been added into IE8).

The change in code is as follows:

  1. .wrap ul{
  2.     padding:5px 25px;
  3.     display:table;
  4. }
  5. .wrap li {
  6.     margin:0 10px;
  7.     text-align:center;
  8.     display:table-cell;          
  9.     padding:5px;
  10.     margin:5px;
  11. }

The ul is set to display:table and the list items are set to display:table-cell which gives the horizontal effect we need. IE would then need an extra style in the conditional comments as we have removed the “haslayout” trigger which was display:inline-block.

  1. <!--[if IE ]>
  2. <style type="text/css">
  3. .wrap{overflow-x:auto;overflow-y:hidden}
  4. .wrap li {display:inline-block}
  5. .wrap li{display:inline}
  6. </style>
  7. <![endif]-->

Just to show it does work here’s the Live version. So as you can see we have two ways of doing the same thing; this is usual for CSS as there is always another way of doing something.

Fade Away

If you refer to the original finished version that I showed right at the start you will see that I have added a couple of elements to tidy it all up. Look closely at the right and left edges of the box and you can see that the image fades away before it gets clipped at the edges of the container. This is accomplished by adding a transparent PNG that fades from 0 -100% opacity at each end of the container.

I’ll quickly explain how to do this for those of you that are interested.

Firstly make your PNG images in your paint package and set the opacity to fade from 0 -100%. You will need 2 images because the image on the left side will fade from right to left and the image on the right side will fade from left to right. I made the images 80px wide and high enough to provide a fade for the image and the text below.

In order to place these images at each end we will need to create another wrapper for the scrollbox and set it to position:relative — this will allow us to easily place the PNG fade images over each end of the scrollbox.

Here is the relevant CSS and HTML only:

  1. .fade{
  2.     width:630px;
  3.     position:relative;
  4.     z-index:1;
  5. }
  6. .fade .lfade,
  7. .fade .rfade{
  8.     position:absolute;
  9.     top:10px;
  10.     width:60px;
  11.     height:135px;
  12.     z-index:999;
  13. }
  14. .fade .lfade{
  15.     left:5px;
  16.     background:url(images/left-fade2.png) no-repeat 100% 0;
  17. }
  18. .fade .rfade{
  19.     right:5px;
  20.     background:url(images/right-fade2.png) no-repeat 0 0;
  21. }
  1. <div id="outer">
  2.     <h1>Sideways Scroll</h1>
  3.     <div class="fade">
  4.         <div class="wrap">
  5.             <ul>
  6.                 <li><a href="#"><img src="images/zimg7-small.jpg" width="108" height="108" alt="example image" /><span>Image Name</span></a></li>
  7.                 <li><a href="#"><img src="images/zimg7-small.jpg" width="108" height="108" alt="example image" /><span>Image Name</span></a></li>
  8.                 <li><a href="#"><img src="images/zimg7-small.jpg" width="108" height="108" alt="example image" /><span>Image Name</span></a></li>
  9.                 <li><a href="#"><img src="images/zimg7-small.jpg" width="108" height="108" alt="example image" /><span>Image Name</span></a></li>
  10.                 <li><a href="#"><img src="images/zimg7-small.jpg" width="108" height="108" alt="example image" /><span>Image Name</span></a></li>
  11.                 <li><a href="#"><img src="images/zimg7-small.jpg" width="108" height="108" alt="example image" /><span>Image Name</span></a></li>
  12.                 <li><a href="#"><img src="images/zimg7-small.jpg" width="108" height="108" alt="example image" /><span>Image Name</span></a></li>
  13.                 <li><a href="#"><img src="images/zimg7-small.jpg" width="108" height="108" alt="example image" /><span>Image Name</span></a></li>
  14.                 <li><a href="#"><img src="images/zimg7-small.jpg" width="108" height="108" alt="example image" /><span>Image Name</span></a></li>
  15.                 <li><a href="#"><img src="images/zimg7-small.jpg" width="108" height="108" alt="example image" /><span>Image Name</span></a></li>
  16.                 <li><a href="#"><img src="images/zimg7-small.jpg" width="108" height="108" alt="example image" /><span>Image Name</span></a></li>
  17.             </ul>
  18.         </div>
  19.         <p class="lfade"></p>
  20.         <p class="rfade"></p>
  21.     </div>
  22. </div>

The faded sections are now positioned correctly at each end and as the images are scrolled they pass under the faded PNG and then fade out gradually. IE6 doesn’t understand PNG transparency so we will have to use the alpha image loader filter (more proprietary CSS) and apply a fix for IE6 only (IE5 doesn’t know how to use the filter but IE5.5. does).

Here is the nasty hack for IE.

  1. <!--[if lt IE 7]>
  2. <style type="text/css">
  3. .fade .lfade{
  4.     background:none;    filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/left-fade2.png',sizingMethod='scale');
  5. }
  6. .fade .rfade{
  7.     background:none;    filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/right-fade2.png',sizingMethod='scale');
  8. }
  9. </style>
  10. <![endif]-->

I have just given conditional comments to all IE versions less than IE7 (I don’t care about IE5 not working with it). When using the alpha image loader filter you must be sure to cancel out any background properties as they are not compatible with the filter. You should know that the filter is not a substitute for the background property and has no methods for positioning or repeating images. It can only use special attributes which are “image”, “scale” and “crop”.

The “image” attribute should be used when images are displayed at image size within the element. The “scale” attribute will scale the image to the size of the element it sits in. “Crop” will crop the image to the element’s size. I will not go in to more detail here on its use but you can find out more here in this CSS Reference.

Referring to the demo, you can see that I have added one final touch and that is to add a fixed message under the scrolling images but still apparently inside the scrollable box. In fact the message isn’t really inside the box I have just placed it there absolutely from outside of the box and therefore it appears to be fixed.

  1. .message{
  2.     position:absolute;
  3.     background:#809900;
  4.     color:#fff;
  5.     font-weight:bold;
  6.     top:73%;
  7.     left:25%;
  8.     width:50%;
  9.     text-align:center;
  10.     z-index:999;
  11.     padding:2px;
  12.     border:2px inset red;
  13. }
  1. </div>
  2.         <p class="lfade"></p>
  3.         <p class="rfade"></p>
  4.         <p class="message">Sideways Scroll Demo</p>
  5.     </div>
  6. </div>
  7. </body>
  8. </html>

Caught by a bug.

This worked very well until I uploaded it to write this article!!!

Viewing the page in Firefox 2 while online showed the following error on first page load.

Figure 8
scroll-fig8.png

In Firefox only the second image was dropping to a new line on first visiting the page. If the page was visited a second time or refresh was clicked then the page loaded perfectly. This proved a difficult bug to fix as nothing logical seemed to work.

The only times I have seen this before in Firefox is when images (or dynamic content) are used and the images don’t have their width and height attributes in the HTML. However this was not the case in this demo and I needed to find another answer (and I needed it now or I’ve just wasted a day writing this).

In the end I found a solution although it makes little logical sense to me. The solution was to set the main parent of the page to have position:relative added but also to have a background color set. The fix only works when both are set together.

  1. #outer{
  2.     width:630px;
  3.     margin:auto;
  4.     position:relative;
  5.     background:#809900;
  6. }

Now the page works well on every visit and there is no dropping of the content. I can’t give you an answer as to why this should fix it other than that it triggers a slightly different rendering algorithm and to tell you the truth I don’t really care as long as it’s working now.

The final result is here and you should view source for the full code rather than grabbing all the snippets I’ve posted above.

Here is a screenshot of the completed layout again.
Figure 9
scroll-fig0.png

That about wraps it up for this article and I hope you have enjoyed the journey. Although I said this was basic stuff we have covered a lot of concepts and I hope most of you will find at least something interesting in the above. Of course the next step would be to provide a main image to be viewed from your gallery but there are plenty of “Light box” scripts (or similar) available that can do that for you.

Until next time just keep scrollin’, scrollin’, scrollin’…….

22 Responses to “Scrolling, Scrolling, Scrolling”

1 Mauricio Samy Silva

Congrats!
Another great, useful and well explained Paul’s article.
I think we can get rid of the *div.wrap* container for de UL element that holds the images, since UL is itself a container.
so *ul.wrap* does the job.
Or, am I missing something?

2 Golgotha

I like the fade away PNGs – nice touch.

The only times I have seen this before in Firefox is when images (or dynamic content) are used and the images don’t have their width and height attributes in the HTML.

I have experienced that too and it pisses me off…

Good tutorial Paul.

3 Paul OB

Thanks Mark :)

@Mauricio -Thanks and yes you are correct we could lose the element named wrap. It was only in the code for the earlier example where I gave the UL a width to force the scrollbar on .wrap

Here is an example with .wrap removed(although box model hacks will now be needed for IE5.x of course).

http://www.pmob.co.uk/search-this/scroll12.htm

Thanks for the comments :)

4 Paul OB

@Mauricio – It seems that removing that extra wrapper has resulted in the second image dropping down in Firefox on first page visit as mentioned earlier in the article. Therefore it looks like the extra wrapper is needed to stabilize Firefox.:(

5 Golgotha

That’s the type of CSS stuff that can drive you mad. It’s like WTF…

That may be a good article to write Paul, CSS stuff that makes you think WTF :)

6 Patrick Burt

Looks cool, very interesting. Very good alternative to say something like Flash..

7 raza

dude.

i was going to find and kill each developer of ie6 personally.

you made my day.

many many thanks.

-raza

8 Paul OB

I just noticed that a slight change is need for IE8 to work so I have updated the example here to include the ie8 fix.

http://www.pmob.co.uk/search-this/scroll12.htm

9 Craig

I’ve just spent the last 24 hours trying to do this and i must have looked at every single possible layout, and then I found this page . awesome, absolutely awesome. If it’s ok with you im going to use the layout in my site but will give credit to you.

Cheers m8

10 Duncan77

… and what was the critical fix needed to get IE8 to work? I’ve looked through the two source files and it wasn’t obvious.

Duncan77

11 Duncan77

Sorry – just worked it out: it’s the display: table-row and display: table-cell rules.

Duncan77

12 Paul OB

Yes Duncan77 that was it :) Sorry I didn’t make it clearer.

13 Rembrant

Dear Paul,

Thank you for your great tutorial! It’s been a great help to me and a very good read in general.

I was trying it out myself but I stumbled upon some strange behaviour if you insert this concept into a fully fluid layout. Safari Firefox and IE just jumble up the page completely, each in it’s own way.

Do you think there would be a solution to use exactly this concept but have the heights of the wrapper, ul, il and img be fluid (so, defined in % of each other) and all widths, except for the wrapper, be undefined? (so to allow fully dynamic database content).

It seems like this could be a great solution to make a horizontally scrolling image gallery/creative portfolio that can adapt to any screen size (I’m thinking mobile devices here for example) and follow along the w3c guidelines. If only I could figure out how to do this without scrambling the whole layout.

e.g. This site ( http://www.landonmetz.com/ ) uses the concept that I have in mind except that:
1. It uses tables
2. The images aren’t fluid

Yours sincerely,

– Rembrant

14 Paul OB

Hi Rembrandt,

The width of the scrolling box is a fluid width and is not defined anywhere. That was the main point of the demo :)

It will be as wide as the content that you specify. The same applies to the height.

I only gave a width to the “parent” container to provide the visual effects I wanted. Without a width the element would be viewport (or parent container) width what ever that may be.

It works fine without a width so you must mean something else as the site you linked to doesn’t seem to have anythng in common with the demo unless I’m misunderstanding something :)

15 Brian

Is there a way to make this work on mobile browsers such as Safari for the iPhone?

16 Paul OB

@Brian: This should work on the iphone as it is. You just have to remember that the iphone needs a 2 finger scroll for any elements that should have a scroll bar.

Of course the iphone doesn’t show the scrollbar which makes it hard for users to realise they need to use a 2 finger scroll and indeed most don’t know about it anyway.

17 Sarah

How do you get this to work in IE 9?

18 Sarah

Sorry I think my problem is actually related to a Jquery plugin compatibility issue with IE.

19 Paul OB

Hi Sarah,

Yes there is a bug in Ie9 (the article is 5 years old now) and I’ve updated the main example here:

http://www.pmob.co.uk/search-this/scroll11.htm

The conditional comments were targeting IE9 in error and there was a bug with the hover effect.

20 Caleb

No matter how I try to do this I get two rows of images. I am down to just straight copy paste and I cant avoid the extra row.

21 Caleb

By the way, I am very new to this, you are like CSS god to me right now.

22 Paul OB

Hi Caleb,

If you view source of the demo : http://www.pmob.co.uk/search-this/scroll11.htm

Then grab the code from there as there were some minor changes since the article was written (5 years ago).

mulberry sale spyder womens jacket cheap new balance 574 mulberry outlet cheap new balance 574 arcteryx outlet mulberry sale spyder womens jacket mulberry sale spyder womens jacket mulberry outlet mulberry outlet new balance 574

Popular Articles

Top 10 Commentators


Subscribe to this feed! Subscribe by Email!

Random Bits Podcast

You need to download the Flash player from Adobe

Blogs Worth Reading