FontFriend 3.0 Released

I’m pleased to announce the imme­di­ate release of Font­Friend 3.0, the Type­kit inte­gra­tion edi­tion. Invok­ing the book­marklet on any Typekit-enabled page will automag­i­cally throw all the fonts in your kit into the cus­tom fam­i­lies list. I’ve set up a demo page with Font­Friend embed­ded and a big Type­kit kit.

Typekit.com uses Rose­wood Fill and Chaparral

My main imag­ined use-case for this fea­ture is the designer try­ing to test out a vari­ety of web­fonts on their page. I’d intro­duced cus­tom lists in Font­Friend 2.5, but they didn’t play well with Type­kit, as I dis­cov­ered when redesign­ing my per­sonal blog. I’d hacked in a fea­ture for my own use, but was never really happy with it.

But then I remem­bered that Type­kit has an API.  They even have an exam­ple book­marklet that lists every font in your site’s kit, doing most of the work for me. A cou­ple of short week­end cod­ing ses­sions later, the fea­ture was inte­grated. Just acti­vate Font­Friend on a Typekit-enabled page and you’ll see the Type­kit logo and your kit’s fonts in the cus­tom list. Check out the demo page to see this in action on a page with a big Type­kit kit.

But wait, there’s more! Font­Friend 3.0 also pop­u­lates your cus­tom font list with every @font-face–declared font fam­ily cur­rently active on your page. See a demo. This only applies to rules declared in stylesheets on the same domain due to cross-domain secu­rity restric­tions, which means that most third party web­font ser­vices are left out in the cold.

Other 3.0 features/changes:

  • Reor­ga­ni­za­tion of the mod­ules to bet­ter suit my imag­ined opti­mum workflow
  • Font weight is now a drop­down to give you numeric access to all weights
  • All drop­downs have arrow tog­gles beside them for speed­ier chang­ing. (I dis­like the tedious “click, move mouse, click again” flow of drop­downs, so this should help.)
  • Drag and dropped @font-face fonts now get thrown in the cus­tom font fam­ily list
  • Drag and drop now uses the asyn­chro­nous Fil­eReader API, which should be much more per­for­mant, espe­cially when drag­ging in mul­ti­ple font files at once. (Thanks to Ryan Sed­don for his work on Font­Dragr that showed me the way.)
  • The pre­vi­ously miss­ing Font Style mod­ule is now included. Hello italics.
  • Big reor­ga­ni­za­tion of the code. It’s still a bit squir­rely, but bet­ter orga­ni­za­tion will make it eas­ier to add (good) fea­tures in the future.

I’d love to sup­port other web­font ser­vices, but none of them have APIs that can do what I’ve done with the Type­kit API (or at least not that I’ve dis­cov­ered). Other ser­vices: please let me know if/when that changes!

Web Typography Pain Points

When I launched mattwie.be, I said that I had some things to say about the state of CSS typo­graphic con­trols. I’m mak­ing good on that threat. Things have come a long way from too-long mea­sures of Times New Roman on a mid-gray back­ground, but CSS still lags behind page lay­out soft­ware in many areas, which is only com­pounded by incon­sis­tent browser implementation.

I’m going to espe­cially focus on ::first-line and ::first-letter pseudo-elements which, to my sur­prise, WebKit has some mas­sive prob­lems with. Specifically:

  • WebKit does not accept text-transform on the ::first-line pseudo ele­ment. This embar­rass­ing bug is almost 6 years old and means that the com­mon typo­graphic prac­tice of set­ting the first line of a para­graph in all-caps is impos­si­ble in Safari, Chrome, and—insanely—iBooks, which uses WebKit for its ebook ren­der­ing. The clos­est you can get is font-variant: small-caps which would work fine if we could also use text-transform: lowercase, but we can’t.
  • WebKit also doesn’t accept a font-family rule in both the ::first-letter and ::first-line pseudo-elements. The lat­ter is usu­ally OK, but the for­mer really sucks. Even worse, in both cases, a font-family rule will cause them to fall back to the sys­tem font!
  • WebKit has a bug where mod­i­fy­ing the DOM of an ele­ment that has a ::first-letter CSS rule attached will result in a phan­tom first let­ter. See QuirksMode’s test case. (Opera does this too.)

Fire­fox isn’t all roses either, despite their ter­rific efforts in bring­ing long-awaited Open­Type fea­tures into CSS. The main thing I noticed was that Fire­fox treats ::first-letter oddly style-wise. It doesn’t seem to behave as a full-fledged block-level ele­ment when set­ting float or dis­play prop­er­ties. It also com­pounds the font-size when the ::first-letter coin­cides with another DOM ele­ment that also sets the font-size.

Some other issues:

  • WebKit sets its pseudo-small caps (when using font-variant: small-caps) smaller than other browsers. It also seems to add some pseudo-emboldening to bet­ter com­pen­sate for the fact that they’re not true small caps.
  • Incon­sis­ten­cies between browsers in con­form­ing to the ::first-letter spec for includ­ing punc­tu­a­tion char­ac­ters. Specif­i­cally, WebKit only seems to include punc­tu­a­tion that pre­cedes the let­ter, not punc­tu­a­tion after it.

I’ve cre­ated a test page that illus­trates a lot of these pain points. I also made a page that demon­strates a WebKit nor­mal­iza­tion strat­egy with some UA sniff­ing and the jQuery fan­cylet­ter plu­gin, which I con­tributed a small patch to along the way. I’d describe that strat­egy, but then this post would never be pub­lished. View source!

Redesign of mattwie.be

I just launched my redesign of my per­sonal blog mattwie.be (for­merly mattwiebe.com) and I couldn’t be hap­pier to finally have it live. This is a full-circle moment for me, as tweak­ing my blog (first on Blog­ger, later on Word­Press) was what launched me into web devel­op­ment. After see­ing that I could pro­duce bet­ter code and design than most of what I was see­ing on the web, I thought I’d give it a go. 3 fun and busy years later, my per­sonal blog has sat stag­nant in both con­tent and design.

Design Phi­los­o­phy

I’m a big fan of design con­straints. For this project–just like my Word­Press theme The Eru­dite—the major design con­straint was “it’s all about the con­tent.” This meant say­ing good­bye to all the cruft of today’s blogs: side­bars, social media shar­ing links, ads, and all the junk that dis­tracts from read­ing the actual con­tent. I might rel­e­gate some typ­i­cal sidebar-type things to the footer (archive nav­i­ga­tion, search) but for now I’m really enjoy­ing the minimalism.

Type & Typography

Web design is 95% typog­ra­phy, and this design pushes that to 99.9%. I’ve made use of Robert Slimbach’s excel­lent Min­ion Pro for body text, while head­lines are set in Carol Twombly and Slimbach’s Myr­iad Pro Con­densed. Both are served by the fine folks at Type­kit. I made exten­sive use of Tim Brown’s Mod­u­lar Scale tool for all dimen­sions, which is why the design (hope­fully) feels nat­ural. My scale is 18px/15px, Musi­cal Fifths.

Also worth not­ing is that advanced web typog­ra­phy is still a land­mine of browser incon­sis­ten­cies and out­right bugs. I will be revis­it­ing some (painful) lessons learned in a future post.

Respon­sive Design

Respon­sive design is fun. Being able to pro­vide a sin­gle tem­plate that works on a vari­ety of devices and at dif­fer­ent screen widths has been the web design holy grail for years, and now we can do it. I tar­geted the iPad por­trait view (768px wide) as the ideal view, as that’s how I enjoy read­ing the most these days. Browsers that don’t under­stand media queries will show this style. I adapt the style to vary­ing degrees for widths of < 1024px (wider screens), 431–649px (iPhone land­scape), and < 431px (iPhone por­trait). I think it turned out pretty well. My focus on con­tent made this process rel­a­tively straightforward.

Post Counts

The only non-standard design ele­ment I included was a post count. This is an attempt to game myself into post­ing more often. I’ve set myself the goal of reach­ing 500 posts by the end of the year, and I now have a con­stant visual reminder of my progress. We’ll see how suc­cess­ful this self–gam­i­fi­ca­tion design ele­ment is. Any­one who’d like to inte­grate this into their own Word­Press tem­plates can grab the code.

A Work in Progress

There’s still more to do. Archives and search need to be designed and exposed. I want a bet­ter expe­ri­ence for the home page; some­thing to describe myself and the site bet­ter to new vis­i­tors. If you have any suggestions/critiques, please sound off in the com­ments below!

The Definitive @font-face Syntax

UPDATE: The syn­tax has already been improved to favour IE9 load­ing WOFF instead of EOT, thanks to some sleuthing by the CSS Ninja.
UPDATE 2: The syn­tax now uses a ? instead of a # because local IE requests choked on the #.

Ethan Dun­ham of Font Squir­rel and Fontspring fame has just released the defin­i­tive @font-face syn­tax. I’ve been hyp­ing it up on my Twit­ter account, but this is too good to restrict to my fol­low­ers there. The new syn­tax is clean, beau­ti­ful, and sim­ple. It looks like:

@font-face {
   font-family: 'MyFontFamily';
   src: url('myfont-webfont.eot?') format('eot'),
        url('myfont-webfont.woff') format('woff'),
        url('myfont-webfont.ttf')  format('truetype'),
        url('myfont-webfont.svg#svgFontName') format('svg');
}

Here’s the magic he found:

The hack trick that makes this work is the ‘?’ fol­low­ing the EOT file­name. Seriously.

Just awe­some. Great work Ethan!

Lessn Shortlinks WordPress Plugin

I recently pur­chased the somad.es domain for use with my own URL short­ener. (Van­ity or own­ing my own URLs: you decide.) I decided to use Alan Hogan’s Lessn More, an improved fork of Shaun Inman’s Lessn. I then decided I wanted to inte­grate the short­link into my Word­Press install, but the exist­ing WP Lessn plu­gin isn’t very good. Its admin page doesn’t adhere to WP secu­rity best prac­tices, it doesn’t use WP’s HTTP API, and it doesn’t prop­erly inte­grate with WP 3.0’s short­link API. In short, it doesn’t do things the WP way.

So, I made my own lit­tle plu­gin. I didn’t want another plu­gin set­tings page, so you have to hard­code your Lessn URL and API key. It inte­grates with the “Get Short­link” but­ton on your write/edit post screen, and the rel­e­vant short­link HTTP header and meta ele­ments are auto-inserted. Only the “post” post_type will get Lessn’d by default, but see the bot­tom of the plu­gin for how to add addi­tional post_types.

<?php
/*
Plugin Name: Lessn Shortlinks
Description: Integrates WP's shortlink functionality with the <a href="http://lessnmore.net/">Lessn More</a> URL shortener. <em>Hasn't been tested with vanilla Lessn, but the API should be compatible.</em> (Edit the file manually to configure)
Version: 1.0
Author: Matt Wiebe
Author URI: http://somadesign.ca/
*/

/**
* SD_Lessn class: integrates WP's shortlink functionality with the Lessn More
* URL shortener.
*
* @uses Lessn More @link http://lessnmore.net/
* @author Matt Wiebe
* @license GPL 2
*
**/

class SD_Lessn {

const API_KEY = 'apikey'; // your Lessn API key
const LESSN_API_BASE = 'http://shorturl.com/-/'; // the API base for your Lessn install
const META_KEY = '_lessnd_url';

private $allowed_types = array('post');

function __construct() {
add_action('publish_post', array($this, 'get_lessnd_url'), 10, 1 );
add_filter('get_shortlink', array($this, 'get_shortlink'), 10, 3 );
}

public function add_post_type( $post_type = '' ) {
if ( $post_type )
$this->allowed_types = array_merge( $this->allowed_types, (array) $post_type );
}

public function get_lessnd_url( $post_id ) {
if ( 'publish' !== get_post_status($post_id) )
return false;

if ( ! in_array( get_post_type($post_id), $this->allowed_types ) )
return false;

if ( $url = get_post_meta( $post_id, self::META_KEY, true) )
return $url;

$params = array(
'api' => self::API_KEY,
'url' => get_permalink($post_id)
);
$api_url = add_query_arg($params, self::LESSN_API_BASE);

$get = wp_remote_get($api_url);

if ( is_wp_error($get) )
return false;

$lessnd_url = wp_remote_retrieve_body($get);

if ( $lessnd_url ) {
update_post_meta( $post_id, self::META_KEY, $lessnd_url );
return $lessnd_url;
}
return false;
}

/**
* @param int $id A post or blog id. Default is 0, which means the current post or blog.
* @param string $contex Whether the id is a 'blog' id, 'post' id, or 'media' id. If 'post', the post_type of the post is consulted. If 'query', the current query is consulted to determine the id and context. Default is 'post'.
*/

public function get_shortlink( $shortlink, $id, $context ) {

if ( 'query' == $context ) {
global $wp_query;
if ( is_singular() ) {
$context = 'post';
$id = $wp_query->get_queried_object_id();
}
}

if ( 'post' !== $context )
return $shortlink;

// Try Lessn'd url.
if ( $try_lessn = $this->get_lessnd_url($id) )
return $try_lessn;
// do_action('elog', $shortlink);
return $shortlink;
}
}

$sd_lessn = new SD_Lessn;

// uncomment line below to add support for the "page" post_type
// $sd_lessn->add_post_type('page');
view raw sd_lessn.php This Gist brought to you by GitHub.

Now, I just need to fig­ure out how to inte­grate short­links for humans rather than just machines.