Wednesday, September 26, 2012

HTML Email Tips

Recently I start to work on HTML Email template which needs to support popular email clients like gmail, hotmail, yahoo mail, Apple Mail, MS outlook etc. I thought it was easy to build HTML email template (based on what we have on web page), however I was wrong when the first version was out and showed up in web email client. Using Chrome developer tool to investigate the root cause, I realized that writing HTML email is totally different from Web page. Simply converting web site HTML/CSS codes to HTML email will not work as desired for these different email clients.

I did 3 versions and referenced to many useful online resources, then got the HTML email template kind of work across email clients. During the development and test, I summarized the tips to create HTML emails. It is interesting to work on this area, though the technical is not savvy.

Layout:
Use Table instead of Div
Table width should be 550-600px
Specify table and cell width
Avoid using CSS margin, use CSS padding or spacer.gif
Images and other HTML elements should reside in table cell
Specify desired alignment
Specify colspans and rowspans
Don't nest table too deep
Use <br> instead of <p> if possible

Styling:
Inline CSS to each HTML element
Limited CSS support (use CSS to format content, but don’t rely on it for layout)
Put style in the BODY of the email, not in the HEAD
Add proper nested closing tag for each element

A list of inline styles that are pretty well supported:
background-color
border
padding
color
font
font-* (e.g. font-family, font-style, font-size, font-weight font-variant etc.)
letter-spacing
line-height
table-layout
text-* (e.g. text-align, text-decoration, text-indent, text-transform)
border-collapse

Image:
Add style=”display:block” in the image tag
Always give images absolute paths
Always use ALT tags
Always provide size attributes for images.

Content:
Absolute no javscript
No video, flash (use annimated gif if really needed)
No forms (Use link instead)
No background-image, use HTML background attribute
Don't only use images (most email client doesn't show images by default)
Use HTML character escape sequences, such as &reg; for ®

Convention (Recommendation):
View it in browser link
Subscribe and opt out
Track your email
Consider mobile version

References:
http://premailer.dialect.ca/
http://htmlemailboilerplate.com/
https://github.com/mailchimp/Email-Blueprints/tree/master/templates
http://www.campaignmonitor.com/css/
http://www.campaignmonitor.com/testing/


Tuesday, September 25, 2012

Audio and Video in Modern Browsers

For detailed HTML5 audio and video introduction, check out http://html5doctor.com

Currently when I look at these 2 tags support status in modern Web browsers, I have to say <audio> and <video> are not fully supported. The reason is different browsers have different media format support in these 2 new HTML5 elements. In project, developers unusually use audio or video libraries to do the heavy lifting stuff, default to use HTML5 media elements, and fallback to Flash or Siliverlight for non-supported media formats.

I checked caniuse.com and html5-audio-the-state-of-play, then summarized the state-of-media support status in most frequent used web browsers. As of today, the latest Chrome is 22.0.1229.79, latest Firefox is 15.0.1, latest Safari is 6.0, iOS Safari 6.0, latest Opera is 12.02.


Sunday, September 16, 2012

jQuery TreeView Plugin

jQueryUI 1.9 beta release added 3 new widgets (Menu, Tooltip, and Spinner) but still no tree view widget in picture though jQueryUI has the plan http://wiki.jqueryui.com/w/page/12138128/Tree. In the plan wiki page, it recommends 2 plugins:

http://www.jstree.com/
http://bassistance.de/jquery-plugins/jquery-plugin-treeview/

I once tried jquery.dynatree.js which supports checkbox and lazy loading of tree branches. In current project, once again there is tree view requirement (ajax/JSON, checkbox tree, optional sorting, optional lazy load tree branches), so it is better to list out some researched plugins for future reference. (I do hope jQueryUI can support tree widget soon).

jsTree (many features, and plugin friendly to support more functionality like checkbox plugin, JSON data plugin etc)

jQuery plugin: Treeview (not maintained any more, recommend jsTree and look forward to jQueryUI support of tree view)

jquery.dynatree.js (basically meet the tree view requirements my project wants, but not as famous as jsTree, and not actively developed)

jQuery File Tree (configurable, ajax file browser plugin for jQuery)

jQuery TreeView Menu (brings together all the most practical features requested in a Tree Menu into one awesome menu script)

jQuery Tree (jQuery UI widget that you can use to add advanced features to an html tree built using nested unordered lists, derived from jQuery checkboxtree plugin)

jQTreeTable (for tree table UI display)

I will compare jsTree and Dynatree to see which one is better for current project.

Wednesday, September 12, 2012

postMessage Sample Codes

Cross-document messaging has 2 parts: sender and receivers. Sender can be parent window or child window,  and reciever can be child window and parent window. (sibling windows should also work, for browser tab or windows, need further research.) Here we only talk about the main window includes one iframe case for cross-document (cross-domain) messaging.

Sender (main window):
    var win = document.getElementById("iframe").contentWindow;
    win.postMessage(
            'the-sample-message',
            "http://www.target-origin.com"
    );


Sender (iframe window):
    parent.postMessage(msg, 'http://www.target-origin');

Receiver (onmessage event):
    window.onmessage = function(e){
        if ( e.origin !== "http://www.origin.com" ) {
            return;
        }
        // parse and validate e.data

        // processing e.data
    };

Receiver (customized event handler):
     var handleMessage = function(e) {
         if ( e.origin !== "http://www.origin.com" ) {
            return;
         }     

        // parse and validate e.data
        // processing e.data
    };

    if (typeof window.addEventListener != 'undefined') {
        window.addEventListener('message', handleMessage, false);
    } else if (typeof window.attachEvent != 'undefined') {
        window.attachEvent('onmessage', handleMessage);
    }


References
http://www.w3.org/TR/webmessaging/#web-messaging
https://developer.mozilla.org/en-US/docs/DOM/window.postMessage
http://html5demos.com/postmessage2

addEvent utility function (from html5demos.com, good for reference)
var addEvent = (function () {
if (document.addEventListener) {
return function (el, type, fn) {
if (el && el.nodeName || el === window) {
el.addEventListener(type, fn, false);
} else if (el && el.length) {
for (var i = 0; i < el.length; i++) {
addEvent(el[i], type, fn);
}
}
};
} else {
return function (el, type, fn) {
if (el && el.nodeName || el === window) {
el.attachEvent('on' + type, function () { return fn.call(el, window.event); });
} else if (el && el.length) {
for (var i = 0; i < el.length; i++) {
addEvent(el[i], type, fn);
}
}
};
}
})();



Nginx Configuration for WPO

Two key configurations for Web performance optimization (WPO). In the future, we will look at how to tune TCP stack on nginx for better performance.

Turn on Gzip for text files
    gzip  on;
    gzip_comp_level 5;
    gzip_min_length  1000;
    gzip_types application/json text/css application/x-javascript text/javascript;

text/html is always compressed.

Add Expires header to static files
    location / {
        if ($request_uri ~* \.(ico|css|js|gif|jpe?g|png)$) {
                        expires 72h;
                        break;
        }
    }

    # This block will catch static file requests, such as images, css, js
    # The ?: prefix is a 'non-capturing' mark, meaning we do not require
    # the pattern to be captured into $1 which should help improve performance
    location ~* \.(?:ico|css|js|gif|jpe?g|png)$ {
        # Some basic cache-control for static files to be sent to the browser
        expires max;
        add_header Pragma public;
        add_header Cache-Control "public, must-revalidate, proxy-revalidate";
    }

    location ~* \.(ico|css|js|gif|jpe?g|png)(\?[0-9]+)?$ {
        expires max;
        break;
    }

Tuesday, September 11, 2012

iframe Communication

iFrame is used on web page to mashup content from same or different domains, same domain looks straightforward, but same-origin-policy prevents direct communication between iframe(s) or parent window if the origins are different.

Same domain:

1. child iframe calls parent window JS function:
window.parent.functionName()

2. parent window calls iframe JS function:
document.getElementById('frameName').contentWindow.functionName()
Other alternatives for above JS code 
window.frames['frameName'].contentWindow.functionName();

var el = document.getElementById('frameName');
if(el.contentWindow) {
    el.contentWindow.functionName();
}
else if(el.contentDocument) {
    //el.contentDocument.functionName();
    el.contentDocument.defaultView.functionName();
}


Cross domain:
HTML5 Web Messaging http://dev.w3.org/html5/postmsg/#web-messaging defines cross document messaging to address this issue, and as of writing, it is supported in most browsers (except for IE7 and below) for iFrame-to-parent-window communication (IE has not implemented cross window/tab messaging yet). The standard API is window.postMessage(message, targetOrigin [,transfer]).

However if we need support old browsers for cross domain messaging, we need look at other hacks or solutions.
  1. Hashchange of iframe or parent window. For instance, parent window change iframe window's fragment (hashchange), and iframe polling the change (or onhashchange event) to get passed fragment identifier
  2. hidden proxy iframe, hashchange based
  3. hidden proxy iframe, resize event based (see https://github.com/ternarylabs/porthole/)
  4. Flash (some library uses flash fallback)
Libraries using postMessage with fallbacks
Client to server cross domain:
  1. proxy server
  2. JSONP
  3. CORS (Cross origin resource sharing)
Reference
http://softwareas.com/cross-domain-communication-with-iframes
http://stackoverflow.com/questions/6309674/wrapping-postmessage-in-jquery