Tom Lauck’s Deseloper.org

A First Date with TypeKit

author:

Several weeks ago, I found myself in a friendly debate with a co-worker over the handling and future of fonts through the web browser.  Hours later, a TypeKit invite landed in my inbox; how coincidental.

Vegetarian Chicken

To break down what is happening with TypeKit, Jonathan Snook has a nice article that articulates the licensing limitation and techniques needed for successful @font-face embedding – TTF/OTF, EOT, and SVG.  These are the basic tenets of utilizing @font-face from a technical standpoint, minus TypeKit’s JavaScript for legal embedding and SVG.

@font-face {
	font-family: 'GothicCustom';
	src: url("LeagueGothic.eot");
	src: local('League Gothic'),
		url("LeagueGothic.svg#lg") format('svg'),
		url("LeagueGothic.otf") format('opentype');
}

Jonathan Snook – Becoming A Font Master

He also encapsulates the fact that font issues break down to essentially two buckets, browser compatibility and licensing.  This is a huge differentiator for TypeKit – all fonts based on your subscription level are properly licensed.  This does not come without a caveat unfortunately.  Rather than choosing from fonts common to designers such as Frutiger, Futrura, Univers, etc – TypeKit presents a list of imitations.  And thus I suddenly felt like I was looking at a Chinese buffet dish labeled as “chicken” even though it’s not – you’re not fooling me!

Rationale: Who cares if it’s not real chicken, Chinese “chicken” tofu kind of tastes and feels like real chicken so stop complaining – it’s healthy for you.  Translation: TypeKit font families aren’t quite what you are used to but most of them are close enough – and they are fully licensed, everyone is happy.

The Vegetarian Dies of Malnutrition

If you are not a fan of JavaScript and are just interested in a purist CSS only solution, you should really leave now – yes, TypeKit relies on JavaScript just as most of its competitors. Comparing apples to apples (in this case TypeKit vs sIFR), TypeKit’s JavaScript footprint is a bit smaller than sIFR’s ~10k compared to sIFR’s ~20k.  But wait – how exactly is the font getting inserted into the page – it’s not like we are using a system font that can just be accessed at the OS level?  As it turns out, each font in TypeKit is upwards of 100k and in my small use case, for 2 fonts in my kit, I was hitting 240k. Now you can trim this down depending on the font you choose and exact character sets, however, this was what the TypeKit editor defaulted to for my demo site’s needs.  

typekit-size

Comparing apples to apples again, in my small use case for 2 separate fonts via a single SWF file – oh and these were my EXACT brand fonts, not imitations – I was hitting about 50k.  This could certainly explain the load and render delay many (not just myself) have been experiencing with TypeKit.  Another contributor to render time could be the fact that TypeKit requires their script to load in the <head>.  This is contradictory to Yahoo’s optimization guidelines and progressive loading – it forces that 250k to be rendered before anything else on page can be rendered.  Did I mention TypeKit costs money too?

File size and loading optimization aside, browser compatibility – the overriding limiting factor we usually face is also an interesting study. Obviously there is always a significant margin in these statistics, but for reference here is the current browser usage share and Flash penetration:

bowser-stats

TheCounter.com

adobe-penetration-200909

Adobe Systems, Inc.

In some of my personal findings with TypeKit, Chrome is a no-go, along with earlier versions of Firefox, IE, Opera, and Safari and sporadic behavior in all of the above. And I’m not the only one.  Again TypeKit is still in beta, so they get a little bit of a freebie here, but the fact remains that @font-face has remained somewhat elusive for so long, for so many reasons, and to think that it is solved right now would be a bit naïve.  By comparison, Flash replacement is somewhat bulletproof these days as Flash has become somewhat ubiquitous.

Give Me My Meat and Potatoes

Indeed, it is hard to argue the need for better handling of non-standard web fonts.  My personal philosophy around non-standard web fonts has always been holistic in nature – sIFR is good, but it still doesn’t solve the problem fully and neither does Cufon for that matter – so I often err on the side of creative use of standard web fonts. TypeKit is definitely a progressive effort to solve the problem of non-standard fonts in the browser.

Maybe I’ve been abused by bad technology hacks in the past, but I think the real issue goes deeper than our siloed world of web browsers and markup.  Which brings me to a conclusion of why we have been trying to implement non-standard web fonts in the first place: designers want finite control.  And this is the very reason why there is such a difference in standards between OS’s standard fonts and more importantly how they are rendered – Apple typically sides with the font designer and Microsoft does not.

The difference originates from Apple’s legacy in desktop publishing and graphic design. The nice thing about the Apple algorithm is that you can lay out a page of text for print, and on screen, you get a nice approximation of the finished product. This is especially significant when you consider how dark a block of text looks. Microsoft’s mechanism of hammering fonts into pixels means that they don’t really mind using thinner lines to eliminate blurry edges, even though this makes the entire paragraph lighter than it would be in print.

The advantage of Microsoft’s method is that it works better for on-screen reading. Microsoft pragmatically decided that the design of the typeface is not so holy, and that sharp on-screen text that’s comfortable to read is more important than the typeface designer’s idea of how light or dark an entire block of text should feel. Indeed Microsoft actually designed font faces for on-screen reading, like Georgia and Verdana, around the pixel boundaries; these are beautiful on screen but don’t have much character in print.

Joel Spolsky – Font smoothing, anti-aliasing, and sub-pixel rendering

Rather than standardizing on one solution for the masses, OS manufactures, browser developers, the W3C, and [you name it standards body here] keep giving us lame excuses instead of real options. And until then we are left with 80% complete excuses for using non-standard web fonts – sIFR, Cufon, and I’m sure TypeKit will not be the last.

Nov 3 2009

A Simple Modal – Redux

author:

Over a year ago I walked through an example of creating the basic foundation for a modal window using jQuery.  The goal was simplicity, minimalism, and flexibility to add-on functionality as needed.

As stated at the outset, this post was meant to illustrate a bare bones and simple example of a modal window. If you wanted to extend the functionality for example, it would be quite simple to [...] suit needs.

Last Year’s A Simple Modal Post

The example was well received in feedback from readers, and there was some constructive criticism as well. Equal to the amount of people that appreciated the minimalistic approach were requests from readers to support IE6, forms, and a host of other odds and ends.  Some readers had some useful feedback for features and additions that I purposefully did not include in an effort to keep things basic.

Therefore, I thought there was a nice opportunity to revisit the basic modal window script and make it a bit more comprehensive in an effort to suit the needs and requests of the aforementioned readers.  So before we get into the code, lets outline some things that have changed:

  • Converted for use as a jQuery plugin.
  • Added IE6 compatibility
  • Added Opera compatibility
  • Added ability to fade in and out
  • Added multiple ways of setting parameters
  • Added multiple content types (‘image’ and ‘iframe’)

View Example | Download Source

The Plugin

(function ($) {

	/**********************************
	* CUSTOMIZE THE DEFAULT SETTINGS
	* Ex:
	* var _settings = {
	* 	id: 'modal',
	* 	src: function(sender){
	*		return jQuery(sender).attr('href');
	*	},
	* 	width: 800,
	* 	height: 600
	* }
	**********************************/
	var _settings = {
		width: 800, // Use this value if not set in CSS or HTML
		height: 600, // Use this value if not set in CSS or HTML
		overlayOpacity: .85, // Use this value if not set in CSS or HTML
		id: 'modal',
		src: function (sender) {
			return jQuery(sender).attr('href');
		},
		fadeInSpeed: 0,
		fadeOutSpeed: 0
	}

	/**********************************
	* DO NOT CUSTOMIZE BELOW THIS LINE
	**********************************/
	$.modal = function (options) {
		return _modal(this, options);
	}
	$.modal.open = function () {
		_modal.open();
	}
	$.modal.close = function () {
		_modal.close();
	}
	$.fn.modal = function (options) {
		return _modal(this, options);
	}
	_modal = function (sender, params) {
		this.options = {
			parent: null,
			overlayOpacity: null,
			id: null,
			content: null,
			width: null,
			height: null,
			modalClassName: null,
			imageClassName: null,
			closeClassName: null,
			overlayClassName: null,
			src: null
		}
		this.options = $.extend({}, options, _defaults);
		this.options = $.extend({}, options, _settings);
		this.options = $.extend({}, options, params);
		this.close = function () {
			jQuery('.' + options.modalClassName + ', .' + options.overlayClassName).fadeOut(_settings.fadeOutSpeed, function () { jQuery(this).unbind().remove(); });
		}
		this.open = function () {
			if (typeof options.src == 'function') {
				options.src = options.src(sender)
			} else {
				options.src = options.src || _defaults.src(sender);
			}

			var fileExt = /^.+\.((jpg)|(gif)|(jpeg)|(png)|(jpg))$/i;
			var contentHTML = '';
			if (fileExt.test(options.src)) {
				contentHTML = '<div class="' + options.imageClassName + '"><img src="' + options.src + '"/></div>';

			} else {
				contentHTML = '<iframe width="' + options.width + '" height="' + options.height + '" frameborder="0" scrolling="no" allowtransparency="true" src="' + options.src + '"></iframe>';
			}
			options.content = options.content || contentHTML;

			if (jQuery('.' + options.modalClassName).length && jQuery('.' + options.overlayClassName).length) {
				jQuery('.' + options.modalClassName).html(options.content);
			} else {
				$overlay = jQuery((_isIE6()) ? '<iframe src="BLOCKED SCRIPT\'<html></html>\';" scrolling="no" frameborder="0" class="' + options.overlayClassName + '"></iframe><div class="' + options.overlayClassName + '"></div>' : '<div class="' + options.overlayClassName + '"></div>');
				$overlay.hide().appendTo(options.parent);

				$modal = jQuery('<div id="' + options.id + '" class="' + options.modalClassName + '" style="width:' + options.width + 'px; height:' + options.height + 'px; margin-top:-' + (options.height / 2) + 'px; margin-left:-' + (options.width / 2) + 'px;">' + options.content + '</div>');
				$modal.hide().appendTo(options.parent);

				$close = jQuery('<a class="' + options.closeClassName + '"></a>');
				$close.appendTo($modal);

				var overlayOpacity = _getOpacity($overlay.not('iframe')) || options.overlayOpacity;
				$overlay.fadeTo(0, 0).show().not('iframe').fadeTo(_settings.fadeInSpeed, overlayOpacity);
				$modal.fadeIn(_settings.fadeInSpeed);

				$close.click(function () { jQuery.modal().close(); });
				$overlay.click(function () { jQuery.modal().close(); });
			}
		}
		return this;
	}
	_isIE6 = function () {
		if (document.all && document.getElementById) {
			if (document.compatMode && !window.XMLHttpRequest) {
				return true;
			}
		}
		return false;
	}
	_getOpacity = function (sender) {
		$sender = jQuery(sender);
		opacity = $sender.css('opacity');
		filter = $sender.css('filter');

		if (filter.indexOf("opacity=") >= 0) {
			return parseFloat(filter.match(/opacity=([^)]*)/)[1]) / 100;
		}
		else if (opacity != '') {
			return opacity;
		}
		return '';
	}
	_defaults = {
		parent: 'body',
		overlayOpacity: 85,
		id: 'modal',
		content: null,
		width: 800,
		height: 600,
		modalClassName: 'modal-window',
		imageClassName: 'modal-image',
		closeClassName: 'close-window',
		overlayClassName: 'modal-overlay',
		src: function (sender) {
			return jQuery(sender).attr('href');
		}
	}
})(jQuery);

As you can see, quite a bit has changed – which is not necessarily a bad thing.  There is now tighter integration with jQuery and more out of the box configuration ability as a result.

Adding Some Style

.modal-overlay {
	position: fixed;
	top: 0;
	right: 0;
	bottom: 0;
	left: 0;
	height: 100%;
	width: 100%;
	margin: 0;
	padding: 0;
	background: #131313;
	opacity: .85;
	filter: alpha(opacity=85);
	z-index: 101;
}
.modal-window {
	position: fixed;
	top: 50%;
	left: 50%;
	margin: 0;
	padding: 0;
	z-index: 102;
	background: #fff;
	border: solid 8px #000;
	-moz-border-radius: 8px;
	-webkit-border-radius: 8px;
}
.close-window {
	position: absolute;
	width: 47px;
	height: 47px;
	right: -23px;
	top: -23px;
	background: transparent url(../images/close-button.png) no-repeat scroll right top;
	text-indent: -99999px;
	overflow: hidden;
	cursor: pointer;
}

Implementation

<a href="modal.html" onclick="$(this).modal({width:833, height:453}).open(); return false;">Modal iFrame</a>
<a href="images/your-image.jpg" onclick="$(this).modal({width:500, height:375}).open(); return false;">Modal Image</a>

Although a little more weight has been added to the script itself, the implementation is more flexible and can be used with just about any jQuery chain – whether its onclick, a document being loaded, you name it.  There is also an added ability to set parameters in your area of choosing – inside the CSS, in the plugin itself, or in the method call or jQuery chain object.

Moving Forward

So if you are looking for something extra simple, head on over to last years post and in the meantime enjoy the added functionality with this updated example.

View Example | Download Source

Oct 21 2009

A Simple Modal

author:

Updated – Version Available

A Simple Modal – Redux

[See a demo here]

Modal windows seem to be the rage these days and somewhat synonymous with “Web 2.0.” And yes, options exist, whether it be Lightbox, Thickbox, or .NET AJAX — to name a few. Recently, Facebox has emerged as a very promising contender. The aforementioned plugins/widgets have proven their usefulness to many developers during their life course. In fact they one might even go so far as to deem “standard” to the plugin of choice.

Yet, what if a scenario arises where you do not need such full featured capability? After all, most of the plugins out there come with their own CSS along with the JavaScript. This is not to say that CSS wouldn’t be necessary if one were to create a homegrown solution. The fact remains that their is still integration work involved.

Therefore, my aim in this post is to illustrate a simple example of leveraging the jQuery framework to create a simple iFrame modal window. Of course a polished plugin will be more robust, however, robust is at times overkill. It is at that point where simplicity comes into play and thus the forthcoming example.

Defining the Basics

First we create an object in JavaScript to encapsulate some core methods and properties that we could potentially reuse.

var modalWindow = {
	parent:"body",
	windowId:null,
	content:null,
	width:null,
	height:null,
	close:function()
	{
		$(".modal-window").remove();
		$(".modal-overlay").remove();
	},
	open:function()
	{
		var modal = "";
		modal += "<div class=\"modal-overlay\"></div>";
		modal += "<div id=\"" + this.windowId + "\" class=\"modal-window\" style=\"width:" + this.width + "px; height:" + this.height + "px; margin-top:-" + (this.height / 2) + "px; margin-left:-" + (this.width / 2) + "px;\">";
		modal += this.content;
		modal += "</div>";	

		$(this.parent).append(modal);

		$(".modal-window").append("<a class=\"close-window\"></a>");
		$(".close-window").click(function(){modalWindow.close();});
		$(".modal-overlay").click(function(){modalWindow.close();});
	}
};

Notice that only three CSS classes need to be defined, “.modal-window”, “.modal-overlay”, and “.close-window”. Because of the fact that we are trying to keep things simple, I’ve decided not to check to null’s in required properties (windowId, content, width, height).

Basic Design

Next the three classes from above need to be defined. The “.modal-overlay” class is the layer that covers the current view and serves as a backdrop for the modal window. “.modal-window” is obviously the window itself. In this case, the modal-window class is very generic since we will rely on the styling in the transparent iFrame for design. Lastly, I chose to implement a close graphic which is displayed using the “.close-window” class. Again, this is very basic.

.modal-overlay
{
	position:fixed;
	top:0;
	right:0;
	bottom:0;
	left:0;
	height:100%;
	width:100%;
	margin:0;
	padding:0;
	background:#fff;
	opacity:.75;
	filter: alpha(opacity=75);
	-moz-opacity: 0.75;
	z-index:101;
}
.modal-window
{
	position:fixed;
	top:50%;
	left:50%;
	margin:0;
	padding:0;
	z-index:102;
}
.close-window
{
	position:absolute;
	width:32px;
	height:32px;
	right:8px;
	top:8px;
	background:transparent url('/examples/modal-simple/close-button.png') no-repeat scroll right top;
	text-indent:-99999px;
	overflow:hidden;
	cursor:pointer;
	opacity:.5;
	filter: alpha(opacity=50);
	-moz-opacity: 0.5;
}
.close-window:hover
{
	opacity:.99;
	filter: alpha(opacity=99);
	-moz-opacity: 0.99;
}

The Grand Opening

Now that we have set some basic styles and defined our core functionality, we can open a new modal window to display our iframe.

var openMyModal = function(source)
{
	modalWindow.windowId = "myModal";
	modalWindow.width = 480;
	modalWindow.height = 405;
	modalWindow.content = "<iframe width='480' height='405' frameborder='0' scrolling='no' allowtransparency='true' src='" + source + "'></iframe>";
	modalWindow.open();
};

Implement

<a href="/example/modal-simple/modal.html" target="_blank" onclick="openMyModal('/example/modal-simple/modal.html'); return false;">Click here to open</a>

Implementation is simple, just make a call to the method created earlier with the source of the modal window.

Beyond Simple ‘Modaling’

As stated at the outset, this post was meant to illustrate a bare bones and simple example of a modal window. If you wanted to extend the functionality for example, it would be quite simple to create more “openMyModal” methods to suit needs. So if Facebox or Thickbox are too much for your application, why not try the simple approach?

Updated – Version Available

A Simple Modal – Redux

Apr 25 2008

Desktop Application Style (Full Page Height) Fluid CSS Layout

author:

For those of you who just want the source code, I’ll cut right to the chase. View the demo.

Now for the explanation.

For a recent project, the design spec dictated a fluid layout. Normally, this would be no problem, however, in this scenario there was a footer that always needed to be pinned to the bottom of the page content did not extend very far.

Rather than pinning the footer to the bottom of the page absolutely, I wanted to footer to scroll with the content when the content was long enough to create browser scrollbars. Rather than create JavaScript to position things onResize or scroll, I opted to create a 100% CSS/XHTML layout that accomplished exactly what I wanted.

Although the outcome is not as lean as I would like, but in the end it gets the job done well. What more can I really ask for?

Nov 3 2007

Semantic Headers and Menus (CSS of Course)

author:

UPDATE: I’ve since rethought the implications of this post and I wanted to add that using h1 as the company name is the right choice is certain scenarios. I simply wished to provide an alternate method.

First it has been a very long time since my last post. My excuse is that I moved…and I’ve been a bit lazy. I felt the need to address a topic that seems to have been brought up to me several times over past couple weeks: CSS site navigation.

When structuring and styling menus, a definition list (dl) should be used for the site title and navigation.

The first roadblock some have with this method is that they feel the h1 tag must be used for the site title. However, using the h1 for the site title (or company name in many cases) is redundant. Your h1 (although many web builders view it improperly as a semantic whore and over use it), has great value in SEO. Because the h1 is suppossedly the most important content on a specific page, why would one waste it something like Widgets, Inc. when it could be used for maybe a content rich headline: Widgets Inc Provides Solutions for All Widgets Manufacturers. I thought the following experience was very valuable

As I observed a blind web user navigate through a few pages, he reported that hearing the h1 content on top of the page was boring and redundant for him. Because his screen reader read the content of the title element first, the title element served as the actual title of the document for him, and the h1—which merely repeated the content of the title element—was useless.

ALA – October 09, 2006 – Working with Others: Accessibility and User Research”

If a blind human and his screen reading software sees the h1 used as the site title as redundant, I wonder how it impacts how a search engines screen reader views your site’s content. Clearly, using the dt instead of the h1 for the site title is not a bad thing whatsoever.

Secondly, if you look at the meaning of a definition list you will see that it fits perfectly with the notion that you are defining your site and there direct relationship between the items (navigation). And to reiterate the advantage of not using h1 for your site name, the site navigation is now minimized along with the site name – since both are redundant and not content rich.

Lastly, stlyling your header is now a breeze. And your html structure won’t give you indigestion due to enclosing your site name, navigation, and possibly one other element (perhaps search) in a wrapping div.

Here is the markup for your reference (or view a mockup page). Using this method, you can easily create dropdown menus by nesting another unordered list (ul) inside of the list item (after the anchor tag).


<dl class="sitedefinition">
	<dt><a href="/">Company Name, LLC</a></dt>
	<dd>
		<ul>
			<li><a href="/company/">Company</a></li>
			<li><a href="/solutions/">Solutions</a></li>
			<li><a href="/strategy/">Strategy</a></li>
			<li><a href="/clients/">Clients</a></li>
			<li><a href="/partners/">Partners</a></li>
			<li><a href="/contact/">Contact</a></li>
			<li><a href="/">Home</a></li>
		</ul>
	</dd>
</dl>

Sep 27 2007

« Older Entries