Responsive Images: Clown Car Technique

Adaptive images are the current hot topic in the Adaptive Design and Responsive Web Design conversations. Why? Because no one likes any of the solutions. New elements and attributes are being discussed as a solution for what is, for most of use, a big headache.

We have foreground and background images. We have large displays and small displays. We have regular resolution and high resolution displays. We have good bandwidth and low bandwidth connections.

Some choose to “waste bandwidth” (and memory) by sending high-resolution images to all devices. Others send regular resolution images to all devices which look less crisp on high resolution displays.

When it comes to background images, we have media queries. This makes it (almost) simple to send the right size and resolution images based on the device pixel ratio, size and / or orientation of the screen.

Proposed solutions with new technology

With content images, it’s a bit more difficult. Most believe that there is no mechanism for the <img> tag to download the right size and resolution image. Polyfills have been created. Services have been formed.

The <picture> element leveraging the semantics of the HTML5 <video> elements, with its support of media queries to swap in different source files was proposed:

<picture alt="responsive image">
     <source src=large.jpg media="(min-width:1600px), (min-resolution: 136dpi) and (min-width:800px) ">
     <source src=medium.jpg media="(min-width:800px), (min-resolution: 136dpi) and (min-width:400px) ">
     <source src=small.jpg>
        <!-- fallback -->
        <img src=small.jpg alt="responsive image">
  </picture>

Another method, using a srcset attribute on the <img> element has also been proposed. The above would be written as:

 <img alt="responsive image"
           src="small.jpg"
           srcset="large.jpg 1600w, large.jpg 800w 1.95x, medium.jpg 800w, medium.jpg 400w 1.95x">

Possible Solutions with Existing Tech: SVG

What many people don’t realize is we already have the technology to serve responsive images. We have had browser support for responsive images for a long, long time! SVG has supported media queries for a long time, and browsers have supported SVG for … well, not quite a long time, but still. Most browsers support media queries in the SVG (test your browser). The main issue is terms of mobile is old Androids lack of support until 3.0..

We can use media queries within SVG to serve up the right image. The beauty of the "Clown Car" technique is that all the logic remains in the SVG file. I’ve called it the "Clown Car" technique since we are including (or stuffing) many images (clows) into a single image file (car).

When you mark up your HTML, you simply add a single call to an SVG file.

<img src="awesomefile.svg" alt="responsive image">

Now isn’t that code simple?

The magic is that SVG supports both media queries and rasterized images.

In our SVG file, using the <image> element, will include the all the images that we may need to serve, and include all the media queries.

Here is the code for one of the SVG files:

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="300" height="329">
  <title>The Clown Car Technique</title>
    <defs>
    <style>
    image {display: none;}
    #small {display: block}
     @media screen and (min-width: 401px) and (max-width: 700px) {
        #medium {display: block}
        #small {display: none}
    }
      @media screen and (min-width: 701px) and (max-width: 1000px) {
        #big {display: block}
        #small {display: none}
    }
     @media screen and (min-width: 1001px)  {
      #huge {display: block}
      #small {display: none;}
    }
    </style>
  </defs>
  <g>
    <image id="small"  height="329" width="300" xlink:href="images/small.png" />
    <image id="medium" height="329" width="300" xlink:href="images/medium.png" />
    <image id="big"    height="329" width="300" xlink:href="images/big.png" />
    <image id="huge"   height="329" width="300" xlink:href="images/huge.png" />
  </g>
  </svg>

Unfortunately, when this file is used, all 4 PNGs are retrieved from the server. To solve this issue, we can use background images instead:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 329" preserveAspectRatio="xMidYMid meet">
 <title>Clown Car Technique</title>
 <style> 
  svg {
    background-size: 100% 100%;
    background-repeat: no-repeat;
  } 
 @media screen and (max-width: 400px) {
  svg {background-image: url(images/small.png");}
 } 
 @media screen and (min-width: 401px) and (max-width: 700px) {
  svg {background-image: url(images/medium.png);}
 } 
 @media screen and (min-width: 701px) and (max-width: 1000px) {
  svg {background-image: url(images/big.png);}
 } 
 @media screen and (min-width: 1001px) {
  svg {background-image: url(images/huge.png);}
 }
 </style>
</svg>

This version only downloads the images required, thereby solving the multi-HTTP and waste of bandwidth concerns. However, it seems to trigger mor Content Security Policy issues than the previous SVG.

The SVG file has it’s own declared size, but when included in HTML, the media query size is based on the proportions of the DOM node in the HTML –. it reflect thespace provided to it.

Open the first SVG file or the second SVG file in your browser, then grow and shrink your browser window. As the window grows and shrinks the image the SVG displays changes. The image size appears to stay the same — because it is the same. In the SVG, all the images to have the same dimensions. Its when we include the SVG in a flexible layout that the magic happens. You’ll note that the first time you load the second one there may be flickers of white as the browser requests the next required PNG.

When you include the SVG in your HTML <img> with a flexible width, such as 70% of viewport, as you grow and shrink the container, the image responds to the changes. The "width" media query in the SVG is based on the element width in which the SVG is contained, not the viewport width.

I have included the first SVG and the second SVG so you can see SVG with both foreground and background images. These foreground images work perfectly in Opera. In Chrome and Safari, I need to open the SVG file first, after which the HTML file containing the foreground SVG image works perfectly*. In Firefox, the SVG works. Firefox supports SVG and supports SVG as background image, but blocks the importing of external raster images due to their content security policy (CSP).

The content security policy does make sense: you don’t want a file to be pulling in untrustworthy content. SVG technology is supported. It is just being prevented from pulling in external raster image. Firefox prevents it altogether. Safari and Chrome work if the SVG is preloaded. We can work with the browser vendors to get this CSP lifted.

The browsers do all support the media queries with the SVG. They all support SVG as foreground or content images. They all support SVG as background images. The support just isn’t all the same.

Responsive SVG for foreground images works. It simply works right out of the box. For background images, it works, but I am still tweaking the code to make the background responsive (in Chrome it works if background-size is declared, but Opera and Safari are using the declared SVG size as the image size… still working on combinations that work everywhere.)

The drawback of the first SVG is that the SVG file is making 4 http requests. So, while we are displaying the right image, we are not saving bandwidth. In the second, the raster images are background image. Only the required image is downloaded.

Another pro for this technique: similar to how we separate content from presentation from behavior: this method enables us to also separate out images — all the logic is in the SVG image instead of polluting our CSS or HTML.

With <object> tag: up Next

<object> can take care of Content Security Policy drawback we see with <img> that disallows the importing of images or script into an <img> file. <object> allows both. I am working on that angle now.

The main question is: should we attempt this with <object>, or should we get browser vendors to change their content security policy?

Note:

* Interestingly, the SVG works best when the raster images are pulled cross domain rather than same origin. You would think, with CSP, it would be the exact opposite.

Web Development Tips

My Twitter account, WebDevTips, has been reactivated. Follow @webDevTips to get (almost) daily Web Development tips in your timeline.


Make Twitter DMs appear as if read in all browsers

Edited July 5, 2015

While the DMs no longer appear unread forever (thanks for the fix, Twitter), the ads are still annoying. Simply drag the Add Killer link to your tool bar and click when necessary.

————————— End Edit —————————

I use Twitter.com to access my tweets. I do so from several different computers and several different browsers on each of those computers. Since Direct Messages read/unread status is stored in local storage, I have to ‘read’ my DMs in every browser on every computer to make them appear read in each of those browsers. I hate that.

What I hate even more is that I have to click on my account drop down, then on direct messages link, then I have to individually open each DM thread to make them appear read, and back out of it before clearing the next.

This was driving me crazy. So, I created a little bookmarklet. I simply added the bookmarklet to each of my browsers. Now, whenever I see that little blue glow I simply click on the little bookmarklet, and the blue glow disappears until I actually get a new DM.

You can get the bookmarklet from my Github

This bookmarklet will mark all of you Twitter direct messages as read simply by deleting the entry in local storage.

The Code:

//Get the URL
var urlistwitter=window.location.href.split('/')[2].split('.'); 

// Check to see if the domain is twitter
if(urlistwitter[urlistwitter.length-2]==='twitter') {

   // remove the local storage item of unread DM references
   window.localStorage.removeItem('dm_threads');
}

// remove the icon that makes them appear unread
document.querySelector('#user-dropdown-toggle .nav-new').classList.remove('nav-new');

Drag this link to your toolbar. When you need to, click it when your Twitter window has focus to remove the localStorage entry and that annoying blue ‘unread’ icon:

Mark DMs as Read

Introducing border-radius

Designers have been including rounded corners in their designs for years. In the early 2000s, when webmasters were creating table based layout, they would include tiny little table cells to add in little corners. With the end of table based layouts, web masters created nifty little tricks. From sliding doors to adding corners with javascript, to the three slice technique, we tried and cried over it all since 2004. Our solutions have involved hours of slicing and dicing images, and millions of non-semantic html hooks for those image.

A little history

Requiring images for decorative corners is a maintenance nightmare. The extra http requests to serve the images slowed down the page load and added to site bandwidth. Rounded corners require either 4 separate images — one for each corner — or a larger sprite image that includes all 4 corners if the design allows, which requires the addition of three, and sometimes 4, hooks for those corners.
And for what? A little decoration.

No more! Enough with markup clutter, extra http requests for decorative images
and JavaScript for presentation. It’s time to let the browser do our heavy lifting, especially since this ‘heavy lifting’ is really very light weight.

The CSS3 border-radius property is not supported on over 60% of the browsers surfing the web. So, why aren’t you using them? The CSS3 border-radius property allows you to create native rounded corners using only CSS. No divitis. No classitis. No extra http requests. No wasted hours in Photoshop.

The border radius property first raised it’s beautiful little head in 2005. Webkit was the first to support the border-radius property, but seemingly is the last to fully support it (more about that later).

With the border-radius property, you can create rounded corners without images in all modern browsers and IE9. You can create rounded corners, elliptical corners, uneven corners and odd effects.

So, how do you create these rounded corners? The syntax is slightly different for rounded corners than for elliptical corners. You can created 4 identical rounded corners with a single value, declare up to four different values — one for each rounded corner, or declare uneven corners by separating the horizontal radius from the vertical radius declarations with a slash in the shorthand or space in the long hand.

Most designs call for rounded corners, so let’s start with round corners first:

The syntax (round corners):

You can use the shorthand to declare identical (declare one value) or up to four different sized corner radii. Or, you can use the long hand to declare each corner separately:

border-radius:  <all-four-same-sized-corners>;
border-radius:  <TL & BR> <TR & BL>;
border-radius:  <TL> <TR> <BR> <BL>;

or

border-top-right-radius: <TR>;
border-bottom-right-radius: <BR>;
border-bottom-left-radius: <BL>;
border-top-left-radius: <TL>;

The code:

Generally, you will want all four corners to have the same look and feel, so you will want all four corners to be equal EXCEPT in the case of top navigation bar tabs, where you will want the top corners to be round and the bottom corners to be rectangular.

You can use the shorthand:

.box {
    border-radius: 1em;
    }
.tab {
    border-radius: 0.5em 0.5em 0 0;
}

or you can use the longhand:

.box {
    border-top-right-radius: 1em;
    border-bottom-right-radius: 1em;
    border-bottom-left-radius: 1em;
    border-top-left-radius: 1em;
    }
.tab {
    border-top-right-radius: 0.5em;
    border-bottom-right-radius: 0.5em;
}

The above will create rounded corners: the vertical and horizontal sides of each corner will be the same: the horizontal radius is the same as the vertical radius. But what if you want elliptical corners? Rounded, but not actually round? Border radius allows for that.

The syntax (rounded or elliptical corners):

If you want rounded corners that are elliptical instead of round, there’s a syntax for that. In the shorthand syntax, separate the horizontal radius from the vertical radius declarations with a slash.

border-radius:  <vertical-radius values> / <horizontal-radius values>;
border-radius:  <TL & BR> <TR & BL> / <TL & BR> <TR & BL>;
border-radius:  <TL> <TR> <BR> <BL> / <TL> <TR> <BR> <BL> ;

If you are using the longhand properties, separate the two radii with a space instead. Notice the values above have a slash, the values below do not.

border-top-right-radius: <TR vertical> <TR horizontal>;
border-bottom-right-radius: <BR vertical> <BR horizontal>;
border-bottom-left-radius: <BL vertical> <BL horizontal>;
border-top-left-radius: <TL vertical> <TL horizontal>;

The code:

These two declarations are equivalent

.shorthand {
    border-radius: 2em 1em 4em 3em/ 0.5em 3em;
    }
 
.longhand {	
    border-top-left-radius:     2em 0.5em;
    border-top-right-radius:    1em 3em;
    border-bottom-right-radius: 4em 0.5em;
    border-bottom-left-radius:  3em;
    }

And now for the bad news

While border-radius property has widespread browser support, there are some discrepancies in browser support.

Older Internet Explorer versions

Border-radius is not supported in IE6, IE7 or IE8. Remember that users access your web site with only one browser. They don’t look at all the different browsers: only web developers do that. So, visitors using these browsers will not see your beautifully rounded corners, but they also won’t know that they are missing anything. Rounded corners are an enhancement. They’re generally not critical to the content of your site. There’s an HTC file called CSS Curved Corner by Remiz Rahnas that can create rounded corner effects for old versions of IE.

Older non-IE browsers that are still lingering

If you’re still supporting Firefox 3.6 and or Safari 4 you’ll want to add the -moz- and -webkit- vendor prefixes respectively. Since Safari 5 was released over a year ago, and Safari 4 has less than 0.75% market share, I have dropped the -webkit- prefix syntax. At the time of this writing, while Firefox 4 has surpassed Firefox 3.6 in the USA market, the trend is not worldwide, so I am still including -moz- prefixed corners. Also, older versions of Firefox used a non-standards syntax for the long hand, so when declaring -moz- prefixed border radii, use the shorthand. If you want to use the long hand, I recommend using the border radius generator to get the FF3.6 and Safari 4 and earlier long hand markup.

Quirks in Modern Browsers

Opera, IE9, Safari 5, Firefox 4 and Chrome all understand the vendorless recommended standard syntax for the four long hand properties and the single shorthand border-radius property, but some browsers do have some bugs:

Safari 5 does not understand percentage values for rounded corners. This is resolved in the webkit nightly builds, so will be resolved in Safari 6. In the meantime, since it doesn’t understand %, it will ignore the entire declaration. The hack is to declare the border radius in other length units first, then declare your percent version for all browsers that do understand percentage values.

Opera currently also have bugs with percentage values. It does understand percents, but does not render them correctly in some cases. The values in elliptical corners is slightly off, and has been fixed in the Opera Next build (build 1024), so will be fixed in their next launch most likely. In most cases, therefore, a hack may not be necessary. When an element is floated, the border radius is completely off in Opera. The border-radius is huge, making the element look almost rectangular, as if there were no border-radius set. If you’re ok with graceful degradation, the Opera user won’t be negatively impacted: they will just see almost what IE 7 users see. If you’re not OK with that, either don’t float your rounded elements if you’ve used percentage values as your radius length, or use other length types (em, px, etc) if your element is floated.

HTML5 Input Attributes & Browser Support

I have updated the HTML5 Web Form Browser support grid to include the various input attributes, for what input type each is relevant, and which browsers support each attribute for each type.

TYPE ⇒

Attribute

Text, search, url, tel Email Password Dateandtime
Date,
Month,
Week,
Time
Dateandtime-local,
number
range color Checkbox, radio file
accept WK, O,
FF, IE
autocomplete O O O O O O O
autofocus WK, O WK, O WK,O WK, O WK, O WK, O WK, O WK, O
checked WK, O,
FF, IE
disabled WK, O,
FF, IE
WK, O,
FF, IE
WK, O,
FF, IE
WK, O,
FF, IE
WK, O,
FF, IE
WK, O,
FF, IE
WK, O,
FF, IE
WK, O,
FF, IE
WK, O,
FF, IE
Form O O O O O O O O
list WK, O WK, O WK, O WK, O WK, O WK, O
max O, WK O, WK O, WK
maxlength WK, O,
FF, IE
WK, O,
FF, IE
WK, O,
FF, IE
min O, WK O, WK O, WK
multiple FF, WK, IE FF, WK
Name WK, O,
FF, IE
WK, O,
FF, IE
WK, O,
FF, IE
WK, O,
FF, IE
WK, O,
FF, IE
WK, O,
FF, IE
WK, O, FF, IE WK, O,
FF, IE
WK, O,
FF, IE
pattern WK, O WK, O WK, O
placeholder WK WK WK
readonly WK, O,
FF, IE
WK, O,
FF, IE
WK, O,
FF, IE
WK, O,
FF, IE
WK, O,
FF, IE
required WK, O WK, O WK, O WK, O WK, O WK, O WK, O
size WK, O,
FF, IE
WK, O,
FF, IE
WK, O,
FF, IE
step O, WK O, WK O, WK
checked WK, O,
FF, IE
value WK, O,
FF, IE
WK, O,
FF, IE
WK, O,
FF, IE
WK, O,
FF, IE
WK, O,
FF, IE
WK, O,
FF, IE
WK, O, FF, IE WK, O,
FF, IE
WK, O,
FF, IE
  • WK = Webkit (tested Safari 5)
  • O = Opera (10.5 on Mac)
  • FF = Firefox (3.6.3 on Mac)
  • IE = Internet Explorer (IE8 on XP)

Browsers that don’t support the type attribute may still support other attributes in the input as the browser may support attributes on the text input type (such as maxlength or size), and will therefore support those attributes on a type it doesn’t support, as the input will default to text type. For example, while IE and FF don’t currently support the email type, they do support the multiple attribute on that type, since they will accept a text type including space separated email addresses.

Resources for this effort include:

Hack for CSS3 Supporting Browsers

Implementing CSS3 features in your CSS file can be complex. You have to make sure that the CSS you’re feeding to FF3.5+, Chrome, Opera and Safari are not being read by FF2, IE6, IE7 and IE8. There’s a simple hack to make sure that your CSS3 is fed only to browsers that support it… it’s forward compliant and it’s valid markup.

selector:nth-of-type(1n)

To target all browsers that support CSS3, and hide from the IEs, simply add :nth-of-type(1n) to your selector.

  h3:nth-of-type(1n)  {
      color: #FFFFFF;
      background-color: #FFFFFF;
      text-shadow:  
           3px 3px 3px rgba(0, 0, 0, 0.4);
}

In the above example, we’ll end up with white text on a white background, with the letters being defined by the drop shadow. You definitely don’t want to feed that to browsers that don’t support text-shadow: white text on white backgroud *IS* illegible.

:nth-of-type(1n) basically means “every”. So, it’s the same as not including it in terms of what selectors will be matched. Do note that you are adding a pseudo-class, so you are adding specificity. This pseudo-class is not understood by browsers that don’t support CSS3 selectors which is the same as those that don’t understand CSS3 properties and CSS3 property values.

For example, I have a row of images with captions going across a page. To make it more interesting, I made the pictures look like Polaroids. It looks fine plain, but why not add some fun CSS3.

/* understood by all browser */
.slides li {
	line-height:1.4;
	float:left; 
	width: 188px;
}
.slides img {
        display:block;
}
/* for CSS3 supportive browsers only */
.slides li:nth-of-type(1n) {
	-moz-box-shadow:0 3px 6px rgba(0, 0, 0, 0.25);
	-moz-transform:rotate(-5deg);
	-webkit-box-shadow:0 3px 6px rgba(0, 0, 0, 0.25);
	-webkit-transform:rotate(-5deg);
	box-shadow:0 3px 6px rgba(0, 0, 0, 0.25);
	transform:rotate(-5deg);
	background:none repeat scroll 0 0 #FFFFFF;
	color:#333333;
	display:inline;
	float:left;
	margin:0 0 27px 0;
	padding:10px 10px 15px;
	text-align:center;
	text-decoration:none;
	width:auto;
}
.slides li:nth-of-type(even){
    -moz-transform:rotate(7deg);
	-webkit-transform:rotate(7deg);
	transform:rotate(7deg);
}
.slides li:nth-of-type(3n){
    -moz-transform:rotate(0deg);
	-webkit-transform:rotate(0deg);
	transform:rotate(0deg);
}

The images look fine in IE, but look cool in FF3.6

Do make sure that the new CSS3 property is generally supported before using this hack. This is a general filter for generally supported CSS3. It works for multiple background images, text-shadow, border radius, and other well supported CSS3 properties and values. Don’t use this for CSS3 transitions, columns and animations until those are better supported in modern browsers. I have grids of browser support for all sorts of CSS3 properties, so take a look at those before relying on this filter.

IE8: The Good: CSS 2.1 Selector Support in Internet Explorer

Internet Explorer 8, IE8, was released on March 19, 2009. Depending on your statistics source, as of July 2009, IE8 already has 17.8% of the browser market share. In the last section we provided an overview of what is new, good, bad and different in IE8. In this article, we take a deeper look at CSS 2.1 support in the IE8 browser, and compare IE8’s CSS support to IE6 and IE7.

CSS 2.1 Support

As mentioned in the overview, IE8 has complete support for CSS2.1. IE8 is the first browser to support all of the W3C CSS2.1 specifications, and currently has the best support of any browser (including Firefox, Safari and Opera) of the CSS 2.1 specifications. One may think (though no one outside of Microsoft does) that this makes IE8 the best browser, but it doesn’t. IE8 may be the first IE to support CSS 2.1, but Firefox, Safari, and Opera have already moved on to supporting features proposed in CSS3.

Internet Explorer 8 supports all CSS 2.1 Selectors

By having complete support for CSS 2.1, IE8 has a lot of improvements over IE7 and IE6 in terms of CSS support. Below are listed all the individual CSS2.1 selectors, with a brief explanation of how IE6, IE7 and IE8 compare. You’ll note that IE8 supports ALL of the selectors listed. While not shown in this grid, Firefox, Opera and Safari all support all the CSS 2.1 selectors, and have been doing so since previous releases.

By having complete support for CSS 2.1, IE8 has a lot of improvements over IE7 and IE6 in terms of CSS support. Let’s look at the differences:

Browser
Pattern Meaning IE6 IE7 IE8
E:active

E:hover

E:focus

Dynamic pseudo-classes are generally thought to be applicable to links and form elements since IE6 and IE7 don’t support them on other elements. IE8 supports pseudo classes correctly on ALL the elements.

Δ Δ
Δ Δ
Χ Χ
E:before

E:after

The ‘:before’ and ‘:after’ pseudo-elements can be used to insert generated content before or after an element’s content. Completely ignored by IE6 and IE7, it is supported by IE8. See generated content

Χ Χ
Χ Χ
*

Universal Selector: any element *{}. While all browsers support this selector, it’s best to use it sparingly if at all.

E

Type or Element selector: a specific element, such a p, td, ol {}

.class

Class selector: a class or several classes, such as: .myClass {}

IE6 does not support dual class names. For example, .one.two {} will target <p class="one two"> in all modern browsers, except IE6, which ignores it. Except for this exception, class selectors are supported by all browsers.

Δ
#id

ID Selector: Matches an element based on it’s ID: #myId {} Supported by all browsers

E F

Descendant selector: Matches any element F that is a child of element E

E > F

Child Combinator: Matches element F that is the first element child of element E

Χ
E + F

Adjacent simbling selector: Matches element F that is a the next sibling of element E. label input {} will match any input that follows a label such as <label>a label</label><input type="text">.

Note that there is a sibling selector – E~F – in CSS3 that is supported by IE7 and IE8, but not IE6

Χ
E[attr]

Attribute Selector: Matches if the element matched has the attribute: input[type] {}.

The exception to the support is that the browsers won’t match the element that has the attribute if the attribute value is empty

Χ
E[attr=val]

Attribute Selector: Matches if the element matched has the attribute: input[type=checkbox] {}.

Χ
E[attr~=val]

Attribute Selector: Matches if the element matched has the value of the attribute value: a[rel~=nofollow] {} should match <a href="..." rel="noindex nofollow">.

Χ Δ
E[attr|=val]

Attribute Selector: Matches if the element matched has the attribute with the value has atleast the val as part of the value: div[lang|=en] should match <div lang="en-us">

Χ Δ
E :first-child

The CSS selector should match the inner div element, because it is the first child of the outer div element Comments are not elements, so they should not be considered when determining the first child.

Χ Δ
E:link

Non visited link (non included above with pseudo classes since only links can be links)

E:visited

Visited link (not included above with pseudo classes since only links can be visited)

E:lang()

Matches element of type E if it is in (human) language c (the document language specifies how language is determined).

Χ Χ
E:first-letter

First letter pseudo-element: Matches the first letter of the element E.

E:first-line

First-line pseudo-element: Applicable to block-level elements, inline-block, table-caption or a table-cell, targets the contents of the first formatted line of a element.

Note that Opera 9.6, Firefox and Safari all support all of the above CSS selectors.

Legend
Full Support
Χ No Support
Δ Some support, but not full support

IE support of :hover pseudoclass

The :hover pseudo-class enables you to alter the presentation of an element when the user mouses over the element. For example, similar to Excel, you can change the color of a table row when the user mouses over a table rows using only CSS. IE6 and IE7, only support the :hover pseudoclass on links (the <a> tag) and some form elements. One very popular use of the hovering is drop down menus. In the past, because of IE6 and IE7, javascript had to be added to make sub-navigation appear on hover in those browsers. IE8, like all other standards compliant browsers, now supports the :hover pseudoclass on all displayed elements.

IE support of :before and :after pseudo-elements

The :before and :after pseudo elements enable you to add content before and/or after specified elements. For example, you can add special characters in front of list items, thereby not limiting yourself to the limited number of default list-style-types. IE6 and IE7 have no support for these pseudo-elements. IE8, however, has fully compliant support for these pseudo-elements. In fact, IE8 has better support for the content property of these pseudo elements than any other browser: better support even than Firefox.

Using differences in CSS selctor support to target browsers

Users of Community MX are encouraged to use conditional comments to target different versions of Internet Explorer. You can also use CSS selectors to target specific browsers. IE6 and IE7 have limited support for CSS 2.1 selectors. IE8 supports all of CSS 2.1 selectors, but very limited support fo CSS 3 selectors. On the other hand, all other non-IE grade-A browsers have support of several CSS 3 selectors. You can use these difference to your advantage to target specific browsers. In the last section, we provided one hack:

p.myclass {
color: green; /* all browsers */
}
body:first-child p.myclass { /* IE8 and all CSS 2.1 compliant browsers */
color: blue;
} body:last-child p.myclass { /* CSS 3 supportive browsers */
color: red;
}

This IE8 CSS filter targets all browsers with a regular element.className selector to target all paragraphs with the myClass class. It then targets all CSS2 compliant browsers with the CSS2.1 pseudo-class. It then filters out IE8 but using CSS3 to target all modern, non-IE browsers. It’s best not to use it, but it is important to understand how CSS can be used to filter browsers so you can follow other people’s code.

Up Next

In this section of IE8: the good, the bad, the ugly (and pretty), we’ve covered IE Support for CSS selectors. In the next section wel will look at IE’s support of CSS 2.1 properties and values of interest.

Introducing IE8: The good, the bad, the (not so) ugly

Browsers come out every day. Webkit has a nightly build. Wireless devices come with their own, often unique, browsers. Even with the plethora of available browsers, Internet Explorer, a browser that is not regularly updated, has over 55% of the browser market. Internet Explorer 6 (IE6), which came out eight years ago, still holds 9% (between 6% and 18%, depending on where you look) of the browser market share. IE8 was released only in March 2009, and by July 2009, it already had 17.8% of the browser market share.

In this article, we take a look at the IE8 browser, and cover some tips and tricks to make sure your sites look good in both old and new browsers. Will cover many of the topics hilited below in greater depth in the next sections of the "Welcome to IE8" series.

CSS 2.1 Support

IE8 has complete support for CSS2.1. In fact, IE8 is the first browser to support all of the W3C CSS2.1 specifications. IE8 passes the Acid2 browser test. You can learn more about the Acid2 test from the web standards project. In brief, it’s test page designed to expose browser CSS2.1 rendering flaws, including testing transparent PNGs, generated content, the box model, and positioning, among others. While other browsers have been passing this test since 2005, Internet Explorer didn’t pass the Acid2 test until the release of IE8 on March 19, 2009. I guess late is better than never.

Internet Explorer 8 supports all CSS 2.1 Selectors

By having complete support for CSS 2.1, IE8 has a lot of improvements over IE7 and IE6 in terms of CSS support. We will take a look at the individual CSS2.1 selectors, and how IE6, IE7 and IE8 compare later in this series. The important things to note are that IE8 supports the :hover pseudo class on all elements, not just links as in previous versions. IE8 also supports the :before and :after pseudo-elements, along with the CSS content and counter properties and values. See CSS3 Selectors and Browser Support for a grid of both CSS 2.1 and CSS3 selector support in all grade A browsers. We’ll be covering all the CSS2.1 selectors in the next section of this series.

Internet Explorer 8 supports all CSS 2.1 Properties and Values

With IE8’s complete support for CSS 2.1, Microsoft Internet Explorer has finally entered the realm of "standards compliant" browsers. IE8 has made great improvements over IE7 and IE6 in terms of CSS property and values support, almost completely supporting the CSS 2.1 specifications. IE8, however, like IE7 and IE6, has no support for any CSS3 properties or values. We will take a deeper look at CSS2.1 properties and values later in this series. In addition to supporting the W3C boxmodel (padding, width, margin) which is discussed next, some hilites include IE8’s complete support of outline, content, z-index, border-spacing, caption-side and empty-cell and support for more values of the display, list-style-type and white-space properties. See my list of CSS properties and values and browser support for a more detailed list of all the properties, values and browser support. We’ll go into greater detail on some of these CSS improvements in the next sections of this series.

Internet Explorer 8 supports the W3C Box Model

Microsoft finally got the W3C box model correct. While you may disagree with the W3C box model, and may think Microsoft, not the W3C, got it right, it is important to follow the standards.

IE8 and all non-IE grade-A broswers use:

total width = margin-left + border-left + padding-left + width + padding-right + border-right + margin-right

but IE6 and IE7, when not in browser standards compliant mode use:

total width = margin-left + width + margin-right

If you really love the IE box model, you can still implement it with:

-ms-box-sizing: border-box;

That’s about all we need to know about the box-model and IE8, so I will not be elaborating on this in future sections.

IE8 Developer Toolbar

IE8 comes with a developer toolbar. The developer toolbar is an improvement on the debugging tools of previous IE versions. It’s an apparent imitation of the Firebug extension for Firefox, but not as robust. Similar to Firebug, you can highlight an element and can edit CSS on the fly. The CSS module informs you of inherited CSS and current values (in reverse order from Firebug). The CSS panel has check boxes next to each css property so you can turn on and off that property.

IE7 Compatibility View

The IE8 chrome provides a button to enable IE7 compatibility view. Compatibility View forces Internet Explorer 8 to display content as if the user were using IE7, with all of IE7’s quirks, hacks and errors.

The weird thing about using this button is that Microsoft actually keeps tabs on it: information is sent to microsoft whenever you press that button, unless you set your preferences otherwise, and lets MS know that "a lot of people are switching rendering modes" for that domain. Microsoft actually keeps a list of websites that these staticstics "prove to them" are best displayed in Compatibility View. Microsoft construes our clicking of that IE7 compatibility view button as feedback that the site doesn’t render right in IE8.

Forcing IE7 of IE8 rendering mode

As mentioned above, IE8 provides the user the ability to change how they view websites: providing the ability to switch back and forth between IE8 and IE7. You can override this, and force the site to be rendered either as IE8 or IE7 (your choice) within the IE8 browser, disabling the IE7 Compatibilty view botton.

To force IE8 rendering mode:

<meta http-equiv="X-UA-Compatible" content="IE=8" />

To force IE7 rendering mode:

<meta http-equiv="X-UA-Compatible" content="IE=7" />.

IE8 bugs

IE8 Disappearing Page Bug: If you put two adjacent nodes, both positioned absolutely, and set only one of x- or y- positioning, you may get a blank page.

IE8 CSS Hack

This IE8 CSS hack uses the star hack to target IE7 and lower, but you can use any other of the many IE hacks to target older IE browseres.

p.myclass {
color: green;
*color: red;
}
body:last-child p.myclass {
color: blue;
}

Conditional comments still work in IE8. Just note that if you used the conditional comment of

<!--[if IE]>
  IE only information here
</![endif]-->

The above will also be read by all Internet Explorer versions, past current and future. If you’ve included this in past websites, check to make sure your sites still work. If you find issues, simply change the [if IE] to [if lte IE7] for if less-than or equal to IE7.

Other Features:

  • Full ARIA (accessible rich internet applications) support
  • hasLayout is no longer a factor
  • <object> nesting, or fallbacks, has been implemented correctly. See the HTML Object element for more information.
  • Native JSON (JavaScript Object Notation) support
  • The ‘style’ property is available via the DOM
  • Supports getElementByName(‘formElementName’);
  • CSS styling of the <legend> element is now supported
  • Supports data URI schema value. Wikipedia does a good job of explaining data URI schema.

Graded Browser Support

Do you really need to test all browsers? Is it even possible? Are you still testing Netscape 4.7 or IE 5? Which browsers are you supposed to test? Which can you ignore? Which browsers need to render your page pixel perfect, and which browsers should render the page, but if they break, you’re willing to live with that? And, for the browsers that you do plan on supporting, what operating system are you going to test them in? There’s Windows, Mac, Unix and Mobile to consider, but then there are various flavors of each: Windows XP, Windows Vista, Windows 2000, Windows ME, Windows 98, etc.

Graded Browser Support

Yahoo! Developer Network provides a list of what they call "grade-A browsers" which has become the defacto norm for browser support. Their article Graded Browser Support is a very clear articulation and formalisation of what many of us have been thinking about and implementing. If you haven’t been thinking about it, you should!

The general idea is that there are 3 classes or grades of web browser:

  • Grade-A: list of browsers we should thoroughly along with which operating system they should be tested on.
  • Grade-C: list of browsers that should be able to present the core functionality & content, but don’t need to be pixel perfect.
  • Grade-X: list of less common browsers and less common operating systems, for which Yahoo! (and you) need provide no testing and no support.

At the time of this writing, grade-A browsers include IE7, IE6, Safari 3.1, Firefox 2 and 3, and Opera 9.5. Grade A operating systems include Windows XP, Vista and 2000, and Mac 10.4 and 10.5.

At the time of this writing, neither Google Chrome or Internet Explorer 8 are included in the Grade A list. IE8 is not on the list since it is still in beta, and Chrome may not be on the list either because it is too new (the page is updated quarterly), it is too rare ( under 0.7% of the browser market share) or because it has a very similar rendering engine to Safari 3.1 (AppleWebKit/525.13 versus AppleWebKit/525.19).

I was surprised to find Windows 2000 still on the list of supported operating systems, and assume that will be downgraded soon. I am not copying the list in this article because whereas Graded Browser Support is updated quarterly, this page won’t be. So, bookmark Graded Browser Support to keep up to date with modern browsers and to stay abreast of what you should support and QA.

Which browser gets put into which grade depends on the market share. If you have a particular population that visits your website, your Grade-A browser may be different. For example, if you are building an Intranet for a company in which all employees are provided with a specific operating system, then that is the only operating system that should be in your grade A listing. Do take a look at your sites web statistics to determine if you have a large population of mobile visitors, old Mac users, unix users or some other population. Generally, the Graded Browser Support should work for 99% of audiences, but for your audience (or the audience you expect), it may differ.

Steps you can take

You will need to check your site in all grade-A browsers. However, there are some things you can do to make the whole process a lot easier:

  • Develop in Firefox with Firebug.
  • Write semantic code, separating content ((X)HTML) from presentation (CSS) from behavior (Javascript).
  • Write valid code, closing all of your elements
  • Add a space before the slash in self-closing, or empty, elements so very old browsers don’t choke: ex. <br />
  • Do NOT include the XML declaration at the top of your XHTML, as it breaks IE5 and sends IE6 into quirks mode.
  • In Javascript, check function capacity. Don’t browser sniff. Don’t use headers or proprietary features for browser detection.
  • In CSS, first create compliant, valid CSS code for compliant browsers before creating fixes for non-compliant browsers.

Staying relevant

Keep up to date on what browsers to support by visiting the Yahoo Graded Browser Support article on a quarterly basis (as that’s how often they update that article). Market Share is a great resources to see the current (and past) popularity of the various generally available browsers.

CSS Reset

Resetting browser default CSS

Whenever I start a new site and begin a new CSS file or CSS file set for the site, my first step is to include CSS to reset the browser CSS defaults.

Different browsers have slightly different default rendering. The default values for margin, padding and line-height differ between browsers. Removing the inconsistent default styling for elements in various browsers creates an equal starting point and allows you to explicitly set your own default settings that are equal in (almost) all browsers. By starting with an equal playing (or presentation) field, your CSS will not only look similar in all browsers, but your CSS file size will be smaller, and the number of aspirin you need to take to complete your site will be reduced.

Code

Here is the code I generally use. I’ll explain it below:

/* CSS BROWSER RESET */

body, div, h1, h2, h3, h4, h5, h6, p, dl, dt, dd, ul, ol, li, 
pre, form, fieldset, legend, input, textarea, label,
blockquote, table, th, td {
		margin: 0;
		padding: 0;
		background-repeat: no-repeat; 
		font-family: Verdana, Arial, Helvetica, sans-serif; 
		font-size: 100%; 
		line-height: 1.4; 
		color: #333333; 
	}
a, span {
		background-repeat: no-repeat; 
		outline: none;	
}

table {
		border-collapse: collapse;
		border-spacing: 0;
	}

fieldset, img, abbr, acronym {
		border: none;
		text-decoration: none; 
	}

ol, ul {
		list-style: none;
	}
caption, th {
		text-align: left;
		font-weight: normal;
	}

q:before, q:after {
		content: '';
	}

input, textarea, select {
		font-family: inherit;
		font-size:inherit;
		font-weight:inherit;
	}


 /* declare your site defaults here */

In your conditionally commented CSS file for IE7 and less include the following:

input, textarea, select {
		font-size:99%;
	}

CSS explained

While you may not use all the elements listed, and you may want your defaults to be slightly different, the above CSS is a good starting point. You might as well include all these elements, because you never know if someone else coding the site, or a future developer, may use those elements.

The first call sets the margin and padding of all elements to none. You won’t have to declare margin and padding of 0 again in your CSS. I have seen style sheets with ‘margin: 0′ included over 100 times. By including this default CSS, you only have to declare margins when you are overwriting the new zero default. Also, you don’t have to remember to explicitly set the body padding and margins.

Different browsers also display h1-h6 differently. This CSS nullifies the browser default settings and makes them look like the rest of your code. This way you decide how you want to display your headings. Also, by declaring a font-size in percentages, we resolve the IE ems rendering issues.

There are some settings in the code above that are redundant or irrelevant and will have no impact, such as setting margins on inline elements. CSS does not penalize you for including properties that are not used. I include all the elements in the first line, even though some of the properties are not used on some of the elements.

The default value for background images is to have them repeat on both the X and Y axis. Generally, you don’t want background images to repeat. The CSS above sets the background-repeat to no-repeat.

Just remember to AVOID use the background shortcut. If you omit one of the elements of the shorthand (background-color,
background-image,
background-repeat,
background-attachment,
background-position) you may inadvertently reset one of the properties to the default.

The call includes several optional/changeable items. Feel free to reset the font-family, color and line-height to your own preferences.

With font-family, include default fonts in the initial CSS browser reset. By declaring the fonts in this way, you will save a lot of characters by not having to declare default fonts elsewhere in your CSS. For example, if you declare your <h1> on your contacts page to have a unique font, you simply have to write something similar to:

#contact h1 { font-family: Hacknslash;} 

If the user doesn’t have the "Hacknslash" font, then it will default to Verdana, Arial, Helvetica, sans-serif, since you declared that in your brower reset CSS.

I chose the grey of #333333 instead of #000000, because black on white can be hard on the eyes. This dark grey is less harsh. You can use whatever color your design requires.

Line height is also up to you. You’ll note that there is no measurement type such as em, px, pt or % included. You can use these measurements. Omitting the measurement sets a number that will be multiplied with the current font-size to set the distance between the lines, similar to declaring em or %.

Since links, spans, code and other in-line elements have no default margin and padding and inherit, I declare them seperately to not overburden the browser rendering engine. I’ve declared two elements in this case as I use a lot of background images in my links and spans and want to ensure that those background images don’t repeat. The outline: none; on the links removes the box you may see around links when the mouse is down.

Note that you should not use the global selector, *, because the browser may overwrite default styling that you want to keep, such as padding on buttons. Also, when the global selector is used, the browser than has to apply the style to every element, which is a heavy load for the browser.

Defaults bullets are removed from ordered and unordered lists. Bullets are placed in different locations in different browsers: Firefox vertically aligns the bullet to text bottom and Internet Explorer vertically aligns the bullet to text top. I like to not only control my bullets, but generally my <li>s are inline, have background images instead of bullets, or are otherwise styled.

The caption and table header declarations are included since browsers tend to center them, and tend to bold table headers. The quote declaration is included since Firefox, Opera and other compliant browsers add quotes to <q>, while Internet Explorer, up to IE7, doesn’t even understand the :before and :after pseudo-classes. (This is resolved in IE8).

Most of the rest of the CSS is self explanatory except perhaps the IE conditional comments portion. Browsers are notorious for rendering forms differently: the input, textarea, select font-size declaration tells IE7 and earlier to not enlarge fonts that are in form elements.

Remember to include your form elements in block level elements. For example, put <textarea> in a <p> element so that it inherits font-family correctly in Opera.

The last line, "declare your site defaults here", is a good spot to declare the other default fonts and colors for your site. If all your h1s are going to be a different color and font, then start with your general, non-classed declarations. Remember to include this Browser Reset CSS at the top of your CSS. In this way, you can use the cascade to declare your defaults without requiring classes. Otherwise, you would have to include additional specificity for things that really should be generally declared.

Other browser reset arguments

There is an argument to remove ALL the defaults, such as bolding of the <strong> element, italicizing of the <em> element, monospacing of the <code> element, etc. The argument is that you should start from scratch, and build up all your own CSS. Below are some additional statements you can consider including in your CSS browser reset:

address, caption, cite, code, dfn, em, strong, th, var { 
	    font-style:normal; 
	    font-weight:normal; 
	} 
	h1, h2, h3, h4, h5, h6 { 
	    font-weight:normal; 
	} 

sup {
		vertical-align: text-top;
	}

sub {
		vertical-align: text-bottom;
	}