Free your popup arrows (from images, mostly)

I've always been a fan of doing things without images when possible. There isn't always a clear reason for it; the classical reasoning is that it saves bandwidth and HTTP requests etc etc, but to be honest my main goal is a challenge. Yes, we often derive the aforementioned benefits, but really it's just fun to try and figure out how to do things that *should* be doable without images in straight HTML+CSS+JavaScript. To that end, today's little project is creating a popup with an arrow pointing back to something coming out of one of the borders. Something that looks a little like this:

Sexy right? That little left arrow is the challenge. First off, some markup:

This is more or less lifted directly from the OpenStudy code base. I'm not going to bother detailing how the owl is taken care of; instead, I'll focus on the borders, drop shadow, and most importantly the left arrow.

Notice that there is a class `left-arrow' on the div. This is because we want to create the system so that it has relatively flexible positioning. On OpenStudy, we use left-arrow, right-arrow, bottom-left-arrow, and top-arrow. For the purposes of this post, we'll focus on left-arrow and right-arrow and leave the rest for tinkering purposes.

First off, you'll notice that there is no element dedicated to the arrow. Unfortunately, this isn't because it isn't necessary; I just like to have markup that is devoid of empty elements that are strictly presentational. When I do need them, as in this case, I put them in after the fact using JavaScript. In this case, when a tooltip is loaded via AJAX, the loading process adds a new div with class `arrow':
This is nearly the end: what remains is taking that div and turning it into the arrow we see above. To do this, we take advantage of CSS transformations. These let us, for example, rotate an element. Here, we will give the div an equal width and height and then rotate it 45 degrees so that it is a diamond instead of a square:

https://gist.github.com/1089727/4db7f762a00d2e8d968cb1df621c0f07f994084d

Here, we apply the 45 degree rotation and set the equal width and height. So far so good. We have a diamond on a container; if we give it a background, we see:

Now we'll give the popup itself just a little bit of styling:

https://gist.github.com/1089727/88342e10db731132e595ca13a5744233e9379d4c

And then we position the arrow absolutely within the containing div and match the background color:

https://gist.github.com/1089727/f17fd009aa3e018cbec630e369df6db49dbe1b1c

The result looks like this:

Two Sides

Let's remember that we wanted to do both left and right arrows, however. We can move the specific positioning stuff to its own class, and add a version for right arrows:

https://gist.github.com/1089727/1e16a91618451883f05b60bd50ee97daf4bb0b63

If we add a version of the div in the markup with the right-arrow class instead of the left-arrow class, we get:

Brilliant!

Fill That Up With Rounded Shadowy Sexiness

Last but not least, we want to add some rounded borders and drop shadows. We'll continue with the CSS3 trend here and use border-radius and box-shadow to provide these. First off, for the main dialog:

https://gist.github.com/1089727/046199815ad28c034a7ee6cbf0901aa4911820b6

That's Real Close Now (tm), but not quite there. If we look at what that produces:

We can see here that the arrows are ugly because they're missing a drop shadow. But now that the arrows are themselves elements, we can make use of box-shadow to give them shadows, too! This was in fact one of the main motivators for making these arrows via CSS and divs: images with drop shadows don't blend well with box-shadowed divs, unless you're very careful about creating the blend area between the box-shadowed div and the arrow image. Instead, we take this approach. Adding the box-shadows to the arrows (note that they are subtly different for the right vs left arrows):

https://gist.github.com/1089727/69e1d8309f8246df007604186a2220c2a64b2eff

Finally, we have this look:

That looks super-sexy.

They Will Not Stop Degrading Us

Sexy though the above is, we do have to think about Lesser Browsers (tm). To this end, at OpenStudy, we degraded our approach to use arrow images without a drop shadow and non-rounded boxes with no drop shadow, as well. We use modernizr, so we vary the CSS styles based on whether CSS transforms are available. If CSS transforms are not available, tough, you get no drop shadows:

The non-drop-shadowed version looks like this now:

Note that the border radius declarations are there whether or not CSS transforms are enabled. On a browser that doesn't support them (*cough* IE7 *cough*), the borders will be sharp, but the arrow will remain. The two arrow images (which could be sprited, but aren't)? Here they are:

Check Dat

That's it. Obviously many of the styles in the popup show in the initial screenshot are missing. The close button is unstyled, the text is generally untreated, and there's no proper close X. But the styles presented here are focused on how we can get a drop-shadowed arrow that varies its side by class name and is built without images. When degrading gracefully to other browsers, we leave the drop shadow at the door and use images for the arrows.

One missing component here is that we arguably shouldn't be using left-arrow and right-arrow are classes. It's my general philosophy that classes should be semantic, indicating what something is rather than what it looks like. In this case, we could use SASS or Stylus or Less or some such package with an appropriate mixin to use some other class or id to apply the proper styles to the arrows. But, I will leave it at that for now. Sexy arrows, maximum CSS goodness. It's all you could ask for.