A more accessible Foundation Reveal modal dialog

by Mike Badgley on November 13, 2012

The modal dialog “Reveal” plugin by Foundation is one of my favorites simply due to the quick-and-easy nature of integrating it within a new or existing project and having it up and running in a short period of time. That and the fact that is has a good amount of available options to allow you to configure it to the requirements of a given project.

However, accessibility wise it is a bit lean, at least in terms of how a keyboard should be able to interact with it. In a recent article on the YUI Accessibility blog, the author outlines a series of steps that should happen when a modal dialog window is triggered (open).

As such, I’ve created a plugin of sorts that achieves this functionality using existing logic that is found within the jQuery UI library – which they use for this same purpose.

I invite you to grab the JavaScript code below and try it out. Any comments/suggestions would be greatly appreciated.

(function( $ ) {
	if(typeof $.fn.reveal !== 'function') return false;

	var caller;

	// This was ripped directly from the jQuery UI 1.9.1 source.
	function focusable( element, isTabIndexNotNaN ) {
		var map, mapName, img,
			nodeName = element.nodeName.toLowerCase();
		if ( "area" === nodeName ) {
			map = element.parentNode;
			mapName = map.name;
			if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
				return false;
			}
			img = $( "img[usemap=#" + mapName + "]" )[0];
			return !!img && visible( img );
		}
		return ( /input|select|textarea|button|object/.test( nodeName ) ?
			!element.disabled :
			"a" === nodeName ?
				element.href || isTabIndexNotNaN :
				isTabIndexNotNaN) &&
			// the element and all of its ancestors must be visible
			visible( element );
	}

	// This was ripped directly from the jQuery UI 1.9.1 source.
	function visible( element ) {
		return $.expr.filters.visible( element ) &&
			!$( element ).parents().andSelf().filter(function() {
				return $.css( this, "visibility" ) === "hidden";
			}).length;
	}

	// This was ripped directly from the jQuery UI 1.9.1 source.
	$.extend( $.expr[ ":" ], {
		data: $.expr.createPseudo ?
			$.expr.createPseudo(function( dataName ) {
				return function( elem ) {
					return !!$.data( elem, dataName );
				};
			}) :
			// support: jQuery <1.8
			function( elem, i, match ) {
				return !!$.data( elem, match[ 3 ] );
			},

		focusable: function( element ) {
			return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) );
		},

		tabbable: function( element ) {
			var tabIndex = $.attr( element, "tabindex" ),
				isTabIndexNaN = isNaN( tabIndex );
			return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN );
		}
	});

	$(document).on('click', 'a[data-reveal-id]', function (e) {
		caller = event.target;
	});

	$('[role="dialog"]').on('reveal:opened', function(e) {
		var tabbables = $(':tabbable', this),
			first = tabbables.filter(':first'),
			last  = tabbables.filter(':last');

			first.focus();

		// prevent tabbing out of modal dialogs
		$(this).bind('keydown', function(event) {
			if (event.keyCode !== 9) {
				return;
			}

			if (event.target === last[0] && !event.shiftKey) {
				first.focus();
				return false;
			} else if (event.target === first[0] && event.shiftKey) {
				last.focus();
				return false;
			}
		});
	});

	$('[role="dialog"]').on('reveal:closed', function(e) {
		$(caller).focus();
	});
})( jQuery );

Forcing Flowplayer videos in an overlay to stop when they are closed

by Mike Badgley on January 19, 2012

This is an issue that primarily affects Internet Explorer – as far up as IE9 and has to do with the way videos (powered by Flowplayer) are handled within an overlay ‘window’.

All other browsers are smart enough to disabled the Flash object when the parent element (overlay) they are embedded in is closed (hidden via CSS), but with IE a bit more grunt work is required.

Depending on what you are using to create your overlays (in my case I am using jQuery Tools), you’ll need to use (or create) a callback function that fires when the overlay is closed. With jQuery Tools the functions you can use are onBeforeClose or onClose.

onClose: function() {
	var video_state = $f("player1").getState();

	if(video_state === 2 || video_state === 3) {
		var t = setInterval(function() {
			if($f("player1").getState() === 3) {
				$f("player1").pause();
				$f("player1").unload();
				clearInterval(t);
			}
		}, 100);
	}
}

Within the callback function defined above, the state of the instance of the Flowplayer object is returned:

var video_state = $f("player1").getState();

This will return one of seven possible values, with only a couple being values we are interested in – 2 (video is buffering) and 3 (video is playing). If the state of the video is  3 (playing), then we can use the Flowplayer methods available to stop or pause the video, but if the video is still buffering (state 2), then those methods are unavailable and will have no effect, which is why I am using setInterval to check for the current video state.

This solution appears to do the trick, but I would appreciate your feedback once you’ve had a chance to test it out in your own environment.

Forcing the figcaption element to wrap to the width of an image using CSS only

by Mike Badgley on September 30, 2011

This article describes a CSS-based solution for creating a floated <figure> element that allows for a caption (<figcaption>) to be displayed beneath – constrained to the width of the image.

An example of a photo and captionThe example on the left is a fairly common design element, yet one that can be a bit of a pain to style if you want to keep things as fluid and flexible as possible.

There are many solutions out there, or course, but I’ve yet to see one that is non-restrictive and/or easy to implement. To often they rely on a JavaScript plugin or an inline style that forces the width of the container to match the width of the image contained within. On a small site this is fine, but when its a site that is going to be managed by a number of people with varying degrees of HTML/CSS skills, I think its important to keep things as simple as possible.

The solution I came up with is based on a Stack Overflow posting I read that has been modified to work on a wider range of browsers – including IE8 and IE9. As mentioned in the introduction, this is a CSS-only based solution.

For the markup, I utilize the new HTML5 <figure> and <figcaption> elements, which are perfectly suited for this type of UI element:

<figure>
	<img height="215" width="215" src="660799.jpg" />
	<figcaption>
		This is a sample caption that should not exceed the width of the image.
	</figcaption>
</figure>

Pretty simple stuff – with the only real item of note being the height and width attributes on the <img> tag. These are required – and really – should be used regardless so that the browser can ‘smartly’ load the image with the proper dimensions.

Taking this markup and floating it to the left or right as you would normally do with an image, it’s easy to see the problem your going to run into. The caption text is going to keep flowing irregardless of the width of the image. To correct this, we simple do the following:

figure {
	float: left;
	display: table;
	width: 87px;
}

Forcing the <figure> element to display as a table means that the content within will flow to the constraints (width) that is placed upon it. Remember back in the bad old days where you would often see a sidebar column sized at 1% so that it would only take up as much horizontal room as was required by the content within? This is the same sort of idea here.

The ‘table’ is being forced to a width of 87 pixels (a completely arbitrary number – I just happen to be a Penguins fan), but because the image inside of it has a width attribute set (in this case 215 pixels), it grows to accommodate the width of the content and as a result the caption ‘grows’ along with it.

A pretty nifty solution that works very well across all modern browsers I tested on – including IE8. Basically this will work on any browser that supports the display: table CSS property.

Fixed: IE7 Button Text Redraw Bug

by Mike Badgley on May 5, 2011

In a recent article by Zoe Mickley Gillenwater, a text redraw bug was brought to light.

Internet Explorer 7 has a bug where, when it redraws the text of buttons after scrolling them out and then back into the viewport, lines of pixels are missing from the text. I can’t figure out a fix and need some help.

There was some pretty good discussion and solutions offered on how to overcome this annoying glitch that appeared to only occur in IE6 and IE7.

In the end, after spending more time than I’d want to admit on figuring out a way around this, I ended up finding a workable, albeit hacky, solution.

Note: Before reading further, I’d encourage you to check out Zoe’s article so you get the full background on the situation.

Yah, you probably ignored that note above, so here’s my Cole’s Notes version. ;)

The <button> element in IE7 will act a bit wonky when padding is applied to it. Instead of their being the amount that was defined in the CSS, IE7 will typically add a whole bunch of extra space. Not exactly a showstopper, but it’s just one of those annoying things … you know?

Anyhow, the solution to this is to add overflow: visible; to the button, and it will respond like all the other browsers. However, once the button is styled further – primarily with font, padding and background type styles – things start acting up in IE7. Basically, when you being to scroll the Web page, the text on the button will often become distorted and sometimes will disappear completely.

After a number of tests, it became apparent that the main culprit to this text redraw issue was the overflow: visible; declaration. Obviously this was required to fix the other padding bug that I mentioned earlier.

Rather than repeat the conversation in the blog post, I’ll bring a long story short and describe what the final fix was.

The key was to wrap the text within the <button> tag with another element (in this case a <span> tag) and then apply all the formatting to the <span> tag.

<button>
	<span>This is my example button</span>
</button>
.button {
	overflow: visible;
	background: #f00;
	display: inline-block;
	width: auto;
	height: auto;
	margin: 0 10px 10px 0;
	border: none;
	text-align: center;
	cursor: pointer;
	*font-size: 0;
}
	.button span {
		padding: 11px 20px;
		font-size: 20px;
	}

In addition to applying the formatting to the <span> tag, the other important step that had to be taken was forcing the font size to be 0 pixels. Setting a font size on the <button> itself was still causing the same redraw issue, and it wasn’t until I set it to 0px (and then re-initialized it on the <span> tag) that the problem went away for good.

View a demo to see the example above in more detail.

How to absolute position images in IE8

by Mike Badgley on May 5, 2011

I came across an strange display bug (?) in IE8 with how it renders inline imagery that is wrapped with an element that has a position of absolute.

Here’s a quick example to give you  an idea of what I’m talking about. Typically – and  depending on the design – I use absolute positioning to fix the corporate logo of the site to the page, and this is always setup as a hyperlink to the Home page.

<a class="logo" href="/">
	<img alt="ACME Inc" src="logo.png" width="100" height="50">
</a>

I then style the <a> tag to be something like this:

.logo {
	left: 20px;
	position: absolute;
	top: 20px;
}

This will work in every browser with the exception of IE8. For some reason, IE8 does not like it when an image’s parent element is absolutely positioned. When this is the case, IE8 will not render the image at all – only the styling that has been applied to the <img> will be displayed (i.e. padding, borders, background color, etc.).

The quick workaround to this is to instead style the <img> tag directly:

.logo img {
	left: 20px;
	position: absolute;
	top: 20px;
}

This sort of bug also seems to happen in other circumstances as well, even when the image is not being absolutely positioned, so its something to keep your eye on as it can be easy to assume that “it will just work” if perhaps a thorough browser check is not being done to the HTML templates and/or Web site. ;)