CSS, JavaScript and XHTML Explained

Quirks, random thoughts and funky finds discovered in day-to-day coding.

 

ISO 8601 date in PHP August 1, 2007

Filed under: PHP, Web Development — admin @ 2:37 pm

Converting ISO 8601 date string in PHP

JavaScript Date Object explained how to convert ISO 8601 dates in Javascript. Thanks to Ryan Kennedy, we have a function to convert ISO 8601 dates in PHP.

This is how you can call the function:

$theDateFormattedMyWay = date("F j, Y", parse_datetime($ISO8601_formate_date]));

For other possible formats, please visit: http://php.net/manual/en/function.date.php.

You need to then include the parse_datetime function in your code. Hopefully the next version of PHP will include this, or something similar

function parse_datetime($datetime) {
     $currentTime = time();
     $offset = date("Z", $currentTime);

     $matches = array();

     // Check to see if we're dealing with a UTC dateTime (ends in 'Z')
     // or if there's an offset specified (ends in '[+-]hh:mm’).
     if(preg_match("/^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})([+-])(\d{2}):(\d{2})$/",
          $datetime, $matches) === 1) {
     	// Offset specified.
     	$dateString = $matches[1];

     	// Calculate the custom offset.
     	$customOffset = $matches[3] * 60 * 60;
     	$customOffset += $matches[4] * 60;

     	// Invert the custom offset as necessary.
	if($matches[2] == "+") {
     		$customOffset = -1 * $customOffset;
     	}

     	// Add the custom offset to the UTC offset to get the offset
     	// from the local timezone.
     	$offset += $customOffset;
     }
     else if(preg_match("/^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})Z$/",
           $datetime, $matches) === 1) {
     	// Using the UTC timezone.
     	$dateString = $matches[1];
     }

     // Parse the date and time portion of the string.
     $datetimeArray = strptime($dateString, "%Y-%m-%dT%H:%M:%S%");

     // Generate the UNIX time. Note that this will be in the wrong timezone.
     $time = mktime($datetimeArray['tm_hour'],
     		$datetimeArray['tm_min'],
     		$datetimeArray['tm_sec'],
     		$datetimeArray['tm_mon'] + 1,
		$datetimeArray['tm_mday'] ,
     		$datetimeArray['tm_year'] + 1900);

      // Return the calculated UNIX time from above along with the offset
      // necessary to correct for the timezone specified.
      return $time + $offset;
}
 
 

JavaScript Date Object July 29, 2007

Filed under: JavaScript, PHP, Web Development — admin @ 11:18 am

Javascript: Things you should know

Note: This is part IV of a "Javascript: Things you should know" series. I assume readers have an understanding of the core language. This section goes over the creation of date objects. Most resources go over creating a current time date object. This goes over the rest. The previous entry was JavaScript Objects. The next entry list all the date object methods. Please let me know what you think and it there is anything I am missing. Enjoy.

Creating JavaScript Date Objects:

There are fours ways of instantiating a date object:

  1. Without parameters
    Returns the users current date based on client computer’s clock.

    new Date();

    Example:
    var currentTime = new Date();

  2. With a numeric parameter:
    Returns the date measured from midnight January 1, 1970 (+/- GMT diff) plus the time in milliseconds that was passed as the parameter

    new Date(milliseconds);

    Examples:
    var startTime = new Date(0); // Returns
    your time when GMT hit the new year.
    var millenium = new Date ((365*30 + 7)*24*60*60*1000); // returns the millenium at GMT, The +7 is for the leap days.

  3. With a string parameter:
    The string parameter must be a date correctly formatted in string format. The Date object only seems to accept 1 date string format, which is provided in the examples below. The flexibility is only in the day: the number may include a leading zero, but it is not required.

    new Date(dateString)

    Examples:
    var auntsBirthday = new Date("September 4, 1902") // She’s 105
    var modifiedTime = new Date("July 27, 2005 12:22:00") // format must be exact

  4. With an array of parameters:
    Pass the different date element parameters in the order above. If you don’t specify all the parameters, or a parameter is non-numeric, 0 is passed. If your value is numeric, but not a valid value (such as hours == 25) no error will be thrown, though it may be a logic error. The most common error is the month parameter: remember that the arrays start at index of 0, so January is 0 and December is 11.

    new Date(year, month, day, hours, minutes, seconds, milliseconds)

    var modifiedTime = new Date(2007,7,27)
    var modifiedTime = new Date(2007,7,27,13,22,0)

Here are a few examples and what gets returned (javascript must be enabled):

  • currentTime = new Date()
  • timeBasis = new Date(0)
  • lastYear= new Date(-365*24*60*60*1000)

  • var currentTime = new Date("November 4, 2008");

  • anniversary = new Date(2003,8,21)
  • exactTime = new Date(1969,0,3,16,4,12,500)

Note:

  • new Date(0) will not return midnight of January first unless your computer set to GMT.

Common JavaScript Date Object Errors

  • new date()
    //Error: Date is case sensitive
  • new Date("412")
    //
    Error: No data conversion
  • new Date("June 31, 2005 29:95:73 ")
    //Logic Error: Too many hours in your day, and there are only 30 days in June.
    Returns July 2, 2005; which is unlikely your intention.
  • new Date("July 27, 2005 12:22pm")
    // invalid date error - doesn’t understand PM
  • new Date("2007-7-27")
    //Invalid Date: - string in wrong format**
  • new Date(1969,12,3,16,4)
    //Returns January 3, 1970 instead of December 3, 1969. Logic Error: monthArray is 0 - 11.

Notes:

  • When passing the month as a number, remember that the array starts at 0. Optional values are 0-11. Javascript will not throw an error, but there will be a logic error.
  • The date string must be of the correct fomat. The minimum is "Month dd, yyyy", to "Month dd, yyyy hh:mm:ss". The Month doesn’t seem to be case sensitive in my tests, but I haven’t checked all browsers. Good coding practices dictate that it should be capitalized. .
  • JavaScript uses the date of midnight, January 1, 1970 UTC as a starting point for all of its calculations.

An Example of Converting a PHP/Unix date to a usable JavaScript date:

So my quandry was that the date I received was written in an unusable format: The date the server sent was similar to 2007-07-22T22:57:35Z - yyyy-mm-ddThh:mm:ssZ, which is the date in ISO 8601 format (see converting ISO 8601 dates in PHP for a completely different take on conversion). I had to convert an ISO 8601 date to a parameter I could use in the Date object constructor

My first thought was to replace the T and Z with spaces, 2007-07-22 22:57:35 , which looks correct, but isn’t.
As we learned above (see Date error example above), date strings much be in the "Month dd, yyyy" format. The yyyy-mm-dd format will not work.

var myStringDate = "2007-07-22T22:57:35Z";
var myStringDate = new Date(myStringDate.replace(/\D/g, " ")) //returns "invalid date".

My second thought was to split the string into parameters.

var myStringDate = "2007-07-22T22:57:35Z";
var myStringDate = myStringDate.replace(/\D/g, " ");
var dObj = myStringDate.split(" ");
          //array is (2007, 07, 22, 22, 57, 35)
var myDate = new Date(dObj[0], dObj[1], dObj[2],
           dObj[3], dObj[4], dObj[5]);

That works, but gives me the wrong date. We have a logic error. The month array starts at 0. month[07] is August, not July. The solution was to subtract 1 from the 2nd parameter

var myStringDate = "2007-07-22T22:57:35Z";
var myStringDate = myStringDate.replace(/\D/g, " ");
var dObj = myStringDate.split(" ");
var myDate = new Date(dObj[0], (dObj[1]-1), dObj[2], dObj[3], dObj[4], dObj[5]);
document.write("Making a date from a string: " + myDate);



Writing Pretty Dates

Javascript 1.2 gave us some prettier ways of writing out dates. Still, you might not find the format you need with the methods provided. Here are some arrays that you should feel free to cut and paste into your code.

dyOfWeek = new Array("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat");
daysOfWeek = new Array("Sunday", "Monday", "Tuesday", "Wednesday",
             "Thursday", "Friday", "Saturday");
monOfYear = new Array("Jan.", "Feb.", "Mar.", "Apr.", "May", "Jun.",
             "Jul.", "Aug.", "Sep.", "Oct.", "Nov.", "Dec.");
monthsOfYear = new Array("January", "February", "March", "April", "May",
    "June", "July", "August", "September", "October", "November", "December"); 

toLocaleDateString() works for much of what I need. But, sometimes you need something a little different. You can either edit using regular expressions, or you can create a pretty date from scratch.

Here are some formats and how to create them. I will use the date we created, the methods described above and the 4 arrays posted here.

(myTime.getMonth() + 1) + "/" + myTime.getDate() + "/" + myTime.getFullYear()
var hours =  myTime.getHours();
var ampm = (hours > 11)? "PM" : "AM";
hours = hours%12;
hours = (hours == 0)? 12 : hours;
time = hours + ":" + myTime.getMinutes() + " " + ampm;
July 2007
monthsOfYear[myTime.getMonth()] + " " + myTime.getFullYear()

Formatting Javascript Dates:

Want to extend the Date object to be nicely formated? Gavin Kistner did the work for us. Extending the Date Object which creates the a custormFormat for the date object. To use this prototype, include the function in your javascript, and call it this way:

var prettyDate = myDate.customFormat('#DDDD#, #MMM# #D#, #YYYY#');
var prettyTime = myDate.customFormat('#h#:#mm##ampm#');

Here’s the code:

Date.prototype.customFormat=function(formatString){ 
    var YYYY,YY,MMMM,MMM,MM,M,DDDD,DDD,DD,D,hhh,hh,h,mm,m,ss,s,ampm,dMod,th;
    YY = ((YYYY=this.getFullYear())+"").substr(2,2);
    MM = (M=this.getMonth()+1)<10?('0'+M):M;
    MMM = (MMMM=["January","February","March","April","May","June","July","August","September","October","November","December"][M-1]).substr(0,3);
    DD = (D=this.getDate())<10?(’0′+D):D;
    DDD = (DDDD=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"][this.getDay()]).substr(0,3);
    th=(D>=10&&D<=20)?’th’:((dMod=D%10)==1)?’st’:(dMod==2)?’nd’:(dMod==3)?’rd’:'th’;
    formatString = formatString.replace("#YYYY#",YYYY).replace("#YY#",YY).replace("#MMMM#",MMMM).replace("#MMM#",MMM).replace("#MM#",MM).replace("#M#",M).replace("#DDDD#",DDDD).replace("#DDD#",DDD).replace("#DD#",DD).replace("#D#",D).replace("#th#",th);
     h=(hhh=this.getHours());
    if (h==0) h=24;
    if (h>12) h-=12;
    hh = h<10?(’0′+h):h;
    ampm=hhh<12?’am’:'pm’;
    mm=(m=this.getMinutes())<10?(’0′+m):m;
    ss=(s=this.getSeconds())<10?(’0′+s):s;
    return formatString.replace("#hhh#",hhh).replace("#hh#",hh).replace("#h#",h).replace("#mm#",mm).replace("#m#",m).replace("#ss#",ss).replace("#s#",s).replace("#ampm#",ampm);
	 } 
 
 

Website Optimization: YSlow Tutorial July 26, 2007

Filed under: Best Practices, Web Development, firebug — admin @ 6:09 pm

Introduction to YSlow: optimizing your actual and perceived download speed

Two days ago Yahoo! officially released their Firebug extionsion "YSlow". YSlow is a tool that coherently presents factors effecting actual and perceived download speed. Many of the features available thru YSlow are avaible thru the Firebug NET tab, and digging thru other Firebug panes. What makes YSlow such an effective tool is that it displays those features in a understandable and actionable way.

Installing Yahoo! YSlow

YSlow is a page analysis tool that helps you optimize your web pages for better perceived and actualy download speed. YSlow is an extension to Firebug which is a FireFox plug-in (Yes, it’s an extension to an extension). You must download and install Firebug: If you need instructions, I wrote a introduction to Firebug tutorial last month.

To install YSlow, download YSlow from the Mozilla website. Click on the "Install Now" button, then on "Install". You will need to restart Firefox for both the YSlow and the Firebug add-ons to work, so you might as well download and install both before restarting FireFox.

Turning YSlow on

While the YSlow icon will always be present in the right of the status bar, it is not actively running and analying all your page visits all of the time. To get YSlow to always be active, righ click on the word YSlow in the status and choose "Autorun" from the popup menu.

AutoRun: Having YSlow on all the time

You likely don’t want YSlow running all the time. The benefit of having YSlow on autorun is that you:

  1. Total download weight and time (to the right of the YSlow icon in the status bar),
  2. Faster access to YSlow features.

The downside is that having YSlow on all the time

  1. Faster perceived download time
  2. Uses RAM

My recommendation is to only have it on autorun if you are actively working on optimizing; and then turn it off the rest of the time.

Turning YSlow on Selectively

Unless you have selected autorun, you have to activate YSlow by opening up Firebug and clicking on the YSlow Tab, which brings you to a page instructing you how to activate YSlow by selecting which type of analysis you’re interested in. Select Performance, Stats or Component. Selecting from the Tools or Help menu will not analyze your page. For example, if you select JSLine from the Tools menu, you get results for the most recently analyzed page. The Tools drop down menu may actually be greyed out to start.

YSlow Screen Shot.

Using YSlow

YSlow Performance

YSlow gives you a grades for each of 13 areas of download speed plus an over grade with total score. You get graded on the number of HTTP requests made, using expires headers, gzipping files, having CSS at the top, javascript at the bottom, not using CSS expressions, minimizing the number of domains hit for page componenents, minifying javascripts, avoiding redirects, removing duplicate javascript functions, turning off eTags and having static files served from Content Distribution Networks (CDN). I will go over most of these in my blog post on improving perceived and actual download speed. Not included in the list is reducing the number of HTTP requests even further for a home page only by using inpage CSS and JavaScript.

More information: If you don’t get an A on any of the parameters, simply click on the arrow to the right of the parameter, and more information will appear. You can also click on the "expand all" link in the upper right which will expand the sections not earning an A with an explanation of what the failings were. No matter your grade, if you click on the name of the parameter, you will be redirected to the Yahoo Developer Network for details on what the parameter means and how it effects your perceived and/or actual download speed.

Changing Grades: If you don’t like the grading system, you can configure YSlow to weight things differently by altering the javascript file. Search for yslow.js on your computer. Mine was located at c:\documents and settings\estelle\Application Data\Mozilla\Firefox\Profiles\extensions\yslow@yahoo-inc.com\default\preferences\.

YSlow Stats Tab

The Stats tab lets gives provides you with 3 bits of information:

  • Page downloads when Cache is empty
    This includes the number of HTTP requests and file weight of all the HTML, JavaScript, CSS files and images, includeing images called from the CSS, downloaded to render the page. A few things to note about this value: if your page is set as the home page for someone, IE pretends the cache is empty and downloads everything, irrespective of expires headers. If you click on the "(est)" next to a cache parameter, YSlow provides you with an estimate as to how your speed can improve.
  • Page downloads when Cache is full
    This includes only the number of HTTP requests and file weight for the files that do not have a future expires date and are not cached. The total includes thell the HTML, JavaScript, CSS files and images not cached.
  • Cookies

YSlow Components Tab

The Components tab describes in more detail each of the files that make up the sum total in "Page downloads when Cache is empty" described above. For each HTML (or PHP, or whatever the main file is), CSS, JavaScript, CSS image, regular image, etc., YSlow grabs the header information and provides the following in human readable form:

  • File Type
  • File URL
  • Expires header date, if any, or today’s date if not explicitly set
  • Gzip status
  • Server response time
  • Un-g-zipped file size
  • E-Tag

If you want more information, clicking on the magnifying glass next to the URL displays the headers (this is also available thru Firebug’s NET tab). If you click on the actual URL, it will open up that URL — be it an HTML file, a CSS file, an Image — in a new browser window.

YSlow Tools Tab

The Tools tab provides "links" to 4 reports: JSLint, JS, CSS, Printable Version

  • JSLint:
    I am not 100% sure, but I think JSLint explains errors that would need to be rectified before passing your JavaScript file thru Crockford’s JSLint minification tool. For JSLint to work, you have to include components in your Javascript that would otherwise be optional in the loosely typed language, such as ending your lines with a semi-colon. The JSLint response warns you of these necessary edits..
  • JS:
    Prints to the browser all the JavaScript that is included in the currently analyzed page
  • CSS:
    Prints to the browser all the CSS that is included in the currently analyzed page. This is similar to the Firefox Developer Toolbar. I prefer the toolbar version since it has the functionality of allowing you to close out individual CSS sources.
  • Printable Version:
    While this may seem like just a printable version of the performance tab, this page is actually very useful. It delineates all the things you can do to score a 100% on the Performance section of YSlow. It basically explains the performance tab in detail — what you would see if you clicked on the "expand all" link in the performance tab.

Missing Features

Dynamic Downloads not captured:
YSlow isn’t perfect. It does not display properties of elements brought into the page dynamically such as multimedia, javascript rendered images, componenents rendered from XMLHTTPRequests, or any DOM changes. You can use Firebug’s NET tab to garner that data. It seems that YSlow takes a look at the page being analyzed, and does an XMLHTTPRequest to get download time information. Firebug, on the other hand, collects and stores the information for each request. For true web page weight, Firebug is more precise. For actual download time, Firebug is also more precise. For perceived download time, however, YSlow gives you a good estimate.

 
 

XHTML Deprecated Elements and Attributes July 24, 2007

Filed under: Web Development — admin @ 10:31 am

If you’re coding with a strict doctype, you definitely don’t want to use any deprecated attributes or elements. So, what are those deprecated elements and attributes that you shouldn’t use? See below:

Deprecated Elements

Name Description Alternative
applet Java applet  
basefont base font size font-size: 100%;
center shorthand for DIV align=center text-align: center;
dir directory list  
font local change to font font-family: arial; font-size: 0.8em;
isindex single line prompt  
menu menu list  
s strike-through text style text-decoration: line-through;
strike strike-through text text-decoration: line-through;
u underlined text style text-decoration: underline;

 

Deprecated Attributes

Attribute Deprecated in these elements CSS (or HTML) Alternative
align caption, img, input, object, legend, table, hr, div, h1, h2, h3, h4, h5, h6, p CSS attribute: text-align
alink, link, vlink body CSS selectors: a, a:link, a:visited, a:hover, a:active, a:visited:hover
CSS attribute: color:
background body CSS attribute: background-image:
bgcolor table, tr, td, th, body CSS attribute: background-color: or background:
border img, object CSS attribute: border:
clear br CSS attribute: clear: left | right | both | none
compact dl, ol, ul CSS attribute: line-height, min-height or height: with overflow: set.
height td, th CSS attribute: line-height for cell content; don’t use tables for layout
hspace img, object CSS attribute: padding
language script HTML attribute: type
HTML attribute value:
MIME type, ex. type="text/javascript"
name img, a, applet, form, frame, iframe, map HTML attribute: id
noshade hr  
nowrap td, th CSS attribute: white-space:
size hr CSS attribute: width: or margin:
start ol Anyone know? Please tell me.
target a Anyone know? Please tell me.
text body CSS attribute: color
type li, ol, ul CSS attribute: list-style-type
value li Anyone know? Please tell me.
version html HTML Markup: use a DTD
vspace img, object CSS attribute: padding: or margin:
width hr, td, th, pre CSS attribute: width:
 
 

Javascript Objects July 20, 2007

Filed under: JavaScript, Web Development — admin @ 12:22 am

Javascript: Things you should know

Note: This is part III of a "Javascript: Things you should know" series. I assume readers have an understanding of the core language. This section goes over objects at a very basic level. Most books cover objects in a confusing manner. Below are really simple examples which, if you have been confused, will hopefully make things make sense. The previous entry was JavaScript Switch Statement Quirks.

JavaScript Objects Demystified

Everything in JavaScript is an object except core types. true, false, null, undefined and numeric values are not objects. Strings, with the length property and numerous methods, are objects.

Most JavaScript objects are collections of name-value pairs. I think of objects as associative arrays. The "name" or key of an object is a string except for in the array object where it can be a string or a incremental integer. The value can be any JavaScript value, including an array or other object.

Creating a JavaScript Object

There are two basic ways to create an object which are semantically equal. You can declare an object using an object function and instantiate the object by using the "new" keyword or you can use the object literal method:

  • var obj = new Object();
  • var obj = {}; // object literal method

Assigning properties to an object

An object’s properties can be assigned with the dot operator or like an associative array::

obj.name = "Estelle";
obj["name"] = "Estelle";

the property values can be retrieved in a similar fashion

var myname = obj.name;

var myname = obj["name"];

The difference between using the dot operator versus the array method is that since the key value is a string, you can use reserved words for the "name". If you plan on creating property names based on user input, this can be aspirin for what otherwise would be a headache. Otherwise, the dot syntax is easier, and reserved words should not be used. Using a reserved word is a bad idea. Both the object name and property name are case sensitive.

obj.for = "Estelle"; // produces an error
obj["for"] = "Estelle"; // allowed

Object Literals

Object literal syntax can be used to initialize the entire object.:

var obj = {
  name: "Estelle",
  gender: "Female",
  outfit: {
     top: "t-shirt",
     bottom: "jeans",
     shoes: "hiking boots"
     }
}

You can chain it together:

obj.outfit.shoes; // hiking boots
obj["outfit"]["bottom"]; // jeans

Even though outfit in the example above seems like it is a newly created object within obj, it isn’t:

outfit.shoes; // error, since outfit is not defined
obj.shoes; // undefined, not an error, since obj is defined, but the property shoes has not been assigned a value

Assigning methods to an object

Methods are simply functions tied to objects. For example, toUpperCase is a method of the string object. The simplest way to attach a method to an object is to use an anonymous function:

var greeting = {
  name: "Estelle",
  message: "this was written by ",
  welcome: function(){
     alert("Objects now make sense");
     },
  sayhi: function(){
     alert(this.message + this.name);
    }
}

welcome is a method of the greeting object. Calling greeting.welcome();, with the parenthesis, will cause the alert.

sayhi is also a method of the greeting object. Calling sayhi.welcome();, with the parenthesis, will cause the alert. The this keyword refers to the object that is calling the function, and will be discussed in further detail in a future entry.

Method names are also case sensitive.

the Window object.

All variables that are not assigned as properties of other objects become properties of the window object.

var animal = {};
var myCat = animal.pet = "Sassafrass";

In this case, animal is an object, pet is a property of the animal object and myCat is a property of the window object.

The following all work and return "Sassafrass":

  • animal.pet;
  • window.animal.pet;
  • myCat;
  • window.myCat;

The following may not return what you expected:

  • pet; // throws an error as pet is a property of the animal object, not the window object
  • window.pet; // undefined
  • window.animal // evaluates to object.

Note: JSON, or JavaScript Object Notation, is a subset of JavaScript’s oject literal notation.

JavaScript Object Properties and Methods

All objects in javascript inherit from the Object object, and therefore inherit the properties and methods of Object, including:

  • constructor property
  • prototype property
    used to assign new properties and methods to future instances of the object type.
  • hasOwnProperty() method
  • isPrototypeOf() method
  • propertyIsEnumerable() method
  • toString() method
  • toLocaleString() method
  • valueOf() method

Extending Objects

It is fairly simple, though not always necessary, to extend objects with new methods and properties. Use the protoype property, inherited from the Object object to add methods to an object. Here are some examples of String, Array and Date object methods.

String.prototype.capFirst = function(){
   return this.charAt(0).toUpperCase() + this.substr(1);
}

String.prototype.trim = function () {
  return this.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1");
};

Array.prototype.sortCaseInsensitive = function(){
    return this.sort(function(a,b){ return (String(a).toLowerCase() > String(b).toLowerCase())? 1: -1;}
}

Date.prototype.customFormat = function(formatString){
  //The code for this is in the javascript date object article.
}
 
 

Safari 3 CSS Support July 10, 2007

Filed under: Browsers, CSS (including hacks), Web Development, iPhone — admin @ 1:50 pm

Safari 3.0 has the best CSS, including CSS3, support of any popular browser. Below I go over Safari CSS Selector support and then show how to include multiple background images, and how to create rounded corners without the use of background images (FF has a similar method)

CSS Selectors and Safari 3.0

Below are the various CSS selectors, including CSS3 selectors, and Safari 3.0 for Windows and iPhone support. Green / √ means current support. Orange / Δ means that the browsers have some support for the selector. Red / Χ means that the browser is non-compliant. Non-compliant selectors can be used and a valid way to target individual browsers.

Selector iPhone Windows XP Comments
*  
E  
.class  
#id  
E F  
E > F  
E + F  
E[attr]  
E[attr=val] Δ Δ Safari is case sensitive in cases where it need not be (this is the exact opposite of the IE7 quirk)
E[attr~=val] Δ Δ
E[attr|=val] Δ Δ
:first-child Δ Δ When a new first child is created via javascript, the previous first child maintain :first-child attributes. Otherwise, this pseudo-class works
:link  
:visited  
:lang() Has an inheritance quirk that I haven’t been able to replicate
:before  
::before  
:after  
::after  
:first-letter  
::first-letter  
:first-line  
::first-line  
The following selectors are new to CSS3 (above were in previous versions)
E[attr^=val] Δ Δ Safari is case sensitive in cases where it need not be (this is the exact opposite of the IE7 quirk)
E[attr$=val] Δ Δ
E[attr*=val] Δ Δ
E ~ F  
:root  
:last-child Χ Χ  
:only-child Χ Χ  
:nth-child() Χ Χ  
:nth-last-child() Χ Χ  
:first-of-type Δ Δ When a new first of a type is created via javascript, the previous match maintain :first-of-type attributes. Otherwise, this pseudo-class works
:last-of-type Χ Χ  
:only-of-type Χ Χ  
:nth-of-type() Χ Χ  
:nth-last-of-type() Χ Χ  
:empty Χ Χ  
:not()  
:target  
:enabled  
:disabled  
:checked  

Mulitple Background Images

In a single element, you can declare multiple background images. If you open up this blog entry in Safari, the following paragraph will look like it’s in a quote bubble:

This is styled only in Safari. No other browsers currently support this CSS3. This is a simple paragraph with a single class. The CSS for this paragraph follows.

#conversation p {
  background:
    url("img/top-left.png") no-repeat top left,
    url("img/top-right.png") no-repeat top right,
    url("img/bottom-left.png") no-repeat bottom left,
    url("img/bottom-right.png") no-repeat bottom right,
    url("img/left.png") repeat-y left,
    url("img/top.png") repeat-x top,
    url("img/right.png") repeat-y right,
    url("img/bottom.png") repeat-x bottom;
}

CSS Rounded Corners

Safari and Firefox now enable rounded corners simply thru CSS (no more background images>

div.box {
  -moz-border-radius: 5px;
  -webkit-border-radius: 5px;
  border: 1px solid #000;
}

Setting -webkit-border-radius will impact all four corners. You can set corners individually with the following:

  • -webkit-border-top-left-radius
  • -webkit-border-top-right-radius
  • -webkit-border-bottom-left-radius
  • -webkit-border-bottom-right-radius

Notes:

 
 

Web Development for the iPhone July 8, 2007

Filed under: Browsers, Web Development, iPhone — admin @ 11:14 pm

Web Development for the iPhone: Targeting the iPhone Safari browser

Developing for the iPhone

  • The Safari iPhone user agent string is:
    Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420+
    (KHTML, like Gecko) Version/3.0 Mobile/1A543a Safari/419.3
  • Platform string: (iPhone; U; CPU like Mac OS X; en)
  • Version string: Version/3.0 Mobile/1A543a Safari/419.3

To target the iPhone with CSS, use:

<!--[if !IE]>–>
<link media="only screen and (max-device-width: 480px)"
    href="iPhone.css" type="text/css" rel="stylesheet" />
<!–<![endif]–>

The logic of this is that only browsers that understand screen understand only, and of these, only the iphone has a max-device-width of 480px. The reason for the anti-IE comments is that some versions of IE render CSS regadless of media type declarations.

To target the iPhone server-side with PHP you can use:

if (stristr($_SERVER['HTTP_USER_AGENT'], ‘iPhone’)) {}

iPhone Viewport Orientation

The iPhone supports both landscape and portrait views. You can specify CSS based on viewport orientation which you determine via javascript and update the orient attribute of the body element. Target the browser with body[orient="landscape"] or body[orient="portrait"]

iPhone ViewPort Orientation JavaScript

The following javascript snippet detects and sets the iPhone’s viewport orientation by evaluating the innerWidth property of the window object and setting the orient attribute of the body element at regular intervals:

var updateLayout = function() {
  if (window.innerWidth != currentWidth) {
    currentWidth = window.innerWidth;
    var orient = (currentWidth == 320) ? "profile" : "landscape";
    document.body.setAttribute("orient", orient);
    window.scrollTo(0, 1);
  }
};

iPhone.DomLoad(updateLayout);
setInterval(updateLayout, 500);

Hiding the iPhone toolbar

With one line of JavaScript you can hide the big toolbar: window.scrollTo(0, 1); . Include this line of code to your snippet of detecting the phone’s orientation, as the toolbar will reappear when the orientation is changed. Remove it from the snippet above if you want the toolbar to show.

iPhone Viewport Meta Tag

The viewport meta tag properties include width, height, initial-scale, user-scalable, minimum-scale and maximum-scale. The height is calculated based on the width and aspect ratio. The initial-scale is the scale to render when the page first loads; with the default to fit the screen. Unless user scalable is set to no, th user can change the scale through pinching and double tapping of the iPhone.

Property Default Value Minimum Value Maximum Value
width 980 200 10000
height based on aspect ratio 223 10000
inital-scale fit to screen minimum-scale maximum-scale
user-scalable yes no yes
minimum-scale 0.25 > 0 10
maximum-scale 1.6 >0 10

Examples:

<meta name="viewport" content="initial-scale=2.3, user-scalable=no" />
<meta name="viewport" content="width=320; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;" />

The iPhone automatically adjusts font size for readability. This feature can be overridden with -webkit-text-size-adjust. The values for -webkit-text-size-adjust are none (default) | auto | %value.

Comparisons of Safari on the desktop versus the iPhone.

Safari on iPhone supports:

  • Safari supports cookies on both
  • Safari on iPhone allows up to 8 user initiated browser pages to be open at once.
  • Default user preference is set to block pop-up windows.
  • Safari on iPhone supports many MIME types and rich media, including PDF and media file types
  • Images: Safari supports .gif, .jpg, .png, and .tiff
  • Fonts: The iPhone comes with American Typewriter, Arial, Arial Rounded MT Bold, Courier, Courier New,Georgia, Helvetica, Helvetica New, Marker Felt, Times New Roman, Trebuchet MS, Verdana, and Zapfino; so that’s what Safari on the iPhone supports.
  • Other than the :hover pseudoclass which isn’t supported on the iPhone since mouseover effects aren’t supported, Safari on the iPhone supports CSS1, CSS2 and several selectors and attributes of CSS3

Safari on iPhone does not support:

  • Events: mouseover and mouseout, including :hover styles and tool tips, (but it does support onclick and event listeners). Safari on the iPhone does not support the document events of onkeydown, onkeypress and onkeyup, the form-field events of ondblclick, onmouseenter, onmouseleave, onmousemove, and onSelect, and the window events of onresize and onScroll. This is not an exhaustive list, so test your event handlers before listening to me.
  • window.showModalDialog()
  • Plug-ins: Flash or Java, and plug-in installations. Do not ask users to download Flash.
  • File-size: Non-streaming files of over 10MB. CSS, JavaScript and HTML files are limited to 10MB per file. JavaScript is limited to 5 seconds of execution time. Safari for the iPhone does support gzip compression, so compress!
  • The iPhone does not support gifs, png or tiffs over 8 MB and jpgs over 128 MB (but does support larger streaming media files).
  • You can use iFrames, but avoid framesets.

Other iPhone Safari features

Phone numbers are automatically converted to phone links. You should convert them instead of letting Safari control it for you.
<a href="tel:4155551212">415.555.1212</a>.

Notes:

 
 

Javascript Switch Statement Quirks July 3, 2007

Filed under: JavaScript, Web Development — admin @ 10:21 am

Javascript: Things you should know

Note: This is part II of a "Javascript: Things you should know" series. I assume readers have an understanding of the core language. I try to cover quirks that are important, often lead to logic errors but don’t throw an error, and aren’t covered in most books or tutorials. The previous entry was Browser Detection versus Object Detection.

JavaScript switch statement:

There are three things you may or may not know about the switch statement:

  1. there is no datatype conversion ,
  2. once there is a match, all expressions will be executed until the next break or return statement is executed, and
  3. you can include multiple cases for a single block of code.

Data Type is important. JavaScript is NOT loosely typed when it comes to case comparisons

Javascipt is generally a loosely typed language. In other words, there is no need for data type declarations, you can easily change the data type, and you can compare values of different types. Normally in JavaScript data type does not matter. In regular if statement comparisons data type doesn’t matter unless you are using strict comparisons that specifically check for data type:

y = 5;
x = '5';
if(x == y){
  alert("they're the same"); // this alert will show
} 

if(x ===y){
alert("Data types match?"); //This will not show: different types
}

The exception is case values in the switch statement. For the case to be a match, the data types must match. Think for it as switch statements including === (strict equal) instead of == (equal) for case comparisons.

y = 5;
switch(y){
  case '5':
  alert("hi"); // this alert will not show since the data types don't match
}

In the above case, there is no match as 5 and ‘5′ are not the same datatype.

Break or Return statements are necessary

Although not required, if you omit the return or break statement in your case code block, once there is a match, all statements will be executed until the end of the switch statement or until the next break or return statement is encountered, whichever is first.

<script type="text/javascript">
//<![CDATA[
y = 5;
switch(y){
  case 5:
    alert("this matches");
  case 4:
    alert("this does not match, but will be displayed");
    break;
  case 3:
    alert("not shown due to break");
}
//]]>
</script>

In the above switch statement, there is a match in the first case, so the alert is correctly displayed. The script continues executing statements until it encounters the end of the switch statement, a break or a return, whichever comes first. Since there is no break, the second alert is erroneously displayed.

Multiple cases for a single block of code

<script type="text/javascript">
//<![CDATA[
y = 5;
switch(y){
  case 5:
  case 4:
  case 3:
    alert("this matches");
    break;
}
//]]>
</script>

If we extend what we just learned above — that once there is a match, every statement is executed until a break or return if found — then it makes sense that the alert in the above switch statement will be executed if any of the cases match.

 
 

hasLayout

Filed under: Browsers, CSS (including hacks), Web Development — admin @ 10:20 am

HasLayout:

HasLayout is a Microsoft proprietary property that determines how IE will render the dimensions of an element. It’s a boolean read-only value that is either true or false. When an element’s hasLayout property is false, IE has rendering quirks. The most common quirks include disappearing text in IE, and the most common solution is the holly hack. I prefer using float.

Properties that trigger hasLayout for IE:

  • display: inline-block; (even though IE won’t respect "inline-block" it will still trigger layout)
  • height: any valid value except "auto"
  • float: left or right (not none)
  • position: absolute
  • width: any valid value any value except "auto"
  • writing-mode: tb-rl
  • zoom: any valid value except "normal"

DOM for hasLayout:

  • el.style.hasLayout
  • el.currentStyle.hasLayout
  • el.runtimeStye.hasLayout

Other hasLayout notes:

  • body * { zoom:1 } would seem like a good idea, but elements with a zoom property set are a bit more expensive to render, so only add to necessary elements.
  • removing hasLayout: hasLayout is a read only property, so you can’t set it to false in JavaScript. To set hasLayout to false, set with with CSS such as setting position: static, set zoom: normal;, float: none; etc.
 
 

Browser Detection versus Object Detection July 2, 2007

Filed under: Browsers, JavaScript, Web Development — admin @ 11:52 pm

Javascript: Things you should know

Use object detection instead of browser detection

Note: This is part I of a "Javascript: Things you should know" series. I assume readers have an understanding of the core language. I try to cover quirks that are important but aren’t covered in text books. The next entry will be quirks with the javascript switch statement.

Use object detection instead of substring detection to determine browser support of your code. Browser detection involves using navigator.userAgent. There are several reasons why you shouldn’t use browser detection.

  1. Browsers lie about who they are.
  2. You may filter out browsers that support your code or fail to filter out browsers that don’t support your code..
  3. Browser detection isn’t future proof: can’t future proof your code against new browsers.

Instead, use object detection: test to see if your browser supports the object you want to manipulate. If the browser supports your objects, yay! You don’t need to know the name of the browser or version number, just whether or not it will support your code.

The most commonly used object detection to check to see if a browser supports the DOM is:

var supportsDOM = document.createElement && document.getElementsByTagName; 

This object detection does not mean you can use any object. It simply lets me know whether you should even try implementing your javascript in that particular browser. While the above is a good start, you should still do object detection before assuming browser support.

if(supportsDOM){
  var resolution = window.devicePixelRatio;
  alert(resolution);
}

At the time of this writing, the only browser that supports the devicePixelRatio property is Safari. See Targeting Safari 3.0 with CSS and Javascript. Safari will return "1", whereas all other browsers will return "undefined". Basically, just because a browser supports the DOM, it does not mean that it supports every object, property and method of the DOM equally, and that it doesn’t have it’s own propietary methods. Once you’ve determined that your browser supports the DOM, you still have to test for method and property support before using it.

if(obj.addEventListener) {
  //standards code
}
else if(obj.attachEvent) {
  //proprietary code
} 

A prime example is IE’s failure to support the WC3 standard addEventListener. Microsoft has it’s own event handling model, supporting attachEvent instead. When performing bject detection, always test for standards compliant methods before proprietary support. IE7 does not support addEventListener. IE8, or whatever the next version is, may support addEventListener and will continue to support attachEvent for backwards compatibility reasons. When IE finally supports the WC3 standard, putting your object detection in this order will ensure that browsers that support standards, whether or not they also support proprietary methods, will use the standard.

Exceptions to the use oject detection not browser detection rule

If you are still supporting IE 5.2 for the Mac, you may want to use browser detection to exclude it. Mac IE 5.2 returns true for if(document.createElement && document.getElementsByTagName), but crashes when it encounters advanced scripts. See Mac IE Hacks.

If you are actually trying to determine which browser is using for some non-javascript reason, such as maintaining statistics on visitors, then it makes sense to use browser detection.

Note: Apple has a good article on object detection versus browser detection.