<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-2050944435781034945</id><updated>2024-11-08T07:16:31.133-08:00</updated><title type='text'>Cross browser css &amp;amp; javascript</title><subtitle type='html'>Some ideas concerning crossbrowser javascript and css.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://crossbrowser.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2050944435781034945/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://crossbrowser.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>9</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2050944435781034945.post-3445106927648364449</id><published>2010-04-10T00:44:00.000-07:00</published><updated>2010-04-10T00:44:38.532-07:00</updated><title type='text'>Minimizing external javascript requests down to zero.</title><content type='html'>So, the less requests the better right?&lt;br /&gt;
Here is an idea for efficiency freaks to bring amount of requests to external javascript files down to none. Here is how.&lt;br /&gt;
&lt;br /&gt;
1. In your external css file define element: &lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;#javascript { font-family: &quot;alert(&#39;hello world&#39;)&quot;; }
&lt;/pre&gt;&lt;br /&gt;
2. Now in your html page define element with id=&quot;javascript&quot;&lt;br /&gt;
3. On window load run this (jquery example):&lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;   $(function() {
       var sJs = $(&#39;#javascript&#39;).css(&#39;font-family&#39;);
       // here you might need to trim the double quotes off the ends of the sJs
       eval(sJs);
   });
&lt;/pre&gt;&lt;br /&gt;
I have not checked as to the amount of javascript you can stuff into css attribute. It is probable that you could insert your entire minified js file into it. Please post a comment if you get any results, just curious.&lt;br /&gt;
&lt;br /&gt;
Another difficulty with this approach is that you would need to find a way to escape double quotes in your javascript before inserting it into css.&lt;br /&gt;
&lt;br /&gt;
Other than that, it is pretty decent approach: your css loads in the header of the file. No additional requests for js. Minimal javascript needed to be on the page to eval it.&lt;br /&gt;
&lt;br /&gt;
Comments? Ideas?</content><link rel='replies' type='application/atom+xml' href='http://crossbrowser.blogspot.com/feeds/3445106927648364449/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://crossbrowser.blogspot.com/2010/04/minimizing-external-javascript-requests.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2050944435781034945/posts/default/3445106927648364449'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2050944435781034945/posts/default/3445106927648364449'/><link rel='alternate' type='text/html' href='http://crossbrowser.blogspot.com/2010/04/minimizing-external-javascript-requests.html' title='Minimizing external javascript requests down to zero.'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2050944435781034945.post-1375780001876669098</id><published>2009-09-24T15:39:00.001-07:00</published><updated>2009-09-24T15:55:45.633-07:00</updated><title type='text'>Javascript Design Patterns</title><content type='html'>&lt;h2 style=&quot;text-align: center;&quot;&gt;JavaScript Design Patterns&lt;/h2&gt;&lt;b&gt;&lt;span style=&quot;font-size:78%;&quot;&gt;Intent:&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;font-size:78%;&quot;&gt; to convey the meaning of the most commonly used javascript design patterns.&lt;br /&gt;&lt;b&gt;Level: &lt;/b&gt;Intermediate to Advanced&lt;b&gt;&lt;br /&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;font-size:78%;&quot;&gt;&lt;b&gt;Who should read this? &lt;br /&gt;&lt;/b&gt;Everyone who touches with javascript, no matter the seniority.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-size:78%;&quot;&gt;&lt;br /&gt;&lt;b&gt;Naming conventions used below:&lt;/b&gt;&lt;br /&gt;I like to use modified Hungarian Naming Convention for my variables in loosely-typed languages like PHP or JavaScript. This convention uses first letter of the variable to denote the variable type: sName - string, nCount - numeric, fCallback - function, bIsAwesome - boolean, mParam - mixed (more than one type can be expected).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;JavaScript Library used in the examples:&lt;/b&gt;&lt;br /&gt;For the following examples I use PrototypeJS library. Documentation is readily available on the web.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Namespace Pattern&lt;/h3&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;Namespaces are used to confine multiple objects and methods to a scope to prevent their cross-interference and for organizational purposes. It is also a syntax sugar for those appreciating order and structure.&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;code&quot;&gt;var MYAPP = {};&lt;br /&gt;MYAPP.MyModule = function() { ... };&lt;br /&gt;&lt;/pre&gt;&lt;h3&gt;Singleton Pattern&lt;/h3&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;Singleton pattern is used to create a singular object instance and restrict all further instantiations. It is useful when an object that has unique meaning in the scope of the application and no two (or more) objects of the kind can exist.&lt;br /&gt;&lt;br /&gt;&lt;u&gt;Example&lt;/u&gt;: User Agent, JavaScript Page Controller, Logged-in user, etc.&lt;br /&gt;&lt;br /&gt;There are various ways to implement singleton in JavaScript:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;The &lt;b&gt;Object Literal Singleton&lt;/b&gt;:&lt;br /&gt;&lt;pre class=&quot;code&quot;&gt;var s = {&lt;br /&gt;   property: &#39;value&#39;&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;PROS: Ease, Compliant with Prototype&#39;s extension model&lt;br /&gt;CONS: No private encapsulation, Have to maintain comma-separation&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The &lt;b&gt;Closure Singleton: &lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;code&quot;&gt;var s = function {&lt;br /&gt;   var private_property = &#39;value1&#39;;&lt;br /&gt;   return {&lt;br /&gt;       public_property: &#39;value2&#39;&lt;br /&gt;   }&lt;br /&gt;}();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;PROS: Encapsulation of private members&lt;br /&gt;CONS: Readability - must see the end parentheses of potentially long declaration to understand the pattern; not compliant with Prototype&#39;s extension model&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The &lt;b&gt;Constructor Singleton:&lt;br /&gt;&lt;br /&gt;&lt;/b&gt;&lt;pre class=&quot;code&quot;&gt;var s = new function {&lt;br /&gt;   var private_property = &#39;value1&#39;;&lt;br /&gt;   this.public_property = &#39;value2&#39;;&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;PROS: Encapsulation of private members, Readability - the &#39;new&#39; keyword on the first line is easy to understand.&lt;br /&gt;CONS: Not compliant with Prototype&#39;s extension model.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;After evaluation of pros and cons you can see that a case of extending an object to create a singleton is rare to non-existent, so the third pattern has virtually no cons.&lt;br /&gt;&lt;div&gt;&lt;h3&gt;Registerer Pattern&lt;/h3&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;Registerer pattern is used to attach behavior to a group of similar controls on the page, who&#39;s markup was created on the server side. Note, it may also be conjoined with singleton pattern as the following example:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;code&quot;&gt;var Registerer = new Function() {&lt;br /&gt;   this.registerInputExample1 = function(sElementId) {&lt;br /&gt;       var oElement = $(sElementId); // get dom object&lt;br /&gt;       oElement.observe(&#39;click&#39;, function() {&lt;br /&gt;           // handle click occurred on oElement&lt;br /&gt;       });&lt;br /&gt;       oElement.observe(&#39;mouseover&#39;, function() {&lt;br /&gt;           // handle mouseover occurred on oElement&lt;br /&gt;       });&lt;br /&gt;   };&lt;br /&gt; &lt;br /&gt;   this.registerOutputExample2 = function(sElementId) {&lt;br /&gt;       var oElement = $(sElement); // get dom object&lt;br /&gt;       document.observe(&#39;registerer:somecustomevent&#39;, function() {&lt;br /&gt;           oElement.update(&#39;received an event&#39;); // handle how custom event affects the element.&lt;br /&gt;       });&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;u&gt;Output Example:&lt;/u&gt; Imagine a progress bar that must be updated while user rates images. When user rates 100 images using five-star rating widget (described further) The progress bar would show 100% completion.&lt;br /&gt;&lt;br /&gt;&lt;u&gt;Input Example:&lt;/u&gt; Imagine a five star rating widget that will fire event whenever one of the stars is clicked.&lt;br /&gt;&lt;br /&gt;The two widgets are independent from one another and can be rendered multiple times across the page. Both will follow registerer pattern.&lt;br /&gt;&lt;br /&gt;&lt;u&gt;Output Example: &lt;/u&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;code&quot;&gt;var ProgressBar = new Function() {&lt;br /&gt;   this.registerOutputBar = function(sElementId) {&lt;br /&gt;       var oElement = $(sElementId);&lt;br /&gt;       document.observe(&#39;progressbar:setpercent&#39;, function(oEvent) {&lt;br /&gt;           nParentWidth = oElement.parentNode.getWidth();&lt;br /&gt;           nWidth = Math.round(nParentWidth / 100 * oEvent.memo.percent);&lt;br /&gt;           oElement.setStyle({width: nWidth + &#39;px&#39;});&lt;br /&gt;       });&lt;br /&gt;   }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;u&gt;Input Example:&lt;/u&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;code&quot;&gt;var FiveStarRater = new Function() {&lt;br /&gt;   /**&lt;br /&gt;    * @param sElementId (String) Id of a clickable star&lt;br /&gt;    * @param nImageId (Number) Database id of image to rate&lt;br /&gt;    * @param nRating (Number) An integer 1-5 to signify rating&lt;br /&gt;    */&lt;br /&gt;   this.registerInputStar = function(sElementId, nImageId, nRating) {&lt;br /&gt;       var oElement = $(sElementId);&lt;br /&gt;       oElement.observe(&#39;click&#39;, function() {&lt;br /&gt;           Server.updateImageRating(nImageId, nRating); // update image rating via ajax&lt;br /&gt;       });&lt;br /&gt;   }&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This way, you can apply behaviors to numerous inputs and outputs on the page without having to duplicate functionality for each instance.&lt;br /&gt;&lt;br /&gt;PROBLEM:&lt;br /&gt;What if a single star rater is responsible for rating a stream of images? Do we need to register the star for each image? No. The &lt;b&gt;Getter Parameter Pattern&lt;/b&gt; comes to the resque.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;h3&gt;Getter Parameter Pattern&lt;/h3&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;Consider the problem described in the &lt;b&gt;Registerer Pattern&lt;/b&gt; section. The solution is very simple: supply a getter function as a parameter instead of a static image id. The modified code of a registerer will look like this:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;code&quot;&gt;var FiveStarRater = new Function() {&lt;br /&gt;   /**&lt;br /&gt;    * @param sElementId (String) Id of a clickable star&lt;br /&gt;    * @param nImageId (Number) Database id of image to rate&lt;br /&gt;    * @param nRating (Number) An integer 1-5 to signify rating&lt;br /&gt;    */&lt;br /&gt;   this.registerInputStar = function(sElementId, &lt;b&gt;fGetImageId&lt;/b&gt;, nRating) {&lt;br /&gt;       var oElement = $(sElementId);&lt;br /&gt;       oElement.observe(&#39;click&#39;, function() {&lt;br /&gt;           &lt;b&gt;var nImageId = fGetImageId();&lt;/b&gt;&lt;br /&gt;           Server.updateImageRating(nImageId, nRating); // update image rating via ajax&lt;br /&gt;       });&lt;br /&gt;   }&lt;br /&gt;};&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The getter would be a zero parameter function that in the context of a situation knows how to retrieve a single value:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;code&quot;&gt;var nImageId = 234;&lt;br /&gt;function getImageId() {&lt;br /&gt;   return nImageId;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Register the elements&lt;br /&gt;FiveStarRater.registerInputStar(&#39;star-one&#39;, getImageId, 1);&lt;br /&gt;...&lt;br /&gt;FiveStarRater.registerInputStar(&#39;star-five&#39;, getImageId, 5);&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This makes our FiveStarRater context-independent: the knowledge of how to retrieve a context-dependent value (such as nImageId) is now delegated to the caller scope.</content><link rel='replies' type='application/atom+xml' href='http://crossbrowser.blogspot.com/feeds/1375780001876669098/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://crossbrowser.blogspot.com/2009/09/javascript-design-patterns.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2050944435781034945/posts/default/1375780001876669098'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2050944435781034945/posts/default/1375780001876669098'/><link rel='alternate' type='text/html' href='http://crossbrowser.blogspot.com/2009/09/javascript-design-patterns.html' title='Javascript Design Patterns'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2050944435781034945.post-549561109806651162</id><published>2009-05-07T01:12:00.000-07:00</published><updated>2009-05-09T03:34:58.673-07:00</updated><title type='text'>Prototype.js decoupling - Antenna</title><content type='html'>I am referring to &quot;shedding the vile old ways&quot;&lt;br /&gt;(as Prototype developers called it) in &lt;a href=&quot;http://www.prototypejs.org/api/event/observe&quot;&gt;http://www.prototypejs.org/api/event/observe&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This is called a &quot;decoupling&quot;.&lt;br /&gt;&lt;br /&gt;Pros of this approach:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Can dynamically attach listeners to any event in DOM&lt;/li&gt;&lt;li&gt;Can attach multiple listeners&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;Cons:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Easy to lose track of what is going on in the system on each event&lt;/li&gt;&lt;li&gt;Very hard to debug without proper tools&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;Imagine if all of your objects are communicating via events (not method calls),&lt;br /&gt;how would you trace these communications?&lt;br /&gt;&lt;br /&gt;Apparently, there is no tools yet to do exactly that. And prototype.js does not provide a good way to trace events. So I decided to solve it for myself and, hopefully, some of you may find this solution useful.&lt;br /&gt;&lt;br /&gt;I called this solution &lt;span style=&quot;font-weight: bold;&quot;&gt;&quot;Antenna&quot;&lt;/span&gt; just because I could not think of a better way to describe what it does in one word. It catches the events &quot;in the air&quot;, much like a real antenna does with all sorts of electromagnetic events.&lt;br /&gt;&lt;br /&gt;So here goes:&lt;br /&gt;&lt;br /&gt;1. We are going to modify prototype.js to fire debug events whenever the following things happen:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Event listener is registered&lt;/li&gt;&lt;li&gt;Event listener is unregistered&lt;/li&gt;&lt;li&gt;Event is fired&lt;/li&gt;&lt;li&gt;Event is handled&lt;/li&gt;&lt;/ul&gt;Find line that defines &quot;Object.extend(Event, (function() { .... &quot;  (line 3936 in version 1.6.0.3)&lt;br /&gt;Find &quot;return&quot; clause for this object (line 4009)&lt;br /&gt;Modify it as follows.&lt;br /&gt;&lt;pre class=&quot;code&quot;&gt;&lt;br /&gt;return {&lt;br /&gt; observe: function(element, eventName, handler) {&lt;br /&gt;   element = $(element);&lt;br /&gt;   var name = getDOMEventName(eventName);&lt;br /&gt;  /*************** ANTENNA CODE *****************/&lt;br /&gt;  if (DEBUG &amp;amp;&amp;amp; eventName.indexOf(&#39;antenna:&#39;) != 0) {&lt;br /&gt;&lt;br /&gt; var callerScope = arguments.callee.caller.caller;&lt;br /&gt;&lt;br /&gt;   handler = handler.wrap( function (f, e) {&lt;br /&gt;     document.fire(&#39;antenna:event_capture&#39;,{&lt;br /&gt;   eventName: (e.eventName ? e.eventName : e.type),&lt;br /&gt;   element: e.findElement(),&lt;br /&gt;   handler: f,&lt;br /&gt;   callerScope: callerScope&lt;br /&gt;  });&lt;br /&gt;  return f(e);&lt;br /&gt;   });&lt;br /&gt;&lt;br /&gt;   document.fire(&#39;antenna:event_observe&#39;, {&lt;br /&gt;   eventName: eventName,&lt;br /&gt;   element: element,&lt;br /&gt;   handler: handler,&lt;br /&gt;   callerScope: callerScope&lt;br /&gt; });&lt;br /&gt;  }&lt;br /&gt;  /**********************************************/&lt;br /&gt;&lt;br /&gt;  var wrapper = createWrapper(element, eventName, handler);&lt;br /&gt;   if (!wrapper) return element;&lt;br /&gt;&lt;br /&gt;   if (element.addEventListener) {&lt;br /&gt;     element.addEventListener(name, wrapper, false);&lt;br /&gt;   } else {&lt;br /&gt;     element.attachEvent(&quot;on&quot; + name, wrapper);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   return element;&lt;br /&gt; },&lt;br /&gt;&lt;br /&gt; stopObserving: function(element, eventName, handler) {&lt;br /&gt;   element = $(element);&lt;br /&gt;   var id = getEventID(element), name = getDOMEventName(eventName);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   if (!handler &amp;amp;&amp;amp; eventName) {&lt;br /&gt;     getWrappersForEventName(id, eventName).each(function(wrapper) {&lt;br /&gt;       element.stopObserving(eventName, wrapper.handler);&lt;br /&gt;     });&lt;br /&gt;     return element;&lt;br /&gt;&lt;br /&gt;   } else if (!eventName) {&lt;br /&gt;     Object.keys(getCacheForID(id)).each(function(eventName) {&lt;br /&gt;       element.stopObserving(eventName);&lt;br /&gt;     });&lt;br /&gt;     return element;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   var wrapper = findWrapper(id, eventName, handler);&lt;br /&gt;   if (!wrapper) return element;&lt;br /&gt;&lt;br /&gt;  /*************** ANTENNA CODE *****************/&lt;br /&gt;  if (DEBUG &amp;amp;&amp;amp; eventName.indexOf(&#39;antenna:&#39;) != 0) {&lt;br /&gt;    document.fire(&#39;antenna:event_unobserve&#39;, {&lt;br /&gt;  eventName: eventName,&lt;br /&gt;  element: element,&lt;br /&gt;  handler: handler,&lt;br /&gt;  callerScope: arguments.callee.caller.caller&lt;br /&gt; });&lt;br /&gt;  }&lt;br /&gt;  /**********************************************/&lt;br /&gt;&lt;br /&gt;   if (element.removeEventListener) {&lt;br /&gt;     element.removeEventListener(name, wrapper, false);&lt;br /&gt;   } else {&lt;br /&gt;     element.detachEvent(&quot;on&quot; + name, wrapper);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   destroyWrapper(id, eventName, handler);&lt;br /&gt;&lt;br /&gt;   return element;&lt;br /&gt; },&lt;br /&gt;&lt;br /&gt; fire: function(element, eventName, memo) {&lt;br /&gt;   element = $(element);&lt;br /&gt;   if (element == document &amp;amp;&amp;amp; document.createEvent &amp;amp;&amp;amp; !element.dispatchEvent)&lt;br /&gt;     element = document.documentElement;&lt;br /&gt;&lt;br /&gt;   /*************** ANTENNA CODE *****************/&lt;br /&gt;  if (DEBUG &amp;amp;&amp;amp; eventName.indexOf(&#39;antenna:&#39;) != 0) {&lt;br /&gt;    document.fire(&#39;antenna:event_fire&#39;, {&lt;br /&gt;  eventName: eventName,&lt;br /&gt;  element: element,&lt;br /&gt;  memo: memo,&lt;br /&gt;  callerScope: arguments.callee.caller.caller&lt;br /&gt; });&lt;br /&gt;  }&lt;br /&gt;  /**********************************************/&lt;br /&gt;&lt;br /&gt;   var event;&lt;br /&gt;   if (document.createEvent) {&lt;br /&gt;     event = document.createEvent(&quot;HTMLEvents&quot;);&lt;br /&gt;     event.initEvent(&quot;dataavailable&quot;, true, true);&lt;br /&gt;   } else {&lt;br /&gt;     event = document.createEventObject();&lt;br /&gt;     event.eventType = &quot;ondataavailable&quot;;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   event.eventName = eventName;&lt;br /&gt;   event.memo = memo || { };&lt;br /&gt;&lt;br /&gt;   if (document.createEvent) {&lt;br /&gt;     element.dispatchEvent(event);&lt;br /&gt;   } else {&lt;br /&gt;     element.fireEvent(event.eventType, event);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   return Event.extend(event);&lt;br /&gt; }&lt;br /&gt;};&lt;br /&gt;})());&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Note, that we must have &lt;span style=&quot;font-weight: bold;&quot;&gt;DEBUG=true&lt;/span&gt; in order for this to work - we would not want this to happen all the time: too much overhead, right?&lt;br /&gt;&lt;br /&gt;2. In order to catch these events all you need to do is to define 4 observers as follows:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;code&quot;&gt;&lt;br /&gt;&lt;br /&gt;document.observe(&#39;antenna:event_observe&#39;,   function(e) { ... });&lt;br /&gt;document.observe(&#39;antenna:event_unobserve&#39;, function(e) { ... });&lt;br /&gt;document.observe(&#39;antenna:event_fire&#39;,      function(e) { ... });&lt;br /&gt;document.observe(&#39;antenna:event_capture&#39;,   function(e) { ... });&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I am currently working on a crossbrowser presentation layer for this solution, so more code to follow.</content><link rel='replies' type='application/atom+xml' href='http://crossbrowser.blogspot.com/feeds/549561109806651162/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://crossbrowser.blogspot.com/2009/05/prototypejs-decoupling-solution-antenna.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2050944435781034945/posts/default/549561109806651162'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2050944435781034945/posts/default/549561109806651162'/><link rel='alternate' type='text/html' href='http://crossbrowser.blogspot.com/2009/05/prototypejs-decoupling-solution-antenna.html' title='Prototype.js decoupling - Antenna'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2050944435781034945.post-4356299156020105151</id><published>2009-04-24T00:23:00.001-07:00</published><updated>2009-05-09T03:31:08.585-07:00</updated><title type='text'>CSS guidelines</title><content type='html'>&lt;b&gt;&lt;font size=&quot;4&quot;&gt;Purpose&lt;/font&gt;&lt;/b&gt;&lt;br&gt;&lt;br&gt;As we all know, css is not the most straight-forward of the languages. &lt;br&gt;There are several dimensions of inheritance. There are different browsers to write for. There are hacks that defy logic. Etc.&lt;br&gt;Needless to say, css can get very messy and intangled. Not a surprize that it often treated like garbage, semi-intentionally swept under the couch. &lt;br&gt;Sometimes, it gets pushed into the most unpredictable places: html, js, php, java and sometimes even SQL. Good luck debugging this!&lt;br&gt;&lt;br&gt;The purpose of this guideline is to introduce a set of clear and simple rules that, if followed, will:&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1. Void most of the headache.&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2. Bring beauty and structure to our CSS development cycle.&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3. Minimize size of CSS load.&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4. SIGNIFICANTLY ease the code maintenance.&lt;br&gt;&lt;br&gt;&lt;b&gt;&lt;font size=&quot;4&quot;&gt;1. Clear separation&lt;/font&gt;&lt;br&gt;&lt;br&gt;&lt;/b&gt;Treat CSS like any other language - separate it into it&#39;s own tier, let it shine on it&#39;s own.&lt;br&gt;&lt;br&gt;&lt;ol&gt;&lt;li&gt;&amp;nbsp;The only place for CSS is in &quot;.css&quot; file.&lt;/li&gt;&lt;ol&gt;&lt;li&gt;No inline CSS - the only part of CSS that should appear inside HTML tags are class names and ids.&lt;/li&gt;&lt;li&gt;No CSS on server side&amp;nbsp; - class names and ids are ok&lt;/li&gt;&lt;li&gt;No CSS in JS - Javascript should NOT edit styles, but swap classes instead.&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;u&gt;&lt;br&gt;Example&lt;/u&gt;: &lt;br&gt;&lt;blockquote&gt;[ CORRECT ]&lt;br&gt;myButton.onMouseOver = function() { myButton.addClass(&#39;my-button-over&#39;); }&lt;br&gt;&lt;br&gt;[ WRONG ]&lt;br&gt;myButton.onMouseOver = function() { myButton.setStyle(&#39;background-color&#39;,&#39;red&#39;); }&lt;br&gt;&lt;/blockquote&gt;&lt;u&gt;The ONLY Exception&lt;/u&gt;:&lt;br&gt;Sometimes width, height, top, left and&lt;br /&gt;display, etc. properties are changed internally by various animation&lt;br /&gt;routines in JS.&amp;nbsp; It is ok to define these&lt;br /&gt;css properties inline, but only these. If the new routine is being&lt;br /&gt;written - please try only using addClassName and removeClassName routines to swap css classes that are defined externally.&lt;br&gt;&lt;br&gt;&lt;/li&gt;&lt;/ol&gt;&lt;li&gt;DO NOT use ids (#id) notations in CSS, reserve them for JavaScript identification. Instead use CSS classes (.myclass).&lt;br&gt;&lt;br&gt;&lt;/li&gt;&lt;li&gt;If JS needs to use CSS classes, they must be prepended with &quot;js-&quot; notation, and NEVER be used to apply styles with CSS to &lt;br&gt;avoid introducing bugs in JavaScript when CSS selector is changed.&lt;br&gt;&lt;/li&gt;&lt;/ol&gt;&lt;b&gt;&lt;br&gt;&lt;font size=&quot;4&quot;&gt;2. File system structure&lt;/font&gt;&lt;br&gt;&lt;/b&gt;&lt;br&gt;&lt;ol&gt;&lt;li&gt;Take advantage of minimization - create separate CSS file for each specific purpose. &lt;br&gt;It is easier to read, debug and remove. Writing short, consise CSS files will help making the code self-explanatory.&lt;br&gt;&lt;br&gt;&lt;/li&gt;&lt;li&gt;Divide files into two groups:&lt;br&gt;a. Generic - Styles that are used to skin reusable widgets or modules. Styles that MAY be applied to a similar module elsewhere.&lt;br&gt;b. Specific - Styles responcible for particular page or a module. Styles that will NOT be used anywhere else but there. &lt;br&gt;&lt;br&gt;&lt;u&gt;Example&lt;/u&gt;: &lt;br&gt;Consider a dialog widget that is used in multiple places across the site. &lt;br&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;br&gt;Our generic skin css file will be called &lt;i&gt;module.dialog.skin1.css.&lt;/i&gt; &lt;br&gt;This file will abstract the generic looks of the dialog widget regardless of the markup that goes inside it. The &lt;i&gt;module.dialog.skin1.css&lt;/i&gt; does not,&lt;br&gt;and should not know about it&#39;s possible contents. This file is&lt;br /&gt;similar to a base class in the inheritance paradigm of any programming&lt;br /&gt;language.&lt;br&gt;&lt;br&gt;For a specific dialog that will, say, display a user profile information, the specific css file will be called &lt;i&gt;module.dialog.profilepopup.css&lt;/i&gt;&lt;i&gt;. &lt;/i&gt;&lt;br&gt;This file will contain styling properties of the profile&lt;br /&gt;displayed within the dialog. It may or may not override styles&lt;br /&gt;inherited from&amp;nbsp;&lt;i&gt;module.dialog.skin1.css&lt;/i&gt;&lt;i&gt;.&lt;br&gt;&lt;/i&gt;The &lt;i&gt;module.dialog.profilepopup.css&lt;/i&gt; can be compared to an OOP subclass of &lt;i&gt;module.dialog.skin1.css&lt;/i&gt;&lt;i&gt;.&lt;/i&gt; &lt;br&gt;&lt;br&gt;This&lt;br /&gt;way, we will have only one file that defines the generic looks of the&lt;br /&gt;dialog, and multiple specific files for any specific dialog. And no&lt;br /&gt;extra CSS.&lt;br&gt;&lt;/li&gt;&lt;/ol&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br&gt;&lt;font size=&quot;4&quot;&gt;&lt;b&gt;3. File naming conventions&lt;/b&gt;&lt;/font&gt;&lt;br&gt;&lt;br&gt;&lt;ol&gt;&lt;li&gt;Use all-lowercase filenames.&lt;/li&gt;&lt;li&gt;Use underscores (not dashes) in filenames&lt;/li&gt;&lt;li&gt;Use periods &quot;.&quot; to separate hierarchial namespaces within the filename:&lt;br&gt;&lt;blockquote&gt;&amp;lt;module_type&amp;gt;.&amp;lt;module_name&amp;gt;.&amp;lt;module_specific&amp;gt;.css&lt;br&gt;&amp;lt;module_type&amp;gt; : [&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; common,&amp;nbsp; // contains element styles common across ALL pages (reset, fonts, grids, forms, etc.)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; page, &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; // a single html page, including BODY tag&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; partial, &amp;nbsp;&amp;nbsp;&amp;nbsp; // a single partial page loaded with ajax&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; module&amp;nbsp; &amp;nbsp; // a widget like dialog, button, pager, grid, custom form element, etc.&lt;br&gt;]&lt;br&gt;&amp;lt;module_name&amp;gt;&amp;nbsp; : arbitrary&amp;nbsp;&amp;nbsp; // a name of a page, layout&lt;br /&gt;or widget. Corresponds to js or php widget file name.&lt;br&gt;&amp;lt;module_specific&amp;gt; : arbitrary&amp;nbsp; // a&lt;br /&gt;specific instance of &amp;lt;module_name&amp;gt;. Corresponds to the page name of occurrence. &lt;br&gt;&lt;/blockquote&gt;This will spare you firebugging, greping and searching your&lt;br /&gt;entire codebase for styles that correspond to your module or widget.&lt;br /&gt;You will know EXACTLY the file you need. &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br&gt;&lt;font size=&quot;4&quot;&gt;&lt;b&gt;4. CSS Selectors&lt;br&gt;&lt;/b&gt;&lt;/font&gt;&lt;br&gt;&lt;ol&gt;&lt;li&gt;Use dashes instead of underscores in your selectors.&amp;nbsp; This is just a widely accepted web standard.&lt;/li&gt;&lt;li&gt;Add a CSS class to the outmost HTML tag of your module/widget/layout that has the SAME NAME as &amp;lt;module_name&amp;gt; or &amp;lt;module_name&amp;gt;-&amp;lt;module_specific&amp;gt; your CSS file &lt;br&gt;(replacing underscores with dashes, of course)&lt;/li&gt;&lt;li&gt;Use short but descriptive names for classes in any other inner tag. (Further referred to as &quot;inner classes&quot;)&lt;/li&gt;&lt;li&gt;ALWAYS define inner classes through the class of the outmost tag. &lt;u&gt;&lt;br&gt;&lt;br&gt;Examp&lt;/u&gt;&lt;u&gt;le&lt;/u&gt;: &lt;br&gt;Inside of our&lt;i&gt; module.dialog.skin1.css&lt;/i&gt;. file we need to skin a title bar and four corners:&lt;br&gt;&lt;blockquote&gt;[ CORRECT ]&lt;br&gt;.dialog-skin1 {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* define css properties to inherit within the skin: font, background, etc */&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; background-color: #CCC;&lt;br&gt;&amp;nbsp;}&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; .dialog-skin1 .title {&lt;br&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; background-color: #666;&lt;br&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; color: #FFF;&lt;br&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; font-weight: bold;&lt;br&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; .dialog-skin1 .corner-n {&lt;br&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; width: 15px;&lt;br&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; height: 15px;&lt;br&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; background: url(images/dialog_corner_north.gif) no-repeat;&lt;br&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; }&lt;br&gt;&lt;/blockquote&gt;Prepending style selector with the widget/module/layout&lt;br /&gt;identifier will make sure that these styles will NEVER interfere with&lt;br /&gt;any other style outside the module.&lt;br&gt;&lt;blockquote&gt;[ WRONG ]&lt;br&gt;.dialog-skin1 {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; background-color: #CCC;&lt;br&gt;}&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; .title {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; background-color: #666;&lt;br&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; color: #FFF;&lt;br&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; font-weight: bold;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; .corner-n {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; width: 15px;&lt;br&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; height: 15px;&lt;br&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; background: url(images/dialog_corner_north.gif) no-repeat;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&lt;/blockquote&gt;There is a great chance that &quot;.title&quot; or &quot;.corner-n&quot; may&lt;br /&gt;be defined elsewhere in the application and you will end up overriding&lt;br /&gt;it.&lt;br&gt;&lt;/li&gt;&lt;/ol&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;br&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font size=&quot;4&quot;&gt;&lt;b&gt;&lt;br&gt;5. Indentation and grouping of styles&lt;br&gt;&lt;/b&gt;&lt;/font&gt;&lt;br&gt;&lt;ol&gt;&lt;li&gt;Group styles inside the CSS file just the way they appear in HTML - Outer first, inner after&lt;/li&gt;&lt;li&gt;[Optional] You may want to indent styles just as you would indent HTML tags they appear in - Outer less indented, inner more indented&lt;br&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br&gt;&lt;blockquote&gt;&lt;u&gt;Example&lt;/u&gt;:&lt;br&gt;&lt;br&gt;selector1 {&lt;br&gt;}&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; selector1 selector2 {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; selector1 selector2 selector3 {&lt;br&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; selector1 selector4 {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; selector1 selector5 {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&lt;/blockquote&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;br&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;This way you will ALWAYS know where in the file to look for a specific style.&lt;br&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; You will clearly see the style inheritance structure.&lt;br&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; You can at-a-glance identify how your CSS applies to HTML (vertical readability)&lt;br&gt;&lt;br&gt;&lt;font size=&quot;4&quot;&gt;&lt;b&gt;6. Grids&lt;br&gt;&lt;br&gt;&lt;/b&gt;&lt;/font&gt;&lt;ol&gt;&lt;li&gt;Use grid classes to define positioning of your HTML elements. (Documentation coming soon)&lt;/li&gt;&lt;/ol&gt;&lt;br&gt;&lt;font size=&quot;4&quot;&gt;&lt;b&gt;7. Appendix. Crossbrowser CSS Hacks&lt;/b&gt;&lt;/font&gt;&lt;br&gt;&lt;br&gt;Browser specific hacks (order is important):&lt;br&gt;&lt;br&gt;&lt;blockquote&gt;.myClass {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; width: 100px;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* Affects: FF, Safari, Opera, IE5, IE6, IE7, Targeting: FF, Safari, Opera */&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; .width: 102px;&amp;nbsp;&amp;nbsp; /* Affects: IE5, IE6, IE7, Targeting: IE7 */&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; _width: 101px;&amp;nbsp; /* Affects: IE6, IE5, Targeting: IE6, IE5 */&lt;br&gt;}&lt;br&gt;&lt;/blockquote&gt;&lt;br&gt;IE8 Support&lt;br&gt;The best (google and facebook approved) solution is to make IE8 behave like IE7 by adding the following meta tag:&lt;br&gt;&lt;br style=&quot;font-family: Verdana;&quot;&gt;&lt;blockquote&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;font-family: Verdana;&quot; class=&quot;start-tag&quot;&gt;meta&lt;/span&gt;&lt;span style=&quot;font-family: Verdana;&quot; class=&quot;attribute-name&quot;&gt; http-equiv&lt;/span&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;font-family: Verdana;&quot; class=&quot;attribute-value&quot;&gt;&quot;X-UA-Compatible&quot; &lt;/span&gt;&lt;span style=&quot;font-family: Verdana;&quot; class=&quot;attribute-name&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;font-family: Verdana;&quot; class=&quot;attribute-value&quot;&gt;&quot;IE=EmulateIE7&quot; &lt;/span&gt;&lt;span style=&quot;font-family: Verdana;&quot; class=&quot;error&quot;&gt;&lt;span class=&quot;attribute-name&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br&gt;&lt;/blockquote&gt;&lt;pre id=&quot;line1&quot;&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&lt;br&gt;One less IE browser to code for :)&lt;br&gt;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;/pre&gt;&amp;nbsp;&lt;br&gt;</content><link rel='replies' type='application/atom+xml' href='http://crossbrowser.blogspot.com/feeds/4356299156020105151/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://crossbrowser.blogspot.com/2009/04/css-guidelines.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2050944435781034945/posts/default/4356299156020105151'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2050944435781034945/posts/default/4356299156020105151'/><link rel='alternate' type='text/html' href='http://crossbrowser.blogspot.com/2009/04/css-guidelines.html' title='CSS guidelines'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2050944435781034945.post-7297404084988187669</id><published>2008-07-29T16:42:00.000-07:00</published><updated>2009-05-09T03:41:11.627-07:00</updated><title type='text'>Firefox/Opera Scrollbar fix in CSS</title><content type='html'>Annoying behavior in FF: when navigating between page with height&lt;100% and page with height&gt;100% you will experience a horizontal shift in layout caused by added vertical scrollbar. This is a very nice and simple fix that enables a vertical scrollbar holder at all times.&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;code&quot;&gt;&lt;br /&gt;html {&lt;br /&gt;  overflow-y: scroll;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://crossbrowser.blogspot.com/feeds/7297404084988187669/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://crossbrowser.blogspot.com/2008/07/firefoxopera-scrollbar-fix.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2050944435781034945/posts/default/7297404084988187669'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2050944435781034945/posts/default/7297404084988187669'/><link rel='alternate' type='text/html' href='http://crossbrowser.blogspot.com/2008/07/firefoxopera-scrollbar-fix.html' title='Firefox/Opera Scrollbar fix in CSS'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2050944435781034945.post-5377022552213620199</id><published>2008-07-21T18:46:00.000-07:00</published><updated>2009-05-09T03:40:06.714-07:00</updated><title type='text'>CSS Browser Detection</title><content type='html'>&lt;pre class=&quot;code&quot;&gt;&lt;br /&gt;.myclass {&lt;br /&gt;  color: red;     /* All browsers [Target: FF,NS] */&lt;br /&gt;  _color: green;  /* IE6- [Target: IE6-] */&lt;br /&gt;  .color: blue;   /* IE7, IE6- [Target: IE7] */&lt;br /&gt;}&lt;br /&gt;body:last-child:not(:root:root) .myclass {&lt;br /&gt;  color: purple;  /* Safari, Konqueror [Target: Safari, Konqueror] */&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;For IE8 You can just use meta tag to make it behave like IE7 (Facebook, Google are using this technique)&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;code&quot;&gt;&lt;br /&gt;&amp;lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=EmulateIE7&quot; /&amp;gt;&lt;br /&gt;&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://crossbrowser.blogspot.com/feeds/5377022552213620199/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://crossbrowser.blogspot.com/2008/07/browser-detection.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2050944435781034945/posts/default/5377022552213620199'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2050944435781034945/posts/default/5377022552213620199'/><link rel='alternate' type='text/html' href='http://crossbrowser.blogspot.com/2008/07/browser-detection.html' title='CSS Browser Detection'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2050944435781034945.post-8792530188730311496</id><published>2008-07-18T16:00:00.000-07:00</published><updated>2008-07-18T16:20:32.765-07:00</updated><title type='text'>Inline Block</title><content type='html'>Elements may appear inline, yet retaining box models of block elements:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;code&quot;&gt;&lt;br /&gt;/* FF,NS */&lt;br /&gt;html&gt;body .inline-block {&lt;br /&gt;  display: -moz-inline-box; /* [FF3]+ */&lt;br /&gt;  display: inline-block; /* (FF3)- */&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* Safari, Webkit, Opera */&lt;br /&gt;.inline-block {&lt;br /&gt;  position: relative;&lt;br /&gt;  display: inline-block;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* (IE7)- */&lt;br /&gt;/* to inline does the trick. */&lt;br /&gt;* html .inline-block {&lt;br /&gt;  display: inline;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* [IE7]+ */&lt;br /&gt;*:first-child+html .inline-block {&lt;br /&gt;  display: inline;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://crossbrowser.blogspot.com/feeds/8792530188730311496/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://crossbrowser.blogspot.com/2008/07/inline-block.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2050944435781034945/posts/default/8792530188730311496'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2050944435781034945/posts/default/8792530188730311496'/><link rel='alternate' type='text/html' href='http://crossbrowser.blogspot.com/2008/07/inline-block.html' title='Inline Block'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2050944435781034945.post-1170471048334583511</id><published>2008-01-31T16:51:00.000-08:00</published><updated>2009-05-09T03:40:43.769-07:00</updated><title type='text'>CSS Fixed footer, fixed header</title><content type='html'>&lt;pre class=&quot;code&quot;&gt;&lt;br /&gt;/* Tested in IE6,IE7, Safari and FF */&lt;br /&gt;&lt;br /&gt;html, body {&lt;br /&gt; padding: 0;&lt;br /&gt; margin: 0;&lt;br /&gt; _background: url(nothing) fixed;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.fixed-bottom {&lt;br /&gt; position: fixed;&lt;br /&gt; bottom: 0;&lt;br /&gt; left: 0;&lt;br /&gt; _position: absolute;&lt;br /&gt; _top: expression(document.body.scrollTop + (document.body.clientHeight - this.clientHeight));&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.fixed-top {&lt;br /&gt; position: fixed;&lt;br /&gt; top: 0;&lt;br /&gt; left: 0;&lt;br /&gt; _position: absolute;&lt;br /&gt; _top: expression(eval(document.body.scrollTop));&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://crossbrowser.blogspot.com/feeds/1170471048334583511/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://crossbrowser.blogspot.com/2008/01/fixed-footer-fixed-header-ie6.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2050944435781034945/posts/default/1170471048334583511'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2050944435781034945/posts/default/1170471048334583511'/><link rel='alternate' type='text/html' href='http://crossbrowser.blogspot.com/2008/01/fixed-footer-fixed-header-ie6.html' title='CSS Fixed footer, fixed header'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2050944435781034945.post-1799321906616892907</id><published>2008-01-31T16:34:00.000-08:00</published><updated>2009-05-09T03:42:51.516-07:00</updated><title type='text'>CSS PNG Transparency</title><content type='html'>This sample provides a CSS class that fills a background of an element with a semi-transparent PNG. This one does a shadow-fading effect along a horizontally stretched DIV or TD:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;code&quot;&gt;&lt;br /&gt;/* Tested in IE6, IE7, Safari and FF. */&lt;br /&gt;.fade-down-white {&lt;br /&gt;  background: transparent url(images/fade_down_white.png) top repeat-x;&lt;br /&gt;  height: 50px;&lt;br /&gt;  width: 100%;&lt;br /&gt;  _background: none;&lt;br /&gt;  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src=&#39;images/fade_down_white.png&#39;,&lt;br /&gt;sizingMethod=&#39;scale&#39;);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://crossbrowser.blogspot.com/feeds/1799321906616892907/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://crossbrowser.blogspot.com/2008/01/css-png-transparency.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2050944435781034945/posts/default/1799321906616892907'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2050944435781034945/posts/default/1799321906616892907'/><link rel='alternate' type='text/html' href='http://crossbrowser.blogspot.com/2008/01/css-png-transparency.html' title='CSS PNG Transparency'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>