Bespin Concept Defrag Command; Exploring some fun visualizations Google App Engine and The Java Web; The Wrong Java?
Apr 06

Creating custom scrollbars with CSS; How CSS isn’t great for every task

Ajax, Bespin, JavaScript, Web Browsing with tags: , , Add comments

Have you tried to create a nice rich experience and then been fighting the “defaults” to go the extra mile? This reared its head with me recently with Bespin. There are certain commands that pull up divs of content and we need to scroll through it. The problem is that the native scroll bar looks so out of place:

uglyscrollbar

WebKit recently released the ability to style scrollbars in HTML elements (but not the main window, which you have been able to do in IE for donkeys years much to many peoples chagrin).

I decided to take it for a spin and loaded up the examples that show you being able to do every type of scrollbar that you can imagine:

manyscrollbars

So, it shouldn’t be so hard should it. From the blog post I see a few magically ::-webkit-scrollbar CSS properties that I can plugin and be on my way. But looking at the example view source you see many pieces like this:

:not(.none):not(.double-start)::-webkit-scrollbar-track-piece:vertical:end:single-button,
:not(.none):not(.double-start)::-webkit-scrollbar-track-piece:vertical:end:double-button,
.single::-webkit-scrollbar-track-piece:vertical:end,
.double-end::-webkit-scrollbar-track-piece:vertical:end,
.double-both::-webkit-scrollbar-track-piece:vertical:end {
    margin-bottom: -6px;
}

Holy pseudo classes batman! To be fair, this is partly due to the example page having many types of scrollbars in one (hence the not this and not that but the other) but there are still nested classes that you need to grok to get this going.

I quickly built a debug scrollbar where I styled the various pieces with simple colors and borders so I can see which was which. I also went about making the scrollbar have one up arrow on top, and one down arrow on the bottom.

debugscrollbar

The parts and pieces of a scrollbar are quite simple:

  • Thumb: This is the piece that shows you where you are in the scrollbar. This is the chap that you can move around
  • Track: This is the area of the scrollbar that you can move the thumb up and down, or along (depending on the orientation). There is both the area between the top and the thumb, and between the bottom of the thumb and the bottom of the scrollbar
  • Buttons: There may be buttons that you can click to increment or decrement the selection (which moves the thumb). There are various styles (single button, double button, etc)
  • Resizer: This can change the are of the element (e.g. enlarge of shrink)
  • Corner: This area may show up with both horizontal and vertical scrollbars open

The debug scrollbar kinda shows these areas off in a simple visual way. Note how using display: block|none enabled me to setup the single button on top and bottom functionality:

/* Turn on a 13x13 scrollbar */
::-webkit-scrollbar {
    width: 13px;
    height: 13px;
}
 
::-webkit-scrollbar-button:vertical {
    background-color: red;
    border: 1px dashed blue;
}
 
/* Turn on single button up on top, and down on bottom */
::-webkit-scrollbar-button:start:decrement,
::-webkit-scrollbar-button:end:increment {
    display: block;
}
 
/* Turn off the down area up on top, and up area on bottom */
::-webkit-scrollbar-button:vertical:start:increment,
::-webkit-scrollbar-button:vertical:end:decrement {
    display: none;
}
 
/* Place The scroll down button at the bottom */
::-webkit-scrollbar-button:vertical:increment {
    background-color: black;
    border: 1px dashed blue;
}
 
/* Place The scroll up button at the up */
::-webkit-scrollbar-button:vertical:decrement {
    background-color: purple;
    border: 1px dashed blue;
}
 
::-webkit-scrollbar-track:vertical {
    background-color: blue;
    border: 1px dashed pink;
}
 
/* Top area above thumb and below up button */
::-webkit-scrollbar-track-piece:vertical:start {
    border: 1px solid #000;
}
 
/* Bottom area below thumb and down button */
::-webkit-scrollbar-track-piece:vertical:end {
    border: 1px dashed pink;
}
 
/* Track below and above */
::-webkit-scrollbar-track-piece {
    background-color: green;
}
 
/* The thumb itself */
::-webkit-scrollbar-thumb:vertical {
    height: 50px;
    background-color: yellow;
}
 
/* Corner */
::-webkit-scrollbar-corner:vertical {
    background-color: black;
}
 
/* Resizer */
::-webkit-scrollbar-resizer:vertical {
    background-color: gray;
}

By moving the scrollbar around I could quickly see how this all worked, and it got me to this point which enabled me to plugin the images to make this puppy work for Bespin:

bespinscrollbar

There were a couple of key tweaks needed to make this work:

Getting the buttons working

I used the same trick used in the debug example to turn on the up area above, and the down area below, and then it was just a matter of targeting the correct area for the arrow images:

/* Turn on single button up on top, and down on bottom */
::-webkit-scrollbar-button:start:decrement,
::-webkit-scrollbar-button:end:increment {
    display: block;
}
 
/* Turn off the down area up on top, and up area on bottom */
::-webkit-scrollbar-button:start:increment,
::-webkit-scrollbar-button:end:decrement {
    display: none;
}
 
/* Place The scroll down button at the bottom */
::-webkit-scrollbar-button:end:increment {
    background-image: url(images/scroll_cntrl_dwn.png);
}
 
/* Place The scroll up button at the up */
::-webkit-scrollbar-button:start:decrement {
    background-image: url(images/scroll_cntrl_up.png);
}

Get the track pieces to show

Next up was getting the gutter to show up. As mentioned early on, there is one track, but two areas that can show…. before the thumb and after. You can target these areas via -webkit-scrollbar-track-piece:start || :end and then it is a matter of using the multiple background ability available in new browsers. First we have the top of the gutter, and then a recurring background (and the same for the bottom). This way it just grows with the area that it gets:

/* Top area above thumb and below up button */
::-webkit-scrollbar-track-piece:vertical:start {
    background-image: url(images/scroll_gutter_top.png), url(images/scroll_gutter_mid.png);
    background-repeat: no-repeat, repeat-y;
}
 
/* Bottom area below thumb and down button */
::-webkit-scrollbar-track-piece:vertical:end {
    background-image: url(images/scroll_gutter_btm.png), url(images/scroll_gutter_mid.png);
    background-repeat: no-repeat, repeat-y;
    background-position: bottom left, 0 0;
}

The Thumb

To get the thumb working, I thought I would do the same background image trick with three images (top of thumb, bottom of thumb, and background for the middle). Unfortunately this didn’t seem to work for me as I couldn’t get the middle to not go through the top and bottom. So, instead, I went with another new CSS trick: border-image. Here I splice the top and bottom of a thumb (the top and bottom 8 pixels) and stretch the rest:

/* The thumb itself */
::-webkit-scrollbar-thumb:vertical {
    height: 56px;
    -webkit-border-image: url(images/scroll_thumb.png) 8 0 8 0 stretch stretch;
    border-width: 8 0 8 0;
}

John Resig has a nice readable post on border-image.

And, there you have it. Now we can have nice Bespin-y scrollbars throughout Bespin. This may not be complete though, as we have the ability to also tie in :active and :hover work if we wish (change the color when selecting etc).

Of course, many people had “custom scrollbars”. There are plenty of comments on the original Surfin’ Safari post, and various rants about Flash versions. I agree that we have all seen bizarre Flash versions of scrollbars that don’t look like them at all, and where the designer didn’t bother to put in support for the mousescroll ability etc, but this is a bit different. It let’s you merge in your look and feel, yet with native scrollbar functionality.

And, with Google recreating the button maybe we can feel a little bit better about tweaking the look of common UI elements as long as they are familiar enough to users to still make natural sense.

Now, the CSS declarative way to do scrollbars seems to get pretty ugly to me with all of he pseudo classes and various magic to get the functionality that you would like. I have to admit to liking Kevin’s demo of Flash Catalyst at Web 2.0 Expo and how it lets designers build out a scrollbar. We should be inspired to do tools like this. What if we had an API that wasn’t CSS, but let us say: “I want a Mac style double on the bottom button scrollbar. And, here is a thumb, here is a track, go for it”.

That being said, at least we do have the ability to do this kind of thing now. I hope that other browsers follow WebKit in this instance.

22 Responses to “Creating custom scrollbars with CSS; How CSS isn’t great for every task”

  1. Ted Mielczarek Says:

    Personally I find Google’s reskinned buttons annoying. Firefox goes out of its way to render buttons the way your OS intends, and they throw all that away? Similarly, I don’t personally like reskinned scrollbars.

  2. dion Says:

    Ted,

    This is what user styles are for? I like having the developer able to do what he feels is best, and then having the user, who knows best how HE feels, to be able to override anything.

    Cheers,

    Dion

  3. David Kaneda Says:

    I can see how custom scrollbars are a controversial topic, but I think they’re well worth it. Browser default bars are extremely intrusive, especially when used with overflow:auto for web apps. I often end up resorting to a jQuery plugin. For instance, see this page recently completed: http://www.upenn.edu/curf/fellowships/fellowships-directory – The overflow section helps simplify the page design, by providing a scrollable list, but a default scroll bar would have totally interrupted the page flow.

    PS. Dion, lovely style for Bespin, there. Will have to get something like that on WebKitBits…

  4. Jaap Says:

    With the right amount of squeezing you’d probably be able to get those images in there as data uri’s ;-)

  5. dion Says:

    @David,

    I agree!

    @Jaap,

    Ohhhhh very cool idea :)

  6. Robert Schultz Says:

    Any chance of an ‘after’ screenshot that shows the same view you showed at the beginning of the article but with the new themed scrollbar? :)

  7. Augustin Says:

    I created a clean solution based on the ajaxToolkit:SliderExtender and JQuery library:

    http://aspdotnetpassion.blogspot.com/search/label/SliderExtender

  8. Maurice Says:

    Really great! When you run chrome as an application, its like its own custom program… amazing!

    I would love you to add a broken down version for the bottom scroll bars as I’ve added your example to a web app we’ve been working on, and if you resize your chrome window you start getting crazy looking colors on the bottom of the screen.

    I might do it myself and I’ll link it back here if / when it’s done.

  9. Ahmad Ali Says:

    Can it put in the left not in the right like the default one ??

  10. Gwen Says:

    Is there a way to make this work in other browsers than Safari?

  11. Gabriele Gualco Says:

    Very very nice!
    Thanks so much!

    :)

  12. Falenone Says:

    Nice

  13. Web Design Brisbane Says:

    I have been using this on one of our chrome only SAAS’s, and noticed recently that the actual draggable / scrollable part of the scroll bar has been warped and is now a little thinner? Any thoughts?

  14. Matthieu Says:

    please keep that comment hidden too… i have a hard time with using this to resize a div inside a skinned div… On the right side, when i select a corner and move it, the vertical slidebar moves a step of its own size on the left and leave a blank space of its size on the right… I’m trying to deal with it but it currently displays like “this http://www.nightmaredream.com/Sanstitre-4.html

    This tool really makes my year! With this bars-kit i will really end up with a perfect page :)

    Another question that i may get answered if i read the post again is.. how can i add repeat regions to the scrollbar’s background? I’d like to make a black and white candycane style background that would mirror to center and i’d like it to repeat x or y :)

    Well… i whish my communication method of asking to publish not the comment doesn’t incomfort you… :P

  15. Matthieu Says:

    Address changed: http://www.nightmaredream.com all in a short :P
    Scroll theme still work well today :)

  16. Japa Alekhin Says:

    hi i’m looking for a way to create a really custom scrollbar… i have an idea to create custom divs and graphics and make it work through js/jquery.. but i’m trying to look for a more non-troublesome way…

  17. Web Design Watford Says:

    Glad I stumbled across this site, been looking for a way to modify the standard CSS overflow scrollbar and will be trying this out on our newest build – will let you know how we get on!

  18. Steve Says:

    Got the three part thumb to work. The trick is the background-clip property.

    You set a transparent background (or padding, if you prefer [both work]) to the height of one of the end caps, and set their position as appropriate; no-repeat. The real trick is the center piece.

    For the center piece, you set background-clip:content-box; the end caps are set to background-clip:border-box (or padding-box if you used padding for spacing).

    This way, the size of the box really only controls the size of the center segment… even if size is set to 0, the end caps will still show up.

    Seems to work pretty flawlessly.

    Will attempt to paste code, but will probably get code-sniffer-nipped.

    #test
    {
    padding:25px 0px;

    /* Padding = Height of one cap */

    height:200px;
    width:50px;

    /* width = width of cap */

    background:url(thumbTop.png), url(thumbMiddle.png), url(thumbBottom.png);
    background-position:top left, top left, bottom left;

    /* background size of individual pieces. Middle height irrelevant */
    background-size:50px 25px, 50px 0px, 50px 25px;

    background-repeat: no-repeat, repeat-y, no-repeat;
    background-clip: padding-box, content-box, padding-box;
    background-origin:padding-box;
    }

  19. Steve Says:

    demo of the solution can be found (probably not long term) at worknetnow.com/demo/webkit-custom-scrollbars.htm

  20. ThinkManify Says:

    @dion: In my own website, I built in a styleswitcher by dynamicdrive.com – it allows you to make a list of styles, and when clicked, change the overall style of the whole webpage. URL: http://dynamicdrive.com/dynamicindex9/stylesheetswitcher.htm

    BTW: This is awesome.

  21. Tuukka Virtaperko Says:

    Didn’t work, unfortunately. I probably need to call the scrollbar somehow, but don’t know how. All I knew how to do was to copypaste all that into style.css. I know how to edit the CSS itself, but I don’t know how to assign that CSS as the scrollbar of a certain div.

  22. Nesma Says:

    Thanks a lot .. I try learning CSS gradually and this is a big help for me!

    I tried using it here .. http://soulfight-a-devianty.deviantart.com/journal/Devious-Journal-Entry-224732884

Leave a Reply

Spam is a pain, I am sorry to have to do this to you, but can you answer the question below?

Q: What is the number before 3? (just put in the digit)