CSS, JavaScript and XHTML Explained

Estelle Weyl’s Blog of quirks, random thoughts and funky finds discovered in day-to-day coding

 

Web Development for the iPhone: HTML, CSS & JS Support December 5, 2009


Safari and Safari for the iPhone support all HTML elements, including deprecated elements and even some proprietary elements that were never part of any W3C specifications. In addtion, Safari is supporting some HTML5 elements, even though the HTML5 specifications have not been finalized. I’ve also added the attributes that each element supports. I didn’t include id, class, style, dir & title, since all elements basically support those, but I did include element specific attributes as well as some webkit only attributes.

iPhone Support for CSS3 Selectors

All CSS Selectors are supported by Safari on the iPhone. See CSS browser support for a chartcomparison of all the selectors. Selectos include:

  • *
  • E
  • .class
  • #id
  • E F
  • E > F
  • E + F
  • E[attribute]
  • E[attribute=value]
  • E[attribute~=value]
  • E[attribute|=value]
  • :first-child
  • :link
  • :visited
  • :lang()
  • :before
  • ::before
  • :after
  • ::after
  • :first-letter
  • ::first-letter
  • :first-line
  • ::first-line
  • E[attribute^=value]
  • E[attribute$=value]
  • E[attribute*=value]
  • E ~ F
  • :root
  • :last-child
  • :only-child
  • :nth-child()
  • :nth-last-child()
  • :first-of-type
  • :last-of-type
  • :only-of-type
  • :nth-of-type()
  • :nth-last-of-type()
  • :empty
  • :not()
  • :target
  • :enabled
  • :disabled
  • :checked
  • see them all

iPhone Support for CSS3 properties

Almost all CSS2.1 properties and values are supported by Safari on the iPhone, except for some keyword values for content. Position: absolute is supported, but due to the viewport, does not appear to be supported. See the list of all CSS2.1 properties and values by browser for more details. In addition, the iPhone Safari browser supports some CSS3 type properties and values including:

Some CSS3 including the following, which will be discussed in future blog posts.

  • hsl(), rgba(), hsla() color support
  • native rounded corners (-webkit-border-radius)
  • IE box model (-webkit-box-sizing)
  • Shadows on text (text-shadow was in CSS2.0)
  • Shadows on elements (-webkit-box-shadow)
  • multiple background images
  • opacity /gradient transparency
  • @font-face web fonts
  • CSS Animation
  • Media Queries
  • namespaces

iPhone & Safari Support for HTML elements, including HTML5

includes HTML attributes for the iPhone and Safari

Below is a grid of all of the elements, including deprecated elements (at the way bottom), and HTML5 elements interspersed with HTML4 elements in alphabetical order.

<ELEMENT> Element Name Safari
Version
iPhone Support Attributes (and Notes in italic)
Elements occuring outside the body element
<!DOCTYPE> Document Type Declaration 1.0 1.0  
<html> html 1.0 1.0 manifest (Saf. 4, iphone 2.2)
<head> document head 1.0 1.0 profile
<base /> url base for links 1.0 1.0 href, target
<link /> link 1.0 1.0 charset, href, media, rel, rev, target
<meta /> meta 1.0 1.0 content, name, http-equiv, scheme
<style> style 1.0 1.0 media, type
<script> script 1.0 1.0 charset, defer, language, src, type
<title> document title 1.0 1.0  
Elements Occuring in the <body> in HTML 4.01 and HTML5
<body> document body 1.0 1.0 bgproperties (value: fixed)
<a> Anchor 1.0 1.0 different event handlers for iPhone than Safari
accesskey, charset, href (required), hreflang, rel, rev, shape (rect/cirlce/poly), target (deprecated, but useful), type

<abbr>

Abbreviation 1.0 1.0 title shows on hover in Safari
<acronym> acronym 1.0 1.0 title shows on hover in Safari
<address> address 1.0 1.0 italic
<area> image map area 1.0 1.0 accesskey, alt (required), coords, href (required), hreflang, shape (rect/cirlce/poly), target
<article>       HTML5
<aside>       HTML5
<audio> audio 3.1 3.0 HTML5: Similar to object, can nest sources and content to cascade until supported found.
Audio support includes AAC, M4A, MP3, Wave, AIFF , Apple Lossless, Quicktime, but not OGG;

autoplay, controls, end, loopend, loopstart, playcount, src, start
<bdo> bi-directional override 1.0 1.0  
<blockquote> long quote 1.0 1.0 cite

<br>

break return or forced line break 1.0 1.0  
<button> push button 1.0 1.0 accesskey, disabled, type, value
<canvas> canvas drawing region 1.3 1.0 HTML5: Stroke and fill colors, rgba/hsla colors, paths, rectangles, shadows, gradients, patterns, translations, rotation and scale
<caption> caption 1.0 1.0  
<cite> citation 1.0 1.0  
<code> code 1.0 1.0  
<col /> column 1.0 1.0 char, charoff, span
<colgroup> column group 1.0 1.0 char, charoff, span
<dd> definition description 1.0 1.0  
<del> delete 1.0 1.0 datetime

<dfn>

definition 1.0 1.0  
<div> generic block element 1.0 1.0 aria-checked, aria-level, aria-pressed, aria-valuemax, aria-valuemin, aria-valuenow, role (Safari 4.0)
<dl> definition list 1.0 1.0  
<dt> definition term 1.0 1.0  
<em> emphasized text 1.0 1.0  
<fieldset> field set 1.0 1.0  
<figure>       HTML5
<footer>       HTML5
<form> form 1.0 1.0 accept, accept-charset, action, enctype. method, target
<frame /> frame 1.0 1.0 frameborder, longdesc, marginheight, marginwidth, noresize, scrolling (yes/no/auto), src
<frameset> frameset 1.0 1.0 cols, rows
<h1-6> headers 1.0 1.0  
<header>       HTML5
<hgroup>       HTML5
<hr /> horizontal rule 1.0 1.0  
<iframe> internal frame 1.0 1.0 frameborder, longdesc, marginheight, marginwidth, scrolling (yes/no/auto), src
<img /> image 1.0 1.0 alt (required), composite, ismap, longdesc, src, usemap
<input /> input 1.0 1.0 accept, accesskey, alt, autocapitalize (iphone 1.1, values: on/off), autocomplete, autocorrect (iphone 1.1, values: on/off), autosave (safari), checked, disabled, incremental (safari), ismap, max, maxlength, min, placeholder, results, src, type, usemap, value
<ins> Insert 1.0 1.0 datetime
<kbd> keyboard 1.0 1.0  
<keygen> key generation 1.0 1.0 challenge, keytype
<label> label 1.0 1.0 accesskey, for
<legend> caption for fieldset 1.0 1.0 accesskey
<li> list item 1.0 1.0 type, value
<map> image map 1.0 1.0  
<mark>       HTML5
<meter>       HTML5
<object> object 1.0 1.0 archive, classid, codetype, data, declare, loop, type, usemap

<ol>

ordered list 1.0 1.0 type
<optgroup> option group 1.0 1.0 disabled, label
<option> option 1.0 1.0 disabled, label, selected, value
<p> paragraph 1.0 1.0  
<param> parameter 1.0 1.0 type, value, valuetype
<pre> preformatted text 1.0 1.0  
<progress>       HTML5
<q> inline quotation 1.0 1.0 cite
<samp> sample computer code 1.0 1.0  
<select> option selector 1.0 1.0 disabled, multiple
<source>   3.1   HTML5
media
<span> span (generic non-semantic container) 1.0 1.0 aria-checked, aria-level, aria-pressed, aria-valuemax, aria-valuemin, aria-valuenow, role (Safari 4)
<strong> strong emphasized text 1.0 1.0  
<sub> subscript 1.0 1.0  
<sup> superscript 1.0 1.0  
<table> data table 1.0 1.0 frame (values: above, below, hsides, vsides, rhs, lhs, box, border), rules (values: none, groups, rows, cols, and all), summary
<tbody> table body 1.0 1.0 char, charoff
<td> table data cell 1.0 1.0 abbr, axis, char, charoff, colspan, headers, rowspan, scope
<textarea> text area 1.0 1.0 accesskey, cols, disabled, readonly, rows, wrap
<time>       HTML5
<tfoot> table footer 1.0 1.0 char, charoff
<th> table header cell 1.0 1.0 abbr, axis, char, charoff, colspan, headers, rowspan, scope
<thead> table head 1.0 1.0 char, charoff
<tr> table row 1.0 1.0 char, charoff
<ul> unordered list 1.0 1.0  
<var> variable 1.0 1.0  
<video> video 3.1 3.0 HTML5
autoplay, controls, end, loopend, loopstart, playcount, poster, src, start
Elements you should not be using, that are still valid
<tt> teletype 1.0 1.0  
<i> italic
<b> bold
<big> big font
<small> small font
<noframes> no frames 1.0 1.0  
<noscript> no script 1.0 1.0  
Elements that are deprecated or were never in a W3C spec, but you may still see on older websites
<applet> applet 1.0    
<center> center 1.0 1.0  
<dir> direction 1.0 1.0  
<embed> embed 1.0 1.0 use object instead
hidden, loop, pluginpage, pluginspage, pluginurl
<font> font 1.0 1.0  
<layer> layer 1.0 1.0  
<listing> listing 3.0 1.0 use <pre> instead. from HTML 3.2
<marquee> ,arquee 1.0 1.0 behavior, direction, loop, scrollamount, scrolldelay, truespeed
<menu> menu 1.0 1.0  
<nobr> no break 1.0 1.0  
<noembed> no embed 1.0 1.0  
<nolayer> no layer 1.0 1.0  
<plaintext> plaintext 1.0 1.0  
<strike> strikethrough 1.0 1.0 use <del>
<u> underline      
<wbr> with breaks 1.0 1.0  
<xmp> sequence of literal characters 1.o 1.0  


Safari and iPhone Event Handlers:

Event Safari iPhone Explanation
onabort 1.0 1.0 When an image element is aborted during load. (for <img /> elements)
onbeforecopy 1.3   before the element is copied.
onbeforecut 1.3   before the element is cut.
onbeforepaste 1.3   before the element has something pasted into it.

onbeforeunload 1.3   before the element is unloaded from the page.

onblur 1.0 1.0 when the element loses focus.

onchange 1.0 1.0 when the element changes its value.

onclick 1.0 1.0 when the element is clicked.

oncontextmenu 1.1   when the element is right-clicked or when the mouse button is held down long enough to generate a contextual menu.

oncopy 1.3   when the element is copied.

oncut 1.3   when the element is cut.

ondblclick 1.0   when the element is double-clicked.

ondrag 1.3   when the element is dragged.

ondragend 1.3   when the element is done being dragged.

ondragenter 1.3   when a drag has entered the element.

ondragleave 1.3   when a drag has left the element.

ondragover 1.3   when a drag is over the element.

ondragstart 1.3   when the element has started to be dragged.

ondrop 1.3   when the element is dropped.

onerror 1.0 1.0 when the element has an error in loading.

onfocus 1.0 1.0 when the element gets focus.

ongesturechange   2.0

When fingers are moved during a gesture.

(proprietary)

ongestureend   2.0

When the gesture ends (when there are 1 or 0 fingers touching the surface).

(proprietary)

ongesturestart   2.0

When two or more fingers touch the surface.

(proprietary)

oninput 1.3 1.0 when text is entered into the element.
onkeydown 1.0 1.0 when a key is pressed over the element.

onkeypress 1.0 1.0 when a key is pressed and released over the element.

onkeyup 1.0 1.0 when a key is released over the element.

onload 1.0 1.0 when the element finishes loading.

onmousedown 1.0 1.0 when the mouse button is pressed over the element.

onmousemove 1.0 1.0 when a key is moved within the element.

onmouseout 1.0 1.0 when the mouse leaves the element.

onmouseover 1.0 1.0 when the mouse is over the element.

onmouseup 1.0 1.0 when the mouse button is released over the element.

onmousewheel 1.0 1.0 when the mouse wheel button is rotated.

onorientationchange   1.1

When the orientation of the device changes.

onpaste 1.3   when the element is pasted.

onreset 1.0 1.0 when the form element is reset.

onresize 1.0 1.0 when the element is resized.

onscroll 1.2 1.0 when the element is scrolled (a text box would use this, for example).
onsearch 1.3  

when a search is performed.

(proprietary)

onselect 1.0 1.0 when text within the element is selected.

onselectstart 1.3   when the element begins to be selected. You can use this to prevent selections.

onsubmit 1.0 1.0 when the form element is submitted.

ontouchcancel   2.0

When the system cancels tracking for the touch.

(proprietary)

ontouchend   2.0

When a given event lifts from the surface.

(proprietary)

ontouchmove   2.0

When a finger for a given event moves on the surface.

(proprietary)

ontouchstart   2.0

When a finger for a given event touches the surface.

(proprietary)

onunload   2.1 when the element is unloaded from the page.

 

Other iPhone posts in my blog

 
 

Moving from Web 1.0 to Web 2.0 November 21, 2009

Filed under: AJAX, Best Practices, Browsers, Web Development, firebug — Estelle Weyl @ 9:22 pm

Moving from Web 1.0 to Web 2.0: Skills you need to know to stay relevant.

Here is the audio.

 
 

22 Questions to Ask Before Developing a Website April 29, 2009

Filed under: Best Practices, SEO, UED, Web Development — Estelle Weyl @ 12:37 am

I developed this “Website Development Questionnaire” in 2002. It is old, but it still serves me well, so I thought I would share. I don’t actually add the bold or italic sections below. Those were added here to help you understand the rationale for the questions:


1) Corporate Identity: Corporate Information (for site development):
Company Name (Legal)
Company Name (Branding)
Company Tag Line:
Company Phone Number
Company Fax Number
Address:
Other contact information
Business hours of operation (store hours / when phones will be answered, if relevant)

2) Domain Names and Hosting:
Main Domain Name:
What other domain names do you own?
Do you have web hosting? If so, what type (IIS, Apache?)

3) Briefly describe what your company does:

4) Adjectives: Please list 5 (or more) adjectives that you think describe your company or should describe your company in order of relevance / importance

This information is used to get a sense for design, and to help in SEO

5) Competitors: Are there any websites that you would consider your “competition”? Feel free to provide more information on how they are your “competition”, but, at minimum, provide for each competitor, include the company name, web address, and a list of “keyterms” that describe what they do and/or sell.


In addition to getting a good look at what key terms they may be targeting, I take a look at these sites to get an idea of the features they may need, target audiences we should be considering, and what the competition will be like in terms of SEO

6) Favorite Sites: Please list 5 websites you like. Include the URL, what you like about each site, and what you would improve upon.

These sites don’t have to be in the same business realm. By getting sites they like, i get a good feeling for their design sense. By finding out what they would improve upon, you learn alot more about what they are looking for in their site.

7) Least favorite sites: Please list 5 websites you don’t like, Include the URL. What don’t you like about these sites? What redeeming qualities to they have?

The pitfalls they list tells you what you need to avoid. Though redeeming qualities are rarely included when clients fill out this list, I get a good sense of what they like when they do answer that question. I usually find that the redeeming qualities from this answer helps me understand better their answer to question 6 above.

8) Products / Services: List the top ten products / services you provide

This should be redundant to the answer of question 5. If it’s not, I usually have to do some business development with the client to get them to focus the purpose of their site. I ask this question this way as well because I don’t want to start developing a site for a client if they haven’t finished developing their business strategy.

9) Selling points: Tell us why you, your products or your services are better than your competition (both online competitors from question 3, and offline competition)

10) User goals: Why do you think people will visit your site? When people don’t know you exist, why would they find you or happen upon your site? Why would they come back? If they do know you, why would they take the time to visit your site?

Most clients think users will just come to their site. This question helps them focus on why an average Jane or John Doe may end up on their site. Many brochure sites get most of their visits from people looking for an address or phone number. You can create a one page website for that. This helps the client focus on what the site’s real goals should be.

11) Target Audience: What types of visitors do you want to get? Who is your target audience? (age, education, and other demographics? Job status? Economic status? Role in the community?) Describe your “average” visitor as best you can.

The layout targeting a Japanese middle school students will be very different from a site targeting rural agricultural workers or British graduate school applicants. Knowing your target audience, their culture, their technical savvy, and their internet expectations can help you design your page in terms of look and feel and help you determine site functionality and user experience design

12) Secondary Audience: What other visitors is your site going to get? Job seekers? Board members?

This helps me determine what additional pages to include in a site. Your client may be a sole proprietor, but they may want to hire, incorporate and/or get venture capital funding. Making sure your site can grow to accommodate future features is important. Thinking about those potential features before beginning the design process give you an added edge.

13) Technical: How technically savvy is your average visitor?

14) Accessibility & Usability: Will web visitors have any special needs? (eyesight, language, mobility, reading level?)

15) Site Purpose: What do you want the visitor in question 11 (and 12) to do when they get to your site? What are your goals for the web site in terms of visitor actions? What do you think your site visitor should accomplish on your site?

16) Site Goals: What are your goals for the web site in terms of you company goals? How is your site supposed to help your business? What is the purpose of your site?

17) Site Analytics: What are your goals for the web site in terms of popularity and virality? What type of exposure do you anticipate your website, when “successful” should achieve?

This question has dual purposes: The first is to help set numeric goals for the site that can be tested with common analytics. The second is to guage the sense of reality of the client: if they expect to reach 1,000,000 page views their first month, they’ll let you know their expectations via this question. This is the time to take some sense into them so they aren’t disappointed and don’t set their expectations too high

18) Site Features: What features do you think your website should include? (calendar, forum, login, price comparison chart, contact form, anything?)
For each feature, please state the goal of said feature.

Some clients want the moon. By stating the goal of each feature, they may realize they don’t need the moon. Other clients have no clue what is available to them. They never ask for a contact form at the initial contact, but i have yet to have a sole proprietor client who doesn’t want a contact form after reading this questionnaire they just never thought of it. This question helps define which features are necessary even if they weren’t originally thought of, and which ones sounded good originally, but really won’t help.

19) Site No Nos: Do you have any definite remarks on what you DON’T want to have on your website? (Flash, splash page, the color pink?) Sharing why you don’t want a feature will help me get an understanding of your user experience tastes, so feel free to elaborate.

This question is really helpful as is. Adding the examples has helped me explain against the dreaded splash page.

20) Other: Anything else I should know?

21) Product Manager: Company Contact(s) Information for web decisions:
Primary Contact Name:
Contact Email Address:
Contact Phone:

Secondary Contact Name:
Contact Email Address:
Contact Phone:

Other contact information

22) Billing Contact: Company contact information for Contracts & Billing:
Name:
Department:
Address:
Phone:
Fax:
Email:
Other contact information

Always know who is going to pay you before you start working


 
 

WAI-ARIA: Accessible Rich Internet Applications basics March 14, 2009

Filed under: AJAX, Accessibility, Best Practices, Web Development — Estelle Weyl @ 10:57 pm

What is ARIA?

ARIA stands for Accessible Rich Internet Applications. With the proliferation of internet applications, there has been an increase in the number of sites requiring javascript that update without page refreshes. This imposes accessiblity issues that weren’t addressed by WCAG 1, as those specifications were written when “sites must work without javascript” was a reasonable accessibility specification. With the increase of web based “applications” (versus “sites”) requiring JavaScript, and improved support of javascript in assistive technologies, new accessibility issues have emerged. ARIA attempts to handle some of those issues. Through the inclusion of roles, states and properties your dynamically generated content can be made accessible to assistive technologies. Additionally, static content can be made more accessible thru these additional, enhanced semantic cues.

Why use ARIA?

By including ARIA accessibility features on your website you are enhancing the accessibility of your site or application. By including roles, states and properties, ARIA enables the developer to make the code semantically richer for the assistive technology user. ARIA enables semantic description of element or widget behavior and enables information about groups and the elements within them. ARIA states and properties are accessible via the DOM.

Similar to including the title attribute, ARIA is purely an enhancement and will not harm your site in any way. In other words, there is no valid reason to not include these features! DojoTools currently supports ARIA. Now that IE8 and Firefox 3 (both in beta at the time of this writing) support ARIA, the other JavaScript libraries should soon follow suit.

The easiest to include and most important properties of ARIA are the inclusions for the role attribute, and inclusion of states and properties.

How to incorporate ARIA

  1. Use XHTML the way it was meant to be used wherever possible. Limit ARIA usage to augment XHTML: only use it when XHTML does not support all the semantics required .
  2. Apply ARIA the role attribute in cases where the XHTML needs to be semantically enhanced and in cases where elements are being employed outside of their semantic intent. This includes setting up relationships between related elements (grouping)
  3. Set ARIA states and properties. Set the properties and initial state on dynamically and user changing elements. States, such as “checked”, are properties that may change often. Assistive technology that supports ARIA will react to state and property changes. role changes, on the other hand, may confuse the assistive technology
  4. Support full, usable keyboard navigation. Elements should all be able to have keyboard focus. I am not covering this here, but you can read up on this at For a more in-depth understanding of keyboard navigation see ARIA Best Practices
  5. Make the visual user interface visually match the defined states and properties in browsers that support the ARIA CSS pseudo-classes.

The ARIA role attribute

The role attribute enables the developer to create semantic structure on repurposed elements. While to a sited user, the above example of a span repurposed as a checkbox is not noticeable, the role attribute makes this seemingly non-semantic mark up accessible, usable and interoperable with assistive technologies. Two notes about roles: 1) once set, a role should not be dynamically changed, since this will confuse the assistive technology, and 2) roles take precendence over element default semantic meaning.

Example: Your designer insists that they want the checkboxes on your page to look a certain way. “Impossible” you say. You know that you can use CSS to make a span look like a checkbox. The sited user would never know that your weren’t using <input type="checkbox"...., but for accessibility concerns, you know a screen reader user will not know it’s a checkbox. With the ARIA role attribute included in your code, a both a browser and screen reader that support ARIA, you can make your repurposed span accessible with:

Of course, this case makes me cringe, since it doesn’t work without javascript and it is not inherintly semantic. However, if you are creating a web application requiring javascript, and you are coding this when browsers actually support ARIA, then you gotta do what you gotta do. If you include spans transformed into checkboxes, you will need to include equivalent unobtrusive onkeydown and onclick events.

Implementation of the ARIA role attribute

<ul role="navigation">

  <li><a href="mypage.html">My Page</li>
  <li>....</li>
</ul>

Values for the ARIA role attribute (For descriptions, roll over the items below)

Note: when i have time to populate a dB, i will add a little ajaxian explanation as to the possible parents and children of each role. In the meantime, please visit WAI-ARIA Roles.

ARIA states and properties

Whereas roles are a static attribute of elements, states are properties that can change with user and server interactions. Properties include both dynamic states that need to be updated, and static properties, such as “required”.

Values for the ARIA States (For descriptions, roll over the items below)

Values for the ARIA Properties (For descriptions, roll over the items below)

Certain properties belong with certain roles. For example, autocomplete makes sense with the roles combobox and textbox. The value of the property or state is also limited to certain value types. In our autocomplete example, the value would need to be selected from a list of predetermined values, whereas a checkbox could have a state of invalid, disabled, required or checked, to name a few, with a bolean as the value.

Working with ARIA in Rich Internet Applications

ARIA and Live Regions

Live regions are sections of a web page or application that change dynamically either thru automatic updates or user interaction.
There are 5 properties specific for Live Regions:

Politeness levels: Should ARIA intrude on the user on updates?

The value of the “live” state are expressed in terms of “politeness” levels. “Polite” regions notify of updates but do not interrupt users, and updates take low priority. A level of “rude” would indicate that the assistive technology should interupt the users current action to provide update information. A good example of using a polite level would be the ticker on a financial page — the user does not need to be interupted every 10 seconds to be informed as to whether a stock value has change. An example of a time to use a “rude” level is when the user has completed a step in a checkout process and the next step is visible. Values: Off, Polite, Assertive, Rude.

Validating your XHTML when including un-speced attributes

This section is not finished
There is a tweak that you need to make in your XHTML page if you include ARIA: you need to use XHTML 1.1 and include the ARIA module in your header area. XHTML 1.0 does not support modularization. The ARIA States and Properties attributes will be understood by user agents in XHTML 1.0 by declaring and using the appropriate namespace the same as for XHTML 1.1, but such documents will not validate to the XHTML 1.0 DTD. None of the DTD snippets below enable validation, but I will update when the modules and/or specifications are updated:


xmlns:aaa=”http://www.w3.org/2005/07/aaa” lang=”en”>

Notes:

  • ARIA and HTML: HTML 4.01 is non-extensible, so you can’t use namespaces for the property and state names. Please view the specs as they become available to see the HTML 4.01 support for ARIA.

Note: This blog is still in development, but it’s come a long way, and it is likely already a bit helpful. I will be adding more example snippets and more about live regions and handling dynamic changes, so come back next week if you want to read more. The original post was 03/12/08 but I’ve reposted it since WAI-ARIA is finally being better supported by YUI, Dojo, jQuery, IE8, Safari 4, and other browsers.

 
 

Canonical tag for SEO February 12, 2009

Filed under: Best Practices, SEO, Web Development — Estelle Weyl @ 9:57 pm


Google, Yahoo and Microsoft are now supporting the canonical meta tag as the standard for identifying the actual source of your content: the real URL that you want to recieve page rank for your key terms.

Many sites have the same content show up with different URLs due to search features, dynamically generated URLS, tags, etc. Google, Yahoo and other search engines have been knocking your sites for having duplicate content as if you were spamming your terms. In other words, having multiple URLs pointing to the same content has been hurting your page rank and your site.

Now you have a way to make sure that your multiple content helps you instead of hurts you.

Implementing the CANONICAL meta tag

  1. Pick one URL for your page - “the pretty, preferred or canonical URL” (to quote Matt Cutts). For example, this page’s main, or canonical, URL is http://www.evotech.net/blog/2009/02/canonical-tag-for-seo/, though you may find it thru http://www.evotech.net/blog/?p=69 or http://www.evotech.net/blog/?s=SEO, http://www.evotech.net/blog/category/seo/ or simply http://www.evotech.net/blog.
  2. Figure out how to include your page’s main URL in pages that are dynamically generated. For example, I need to figure out how to include my primary URL - http://www.evotech.net/blog/2009/02/canonical-tag-for-seo/- in the web page showing this content no matter which URL from the bullet point above is shown.
  3. Once you know how to get the URL you picked in step 1 into your possible other pages feeding the content from your main URL, place the canonical link tag inside the tag with the main content’s URL. For this example, I would place: <link rel=”canonical” href=”http://www.evotech.net/blog/2009/02/canonical-tag-for-seo/” /> in my header.

The syntax is similar to the stylesheet link tag:

<link rel=”canonical” href=”http://www.yourdomain.com/yourpage” />

The canonical tag is ONLY for webpages in the same domain. So, http://evotech.net/blog pointing to http://blog.evotech.net or http://www.evotech.net/blog is fine. However, I can’t point http://estelleweyl.com/blog to http://evotech.net/blog if I were to have that URL as an addon domain on this server.

Now I just have to figure out how to do step 2 so I can create canonical links for this blog.

Added Notes:

Lori basically figured it out for us: (copied from http://beedragon.com/wp-test-site/2009/02/13/add-canonical-link/). Thanks!

Add canonical link tag to head

<?php if ( is_single() || is_page() ) { ?>
<link  rel="canonical" href="<?php the_permalink(); ?>" />
<?php } ?>

Occurs to me now that you’d have to hardcode main url, then get the slug and other url info dynamically:

<?php if ( is_single() || is_page() ) { ?>
<link rel="canonical" href="http://mainurl.com/<?php echo the_time('Y'); ?>/<?php echo the_time('m'); ?>/<?php echo the_time('d'); ?>/<?php echo $post->post_name; ?>" />
<?php } ?>

There is probably a prettier and/or more efficient way to do that, but can’t think of one at the moment.


 
 

hover pseudoclass for the iPhone December 28, 2008

Filed under: Best Practices, CSS (including hacks), HTML, IE7, JavaScript, Web Development, iPhone — Estelle Weyl @ 9:38 pm

Since you’re not hovering, there is no hover pseudo class on the iPhone. instead they have touch events. To simulate the :hover pseudo class, include javascript similar to this:

var myLinks = document.getElementsByTagName('a');
for(var i = 0; i < myLinks.length; i++){
   myLinks[i].addEventListener(’touchstart’, function(){this.className = “hover”;}, false);
   myLinks[i].addEventListener(’touchend’, function(){this.className = “”;}, false);
}

and in your CSS add something similar to:

a:hover, a.hover { /* whatever your hover effect is */ }

Notes:

  • onTouchStart is similar to onMouseOver and onTouchEnd is similar to onMouseOut
  • You’ll likely want something more complex than simply removing the class on touch end. This is just a very simple example that will replace all classes on all your links with a "hover" class, which is probably not what you want. But you get the idea.
  • You can use this on all elements, not just links.

-Estelle Weyl

Note:

 
 

15 JavaScript Gotchas October 19, 2008

Filed under: Best Practices, JavaScript, Web Development — Estelle Weyl @ 2:02 am

We all know that JavaScript can trip you up. Here are a 15 common traps that can trip you up when coding javascript. You likely know most of the code on the page, but if you keep these 15 gotchas in your mind, coding and debugging will be less of a headache:

  1. Case sensitivity: Variable names, properties and methods are all case sensitive
  2. Mismatching quotes, parenthesis or curly braces will throw an error
  3. Conditional Statments:3 common gotchas
  4. Line breaks: Always end statements in semi-colons to avoid common line break issues
  5. Punctuation:Trailing commas in object declarations will trip you up
  6. HTML id conflicts
  7. Variable Scope: global versus local scope
  8. string replace function isn’t global
  9. parseInt should include two arguments
  10. ‘this’ and binding issues
  11. Function overloading: Overwriting functions, as overloading doesn’t exist
  12. Setting default values for parameters in case you omit them
  13. For each loops are for objects, not arrays
  14. switch statements are a little tricky
  15. Always check for Undefined before checking for null
Case Sensitivity
Variables and function names are case sensitive. Like mismatched quotes, you already know this. But, since the error may be silent, here is the reminder. Pick a naming convention for yourself, and stick with it. And, remember that native javascript function and CSS properties in javascript are camelCase.

getElementById(’myId’) != getElementByID(’myId’); // it should be “Id” not “ID”
getElementById(’myId‘) != getElementById(’myID‘); // “Id” again does not equal”ID”
document.getElementById('myId').style.Color; // returns “undefined”
Mismatching quotes, parenthesis and curly brace
The best way to avoid falling into the trap of mismatched quotes, parentheses and curly brackets is to always code your opening and closing element at the same time, then step into the element to add your code. Start with:

var myString = ""; //code the quotes before entering your string value
function myFunction(){
     if(){   //close out every bracket when you open one.

	 }
}

//count all the left parens and right parens and make sure they're equal
alert(parseInt(var1)*(parseInt(var2)+parseInt(var3))); //close every parenthesis when a parenthesis is open

Every time you open an element, close it. Put the arguments for a function into the parenthesis after you’ve added the closing parenthesis. If you have a bunch of parenthesis, count the opening parenthesis and then the closing parenthesis, and make sure those two numbers are equal.

Conditional statements (3 gotchas)
  1. All conditional comments must be within parentheses (duh!)
    if(var1 == var2){}
  2. Don’t get tripped up by accidentally using the assignment operator: assigning your second argument’s value to your first argument. Since it’s a logic issue, it will always return true and won’t throw an error.
    if(var1 = var2){} // returns true. Assigns var2 to var1
  3. Javascript is loosely typed, except in switch statements. JavaScript is NOT loosely typed when it comes to case comparisons.
    var myVar = 5;
    if(myVar == '5'){ // returns true since Javascript is loosely typed
      alert("hi");  //this alert will show since JS doesn't usually care about data type.
    }
    switch(myVar){
      case '5':
      alert("hi"); // this alert will not show since the data types don't match
    }
Line Breaks
  • Beware of hard line breaks in JavaScript. Line breaks are interpreted as line-ending semicolons. Even in a string,if you include a hard line break in between quotes you’ll get a parse error (unterminated string).
        var bad  = '<ul id="myId">
                       <li>some text</li>
                       <li>more text</li>
                    </ul>'; // unterminated string error
    
        var good = '<ul id="myId">' +<li>some text</li>‘ +
                       ‘<li>more text</li>‘ +
                   ‘</ul>’; //correct
  • The line break being interpreted as a semi-colon rule, discussed above, does not hold true in the case of control structures: line breaks after the closing parenthesis of a conditional statement is NOT given a semi-colon.

Always use semi-colons and parenthesis so you don’t get tripped up by breaking lines, so your code is easier to read, and, less thought of but a source of quirks for those who don’t use semicolons: so when you move code around and end up with two statements on one line, you don’t have to worry that your first statement is correctly closed.

Extra commas
The last property in any JavaScript object definition must never end with a comma. Firefox won’t barf on the trailing, unnecessary commas, but IE will.

HTML id conflicts
The JavaScript DOM bindings allow indexing by HTML id. Functions and properties share the same namespace in JavaScript. So, when an id in your HTML has the same name as one of your functions or properties, you can get logic errors that are hard to track down. While this is more of a CSS best practice issue, it’s important to remember when you can’t solve your javascript issue.

var listitems = document.getElementsByTagName('li');

var liCount = listitems.length; // if you have <li id="length">, returns that <li> instead of a count.

If you’re marking up (X)HTML, never use a javascript method or property name as the value for an ID. And, when you’re coding the javascript, avoid giving variables names that are ID values in the (X)HTML.

variable scope
Many problems in javascript come from variable scope: either thinking that a local variable is global, or overwriting a global variable unwittingly with what should be a local variable in a function. To avoid issues, it’s best to basically not have any global variables. But, if you have a bunch, you should know the “gotchas”.

Variables that are not declared with the var keyword are global. Remember to declare variables with the var keyterm to keep variables from having global scope. In this example, a variable that is declared within a function has global scope because the var ke

anonymousFuntion1 = function(){
	globalvar = 'global scope'; // globally declared because "var" is missing.
	return localvar;
}();

alert(globalvar); // alerts 'global scope' because variable within the function is declared globally

anonymousFuntion2 = function(){
	var localvar = 'local scope'; //locally declared with "var"
	return localvar;
}();

alert(localvar); // error "localvar is not defined". there is no globally defined localvar

Variable names that are introduced as parameter names are local to the function. There is no conflict if your parameter name is also the name of a global variable as the parameter variable has local scope. If you want to change the global variable from within a function that has a parameter duplicating the global variable’s name, remember that global variables are properties of the window object.

var myscope = "global";

function showScope(myscope){
  return myscope; // local scope even though there is a global var with same name
}
alert(showScope('local'));

function globalScope(myscope){
  myscope = window.myscope; // global scope
  return myscope;
}
alert(globalScope(’local’));

You should even declare variables within loops

for(var i = 0; i < myarray.length; i++){}
string replace
A common mistake is assuming the behavior of the string replace method will impact all possible matches. Infact, the javascript string replace method only changes the first occurrence. To replace all occurrences, you need to set the global modifier.

  var myString = "this is my string";
  myString = myString.replace(/ /,"%20"); // "this%20is my string"
  myString = myString.replace(/ /g,”%20″); // “this%20is%20my%20string”
parseInt
The most common error with parding integers in javascript is the assumption that parseInt returns the integer to base 10. Don’t forget the second argument, the radix or base, which can be anything from 2 to 36. To ensure you don’t screw up, always include the second parameter.

parseInt('09/10/08'); //0parseInt('09/10/08',10); //9, which is most likely what you want from a date.
‘this’
Another common mistake is forgetting to use ‘this‘. Functions defined on a JavaScript object accessing properties on that JavaScript object and failing to use the ‘this’ reference identifier. For example, the following is incorrect:

function myFunction() {
  var myObject = {
     objProperty: "some text",
     objMethod: function() {
		alert(objProperty);
		}
     };
  myObject.objMethod();
} 

function myFunction() {
  var myObject = {
     objProperty: "some text",
     objMethod: function() {
		alert(this.objProperty);
		}
     };
  myObject.objMethod();
}

There’s an A List Apart article that puts this binding issue into plain English

Overwriting functions / overloading functions
When you declare a function more than once, the last declaration of that function will overwrite all previous version of that function throwing no errors or warnings. This is different from other programming languages, like java, where you can have multiple functions with the same name as long as they take different arguments: called function overloading. There is no overloading in javascript. This makes it vitally important to not use the names of core javascript functions in your code. Also, beware of including multiple javascript files, as an included script may overwrite a function in another script. Use anonymous functions and namespaces.

(function(){
	// creation of my namespace
    // if namespace doesn’t exist, create it.	if(!window.MYNAMESPACE) {		window['MYNAMESPACE'] = {}; 		}

    // this function only accessible within the anonymous function
    function myFunction(var1, var2){
		//local function code goes here
    }

    /* attaches the local function to the namespace
       making it accessible outside of the anoymous function with use of namespace */
    window['MYNAMESPACE']['myFunction'] = myFunction; 

 })();// the parenthesis = immediate execution	  // parenthesis encompassing all the code make the function anonymous
Missing Parameters
A common error is forgetting to update all the function calls when you add a parameter to a function. If you need to add a parameter to handle a special case call in your function that you’ve already been calling, set a default value for that parameter in your function, just in case you missed updating one of the calls in one of your scripts.

function addressFunction(address, city, state, country){
      country = country || “US”; // if country is not passed, assume USA
      //rest of code
    }

You can also get the length of the argument array. But we’re focusing on “gotchas” in this post.

For each

The “for” loop in javascript will iterate it over all object attributes, both methods and properties, looping thru all of the property names in an object. The enumeration will include all of the properties—including functions and prototype properties that you might not be interested in—so filter out the values you don’t want using hasOwnProperty method and typeof to exclude functions. Never use for each to iterate thru an array: only use for each when needing to iterated thru object properties and methods.

  • for each (var myVar in myObject) iterates a specified variable over all values of object’s properties.
  • for (var myVar in myObject) iterates a specified variable over all the properties of an object, in arbitrary order. The for...in loop does not iterate over built-in properties. For each distinct property the code is executed
  • for (var 1=0; i < myArray.length; i++) iterates thru all the elements of an array.

To fix the problem, generally you’ll want to opt for for ... in for objects and use the for loop for arrays:

listItems = document.getElementsByTagName('li');

for each (var listitem in listItems){
    // this goes thru all the properties and methods of the object,
    // including native methods and properties, but doesn't go thru the array: throws error!
   }

//since you have an array of objects that you are looping thru, use the for loop
for ( var i = 0; i < listItems.length; i++) {
    // this is what you really wanted
   }
Switch statements
I wrote a whole blog post on switch statement quirks, but the gist is:

  • there is no data type conversion
  • once there is a match, all expressions will be executed until the next break or return statement is executed, and
  • you can include multiple cases for a single block of code
Undefined ≠ null
Null is for an object, undefined is for a property, method or variable. To be null, your object has to be defined. If your object is not defined, and you test to see whether it’s null, since it’s not defined, it can’t test, and will throw an error.

if(myObject !== null  && typeof(myObject) !== 'undefined') {
	//if myObject is undefined, it can't test for null, and will throw an error
}

if(typeof(myObject) !== 'undefined' && myObject !== null) {
	//code handling myObject
}

Harish Mallipeddi has an explanation of undefined versus null

dt {font-weight:bold; font-size:116%;}

 
 

CSS Hack for Google Chrome and Safari 4 September 2, 2008

Filed under: Best Practices, CSS (including hacks), Web Development — Estelle Weyl @ 9:29 pm

Valid CSS filter targeting Google Chrome and Safari 4

To target only webkit, which includes Google and Safari, encompass all the CSS that you want to use just to target Webkit in the following @media block:

@media screen and (-webkit-min-device-pixel-ratio:0) {
.myClass { background-color: #FF0000; }
#myId {color: #0000FF;}
p, a, li {text-shadow: 3px 3px 3px rgba(0, 0, 0, 0.4);
}

The rest of this post is outdated.


NOTE: WHAT IS BELOW IS OLD, AND NOW TARGETS Opera, Firefox, Safari and Chrome.

NOTE: This was written in 2008 for Safari 3.1 and the original release of Chrome. This is NO LONGER VALID as a filter, since, like all forward thinking filters, it now targets all the modern browsers that support CSS3 Selectors.

Non-compliant selectors can be used and a valid way to target individual browsers. Chrome supports every selector, just like Safari 3.1. My recommendation is to use the body:first-of-type hack, the CSS hack/filter for Safari as a filter for Safari 3+ and Chrome. There should be no reason to target Chrome with the exclusion of Safari 3.1, but if you want to target both, filtering out Safari 3.0, I would try using:

body:nth-of-type(1) p{
   color: #333333;
}

Only the Google Chrome and Safari 3.1 browsers will show paragraphs as grey. The logic is:

  • web pages only have one body element
  • only those two browsers support the pseudo-class of :nth-of-type()
  • body:nth-of-type(1) will match the first, and only, body element.

Use it as a predecessor to more specific selectors targeting the body’s children.

Note: as more browsers become more standards compliant, they will understand this code as well. IE6, IE7, IE8 will never understand it. Newer versions of Safari, Chrome and Firefox will.

 
 

Yet Another Image Replacement Method September 19, 2007

Filed under: Best Practices, CSS (including hacks), Web Development — Estelle Weyl @ 9:39 pm

Semantic CSS Image Replacement

Yes, "YAIRM" ("Yet Another Image Replacement Method") is a crappy acronym. Anyhow….

There have been several image replacement suggestions made over the past 5 years. Semantically, some just don’t make sense. Of course, the accessibility of your image replacement method and the semantic "correctness" has to do with how you code your HTML.

Pros

  • This method works for both in-line and block style elements.
  • Accessible to screen readers and non-image/non-screen media.
  • Does not add extra elements only for styling (no extra span).
  • Works cross browser

Cons

  • Using images for text does not allow for text resizing (like all IR methods).
  • Does not handle "images off/CSS on" scenario; but neither do most layouts with background images, such as the sidebar on this blog.

When I need to replace a header or some other text with an image, I simply give the element my image replacement class (<h1 class="imgreplacement">), and declare the background image, height and width I want to use either by providing an ID and defining the background image in the #id selector, or by targeting the element through specific/unique cascade. I place all of my image replacement css in a media="screen". Even though the media attribute is not heeded by all browsers, it is heeded by devices that are not screens. If your user than prints your webpage, the text that was replaced by an image in the browser will print as it semantically should.

The CSS for the Image Replacement class:

.imgreplacement {
  display:-moz-inline-box;
  display:inline-block;
  background:transparent none 0 0 no-repeat;
  text-indent:-3000px;
  font:0/0 Arial;
  overflow:hidden;
  color:rgba(255,255,255,0);
  vertical-align:bottom;
}

XHTML markup and CSS Overrides:

With my image replacement class, the image replacement method is reusable.

<h1 class="imgreplacment" title="Tool Tip Text here">Semantic Text</h1>
<a href="link.html" class="imgreplacement">Text that makes sense for this link</a>
<button class="imgreplacement" title="Close">Close Module</button>

h1.imgreplacement {
  background-image: url(path/headerimage.jpg);
  height: 60px;
  width: 540px;
	 background-position: 20px 10px;
}

a.imgreplacement {
  background-image: url(path/linkimage.jpg);
  width: 120px;
  height: 60px;
}

button {
  background-image:url(images/redx.gif);
  width: 18px;
  height: 18px;
  border: none; // overwrite default border
  cursor: pointer;
}

This is the button: . Note that is has layout, but it’s inline, and it has a tool-tip

Explanation of the Image Replacement Class:

The imgreplacement class does the following:

  • display:-moz-inline-box;
    and display:inline-block; displays the element as an inline block. inline-block is not part of the CSS specifications, but it is supported by IE and all other grade-A browsers other than Firefox. This enables the image replacement to work on inline elements by enabling them to have width and height. The first line, -moz-inline-box, is for mozilla based browsers that don’t render inline-block. The second line is for IE, Safari 3 and Opera, though IE does not render inline-block truly inline.
  • background: transparent none 0 0 no-repeat; sets a default to non-repeated background image placed at the top-left of the element block, but does not declare a background image, enabling you to overwrite the none with an image via a second, more precise, CSS declaration
  • text-indent:-3000px; Text indent only applies to block elements. text-indent, when implemented, moves the start of the first line of text to the left or right depending on whether the property is assigned a negative or positive value. The text-indent is applied to inline-block elements, but not to -moz-inline-box. Note that IE does not render text-indent correctly, so generally I override the text-indent property for IE, but in this case the disappearing text quirk is to our benefit.
  • font:0/0 Arial; Makes the font tiny or invisible for browsers. There are a few quirks: Opera doesn’t render this shorthand, and renders font-size: 0; at about 7px; IE6 and IE7 both render the font at about 1px and Safari doesn’t render font at size 0, but does intermittently underline the non-visible character at about 1px width per character.
  • overflow:hidden hides anything that might be wider than the space provided. IE6 has the bad habit of deciding to grow elements to fit the content even if the size of the element is defined.
  • color:rgba(255,255,255,0); Makes the font color transparent (opacity of 0) for those browsers that understand opacity via RGBA, which is a feature of CSS3 (Safari 3 and pre-alpha version of Firefox 3, but not IE6, IE7 or Firefox 2 for Windows).
  • vertical-align:bottom; is required for the inline elements - it places them at the same level vertically with respect to the text around it across all grade-A browsers.

Additional tidbits

  • You have to define the width, height and background image of your element.
  • If needed, you can set the background position of the replacement image. It causes fewer cross browser issues to place the background image rather than setting margins due to differences in browsers interpretations of the box-model.
  • Remember to use sematic markup. If the image is an area header, use h1-h6. If it’s a link going somewhere, use <a>. If it isn’t linking anywhere, it’s not a link!
  • You can enhance the image replacement with a title. The title will display in some browsers as a tool tip. This may enhance the accessibility for those who use tooltips regularly.
  • You can declare a different background image using the :hover pseudoclass, so when the user hovers over the element with the mouse pointer, the image changes.

While I just showed you a method of doing image replacement, I must caution against it. Using images for text is not optimum for accessibility. This method enables assistive devices to read your text with the semantic meaning defined by the encompassing element(s). This method enables users of alternative devices, such as cell phones, and text-only browsers to read your content. It also meets web standards in terms of separating content from presentation. However, when you use images to render text, your visitor is unable to control the font-size; which makes your site less than accessible. If you are required to use images instead of text to render content, and you can’t convince your client (boss, designer or contractee, or even yourself) of the stupidity (there, i said it) of using images for text, then this is the best method of making your inaccessible page accessible to the most people. Just try to make the text in your image large enough to be read by a user.

 
 

Favicons: why and how to create favicons September 3, 2007

Filed under: Best Practices, Cursors & Icons, SEO, Web Development — Estelle Weyl @ 9:35 pm

The "WHY" of Favicons

Favicons ARE an integral part of your website and branding.

Favicons are the single most important graphic appearing on a website. While that sounds like a strong statement, it’s true. Favicons are the least expensive and most overlooked visual branding opportunity.

Favicons are the 16 x 16 pixel images that show up in the navigation bar of your browser. They also appear in browser’s bookmark/favorites menu. You might think, "big whoop! that’s not vital." But those aren’t the only places they appear.

They also appear at the bottom of my blog: not my favicon, but the favicon for stumbleupon, digg, technorati, del.icio.us, etc. Web developers and copy editors don’t even need to use the names of those online brands: everyone recognizes these networking favicons.

They now also appear next to the page title on the tabs in tabbed browsers: if a user has 25 browser tabs, each tab may be as narrow as just the favicon: would you prefer your visitors see Internet Explorer’s blue E, Safari’s blue compass, an icon of a page (Firefox and Opera), or would you prefer that they see your logo? If they see a logo, they recognize immediately what site is opened in each tab: you want to be one of those recognized pages.

Are you looking at your open browser tabs? Can you tell which pages are which? Have you checked your bookmarks list? Are there some bookmarks that stand out more than others? Have you looked at the bottom of this blog entry? Depending on how many toolbars you have downloaded and have open, you may have a plethora of favicons there too. So, have I convinced you?

The "HOW" of Favicons: How to design & create a FavIcon:

Designing a Favicon:

  • If you have a logo that easily translates into something that looks decent at 32 x 32 or 16 x 16, use it.
  • If you can avoid using the color blue, especially the glassy shiny blue of IE, avoid using it.
  • Keep it simple. Yahoo uses a Y!, Google uses a G. Flickr uses two little circles. Delicious is a square made of 4 squares. IE is an E. These are all ones you know.
  • If your logo is very complex, try using just a part of it such as the first letter. If your first letter doesn’t represent your company well enough (like in the case of this blog), use your logo color to abstract an image.

Creating a FavIcon: Converting an image to a .ico

  • Following the suggestions above, create a 48×48 or a 32 x 32 image that you will use as your favicon. Save it.
  • If you have photoshop, you can download a Favicon extension for Photoshop. If you don’t have photoshop, or don’t want to deal with extensions, you can visit Dynamic Drive and use their tool to convert your .jpg, .png or .gif into a .ico file. The file created will be called favicon.ico. You will be directed to download it.
  • Upload the .ico file to the root directory of your website.
  • If your favicon is named favicon.ico, then you don’t need to add code. However, if you don’t have the .ico file in your top level directory, or if you saved it under a different file name, or if you have different favicons for different parts of your site (not usually a good idea, but Yahoo has different icons for some of their properties, such as Yahoo! answers), then include the following in the header:
     

    <link rel="shortcut icon" href="http://www.mysite.com/myicon.ico" type="image/x-icon" />

Uses of Favicons

Now your favicon can appear all across the web: