Coding with Jesse

How to deliver XHTML 1.1

A while back, one of my first posts was This site is valid XHTML 1.1, where I explained what I had to do to change the markup from XHTML 1.0 to 1.1. However, I guess I was a total liar in saying that's all I had to change. This is because Internet Explorer doesn't support XHTML 1.1.

So, using PHP, I had to deliver alternative markup to Internet Explorer and Firefox (rather, between browsers that don't support XHTML 1.1 and those that do).

Luckily, we don't have to use any complex browser detection. Instead, we can just inspect the HTTP-ACCEPT header. Browsers supporting XHTML 1.1 will have "application/xhtml+xml" in this list, and those that don't won't. Using PHP, I have the following code at the top of every page:

if ($_SERVER['HTTP_ACCEPT'] != null
    && strpos($_SERVER['HTTP_ACCEPT'], 'application/xhtml+xml') == false) {
	$xhtmltype = '1.0';
	header("Content-type: text/html; charset=utf-8");
} else {
	$xhtmltype = '1.1';
	header("Content-type: application/xhtml+xml; charset=utf-8");
}

XHTML is actually a subset of XML, and as a result we need to change a few other things. Mainly, the stylesheet is attached as an xml processing instruction at the start of the document instead of in the <head> tag. At the same time, we output the <!DOCTYPE> tag for each version of XHTML.

if ($xhtmltype == '1.1') {
     echo '<'.'?xml version="1.0" encoding="utf-8"?'.'gt;';
     echo '<'.'?xml-stylesheet href="/screen.css" type="text/css"?'.'>';
     echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" ';
     echo '"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">';
} else {
     echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" ';
     echo '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
}

As I mentioned in the previous article, I had to remove the lang attribute from the <html> tag. However, it is required with XHTML 1.0. So, again, we need to deliver two versions:

<html xmlns="http://www.w3.org/1999/xhtml" 
xml:lang="en"<?php if ($xhtmltype == '1.0') echo ' lang="en"'; ?>>

Next, we have to provide a few more tags that are required still for XHTML 1.0 in the <head> tag:

<?php
if ($xhtmltype == '1.0') {
     echo '<link rel="stylesheet" type="text/css" media="screen"';
     echo ' href="screen.css" id="stylesheet"/>';
     echo '<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>';
}
?>

That's it for most web pages. However, I should include the changes I needed to make to deliver Chitika and Adsense ads. For XHTML 1.1 visitors, we put an <object> tag on the page, and the Adsense code in an external HTML document. For XHTML 1.0 visitors, we embed the <script> code like normal. If you want more details and examples, go check out this article.

Well that's about it. I guess the only other thing I need to do differently is be extremely careful the content on the site doesn't break validation. As soon as a closing tag is missing or an & unescaped, Firefox won't render the page, instead reporting an error. This is actually a strong feature of XHTML in my eyes. Being completely unforgiving about invalid pages will improve the quality of the web eventually (once people move away from HTML). Though, of course, there is a tradeoff of actually having to make valid pages 100% of the time :)

Published on December 4th, 2005. © Jesse Skinner

About the author

Jesse Skinner

I'm Jesse Skinner. I'm a self-employed web developer. I love writing code, and writing about writing code. Sometimes I make videos too. Feel free to email me if you have any questions or comments, or just want to share your story or something you're excited about.