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

Realignment, irama.org 4.0

I figure it’s high time to start posting again, and long overdue to update the site template—some of the legacy cruft was getting a little embarrassing.

I had an irama.org 3.0 design in the works a few years ago. Noting came of it. Thank goodness, it was awful. I can’t bring myself to show you.

This update (skipping straight to 4.0) features a clean, minimal design, focusing on the content. The overall colour scheme and structure has remained as it always was (it’s just a realignment, after all).

The code is a fairly heavily modified version of the simple Skeleton theme for WordPress—I’ve given up rolling my own themes from scratch, the amount of effort required to output cleaner code is just too high. With legacy cruft gone, there’s room to embrace contemporary technologies: HTML5 replacing XHTML, CSS3 media queries for responsive layout to replace the old JavaScript-driven approach.

I haven’t testing the IEs yet. If you’re using IE, I’m sorry, how embarrassing for you 😉

I’m sure there will be tweaks to come in future.

Edit (11/04): For this design I played with visual hierarchy using ‘negative visual weight’—i.e. fading back secondary elements so the content stands out. This reduces accessibility for some visitors. If this applies to you, I apologise—please let me know how you prefer to deal with sites that have colour contrast issues? e.g. Do you: a) Use a custom style sheet? b) Look for a ‘zoom layout’ or ‘accessible version’ button? c) Curse the designer and leave/complain?

Posted in

WIP—Rise of the Red Dragon

A Work In Progress. Feedback welcome (here or on soundcloud), be gentle 😉

Part two of a two (or three) part suite loosely themed around the conflicted nature of a fallen angel. Mostly just an excuse to play with MIDI and VIs!

Posted in


I’ve always loved music. I spent a lot of time playing music when I was younger. I studied it at uni (majoring in composition), then changed focus to IT and haven’t written a dot since. Until recently…

After a long break I’ve been getting back into composition, but in a much more organic way than I have before. While studying composition, I felt a (real or imagined) expectation that I’d output sophisticated, intellectual, original, contemporary art music. Which was frankly quite stifling!

I don’t feel like I ever really ‘found my voice’ as a composer. I intend to work my way (slowly) towards that now. Along the way I’m likely to output much that is derivative of in homage to those who inspire me musically (sure to talk about them here in future).

I will post bits and pieces here as I work on them. Always happy for feedback, ideas or advice.

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.


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:


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