Category Archives: Technology

Pure CSS ‘tags’—ala SoundCloud

For the recent irama.org realignment I wanted to emulate the cute little ‘tags’ that sit below a track on SoundCloud.

I wanted to try to do as much as possible using CSS alone—without background images, too many extra elements, or general hackery. Ideally, the markup would be:

<a href="…">Tag text</a>

There are lots of posts around the interwebs about CSS triangles, but it’s hard to find a concise tutorial for putting an arrowhead on the end of a box. So I started by pinching borrowing a technique Ben pulled together for a site we were working on.

I noticed the negative margins were not playing nicely with iOS so I switched to relative positioning to offset the arrowhead. This also simplifies the padding/margin calculations, makings the final solution easier to tweak.

.tags a {
	float: left;
	background: #c5c5c5;
	color: #fff;
	text-decoration: none;
	margin: 0 0 10px 18px;
	padding: 2px 10px 1px;
	border-top-right-radius: 3px;
	border-bottom-right-radius: 3px;
	position: relative;
	transition: all .25s linear;
	text-shadow: 0 1px 1px rgba(0, 0, 0, 0.4);
	white-space: nowrap;
	line-height: 21px;
}

.tags a:before {
	content: "";
	border-style: solid;
	border-color: transparent #c5c5c5 transparent transparent;
	border-width: 12px 13px 12px 0;
	position: absolute;
	left: -13px;
	top: 0;
	transition: all .25s linear;
}

Hover states need to cover the anchor background and the triangular border colour…

.tags a:hover {
	background-color: #39F;
}
.tags a:hover:before {
	 border-color: transparent #39F transparent transparent;
}

For the ‘hole’ punched in the tag, I thought I’d have to rely on a background image. Ben made a good point about reusing the bullet from a list item (which worked, with some negative margin trickery).

I finally thought to check the approach that soundcloud actually take and I was pleasantly surprised… clean minimal markup and a CSS-only solution!

Why didn’t I check their implementation sooner??

In the end, I borrowed their approach for the hole…

.tags a:after {
    background: none repeat scroll 0 0 #FFFFFF;
    border-radius: 50% 50% 50% 50%;
    box-shadow: 0 1px 1px #737373 inset;
    content: "";
    height: 5px;
    left: -1px;
    position: absolute;
    top: 10px;
    width: 5px;
}

Which ends up looking like this…

Screenshot of two tags in situe next to a blog post

Hats off to the designers and front end devs at soundcloud, they know what they are doing!

Posted in

Get the text within an element—including alt text—using jQuery

When working on the butterfly lightbox I needed a way to grab the text with a link including the alt text from any images within.

I couldn’t find any existing approaches, so I put together this small plugin to do the job. I thought I should post it here before I forget, or in case anyone else might find it useful too.

Example

If you had the following html:

<a id="smiley" href="">The symbol for happiness is <img src="smiley.png" alt="a smiley face" /></a>

You could grab the accessible text using the jQuery plugin like this:

$('#smiley').accessibleText();

Which would return the text ‘
The symbol for happiness is a smiley face

‘.

Plugin code

/**
 * jQuery plugin that returns the text nodes within the target element, combined/concatenated 
 * with any alt text or input values.
 */
$.fn.accessibleText = function() {
	if (this.is('img')) {
		return this.attr( 'alt' );
	} else if (this.is('input')) {
		return this.attr( 'value' );
	} else {
		return $.map( this.contents(), function( domElement ) {
			if ( domElement.nodeType === 3 ) {
				return domElement.data;
			} else if ( domElement.nodeType === 1 ) {
				var $element = $( domElement );
				if ( $element.is( 'img, imput' ) || $element.find( 'img[alt], input[value]' ).length > 0 ) {
					return $element.accessibleText();
				} else {
					return $element.text();
				}
			}
		}).join( '' );
	}
};

Let me know if you found this useful, or if you know of a better solution!

Edit: Much improved version above, thanks to Ben!
Edit again: I have updated it again to support input elements, and support using the plugin on inputs and imgs directly (this should really go on github).
Final edit: Here it is, accessibleText on github.

Posted in

Butterfly lightbox, now with gallery support

By popular demand (thanks Ray) the butterfly lightbox has been extended with new functionality.

The biggest new feature is the addition of support for galleries. Specify a gallery using either a container element to wrap the related links, or by using the same rel attribute on related links allows a series of lightbox links to work together, with ‘next’ and ‘previous’ controls presented beside the lightbox content to allow navigation between each gallery item.

Try it out here:

See full examples, downloads and changelog for more detail.

Posted in

Cached images have no width or height in webkit (e.g. Chrome or Safari)

Stackoverflow (SO) has always been a handy resource. Today I noticed a particularly valuable comment with 0 votes.

I created an SO account with the explicit purpose of voting this comment upwards, but unfortunately, I have no reputation on SO, and am not able to do this (yet).

For lack of a better way to credit JKS for his insightful solution I thought I’d recognise it here.

Problem

In webkit browsers (e.g: Chrome or Safari) the onload event fires for both cached and non-cached images, but images loading from cache seem to return dimensions of 0—for both width and height.

Solution

JKS proposes a simple solution, a seemingly redundant setTimeout before taking your measurements seems to magically restore cached image dimensions. In jQuery, that would look like this:

$('img').load(function(){
    setTimeout(function(){
        // do something based on $('img').width and/or $('img').height
    }, 0);
});

Thanks

Thanks again to JKS for the tip!

Posted in

Cache manifests and Firefox

I’ve been playing with offline web applications this afternoon. Generally, it’s pretty straightforward:

  1. Reference your manifest file in the <html> tag of each page.
  2. Fill out your .manifest file with the relevant resources you want to be cached and available offline.
  3. Configure your server to serve .manifest files at text/cache-manifest.

Most browsers picked this up fine (tested: Opera 11, Chrome 7, Mobile Safari iOS 4.3), but unfortunately I ran into…

Firefox issues

Firefox (tested: 3.6.13 and 4.0b11) refused to pull resources back from appCache—even though it reported successfully caching 175kB of data—or request any resources that weren’t cached. Firefox just presented the plain HTML for each pages without loading images, stylesheets, scripts or any other assets.

After much searching and trial and error, I came across a recommendation on stackoverflow to use http://* within the NETWORK section of the manifest for the sake of Firefox, and sure enough…

It works!

Final code samples as follows…

HTML (/index.html)

<!DOCTYPE HTML>
<html manifest="/path/to/my.manifest">
<body>
...
</body>
</html>

Manifest (/path/to/my.manifest)

CACHE MANIFEST
#ver0.08

CACHE:
images/bg-noise-tile.png
images/site-name-bg.png
images/menu-bar-divide.png
# etc ...

NETWORK:

http://*

*

Apache configuration (/.htaccess)

# Ensure manifests are served using the correct mime type
AddType text/cache-manifest .manifest

Thank you

Thanks to dalibor for pointing out that http://* is required for Firefox.

One other handy resource is Mark Pilgrim‘s Let’s take this offline, and if it had mentioned http://* it would have been perfect!

Posted in