Gone In 60 Frames Per Second: A Pinterest Paint Performance Case Study

Gone In 60 Frames Per Second: A Pinterest Paint Performance Case Study

Today we’ll discuss how to improve the paint performance of your websites and Web apps. This is an area that we Web developers have only recently started looking at more closely, and it’s important because it could have an impact on your user engagement and user experience.

Nice summary on Smashing Magazine!

Accessing XML attribute named “type” using jQuery.attr() broken on IE 7

I ran into an issue with jQuery 1.10.1 on IE 7. Accessing the XML attribute named “type” with $.attr( “type” ) throws an error in the new function interpolationHandler(); Here’s a little test HTML document:

<!DOCTYPE html><html><head></head><body>
 
<!--jQuery 1.10.1 in IE 7 throws SCRIPT450 (wrong number of arguments) error in function interpolationHandler(){}-->
<script src="http://code.jquery.com/jquery-1.10.1.js"></script>
 
<script type="text/javascript">
 
    var xmlString = '<list><item type="type-a" other="other-a"/><item type="type-b" other="other-b"/></list>';
    var xml = $.parseXML( xmlString );
 
    $( xml).find( "item" ).each( function() {
 
        // Always works
        var otherValue = $(this).attr( "other" );
        alert( otherValue );
 
        // jQuery 1.10.1 in IE 7 throws SCRIPT450 (wrong number of arguments) error in function interpolationHandler(){}
        var typeValue = $(this).attr( "type" );
        alert( typeValue );
 
    });
 
</script></body></html>

Bug report on jQuery bug tracker: http://bugs.jquery.com/ticket/13974

USING JQUERY 1.9.1 WORKS JUST FINE!

Avoid iFrame content clipping with CSS transform on iOS

The HTML(5) version of our SCORM based e-learning runtime heavily uses i-frames as template containers. This architecture gives a lot of flexibility but since customers mainly request iPad support we where very unhappy with Safari’s rendering capabilities on iOS. Of course we use CSS transform to get the best animation performance on mobile devices, but in Apple’s mobile browser you’ll likely see huge clipping rectangles during hardware accelerated transitions.

There was not much information about that issue online but at least this entry on stackoverflow suggested there is not much you can do. Well, it took a lot of trail an error testing time but finally we nailed it. The solution is quite simple:

Whenever you use CSS transform with i-frames or it’s parents you also need to apply a basic CSS transform to the body tag of your i-frame content. That’s it. You can also use other contents within the loaded frame HTML page but the body tag seems to be the perfect target.

So this is a little JavaScript code snipped:

// Reference to your iFrame HTML element
var iFrameElement = document.getElementById( "yourIFrameID" );
 
// Avoid clipping by applying simple css transfrom3D to the iframe content itself
$( iFrameElement.contentWindow.document.body ).css( "-webkit-transform", "translate3d(0,0,0)" );
 
// Start your iFrame transition (from a visible position)
$( iFrameElement ).css( "-webkit-transform", "translate3d(-1000px,0,0)" );

UPDATE: Make sure you start from a visible position!

Don’t forget to remove CSS transform after your animation is done:

// Don't forget to reset after your transition has finished!
$( iFrameElement.contentWindow.document.body ).css( "-webkit-transform", "none" );

I suggest to use “none” as the default value. We sometimes experienced weird behavior using an empty string…

Have fun coding!

Removing comments in CSS, HTML and ECMAScript (JavaScript)

While working on an Adobe AIR based source code editor I was looking for an easy way to remove comments from different kind of source codes. What first seemed like an easy regular expression turned out to be much more complex because comment pre- and suffixes can also occur in string literals or regular expressions and our old friend Internet Explorer allows HTML conditional comments and JavaScript conditional compilation. Great.

First I had a look at YUICompressors source code and Google Page Speed but then I decided to port a script for removing JavaScript comments created by James Padolsey.

I just improved the recognition for regular expressions a little and since this code should work with all ECMAScript based source codes I named my class ECMAScriptParser instead of JavaScriptParser:

package de.superclass.parser
{
	/**
	 * @author Markus Raab (superclass.de | blog.derRaab.com)
	 */
	public class ECMAScriptParser
	{
		/**
		 * Removes inline and block comments from an ECMAScript source string. 
		 * 
		 * This is a port of James Padolsey	 with an slightly improved RegExp recognition.
		 * @see: http://james.padolsey.com/javascript/removing-comments-in-javascript
		 * 
		 * @param ecmaScript		ECMAScript source string
		 * @param removeCondComp	Optional (default=false) - Whether to remove Internet Explorers JavasScript conditional compilation comments or not.   
		 * @return					ECMAScript source string without comments
		 */
		public static function removeComments( ecmaScript : String, removeCondComp : Boolean = false ) : String
		{
			var modeSingleQuote		: Boolean = false;
			var modeDoubleQuote		: Boolean = false;
			var modeRegExp			: Boolean = false;
			var modeBlockComment	: Boolean = false;
			var modeLineComment		: Boolean = false;
			var modeCondComp		: Boolean = false; 
 
			var vector : Vector.<String> = Vector.<String>( ( '__' + ecmaScript + '__' ).split( '' ) );
				vector.fixed = true;
 
			var c : int = vector.length;
 
			for ( var i : int = 0; i < c; i++ )
			{
				var string : String = vector[ i ];
 
				if ( modeRegExp )
				{
					if ( string === '/' && vector[ i - 1 ] !== '\\' )
					{
						modeRegExp = false;
					}
					continue;
				}
 
				if ( modeSingleQuote )
				{
					if ( string === "'" && vector[ i - 1 ] !== '\\' )
					{
						modeSingleQuote = false;
					}
					continue;
				}
 
				if ( modeDoubleQuote )
				{
					if ( string === '"' && vector[ i - 1 ] !== '\\' )
					{
						modeDoubleQuote = false;
					}
					continue;
				}
 
				if ( modeBlockComment )
				{
					if ( string === '*' && vector[ i + 1 ] === '/' )
					{
						vector[ i + 1 ] = '';
						modeBlockComment = false;
					}
					vector[ i ] = '';
					continue;
				}
 
				if ( modeLineComment)
				{
					string = vector[ i + 1 ];
					if ( string === '\n' || string === '\r' )
					{
						modeLineComment = false;
					}
					vector[ i ] = '';
					continue;
				}
 
				if ( modeCondComp )
				{
					if ( vector[ i - 2 ] === '@' && vector[ i - 1 ] === '*' && string === '/' )
					{
						modeCondComp = false;
					}
					continue;
				}
 
				if ( string === '"' )
				{
					modeDoubleQuote = true;
					continue;
				}
 
				if ( string === "'" )
				{
					modeSingleQuote = true;
					continue;
				}
 
				if ( string === '/' )
				{
					if ( ! removeCondComp && vector[ i + 1 ] === '*' && vector[ i + 2 ] === '@' )
					{
						modeCondComp = true;
						continue;
					}
 
					if ( vector[ i + 1 ] === '*' )
					{
						vector[ i ] = '';
 
						modeBlockComment = true;
						continue;
					}
 
					if ( vector[ i + 1 ] === '/' )
					{
						vector[ i ] = '';
						modeLineComment = true;
						continue;
					}
 
					for ( var k : int = i - 1; true; k-- )
					{
						string = vector[ k ];
						if ( string !== ' ' )
						{
							if ( string === '=' )
							{
								modeRegExp = true;
							}
							break;
						}
					}
				}
			}
			return vector.join( '' ).slice( 2, -2 );
		}
	}
}

Allright – CSS doesn’t allow inline or conditional comments so I removed this script functionality and created a CSSParser class:

package de.superclass.parser
{
	/**
	 * @author Markus Raab (superclass.de | blog.derRaab.com)
	 */
	public class CSSParser
	{
		/**
		 * Removes comments from a CSS string. 
		 * 
		 * This is a shrinked port of James Padolseys script.
		 * @see: http://james.padolsey.com/javascript/removing-comments-in-javascript
		 * 
		 * @param css				CSS string
		 * @return					CSS string without comments
		 */
		public static function removeComments( css : String) : String
		{
			var modeSingleQuote		: Boolean = false;
			var modeDoubleQuote		: Boolean = false;
			var modeBlockComment	: Boolean = false;
 
			var vector : Vector.<String> = Vector.<String>( ( '__' + css + '__' ).split( '' ) );
				vector.fixed = true;
 
			var c : int = vector.length;
 
			for ( var i : int = 0; i < c; i++ )
			{
				var string : String = vector[ i ];
 
				if ( modeSingleQuote )
				{
					if ( string === "'" && vector[ i - 1 ] !== '\\' )
					{
						modeSingleQuote = false;
					}
					continue;
				}
 
				if ( modeDoubleQuote )
				{
					if ( string === '"' && vector[ i - 1 ] !== '\\' )
					{
						modeDoubleQuote = false;
					}
					continue;
				}
 
				if ( modeBlockComment )
				{
					if ( string === '*' && vector[ i + 1 ] === '/' )
					{
						vector[ i + 1 ] = '';
						modeBlockComment = false;
					}
					vector[ i ] = '';
					continue;
				}
 
				if ( string === '"' )
				{
					modeDoubleQuote = true;
					continue;
				}
 
				if ( string === "'" )
				{
					modeSingleQuote = true;
					continue;
				}
 
				if ( string === '/' )
				{
					if ( vector[ i + 1 ] === '*' )
					{
						vector[ i ] = '';
 
						modeBlockComment = true;
						continue;
					}
				}
			}
			return vector.join( '' ).slice( 2, -2 );
		}
	}
}

Good. Lastly I extended the code to remove all comments within HTML source code, which can also contain JavaScript and of course CSS. This is the HTMLParser:

package de.superclass.parser
{
	/**
	 * @author Markus Raab (superclass.de | blog.derRaab.com)
	 */
	public class HTMLParser
	{
		/**
		 * Removes all HTML, CSS and ECMAScript comments from a HTML string.
		 * 
		 * This is an extended port of James Padolseys script with an improved RegExp recognition.
		 * @see: http://james.padolsey.com/javascript/removing-comments-in-javascript
		 * 
		 * @param html						HTML string
		 * @param removeHTMLCondComment		Optional (default=false) - Whether to remove Internet Explorers HTML conditional comments or not.
		 * @param removeJSCondComp			Optional (default=false) - Whether to remove Internet Explorers JavasScript conditional compilation comments or not.
		 * @return							HTML string without comments
		 */
		public static function removeComments( html : String, removeHTMLCondComment : Boolean = false, removeJSCondComp : Boolean = false ) : String
		{
			var modeSingleQuote		: Boolean = false;
			var modeDoubleQuote		: Boolean = false;
			var modeRegExp			: Boolean = false;
			var modeBlockComment	: Boolean = false;
			var modeLineComment		: Boolean = false;
 
			var modeJSCondComp		: Boolean = false;
 
			var modeHTMLComment		: Boolean = false;
			var modeHTMLCondComment	: Boolean = false;
 
			var vector : Vector.<String> = Vector.<String>( ( '__' + html + '__' ).split( '' ) );
				vector.fixed = true;
 
			var c : int = vector.length;
 
			for ( var i : int = 0; i < c; i++ )
			{
				var string : String = vector[ i ];
 
				if ( modeRegExp )
				{
					if ( string === '/' && vector[ i - 1 ] !== '\\' )
					{
						modeRegExp = false;
					}
					continue;
				}
 
				if ( modeSingleQuote )
				{
					if ( string === "'" && vector[ i - 1 ] !== '\\' )
					{
						modeSingleQuote = false;
					}
					continue;
				}
 
				if ( modeDoubleQuote )
				{
					if ( string === '"' && vector[ i - 1 ] !== '\\')
					{
						modeDoubleQuote = false;
					}
					continue;
				}
 
				if ( modeBlockComment )
				{
					if ( string === '*' && vector[ i + 1 ] === '/')
					{
						vector[ i + 1 ] = '';
						modeBlockComment = false;
					}
					vector[ i ] = '';
					continue;
				}
 
				if ( modeLineComment)
				{
					string = vector[ i + 1 ];
					if ( string === '\n' || string === '\r' )
					{
						modeLineComment = false;
					}
					vector[ i ] = '';
					continue;
				}
 
				if ( modeJSCondComp )
				{
					if ( vector[ i - 2 ] === '@' && vector[ i - 1 ] === '*' && string === '/' )
					{
						modeJSCondComp = false;
					}
					continue;
				}
 
				if ( modeHTMLComment )
				{
					// --> 
					if ( string === '-' && vector[ i + 1 ] === '-' && vector[ i + 2 ] === '>' )
					{
						vector[ i + 1 ] = '';
						vector[ i + 2 ] = '';
 
						modeHTMLComment = false;
					}
					vector[ i ] = '';
					continue;
				}
 
				if ( modeHTMLCondComment )
				{
					if ( string === 'i' && vector[ i + 1 ] === 'f' && vector[ i + 2 ] === ']' && vector[ i + 3 ] === '-' && vector[ i + 4 ] === '-' && vector[ i + 5 ] === '>' ) // if]--> 
					{
						modeHTMLCondComment = false;
						i += 5;
					}
					continue;
				}
 
				if ( string === '<' && vector[ i + 1 ] === '!' && vector[ i + 2 ] === '-' && vector[ i + 3 ] === '-' ) // <!--
				{
					if ( ! removeHTMLCondComment && vector[ i + 4 ] === '[' && vector[ i + 5 ] === 'i' && vector[ i + 6 ] === 'f' ) // <!--[if
					{
						modeHTMLCondComment = true;
					}
					else
					{
						vector[ i ] = '';
						modeHTMLComment = true;
					}
				}
 
				if ( string === '"' )
				{
					modeDoubleQuote = true;
					continue;
				}
 
				if ( string === "'" )
				{
					modeSingleQuote = true;
					continue;
				}
 
				if ( string === '/' )
				{
					if ( ! removeJSCondComp && vector[ i + 1 ] === '*' && vector[ i + 2 ] === '@' )
					{
						modeJSCondComp = true;
						continue;
					}
 
					if ( vector[ i + 1 ] === '*' )
					{
						vector[ i ] = '';
 
						modeBlockComment = true;
						continue;
					}
 
					if ( vector[ i + 1 ] === '/' )
					{
						vector[ i ] = '';
						modeLineComment = true;
						continue;
					}
 
					for ( var k : int = i - 1; true; k-- )
					{
						string = vector[ k ];
						if ( string !== ' ' )
						{
							if ( string === '=' )
							{
								modeRegExp = true;
							}
							break;
						}
					}
				}
			}
			return vector.join( '' ).slice( 2, -2 );
		}
	}
}

Let me know if I made a mistake but it seems to work quite well. Or do you know a good library that already does this kind of optimizations?

Well, that’s it for now. Have fun coding!