Lynda Damiata

 

Tom McFarlin on Oct 25th 2011 |
wp.tutsplus.com ::

In the first post, we took a look at how to attach a file – specifically, a PDF – to WordPress posts and pages without having to use a plugin or third-party solution. At this point, you can only upload files – there’s no way to actually deactivate the link or delete the link to the file once it has been uploaded. In this post, we’ll take a look at how to provide some slightly better styling for the download link and how to extend the custom meta box functionality by allowing users to delete files after they’ve downloaded them.

 


Dress It Up

If you followed along with the code in the first post, then you should have a functional demo of how attaching a PDF to a WordPress post (or page) works; however, the overall presentation doesn’t look very good:

figure example

Before going any further, let’s clean this up a bit so that it looks a bit more integrated with the default theme. Remember that we’re using Twentyeleven as our default theme so that we’re all on the same page as we work through the tutorial.

First, let’s move the download link into a more logical location. If you’ve been following along since the first post, you’ll recall that we placed the download link in single.php which is located in the root of the theme directory. Open the file and locate the block of code that looks like this:

get_template_part( 'content', 'single' );
$doc = get_post_meta(get_the_ID(), 'wp_custom_attachment', true);

<a href="    <?php echo $doc['url']; ?>">
Download PDF Here
</a>

Copy all but the first line of code and remove it from the file. This should leave only a call to get_template_part.

Next, locate custom-single.php. This is a template file located in the root of the theme directory. Find the call to the_content() and then paste the code you just copied directly below it. This should result in the following block of code:

the_content();
$doc = get_post_meta(get_the_ID(), 'wp_custom_attachment', true);
<a href="    <?php echo $doc['url']; ?>">
Download PDF Here
</a>

Now, let’s wrap the link in a container so that we can easily style it. I’m giving my container the ID of ‘wp_custom_attachment.’ Feel free to use whatever you like, just remember to refer to it correctly in your stylesheet.

Here’s my markup:

the_content();
$doc = get_post_meta(get_the_ID(), 'wp_custom_attachment', true);
<div id="wp_custom_attachment">
<a href="<!--?php echo $doc['url']; ?-->">
Download PDF Here
</a>
</div><!-- #wp_custom_attachment -->

And here’s my CSS:

.wp_custom_attachment {
margin: 8px 0 8px 0;
border: 1px solid #DDD;
background: #EEE;
padding: 8px;
text-align: center;
border-radius: 4px;
}

Permitting you’ve written everything correctly, the download link should now look like this:

example figure 1

Much better, right? It’s now styled such that it looks to be more tightly integrated with the theme. Remember to make the corresponding changes to page.php, as well (considering that we’re supporting file attachments on both posts and pages).


Download, When Available

Before moving on, we have one more small change to make to the code we just added. Right now, the download link is displayed unconditionally. This means that whether or not a post actually has a file, we’re displaying the download link.

Ideally, we only want to display the download link whenever there is a file to download. As such, we’ll need a conditional. Specifically, we’ll need to get the associated post meta data, determine if there is an actual URL for the file attachment. If so, we’ll display the link; otherwise, we won’t.

In the block of code we just added to content-single.php, place an opening if statement just above the opening wp_custom_attachment tag and close the statement just below the closing container tag. Right now, the code should look something like this:

the_content();
$doc = get_post_meta(get_the_ID(), 'wp_custom_attachment', true);
if() {
<div id="wp_custom_attachment">
<a href="<!--?php echo $doc['url']; ?-->">
Download PDF Here
</a>
</div><!-- #wp_custom_attachment -->
} // end if

We need to check the presence of the document’s URL. There are a number of ways to do this, but I typically check by taking a look at its URL attribute. The resulting code block is:

the_content();
$doc = get_post_meta(get_the_ID(), 'wp_custom_attachment', true);
if(strlen(trim($doc['url'])) > 0) {
<div id="wp_custom_attachment">
<a href="<!--?php echo $doc['url']; ?-->">
Download PDF Here
</a>
</div><!-- #wp_custom_attachment -->
} // end if

At this point, the download link should only display when there is a valid file attached to the give post or page. Try it out.


Deleting The File

At this point, we’ve tied up some loose ends from the previous post and we’re ready to finish up the functionality necessary to delete attachments.

Laying The Foundation

Recall from the last post that once the user attempts to upload a file, we have a serialization function that fires that’s responsible for actually writing the file to disk. For reference, this takes place in save_custom_meta_data.

In order to properly delete a file, we need to track the existing file’s location and whether or not a user has actually requested to delete the file. We’ll do that with a combination of an input box and an anchor.

First, locate the ‘wp_custom_attachment’ function that we created in the last post. This is where we added the file input element. Just below the input element add the following code (the full function will be provided below):

// Create the input box and set the file's URL as the text element's value
$html .= '<input type="text" id="wp_custom_attachment_url" name="wp_custom_attachment_url" value=" ' . $doc['url'] . '" size="30" />';

This will add an a text input element which tracks the value of the uploaded document’s URL. We’ll clean this up a bit later in the tutorial, but for now, let’s introduce an an anchor for deleting the file. Just below the two lines of code we just added, write the following:

$html .= '<a href="javascript:;" id="wp_custom_attachment_delete">' . __('Delete File') . '</a>';

 

Take note: we’ve given the anchor a unique ID. This will be necessary when we begin hooking up the administration area to handle user events. If you don’t give your anchor this ID, make note of whatever you do assign.

We’re not quite done yet. Remember how we setup the single post and page views to conditionally display the download link? We need to do the same thing for the delete link. Specifically, we need to only show the delete link if a document exists. So, in similar fashion, wrap the anchor in a conditional statement that checks for the presence of the document’s URL:

// Display the 'Delete' option if a URL to a file exists
if(strlen(trim($doc['url'])) > 0) {
$html .= '<a href="javascript:;" id="wp_custom_attachment_delete">' . __('Delete File') . '</a>';
} // end if

It’s nothing too heavy, right? To be complete, here’s the full function as it stands:

function wp_custom_attachment() {

wp_nonce_field(plugin_basename(__FILE__), 'wp_custom_attachment_nonce');

$html = '
<p>';
$html .= 'Upload your PDF here.';
$html .= '</p>';
$html .= '<input type="file" id="wp_custom_attachment" name="wp_custom_attachment" value="" size="25" />';

// Grab the array of file information currently associated with the post
$doc = get_post_meta(get_the_ID(), 'wp_custom_attachment', true);

// Create the input box and set the file's URL as the text element's value
$html .= '<input type="text" id="wp_custom_attachment_url" name="wp_custom_attachment_url" value=" ' . $doc['url'] . '" size="30" />';

// Display the 'Delete' option if a URL to a file exists
if(strlen(trim($doc['url'])) > 0) {
$html .= '<a href="javascript:;" id="wp_custom_attachment_delete">' . __('Delete File') . '</a>';
} // end if

echo $html;

} // end wp_custom_attachment
</p>

We’ll revisit this function a little but later in the tutorial but, for now, test it out. First, navigate to a post that has no attachment. You should see the file input box and an empty input box. After uploading a file, you should see the input box contain the URL of the file followed by a link for deleting the file.

But we’re not done yet. After all, the delete link doesn’t actually do anything.

Wiring It Up

Next, locate the ‘js’ directory in the theme root. Add a new file called custom_attachment.js. We’ll write code for this momentarily, but the purpose of the file will be what allows us to actually delete the PDF that we’ve attached to a post.

After that, open up functions.php and add the following function at the end of the file:

function add_custom_attachment_script() {

wp_register_script('custom-attachment-script', get_stylesheet_directory_uri() . '/js/custom_attachment.js');
wp_enqueue_script('custom-attachment-script');

} // end add_custom_attachment_script
add_action('admin_enqueue_scripts', 'add_custom_attachment_script');

This function will read the JavaScript file that we just created and include it on any administrative page in the WordPress backend. Enqueuing and Registering scripts is beyond the scope of the tutorial, but I recommend reading up on it.

Next, let’s revisit the JavaScript file. Generally speaking, the code should do the following things:

  • Determine if the delete link is present
  • If the link is present, attach a custom event handler that clears out the text input that contains the URL of the file
  • Hide the link once the file has been marked for deletion

The source code is below and it has been fully commented to help explain what each line is doing:

jQuery(function($) {

// Check to see if the 'Delete File' link exists on the page...
if($('a#wp_custom_attachment_delete').length === 1) {

// Since the link exists, we need to handle the case when the user clicks on it...
$('#wp_custom_attachment_delete').click(function(evt) {

// We don't want the link to remove us from the current page
// so we're going to stop it's normal behavior.
evt.preventDefault();

// Find the text input element that stores the path to the file
// and clear it's value.
$('#wp_custom_attachment_url').val('');

// Hide this link so users can't click on it multiple times
$(this).hide();

});

} // end if

});

At this point, the file will not be deleted but you should have a functional view. Locate a page that has a file attached to it. Your custom meta box should look something like this:

figure example 2After clicking on the ‘Delete Link’ anchor, the custom meta box should look like this:

example figure 3

If not, double-check your debugging console to verify that you don’t have any JavaScript errors.


Deleting The File

At this point, we’ve done all but actually delete the file. To do this, we’ll need to update the save_custom_meta_data function that we wrote in the first post. Recall that the functional includes a conditional checks the contents of the $_FILES collection coming from the POST request. If the collection is populated, then we serialization the file.

Since we’re attempting to delete the file, the $_FILES collection shouldn’t contain any data so all of our code will need to be contained in an else clause. The full source code for the function will be provided below, but here’s how the functional should work:

  • Check to see if there’s a document associated with the post
  • Check to see if the text box used for tracking the file’s URL is empty
  • If a file exists and the text box is empty, delete the file and update the associated meta data

This should be straightforward: We’ve given each post a text element that contains the URL to the file. If the file URL is empty, it means the user has clicked on the ‘Delete File’ link and is requesting to delete the file. Here’s how we can achieve just that:

// Grab a reference to the file associated with this post
$doc = get_post_meta($id, 'wp_custom_attachment', true);

// Grab the value for the URL to the file stored in the text element
$delete_flag = get_post_meta($id, 'wp_custom_attachment_url', true);

// Determine if a file is associated with this post and if the delete flag has been set (by clearing out the input box)
if(strlen(trim($doc['url'])) > 0 && strlen(trim($delete_flag)) == 0) {

// Attempt to remove the file. If deleting it fails, print a WordPress error.
if(unlink($doc['file'])) {

// Delete succeeded so reset the WordPress meta data
update_post_meta($id, 'wp_custom_attachment', null);
update_post_meta($id, 'wp_custom_attachment_url', '');

} else {
wp_die('There was an error trying to delete your file.');
} // end if/el;se

} // end if

Once the file is deleted, note that we also have to update the post meta data by emptying out the attachment’s value as well as the attachment’s URL value. In the odd case that the file doesn’t delete, we’re displaying a simple error message. Advanced error handling is beyond the scope of this post.

As promised, here’s the full serialization function:

function save_custom_meta_data($id) {

/* --- security verification --- */
if(!wp_verify_nonce($_POST['wp_custom_attachment_nonce'], plugin_basename(__FILE__))) {
return $id;
} // end if

if(defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
return $id;
} // end if

if(!current_user_can('edit_page', $id)) {
return $id;
} // end if
/* - end security verification - */

// Make sure the file array isn't empty
if(!emptyempty($_FILES['wp_custom_attachment']['name'])) {

// Setup the array of supported file types. In this case, it's just PDF.
$supported_types = array('application/pdf');

// Get the file type of the upload
$arr_file_type = wp_check_filetype(basename($_FILES['wp_custom_attachment']['name']));
$uploaded_type = $arr_file_type['type'];

// Check if the type is supported. If not, throw an error.
if(in_array($uploaded_type, $supported_types)) {

// Use the WordPress API to upload the file
$upload = wp_upload_bits($_FILES['wp_custom_attachment']['name'], null, file_get_contents($_FILES['wp_custom_attachment']['tmp_name']));

if(isset($upload['error']) && $upload['error'] != 0) {
wp_die('There was an error uploading your file. The error is: ' . $upload['error']);
} else {
add_post_meta($id, 'wp_custom_attachment', $upload);
update_post_meta($id, 'wp_custom_attachment', $upload);
} // end if/else

} else {
wp_die("The file type that you've uploaded is not a PDF.");
} // end if/else

} else {

// Grab a reference to the file associated with this post
$doc = get_post_meta($id, 'wp_custom_attachment', true);

// Grab the value for the URL to the file stored in the text element
$delete_flag = get_post_meta($id, 'wp_custom_attachment_url', true);

// Determine if a file is associated with this post and if the delete flag has been set (by clearing out the input box)
if(strlen(trim($doc['url'])) > 0 && strlen(trim($delete_flag)) == 0) {

// Attempt to remove the file. If deleting it fails, print a WordPress error.
if(unlink($doc['file'])) {

// Delete succeeded so reset the WordPress meta data
update_post_meta($id, 'wp_custom_attachment', null);
update_post_meta($id, 'wp_custom_attachment_url', '');

} else {
wp_die('There was an error trying to delete your file.');
} // end if/el;se

} // end if

} // end if/else

} // end save_custom_meta_data
add_action('save_post', 'save_custom_meta_data');

By now, you’ve got a fully functioning custom meta box. Give it a try.


Cleaning It Up

We’ve got one last minor change to make just to make our UI complete. Remember the text input that we added earlier in the tutorial that’s responsible for maintaining the file’s URL? We can mark that as hidden – there’s no reason the user needs to see it. The JavaScript source will still use it properly and its value will be read in the serialization function.

The final wp_custom_attachment function should look like this:

function wp_custom_attachment() {

wp_nonce_field(plugin_basename(__FILE__), 'wp_custom_attachment_nonce');

$html = '<p>';
$html .= 'Upload your PDF here.';
$html .= '</p>';
$html .= '<input type="file" id="wp_custom_attachment" name="wp_custom_attachment" value="" size="25" />';

// Grab the array of file information currently associated with the post
$doc = get_post_meta(get_the_ID(), 'wp_custom_attachment', true);

// Create the input box and set the file's URL as the text element's value
$html .= '<input type="hidden" id="wp_custom_attachment_url" name="wp_custom_attachment_url" value=" ' . $doc['url'] . '" size="30" />';

// Display the 'Delete' option if a URL to a file exists
if(strlen(trim($doc['url'])) > 0) {
$html .= '<a href="javascript:;" id="wp_custom_attachment_delete">' . __('Delete File') . '</a>';
} // end if

echo $html;

} // end wp_custom_attachment

These two posts covered a lot of information. There are a number of canned solutions – be it plugins, themes, or other add-ons – available for integrating functionality like this, but part of being a good developer is knowing when to use a third-party solution and when to roll your own.

Additionally, if you’re working with WordPress in a professional capacity, then it’s important to understand the API. Hopefully this series has helped showcase much of what can be done by leveraging core functionality of WordPress.

 

September 30th, 2011 by Jason Grigsby |
cloudfour.com ::

In Responsive IMGs Part 1, I took a high-level look at what responsive IMGs are, the problem they are trying to solve, and the common issues they face. In this post, I’m going to take a deeper look at the specific techniques being used to provide responsive IMGs and try to evaluate what works and doesn’t. If you haven’t read part 1, you may want to do so before reading this post as it will help explain some of the terms I use.

When I started working on this project two months ago, I thought I would get to the end and be able to say, “Here are the three approaches that work best. Go download them and figure out how to integrate them into your systems.” Oh naivety!

What I’ve found is that there is no comprehensive solution. Instead, we have several months of experiments. Each experiment has its own advantages and disadvantages.

Because of this, the best thing we can do is understand the common elements and challenges so that we can start to pick the best parts of each for building our own solutions.

So um… this is a long post. Sorry.

Abandoned approaches

Dynamic Base Tag

Many of the early techniques used javascript to dynamically change the base tag. The new base tag would add directories into the path that would be used to indicate what size image should be retrieved. After the document loaded, the base tag would be removed.

Unfortunately, this approach ran into race conditions that I described in part 1. I found that Google Chrome was downloading both the mobile and desktop images. Scott Jehl found the problem to be a difference between how inline and external javascript is handled. He submitted a bug to webkit which has been marked as “won’t fix” because:

Inserting base element effectively changes all the subsequent URLs on the page. Any script may insert one so to avoid double loads we could never load anything else as long as there is a pending script load. This would mean disabling preloading, which is out of the question.

In theory, you could still use a dynamic base tag inline, but the Filament Group has been primarily using a cookies-based approach instead which seems safer.

Temporary images

Another early technique was to have the src of imgs pointing to a temporary image and then having javascript replace the source with the correct file path. In most cases, the image was an one pixel transparent gif set up with caching which would hopefully prevent the browser from requesting it more than once no matter how many times it was referenced in the page.

The problem with this technique is that if javascript isn’t present, the browser will never download the images.

Javascript-based solutions

Where do you store the path to alternate versions of an image?

If the the img points to ‘small.jpg’, where do you put the information that ‘large.jpg’ is what should be loaded on larger screens?

URL parameters

One solution is to put the path to alternate versions of the image in the src attribute as url parameters. In its simplest form:

<img src="small.jpg?full=large.jpg">

If you have multiple sizes of images, they simply get added as additional values on the url. The key to making this work is coupling it with an .htaccess file.

Potential CDN, proxies, and caching issues

The big drawback to using URL parameters is that it may cause problems with content deliver networks and proxies that doesn’t pay attention to url parameters when caching content. Some caching algorithms ignore anything that has a URL parameter on it which means that pages will slow down because images aren’t cached.

Others will simply cache the first version of the image they see. If the first person behind a proxy cache happened to view the page on a mobile phone, then every subsequent user sees the mobile size image until the cache expires.

How likely is this to be an issue? I had the same question so I asked Steve Souders. He says that it is enough of a problem that you can’t ignore it. This echoes comments by Bryan and Stephanie Rieger at Breaking Development about problems with caching and CDNs.

Therefore, I think we should be looking for techniques that don’t use url parameters.

Examples of this approach:

Data attributes

Instead of putting the file path into the url parameters, the information is put in one or more data- attributes. For example:

<img src=”small.r.jpg” data-fullsrc=”large.jpg”>

Which element has data attributes added to it and how many are added depends on the technique.

Looping through every img tag

The only disadvantage to this technique that I’m aware of is the fact that the javascript has to loop through every image, check for data attributes, and then modify the src attribute depending on screen size. This is probably not a big problem on desktop browsers which is where the loop is mostly to be used.

Examples of this approach

Assumed file structure

In this variation, the file path isn’t included in the HTML document. Instead, it is assumed that the images are put on the server in a regular fashion. For example, all small images might be in /images/sml/ whereas large images are in /images/lrg/.

If this is true, then the html doesn’t need to provide both paths. It just needs to provide the image filename (e.g., boat.jpg) and then let javascript modify the src to be appropriate for the size of the screen (/images/lrg/boat.jpg for desktop).

Examples of this approach

Dynamic file names

One of the things that I suggested in part 1 was that we might need arbitrary image sizes. Some of the solutions are built around the assumption that you can pass the dimensions that you want in the url and get back an image at that size.

Because the images are resized on the fly, there is no need to store alternative file paths in the HTML document. Javascript will modify the filename from something like ‘boat.jpg’ to ‘boat-480×200.jpg’. There is no issue with caching or CDNs because each image is unique.

Some images cannot simply be resized

This approach doesn’t provide a good solution for manually choosing images at different sizes. It assumes that resizing images will work in all cases which we know is not true.

Examples of this approach

Role of .htaccess (or similar rewrite rules)

Many of the solutions rely on server rewrite rules. The examples are usually written using Apache .htaccess files, but they could be any sort of rewrite rule.

Lets look at a snippet of the .htaccess file from Responsive Images JS cookie-based branch to see how rewrite rules are being used:

RewriteEngine On
#large cookie, large image
RewriteCond %{HTTP_COOKIE} rwd-screensize=large
RewriteCond %{QUERY_STRING} large=([^&]+)
RewriteRule .* %1 [L]

The first line turns rewrite rules on. Next comes a couple of conditions (RewriteCond). The first checks to see if there is a cookie called rwd-screensize that has the value of large. The second checks to see if the query string for the url contains a value for large. This .htaccess file is looking for something like:

<img src="small.jpg?large=large.jpg">

If both conditions are met—the cookie is set to large and there is a large value in the query string—then the rewrite rule will send the file that was specified in the query string (in the example above, that would be large.jpg).

The rwd-screensize cookie is set by javascript after it tests for the screen size.

How do you prevent the browser from downloading multiple images?

With the basics out of the way, we can now get to the tricky part. As mentioned in part 1, intercepting the browser before it starts downloading images so that you can evaluate and possibly change the source of those images is tricky and may result in race conditions.

Now that the dynamic base tag has been ruled out, there are two main techniques that remain.

Set a cookie

This is the method that the Filament Group settled on for the Boston Globe. Javascript is inserted into the head of the document so that it evaluates as soon as possible.

After it determines the screen size, it sets a cookie. Every subsequent image request sent from the browser will include the cookie. The server can use the cookie to determine the best image to sent back to the user.

Potential problems

If the browser doesn’t support cookies or the user blocks them, then the javascript will have no effect.

Also, Yoav Weiss has done some testing and shared results that indicate that duplicate files will be downloaded by IE9. Firefox will download duplicate files if the script is external, but not if it internal. This suggests that cookies may also be subject to the race condition problem that caused us to abandon the dynamic base tag approach.

Examples of this approach

Noscript tag

Within the last couple of months, new techniques have emerged that use the noscript tag as a way to prevent extra downloads. The first post I saw describing this technique was by Mairead Buchan. She describe it as having “ the elegance of a wading hippo”. Despite that description, I think this technique holds promise.

A cleaner implementation of the noscript approach was created independently by Antti Peisa. Here is the html:


<noscript data-large='Koala.jpg' data-small='Koala-small.jpg' data-alt='Koala'>
<img src='Koala.jpg' alt='Koala' />
</noscript>

The values for the various sizes of image tags are stored in the data attributes on the noscript tag itself. Antti then provides sample jQuery code used to process the image:


$('noscript[data-large][data-small]').each(function(){
var src = screen.width >= 500 ? $(this).data('large') : $(this).data('small');
$('<img src="' + src + '" alt="' + $(this).data('alt') + '" />').insertAfter($(this));
});

These lines go through the document to find noscript tags with the appropriate data attributes. It tests for the screen size and then inserts a new img tag with the appropriate image path and alt tag.

No race conditions!

When using the noscript tag, there are no rendering race conditions. The image in the noscript tag never starts downloading. Mairead explained that “it works because children of the <noscript> tag are not added to the DOM”.

This makes sense. The browser knows if javascript is available before it starts rendering a page. If javascript is available, there is no reason to worry about doing anything with items inside the noscript tag. If they aren’t getting added to the DOM, they certainly aren’t going to get downloaded.

This technique also has fallbacks if javascript isn’t enabled and doesn’t rely on cookies or htaccess files.

Potential gotchas

The biggest gotcha will be devices that profess to support javascript, but have poor implementations. For example, Blackberry 4.5 has javascript, but javascript cannot manipulate the DOM. Ergo, the noscript tag will not get used because scripts are available, but the script won’t successfully add a new img tag so no images will show.

Please note, this is speculation on my part. I know how Blackberry 4.5 behaves, but I haven’t tested this particular approach on a 4.5 device.

Even though this approach does not create a race condition, it is important that the javascript execute as quickly as possible. Inserting all of these images may require the browser to reflow the page. It also may cause the browser to load assets less efficiently because it cannot start prefetching assets.

Because of the need to execute as quickly as possible, it makes sense to remove the jQuery dependency from Antti’s javascript and put the code in the head of the document.

Examples of this approach

Is screen size the right thing to look at?

Most of these techniques rely on the size of the screen to determine what the image size should be. Andy Hume points out that the size of the screen may be misleading. He writes:

The content driven approach to fixing this is to decide which image to load based on whether the image will be stretched beyond its true pixel width. If you stretch an image beyond its true width it begins to look pixelated or blurry. In this scenario, we want to load in a higher resolution version of the image.

Andy’s fork of the Responsive Images JS tackles this problem (and adds support for nginx).

Boston Globe Responsive IMGs are Busted

I’ve been looking forward to the Boston Globe’s launch for quite some time. It is a tremendous feat of engineering and design. It has the volume of traffic necessary to test different approaches to responsive IMGs and see what works and what doesn’t.

The technique that they chose to use combines data attributes with cookies. Unfortunately, responsive IMGs are currently broken on the Boston Globe site. This is a known problem and they are working on fixing it.

The upshot is that we don’t yet have a large scale deployment of any of these techniques that we can interrogate and point to as validation that a particular combination is battle-hardened.

Most promising javascript only techniques

In my mind, cookies plus data-src and noscript are the two most promising techniques. Both have problems, but they have far fewer gotchas than other approaches.

Server side solutions

Most of the javascript techniques require little, if any, support from the server. There are alternate approaches that leverage the server for a bunch of the heavy lifting.

User agent string parsing

A few people have demonstrated solutions that do light-weight user agent string parsing to identify various mobile phones. If the user agent can be identified as iPhone or Android, then declare the device mobile and set the image size appropriately.

Unlike a lot of developers, I don’t have a problem with device detection based on user agent string. But if you’re going to start doing it for mobile, you have to take on real device detection via WURFL, Device Atlas, etc. Simplistic regular expression matching and assumptions about screen sizes isn’t going to work.

Device detection

There are a couple of different approaches that rely on device detection to determine the screen size and deliver an appropriate image back. Device detection databases are pretty good about having basic information like screen size.

Sencha.io Src (formerly called TinySRC)

James Pearce created a fantastic service called TinySRC. He later went to work for Sencha and TinySRC became Sencha.io Src. Sencha.io Src automatically resizes images for you. You reference Sencha.io Src in your img stag like this:

http://src.sencha.io/http://www.myapp.com/myimg.jpg

When a browser requests the url above, Sencha.io Src will look up the user agent of the device making the request to determine what size image is appropriate. It will then grab the image from your server and resize it. It then caches the resized image so that subsequent requests can be served quickly.

In addition to the automatic mode, Sencha.io Src will also allow you to specify specific sizes that you would like the image resized to.

Combining Responsive Images JS with Sencha.io Src

Andrea Trasatti forked Scott Jehl’s Responsive Images JS to combine responsive IMGs with TinySRC. The script finds the screen size using javascript and then uses htaccess to request the image at the correct size from Sencha.io Src.

Andrea’s version was written fairly early. It still uses dynamic base tags, url parameters, and results in “1 HTTP request for every image that we might avoid”. But all of these problems could be remedied by combining what Andrea started with some of the newer approaches.

Potential drawbacks

First, if you have a religious aversion to device detection, then you probably don’t want to use Sencha.io Src or you need to use it in a scenario where can specify the image size that you want.

As an aside, I’ve found it funny to see people who speak ill of device detection and user agent strings suggest that people use TinySRC. I once saw a slide deck that dismissed device detection and then a couple of slides later talked about how great TinySRC is. If only they knew.

On a more practical level, you have to evaluate whether or not the service will remain up and what happens if all of your content points to sencha urls that suddenly go away. I don’t think Sencha is going to go anywhere anytime soon. I know James well enough to know he’ll want to keep this service running forever if he can. But even all that said, looking at the long term availability of a service is something that needs to be considered.

WURFL-based solution

WURFL is the largest open source device database. After attending the Breaking Development conference earlier this month, Carson McDonald was inspired to develop a WURFL-based solution for images. It’s awesome to see something come together so quickly after the conference.

(BTW, Breaking Development is the best conference in North America for web on mobile. Registration for the next event opens today. You should attend!)

Carson notes that his approach will likely have the same problems with CDNs and caching because different size images come from the same url.

Image resizing services

Google’s mod_pagespeed

Google’s mod_pagespeed Apache module automates many performance tasks and includes an option to scale any images on the fly. There are many ways to scale images (GD, ImageMagick, etc.). I decided to call out mod_pagespeed because it was one I hadn’t considered until I saw it suggested in a forum. I don’t know of anyone who has explored how it might be used in an responsive IMGs solutions.

Combining client and server approaches

Adaptive Images

As you can probably tell by now, there are few solutions that you can simply install and forgot about. Most require at minimum changes to the way you mark up the page. The two solutions that come closest to be plug and play are Sencha.io Src and Adaptive-Images.com.

Adaptive images was developed by Matt Wilcox. It turns the premise of Responsive IMGs on its head by assuming that the markup on the page will contain the large versions of images and will not start with the mobile versions.

The solution consists of three pieces:

1. A small snippet of javascript placed in the head that sets a cookie with the screen width and height.

<script>document.cookie='resolution='+Math.max(screen.width,screen.height)+'; path=/';</script>

2. A .htaccess that rewrites all requests for images to a php file. You declare directories that you want to exempt from this rewrite. For example, you don’t want your media query savvy CSS background images getting routed through the php file.

3. The php file which resizes the image based on breakpoints that you can configure.

The best part of Matt’s solution is that as long as you can separate out your image files so you can exclude ones that shouldn’t be resized, you can implement this technique without making any changes to your existing markup. Existing pages and posts will suddenly have different image sizes.

And now for the problems

Come on, by now you weren’t expecting it to be that simple did you?

Because the images start with the large size, if javascript is not available, the large size will be delivered. The most common devices to not have javascript support are older feature phones. The type of devices that will choke and even crash on large images are older feature phones.

This technique also suffers from the same race conditions that most of the javascript solutions do. The cookie has to be set early to avoid extra downloads.

Update: Matt commented below and points out that the default settings will result in a small image being delivered if javascript isn’t present. The markup will point to a large version, but the php file returns a small version. All of this is configurable.

Also, he is right that the result of the race condition would not be multiple downloads. I think the race condition still exists with different drawbacks, but I’m going continue the conversation in the comments where Matt and I can converse.

I also missed the fact that the url will stay the same regardless of the size of image which can cause issues with CDNs and proxy caching as noted earlier.

Yiibu profile approach

Brian and Stephanie Rieger presented the work they did for browser.nokia.com at Breaking Development conference. For that project, they invented a new way to combine client side information with device detection.

When a browser first requests something from the server, they don’t know anything about the device. So they check with a device detection database to see what they can find out about the size of the screen (and other details). They then check their own local database of tacit knowledge. This a database of things they’ve learned about how specific browsers work and any overrides they want to use. They use the combination of this information to deliver the appropriate HTML, javascript and images.

Once the browser gets this information, a javascript runs that tests the various aspects of the browser including screen size. It then stores this information in a profile cookie.

On the second request, the server receives the profile cookie and compares it to the information it has in its tacit database. It may update the tacit database. It combines the information into a revised profile combining server side information with client feature detection data.

I’m likely doing a poor job of describing the solution. Your best bet is to look at their slides:

This combined technique mitigates the problem of first load without any of the race conditions or potential problems that the client-only solutions have. It also extends beyond images to other content and javascript.

Sounds great. What’s the catch?

It is a complex system and requires significant changes to infrastructure to support. Bryan and Stephanie have published the approach, but the code isn’t available for download. It may be coming, but they took a well-deserved vacation after spending most of the summer working on the Nokia Browser project.

Probably the biggest problem with this approach is that most of us are not the Riegers. They have been doing mobile web for years. Their tacit knowledge of devices is exceptional. Freaking geniuses. That’s hard to replicate.

The same is true of the Boston Globe project. The team working on that included significant portions of the jQuery Mobile team and the guy who coined the phrase responsive web design. Few of us are going to be so lucky on our next project.

Summary

As I’ve reviewed the various techniques, I keep thinking back to something Andy Hume said in response to part 1:

Our current solutions are hugely dependant on the current (and undefined) behaviour of browsers in regard to the page-load race conditions you mention. For example, most responsive image implementations would be compromised if a particular type of look-ahead pre-parser (http://goo.gl/TyzTi) began to speculatively download images before actually parsing the HTML or executing any script. (I half expect us to get bitten by this any day.) One way or the other we need to consort with browser makers to get future-friendly.

That’s the truth of it. Most of these techniques are based on our hope that browsers continue to download assets in the order we have observed to date. If the the order changes or if browsers start pre-parsing more aggressively, the whole house of cards may fall down.

In part 3 of this series, I’m going to look at the conversations going on about ways to change the img tag or replace it with something that will work better with multiple file sources.

Sources and Acknowledgments

I reviewed 18 different techniques for this post. My notes are captured in a Google spreadsheet that you are welcome to review for detailed comments on each library. Thanks to everyone for publishing their thoughts and experiments. I learned a lot from each one.

This series wouldn’t have been possible without the assistance of Scott Jehl and Bryan and Stephanie Rieger. Scott in particular helped me sort out the problems with the main Responsive Images JS library. Thanks to all three of you for putting up with my many naive questions and for taking the time to explain all of the work you’ve been doing!

 

September 27th, 2011 by Jason Grigsby |
cloudfour.com ::

In my post “Where are the Mobile First Responsive Web Designs”, I noted that one of the first things I look for when trying to determine whether or not a responsive web design is “mobile first” is whether or not it has a strategy for handling the IMG tag.

A recent Smashing Magazine round up of responsive web design techniques included several new approaches for handling IMG tags which makes it the perfect time to dig into this problem and the potential solutions in more depth.

Why IMG Tags Suck for Responsive Web Design

If you want your site to load as quickly as possible, you do want to deliver larger files than are needed. Many responsive web design sites provide mobile devices images at sizes appropriate for desktop and ask the mobile device to resize the image.

In my research, I found nearly 80% decrease in file size by delivering images at the actual size they were going to be used on a mobile device.

So what’s the problem with the IMG element in responsive designs? Unlike CSS images which can provide different source files based on screen resolution using media queries, IMGs have a single source attribute.

What are Responsive IMGs?

Responsive IMGs are images delivered using the HTML IMG tag that come from different sources depending the screen size. There are many different techniques for accomplishing Responsive IMGs.

As far as I can tell, Scott Jehl first coined the phrase Responsive Images to describe a javascript solution to the img source problem. He also referred to Responsive IMGs as a general term recently so I’m hopeful he doesn’t mind the fact that I’m extending his definition to describe any technique that attempts to provide images at an appropriate size for a responsive design.

Responsive IMGs Challenges

There are some common challenges that any Responsive IMG technique will face. As we review the various techniques that have been proposed, we need to keep these challenges in mind.

Minimum Bar: Start with Mobile, No Extra Downloads

Scott Jehl set a minimum bar for Responsive IMGs by stating they must do the following:

  1. Start with mobile img
  2. Upgrade to larger size without downloading both

Both of these are worthy and necessary goals.

The First Page Load Problem

Any solution that relies on client-side scripting to make a decision about what image source to display will suffer from a first page load problem. The first time someone visits a site, the server won’t know what size image to provide.

responsive images 1

Image from Bryan Rieger’s Muddling Through the Mobile Web presentation, photo by wscullin, licensed under Creative Commons.

If javascript is added that determines what image size is appropriate, then this information can be retained for the user session via cookies or similar techniques. In theory, on subsequent requests the server can make a decision about what size image to include in IMG tag.

FWIW, the speed of first load is a big deal. The speed of a person’s first experience can dictate their impression of a product and company. Google, Yahoo and others have talked about how minor speed differences makes a big difference in usage of their products.

Rendering Race Conditions

Techniques that rely on adjusting the image source attribute via javascript need to make sure that the modification happens before the image requests start.

Browser makers have done a lot of work to download as many assets as possible at the same time. Usually this is a good thing. But in the case of responsive imgs, the javascript needs to evaluate what size image to retrieve before any image requests start.

A lot of earlier work was done using dynamic base tags. This worked when the javascript was inline in the head tag, but failed to prevent images from downloading twice when an external javascript file is used.

The upshot is that nearly every client side technique requires deep understanding of the order in which different browsers process and download assets. Or more realistically, each approach needs to be tested extensively.

Content Delivery Networks and Caching

When you deliver different size images at the same url, you can run into problems with CDNs and other caching at the edge of the network. If the first person to request an image is on a mobile phone, people who follow via the same CDN or cache will also see the mobile-optimized image even if they are on desktop unless consider CDNs in your strategy.

Future Friendly Responsive IMGs

If we accept that the “quantity and diversity of connected devices—many of which we haven’t imagined yet—will explode”, then we need to consider look for solutions that are future friendly. In addition to the current experimentation, we need to start thinking about what a long term solution might look like.

For example, many of the early solutions for Responsive IMGs consist of two size images: one for desktop and one for mobile screen sizes. Will two image sizes really suffice for all of the devices that are coming?

Also, a lot of the solutions right now tackle one part of the problem. They may tackle the client side changes to switch the image source, but leave as an exercise for the developer to figure out how image resizing will be handled. For shared libraries, limited scope makes sense.

But as we look at what systems will need to do to be successful in the future, we need to think about what we want out of both the server and client side.

Here are some of the things that I think a future friendly technique will need to consider:

  • Support arbitrary image resizing — We cannot anticipate what screen sizes may be coming. We need systems that handle image resizing automatically and support any arbitrary size needed for a particular page.
  • Art direction can override automatic resizing — Not every image can be resized without losing the meaning of the image. Sometimes cropping an image may work better than resizing it. Automatic tools need to easily support manual override.

unreadable image

  • Support for higher resolution displays — What do we do with the iPhone 4’s retina displayand other devices sharing similar high resolution screens? It is an open question about whether we should deliver higher resolution images to those devices given the performance hit that will occur if the person is on a slow connection.But regardless of how we chose to handle it right now, it is clear that the trend towards more pixels per inch on displays is not going away. If anything, we’re seeing indicators that higher density will soon be available on desktop displays as well.This means that our current definition of what is a large image for web is probably too small for future devices. With that in mind, it probably makes sense for systems to accept the highest resolution image possible—even if that resolution isn’t currently being used—so that when new devices become available the high resolution source is already available and hasn’t been lost.
  • Connection speed should be part of the criteria — We can be much smarter about the size of the image we deliver if we can tell something about the network connection. We need an easier way to get at this information.
  • A replacement for the IMG tag? — All of the responsive image solutions are attempting to deal with the fact that the image tag has only a single source. There have been various proposals recently to take a new look at what the tag should be and see if we can find a long term replacement.

That’s my short list. What would you add?

In part 2, I’ll take a closer look at the current alternatives for responsive imgs and which ones hold the most promise.

 

November 9, 2011 |
blog.typekit.com ::
Type study is an ongoing series of guest posts about typography on the web. In this article, Ethan Marcotte dishes up advice on font size.

Yes, it’s true. This is a blog entry about sizing text for the web.

…look, I know you’re still out there. I can hear you breathing.

Sure, sizing text isn’t the most glamorous topic. What’s more, it can get downright contentious, with camps forming around their favorite units of measurement. The truth is, each approach has its own unique strengths and limitations. So below, let’s dive into a few popular methods, discuss them with a bit of equanimity, and wrap up this little essay with a better understanding of our options for font-size.

Our old friend, the pixel

Let’s dive in with a quick little demo. To start us off, I pulled a short passage from an old, favorite book, marked it up in some basic HTML5, and applied some light CSS. If you’d like, you can view my little page.

article example

Now, sharp-eyed reader that you are, you’ve probably noticed the markup’s as modest as the design:

<article>
  <header>
    <h1>
      <img src="dorothy.png" alt="" />A Brief Excerpt from <cite>The Wonderful Wizard of&nbsp;Oz</cite>
    </h1>
    <h2>by <a href="#">L. Frank Baum</a></h2>
  </header>

  <div>
    <p><b>The Lion hesitated</b> no longer, but drank till…</p>
    …
  </div><!-- /end .article-body -->

  <footer>
    <p>Words by …</p>
  </footer>
</article>

Our page is essentially one big article element, which contains:

  1. A header to house the headline (h1.main-title) and byline (marked up oh-so-imaginatively as h2.byline).
  2. The primary text is contained inside a div with a class of article-body.
  3. Finally, a footer element rounds out the copy with some attribution.

Nothing too fancy, right? Well, the styling’s just as unassuming. Now, since this is an article about font sizing, let’s not worry our pretty little heads about layout. Instead, let’s focus on the fonts:

body {
  font: normal 16px/24px adobe-text-pro, Cambria, Georgia, "Times New Roman", Times, serif;
}

.main-title {
  font: normal 30px/36px abril-display, Palatino, Georgia, Times, serif;
}

.main-title cite {
  font-size: 42px;
  line-height: 50px;
}

.article-body {
  font-size: 18px;
}

.caps,
figure,
footer {
  font-size: 14px;
}

From the outset, it’s obvious the page relies heavily on Adobe Text Pro set on the body, with TypeTogether’s elegant (and new!) Abril Display prettying up our .main-title headline. And with those defaults established, the rest of the CSS is dedicated to specifying a few different font sizes: five rules, five different font-size values, each set in pixels. And that’s basically it.

Easy, right? I think that’s half the appeal of the mighty pixel, actually: just how easy it is to use. We can transfer a few pixel values from Photoshop into CSS, and — voilà — your work’s nearly finished. But efficiency aside, I think there’s something appealing about the promise of control that comes with declaring a few quick pixel values, a control that’s so darn appealing to us designers. But for all its strengths, px isn’t the best game in town.

In fact, there’s one well-known drawback to sizing type in pixels: Internet Explorer’s “Text Size” tool (still) won’t resize any text set in pixels. Now, it’s true that many desktop browsers, including more recent versions of IE, include some form of page zoom, which can magnify the size of your entire design, including its text. But older versions of IE are, alas, still out there.

Moreover, exploring alternatives to the venerable pixel might result in some real, practical benefits. Ever built a menu that allowed the user to dynamically change the size of text on a page? I’ve worked on a few, including one that launched recently. If your design’s universally set in pixels, each text size “level” would require you to redeclare sizes for every px-based element of your design. So it’s very possible that on some projects, pixels simply won’t scale. (Pun unfortunate, but intended.)

Now that I’ve stepped off my soapbox, let’s take a look at a slightly more proportional alternative, a unit of measurement that does play nicely with resizing: namely, the em.

Becoming context-aware with ems

Because I’m a sucker for nostalgia, let’s revisit our body rule. Here’s what we’re currently working with:

body {
  font: normal 16px adobe-text-pro, Cambria, Georgia, "Times New Roman", Times, serif;
}

Before we start getting more proportional, let’s tweak it ever so slightly:

body {
  font: normal 100% adobe-text-pro, Cambria, Georgia, "Times New Roman", Times, serif;
}

Catch the difference? All we’ve done is change the font-size value to 100%, setting our document’s base type size to the browser’s default, which is usually 16px. As a result, we’re left with a flexible baseline, a point of reference from which we can size our text up or down using relative units of measurement—specifically, the em.

It’s worth mentioning that some folks prefer setting the body to a font-size of 62.5%, as this gives us a relative baseline of approximately 10px—which can make relative font sizing much, much easier. Richard Rutter, author of the original 62.5% technique, wrote a fantastic article for A List Apart recommending 100% as a better baseline, one that ensured more consistent cross-browser results.

But I digress. Regardless of what your baseline preference might be, our job at this point is to convert our pixel-based font-size values into their em equivalents. To do so, we’ll need to do a teensy bit of math: we’ll simply take the target pixel value we’ve already set, and then divide it by the font-size of its containing element — in other words, its context. The result is our desired font-size, but converted neatly into relative terms, which we can then drop directly into our CSS as ems.

In other words, relative font sizes can be calculated like so:

target ÷ context = result

Let’s take a quick example. Remember our main headline?

.main-title {
  font: normal 30px/36px abril-display, Palatino, Georgia, Times, serif;
}

In order to turn the headline’s 30px size into an em-based value, we need to define it in relationship to its context — that is, the font-size of the body element. Let’s assume our font-size: 100% is roughly equivalent to 16px. So let’s plug our .main-title’s target font size (30px) and its context (16px) into our formula:

30 ÷ 16 = 1.875

Boom. 30px is 1.875 times greater than 16px, so our font size is 1.875em.

Now you may recall that the book’s title was wrapped in a cite element inside our main headline, and sized a bit larger than the text that preceded it:

.main-title cite {
  font-size: 42px;
}

If we want to convert that 42px to ems, it’s important to note that our context has changed. Since we’ve set a font-size on our .main-title headline, the font-size of any elements within need to be expressed in relation to that value. In other words, our cite’s target value of 42px needs to be divided not by 16px, the body’s font-size, but by the 30px we set on our headline:

42 ÷ 30 = 1.4

And that’s it. With a little bit of contextual awareness, we’re left with a proportional font-size for our .main-title headline, as well as the cite inside it:

.main-title { font: normal 1.875em/36px abril-display, Palatino, Georgia, Times, serif; /* 30 / 18 */ } .main-title cite { font-size: 1.4em; /* 42 / 30 */ line-height: 50px; } 

(I personally like including the target and context values as comments in my CSS, usually off to the right of the relevant property. I’ve found it makes revising these relative values much easier, especially since the origin of a value like 1.875em might not be immediately apparent.)

Sizing text proportionally simply requires a little contextual awareness. And that applies to setting our document’s line-height, too. For example:

.main-title {
  font: normal 1.875em/36px abril-display, Palatino, Georgia, Times, serif;  /* 30 / 18 */
}

.main-title cite {
  font-size: 1.4em;  /* 42 / 30 */
  line-height: 50px;
}

The line height in both rules — 36px for .main-title, and 50px for the cite within it — are still in pixels, which means the line-height values won’t scale along with their respective relative font-size values. Presumably because they hate freedom.

But thankfully, we can quickly move those pixel-based values into something more proportional. But this time, our context is the font-size itself, our target the pixel-based line-heights. So with that in mind, let’s do a little bit more math:

36 ÷ 30 = 1.2

50 ÷ 42 = 1.2

There we are: both .main-title and the cite within it have a line-height of 1.2. And since the two elements share the same line height, we can actually just set the value once on the higher element, and let its descendants inherit it:

.main-title {
  font: normal 1.875em/1.2 abril-display, Palatino, Georgia, Times, serif;  /* 30 / 18; 36 / 30 */
}

.main-title cite {
  font-size: 1.4em;  /* 42 / 30 */
}

That is, as the kids say, that. What’s more, we don’t actually need to add units to the line-height, as Eric Meyer’s covered so ably before. Instead, we can leave that proportional value in place, sans pixels, percentages, or ems.

But yes! Context rocks! And armed with that knowledge, we can turn to our remaining pixel-based rules:

.article-body {
  font-size: 18px;
}

.caps,
figure,
footer {
  font-size: 14px;
}

As before, with some simple math and an awareness of a given element’s context, we can turn those values into oh-so-flexible ems:

.article-body {
  font-size: 1.125em;  /* 18 / 16 */
}

/* figure and .caps are children of .article-body, so their context is 18px */
figure,
.caps {
  font-size: 0.777777778em;  /* 14 / 18 */
}

/* The footer's context is the body element, so we'll use 16px here */
footer {
  font-size: 0.875em;  /* 14 / 16 */
}

And with that, we’ve successfully moved our page beyond the pixel. The design’s identical to the original px-based version, but considerably more flexible, proportional, and accessible.

Meet the rem

The em is powerful voodoo indeed, but it’s not without its limitations. Obviously, it requires an awareness of an element’s context, which can be unwieldy at best. What’s more, it can complicate moving modules within your design, as their font-size might be tied to a specific position in the document’s hierarchy. So for especially complicated, content-heavy sites, this could potentially require some work.

Thankfully, there’s been some traction on improving our old friend the em. Introduced in the CSS3 specification, the rem behaves much like the em: it’s a relative unit of measurement, sizing text up or down from a baseline value. But the rem is sized relative to the root of your document—in other words, the value set on the body element.

Here’s what our CSS looks like, once we switch everything over to rems:

body {
  font: normal 100%/1.5 adobe-text-pro, Cambria, Georgia, "Times New Roman", Times, serif;
}

.main-title {
  font: normal 1.875rem abril-display, Palatino, Georgia, Times, serif;  /* 30 / 16 */
}

.main-title cite {
  font-size: 2.625rem;  /* 42 / 16 */
}

.article-body {
  font-size: 1.125rem;  /* 18 / 16 */
}

.caps,
figure,
footer {
  font-size: 0.875rem;  /* 14 / 16 */
}

This is still relative font sizing, so we’re still using our target ÷ context formula. But now, our context is 16px throughout the CSS. That’s right: no more tracking various context values, worrying about which element’s inheriting which font-size value and going slowly mad. And as someone who hates math, this consistency is kind of exciting.

Sadly, support for the rem is still evolving. Firefox 3.6+, Chrome, Safari 5, and IE9 all support the rem. (And IE9+ even resizes text set in rems!) Unfortunately, while support’s broad, that doesn’t mean it’s universal. So if you’re supporting a significant number of browsers beyond that list, you might need to declare a fallback in pixels:

body {
  font: normal 100% adobe-text-pro, Cambria, Georgia, "Times New Roman", Times, serif;
}

.main-title {
  font: normal 30px abril-display, Palatino, Georgia, Times, serif;
  font-size: 1.875rem;  /* 30 / 16 */
}

.main-title cite {
  font-size: 42px;
  font-size: 2.625rem;  /* 42 / 16 */
}

.article-body {
  font-size: 18px;
  font-size: 1.125rem;  /* 18 / 16 */
}

.caps,
figure,
footer {
  font-size: 14px;
  font-size: 0.875rem;  /* 14 / 16 */
}

Sexy? Maybe not. But this hybrid approach leaves us with resizable text in rem-compliant browsers, with a pixel-based fallback for older ones — a match made in heaven.

Pixels, ems, and rems—oh my!

Whether you prefer slinging px or em, or have started dabbling in rem — each approach has its unique drawbacks and strengths, its own unique contributions to the project you’re working on.

Pixels afford a high degree of precision, but at the expense of versatility. And while ems offer us both the control we crave and the accessibility we need, there’s a certain amount of overhead with the contextual math involved. I hope better browser support means rems offer a way forward — but personally, those px-based fallbacks don’t feel like an appropriate trade-off. Hopefully, we’ll be able to move past those fallbacks soon.

Ethan MarcotteEthan Marcotte is an independent designer/developer who’s passionate about web standards, gorgeous design, and how the two intersect. He’s perhaps best known for starting that whole “responsive web design” thing, and even wrote a little book on the topic.