Creating a Nice Slider With jQuery UI

March 29th, 2008

Sliders have many things going for them as a UI element; they offer the benefit restricting the choice a user has, without taking up the space of a drop down. If you need to ask the user to select a number between a range, you can either do an input box with validation, a drop down select element listing each possibility, or you can do a slider.

One drawback of a slider is the user not knowing what he’s selected as there’s no discrete output. If you are sliding to scale something, you can eyeball something, but wouldn’t it be nice if the slider provided some feedback to the user (“50%”) as the user was fiddling with it? I’m going to show you how to do just that with the jQuery UI library.

Sorry kids, the movie has been deleted somehow as a result of the latest WordPress update. I’m working with Mediatemple to see a) what on earth happened with their install script to delete everything that’s NOT WordPress and b) if they can recover anything.

I had a local backup of the demo, thank goodness, so that’s still up. Unfortunately, not the video.

Check out the demo here

The necessary dependencies :

The code I used is as follows :

HTML

<div id='container'>
	<div class="slider_container">
		<div class='small_label'></div>
		<div class='slider_bar'>
			<div id="slider_callout"></div>
			<div id='slider1_handle' class='slider_handle'></div>
		</div>
		<div class='large_label'></div>
	</div>
</div>

CSS

body { background: #284a6e; }
#container { height: 100px; border: 1px solid #284a6e;}
.slider_container { position: relative; margin-top: 50px; height: 40px;}
.small_label { background: url(minus.gif) no-repeat; height: 19px; width: 19px; overflow: hidden; float: left; }
.slider_bar { background: url(bar.gif) no-repeat; height: 19px; width: 260px;  float: left; margin: 0px 5px; position: relative;}
.large_label { background: url(plus.gif) no-repeat; height: 19px; width: 19px; overflow: hidden; float: left; }
.slider_handle { background: url(selector.png) no-repeat; height: 19px; width: 20px; overflow: hidden; position: absolute; top: 1px;}
#slider_callout { background: url(callout.gif) no-repeat; height: 45px; width: 38px; overflow: hidden; position: absolute; top: -50px; margin-left:-10px;  padding: 8px 0px 0px 0px; font-family: "Myriad Pro"; color: #284a6e; font-weight: bold; text-align: center;}

Update: A couple commenters noticed a little outline gremlin in Firefox 3 when using the slider. Just add * :focus { outline:none } to get rid of it. I’m not sure which element the outline is on, so applying it to * can’t hurt ;)

JavaScript

After I recorded the video, it dawned on me that there’s a way to do this that is a bit simpler: by using the ui object passed in by slider, and grabbing the “left” css property of the handle. That way, the callout matches the css handle at all times, with no calculations needed; and you can reserve minValue and maxValue to return values that are useful for your web application.

Thanks to Andrew and John in the comments, I have fixed some bugs with the code. Now you can click on the bar itself and the callout will fire correctly. For this I utilized the “stop” event, checked if the callout was already visible, and displayed it if not.

The code looks like this :


$(function() {
	$('#slider_callout').hide();
	var calloutVisible = false;
	$('.slider_bar').slider({
		handle: '.slider_handle',
		minValue: 0,

		maxValue: 25,
		start: function(e, ui) {
			$('#slider_callout').fadeIn('fast', function() { calloutVisible = true;});
		},
		stop: function(e, ui) {
			if (calloutVisible == false) {
				$('#slider_callout').fadeIn('fast', function() { calloutVisible = true;});
				$('#slider_callout').css('left', ui.handle.css('left')).text(Math.round(ui.value));
			}
			$('#slider_callout').fadeOut('fast', function() { calloutVisible = false; });
		},
		slide: function(e, ui) {
			$('#slider_callout').css('left', ui.handle.css('left')).text(Math.round(ui.value));
		}
	});
});

For reference purposes, here is the code I used in the video :


$(function() {
	$('#slider_callout').hide();
	$('.slider_bar').slider({
		handle: '.slider_handle',
		minValue: 0,
		maxValue: 240,
		start: function(e, ui) {
			$('#slider_callout').fadeIn('fast');
		},
		stop: function(e, ui) {
			$('#slider_callout').fadeOut('fast');
		},
		slide: function(e, ui) {
			$('#slider_callout').css('left', ui.value).text(Math.round(ui.value * (100/240)));
		}
	});
});

Design Inspiration : MSNBC’s Video Page

March 26th, 2008

It seems pretty often that I come across something that inspires the designer in me, so I’m going to make it a point to post them here as often as I can. This way I can share my thoughts with you, my wonderful readers, and perhaps interact with you regarding our thoughts.

Without further ado, my first bit of inspiration is in the form of…

The MSNBC Flash Video Player

MSNBC’s Video Page
Visit the MSNBC Flash Video Player

When I first saw this page in motion, I was pretty impressed by the overall “realism” effect that they were going for. The page has wonderful depth and texture, and it’s super easy to navigate– enticing the user to get lost in its well-structured video hierarchy on the left. However, the thing that struck me most was its use of gradients to create something almost tangible, and the almost complete absence of rounded corners on containers.

Glass soft gradient in the navigation.
Take the navigation bar on the left, for instance. The soft gradients and transparent bar give a nice subtle touch on a mostly invisible design element (it’s only present mainly due to its blurring of the colors behind it). The division is simply a one pixel border and a slight glow at the bottom. At the top a soft gradient represents a nice glare from the top left corner.

“Realistic” gradients give the volume bar a nice look.
The elements in the player have plenty of depth, and there are some great subtle (word of the day) interface elements that give you cues. Increasing the volume not only increases the green slider, but brightens the tones of the green at the same time. Buttons are uniform where they should be, and different where they should be.

Enlarged volume button showing textureHowever, there’s something to these buttons that adds the realism, and it’s more than gradients, shadows and bevels. If you take a look at the speaker button, it’s non-uniformly textured at the top and the left. It’s difficult to see, but it’s there. This makes the colors not so clean and crisp, and softens and texturizes the button.

Dark page + bright colors

The page itself is dark. It’s black. It should be, to display video content well. However, you can’t argue that the page is depressing or dark-feeling, and that’s due to the vivid use of color. The designers took the company’s logo and created an aurora effect across the back that acts almost like a curtain for a reflective stage (where the video is “standing”). All of these metaphors are powerful in building interfaces, especially graphically intensive ones. (see Time Machine and Delicious Library)

1 Deep Columns
The final thing that really stuck out to me was the use of columns that are essentially one deep. You click on a category, and all of the top videos in that category are listed. The designers could have thought “hey we should really provide a way to browse *all* videos here”, but they didn’t. They decided what was most important (recent or top videos) and restricted the result set to that, allowing the navigation to be quick and simple. No intermediate pages, no daunting paginated lists, no sub-tags or categories, just content.

The content is well defined, too: Playlists, Categories, Shows. Examples of playlists are provided to show you the feature. You can add a video to a playlist with just the “plus” button, and you don’t have to sign up for anything.

Visually, the site is pleasing, realistic, and modern. From an interface standpoint, it has taken something typically complicated (see: Google Video) and has made it simple and fun.

Compressing / Minimizing JavaScript with Automator

March 19th, 2008

Automator workflow for YUI CompressorCompressing your JavaScript is a good idea when moving your JavaScript code to your production server. I won’t go into why (because it makes it smaller, duh) so I’ll just assume we’re both cool that it needs to be done.

My compressor of choice is Yahoo’s YUI Compressor, and it comes in a nice Java .jar that you can download and use ’til your heart’s content. However, because I’m lazy, opening the terminal, typing in the command, and feeding it files is just too difficult for me, so I (with the help of a friend of mine) wrote an Automator Finder plugin so you can just right click a .js file and click “minimize” and it creates a new one with .min.js as its extension.

Now there is no bug checking or error returning in this plugin. It’s about as dumb as it can possibly be. When you download it, be sure and point the .jar to the correct YUI .jar file in the perl script or it won’t work. If you have any suggestions for the plugin, be sure and let me know (that is, when I get my comment system working)!

The perl script is just this :


      #!/usr/bin/perl -w
      $CCMD =
      "java -jar ~/Documents/Code/yuicompressor-2.3.5/build/yuicompressor-2.3.5.jar";
      $CARGS = "-o";

      $FN = shift;
      $_ = $FN;
      s/\.js/\.min\.js/g;
      s/ /\ /g;
      $FN2 = $_;

      `$CCMD $FN $CARGS $FN2`

Without further ado, the download is here: Automator YUI Plugin

Image overlapping content in a rounded corner layout

March 17th, 2008

Every now and again, I run into a complex rounded corner layout that requires a bit of finagling with overflows, z-indices and positions. The most common case is that the image I have used for the top corner is overlapping the content within the content div.

The problem

Image overlaps the contentTo see what I mean, check out the demo I put together for illustration purposes. In everything but Firefox 3 beta, the top image overlaps the content within the <div class='content'> div. This behavior is pictured to the right as well.

Now your first thought is that this is a z-index issue, and you wouldn’t be far off (we’ll get to that in a moment), but the cause of the problem is the overflow: hidden attached to the .cap class. If you ditch this (we’ll use the utter magic of Firebug to accomplish this)… voilá, your content is visible. View the previous demo with overflow: hidden removed.

Overflow hidden is off… your content is visible

Is this a bug?

I’m honestly not sure what’s going on here, from a rendering standpoint. It seems like the negative margin on the .cap div is throwing off the renderer, disallowing content from being shown within the box model; that is, it’s a rendering bug. Maybe it’s a commonly known bug? I honestly have no idea; as much development work as I do, you’d think I’d keep up with the trends and bugs with their catchy names. If you know of this being a common bug, please let me know! That is… when I get the comment system up and running.

The thing that makes me wonder if this is a bug is the fact that it happens in all browsers (even the WebKit beta, which seems to be at the forefront of CSS compliance). However, it seems to render just fine in the Firefox 3 beta… so who knows? Not me.

The Fix

Now, on to a fix:

The problem for me, is turning off overflow: hidden can sometimes create its own problems. I’m thinking specifically of IE not adhering to the height: property if the height is smaller than 1em (even if there is no text in the div). In order to fix this, you must use overflow: hidden. It’s good practice if you want a div to maintain a static height, anyway. So how do we fix this and keep overflow: hidden intact?

Z-index! As far as crazy css properties go, this one is pretty reliable across all browsers. The only thing you have to remember is to make sure you put a position: attribute on the div. Z-index is completely unreliable if there is no position: attribute of the div it applies to. In most cases, position: relative; will do just fine without screwing up your layout.

In this case, I applied a z-index of 10 (anything higher than 1 is not necessary, but going overboard is fun) to the .content div, which effectively puts it on “top” of the .cap div. See this fix in action.

I know it’s not a terribly common bug, and it’s not a terribly difficult fix to figure out. However, it bugs me every so often, so I thought I’d share what I’ve learned!