<?xml version="1.0" encoding="utf-8" ?><rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xml:base="http://www.jacklmoore.com"><channel><title>Jack Moore</title><link>http://www.jacklmoore.com</link><atom:link href="http://www.jacklmoore.com/rss" rel="self" type="application/rss+xml"></atom:link><description>Front-end development blog</description><item><title>Web Development Using Virtual Machines</title><link>http://www.jacklmoore.com/notes/development</link><guid>http://www.jacklmoore.com/notes/development</guid><pubDate>Tue, 21 Feb 2012 12:00:00 z</pubDate><description><![CDATA[<h2>Virtualization</h2>

<p>I use <a href="https://www.virtualbox.org">VirtualBox</a>. It's a free, open source, cross-platform virtualization program. I'll use it to create a virtual system platform for running <a href="http://www.ubuntu.com/download/server/download">Ubuntu 11.10 Sever</a> 32-bit as a guest operating system. There are significant benefits to using a virtual machine:</p>

<ol>
<li><p><strong>Replicate your production environment.</strong><br/>
Avoid headaches by developing on same software configuration and hardware limitations as your production environment.</p></li>
<li><p><strong>Easy to copy, transfer, backup, and restore.</strong><br/>
VirtualBox has a snapshot feature that can be used at any time to save the current machine state. Experiment without hesitation knowing that you can always revert to a previous save state. The virtual machine can be copied for use on another computer or used as the starting point for a new machine.</p></li>
<li><p><strong>No network is necessary to communicate with the virtual server.</strong></p></li>
</ol>

<h2>Creating A New Virtual Machine</h2>

<p>In VirtualBox, clicking 'New' opens the new virtual machine wizard. It's just a few steps and the defaults are fine. Choose Linux for OS Type and Ubuntu for the version. The memory defaults to 512 MB, which is on par with an entry level VPS.  This can be adjusted at any time. Once the VM is created, select it and click on 'Settings'.</p>

<h3>Storage</h3>

<p>Go to the storage option and click on the empty IDE controller. Mount the Ubuntu iso as a DVD drive. When the guest system is started it will boot from the drive and load Ubuntu's installer.</p>

<p><img src="/img/vbox/mountiso.png" alt="mount the server iso" title="" /></p>

<h3>Network</h3>

<p>I have the network adapter attached to NAT. From the advanced settings, open 'Port Forwarding'. I added a forwarding rule for http requests.  Any requests to port 80 on the host will be forwarded to the guest, allowing me to access Apache as if it were running locally.</p>

<p><img src="/img/vbox/forwarding.png" alt="forward http requests" title="" /></p>

<h3>Shared Folders</h3>

<p>Instead of constantly transfering files from host to guest, I'm going to set up shared folders so that Apache can serve files directly from the host.</p>

<p><img src="/img/vbox/share.png" alt="setup file sharing" title="" /></p>

<h2>Starting The Virtual Machine</h2>

<p>I am going to handwave over the specifics of using LAMP. However, the OS installation process should be straight forward. There aren't many things to go wrong when installing a GUI-less system on virtualized hardware. For the sake of brevity, I picked LAMP Server during the software selection stage to have those packages automatically installed.</p>

<p><img src="/img/vbox/software.png" alt="install the LAMP packages" title="" /></p>

<h3>First Login</h3>

<p>Update the package index and upgrade existing packages:</p>

<pre><code>sudo apt-get update
sudo apt-get upgrade
</code></pre>

<p>This might be a good place to create a snapshot. If anything goes wrong, just revert to the snapshot.</p>

<h3>VirtualBox Guest Additions</h3>

<p>The Guest Additions package needs to be installed in order to access the shared folder. Guest Additions has a couple of prerequisite packages (dkms and linux-headers) that we'll want to install first. Click on 'Devices' and select 'Install Guest Additions'.  This adds a device to the system that will need to be mounted before we can access it's file system. The device should be under /dev/cdrom and we can mount it to the existing /media/cdrom. Then we can run the VBoxLinuxAdditions script which will install Guest Additions. After, you'll need to logout / login for the shared folder to be auto-mounted.</p>

<p>Once you've clicked on 'Install Guest Addtions', execute the following commands:</p>

<pre><code>sudo apt-get install linux-headers-$(uname -r)
sudo apt-get install dkms
sudo mount /dev/cdrom /media/cdrom
sudo sh /media/cdrom/VBoxLinuxAdditions.run
logout
</code></pre>

<p>The name of the shared folder will be prefixed with 'sf<em>' and it will be mounted under /media. Since I named my shared folder 'projects', the path will be /media/sf</em>projects/. Currently, Apache does not have read/write permissions for the shared folder. The Apache user (www-data) will need to be added to the vboxsf group to have those permissions. I added my user as well.</p>

<pre><code>sudo usermod -aG vboxsf www-data
sudo usermod -aG vboxsf jack
</code></pre>

<h3>Configure Apache</h3>

<p>I'm going to make two small additions to Apache's httpd.conf. I'm going to get Apache a ServerName, but more importantly, I am going to turn off EnableSendfile. There are outstanding cache issues related to using VirtualBox's shared folders, turning EnableSendfile off will help Apache send fresh files.</p>

<p><code>File: /etc/apache2/httpd.conf</code></p>

<pre><code>ServerName ubuntu
EnableSendfile off
</code></pre>

<h3>Configure Apache's Virtual Hosts</h3>

<p>Let's create a virtual host that serves files from the shared folder. I'm going to use 'dev' as my TLD to indicate that the site is hosted on my development environment. First we need to create an entry for a new site in Apache's sites-available directory:</p>

<p><code>File: /etc/apache2/sites-available/jacklmoore.dev</code></p>

<pre><code>&lt;VirtualHost *:80&gt;
    ServerName jacklmoore.dev
    DocumentRoot /media/sf_projects/jacklmoore
&lt;/VirtualHost&gt;
</code></pre>

<p>Now enable the site and reload Apache:</p>

<pre><code>sudo a2ensite jacklmoore.dev
sudo service apache2 reload
</code></pre>

<p>Add an entry to your host machine's <a href='http://en.wikipedia.org/wiki/Hosts_(file)'>hosts</a>  file mapping the server name to your local address. Because port 80 was forwarded, all local HTTP requests will be forwarded to the virtual machine.  There, Apache will check to see if there is a site enabled by that name.</p>

<p><img src="/img/vbox/yodawg.png" alt="I heard you like websites" title="" /></p>]]></description></item><item><title>CSS Ribbon Menu</title><link>http://www.jacklmoore.com/notes/css3-ribbon-menu</link><guid>http://www.jacklmoore.com/notes/css3-ribbon-menu</guid><pubDate>Wed, 1 Feb 2012 12:00:00 z</pubDate><description><![CDATA[<iframe class='demo' src='/demo/ribbon.html?reload=3' style='height:130px' frameborder='0'></iframe>

<h2>Browser Support</h2>

<p>IE8 and IE9 do not support CSS3 transitions, so the hover state will not be animated for those browsers.  Otherwise it looks and functions the same, which I think is a very acceptable fallback.  IE7 lacks support the <code>:before</code> and <code>:after</code> pseudo-elements, so the ribbon will not have the forked ends or display folds while hovering.  The pseudo-elements could be replaced with actual markup IE7 support is needed.</p>

<h2>The HTML</h2>

<pre><code>&lt;div class='ribbon'&gt;
    &lt;a href='#'&gt;&lt;span&gt;Home&lt;/span&gt;&lt;/a&gt;
    &lt;a href='#'&gt;&lt;span&gt;About&lt;/span&gt;&lt;/a&gt;
    &lt;a href='#'&gt;&lt;span&gt;Services&lt;/span&gt;&lt;/a&gt;
    &lt;a href='#'&gt;&lt;span&gt;Contact&lt;/span&gt;&lt;/a&gt;
&lt;/div&gt;
</code></pre>

<p>The forked ends and folds are created with CSS pseudo-elements, allowing for very clean HTML.</p>

<h2>The CSS</h2>

<h3>Forked ends</h3>

<pre><code>.ribbon:after, .ribbon:before {
    margin-top:0.5em;
    content: "";
    float:left;
    border:1.5em solid #fff;
}

.ribbon:after {
    border-right-color:transparent;
}

.ribbon:before {
    border-left-color:transparent;
}
</code></pre>

<p>Here the <code>:before</code> and <code>:after</code> pseudo-elements are used to create empty elements with a thick border. The border has one edge set to transparent.  This leaves the element looking like it had a triangular section removed, creating the forked look.</p>

<h3>Links</h3>

<pre><code>.ribbon a:link, .ribbon a:visited { 
    color:#000;
    text-decoration:none;
    float:left;
    height:3.5em;
    overflow:hidden;
}
</code></pre>

<p>The links and the forked ends are all floated left so that they fit flush against each other.  The hidden overflow hides the folds that are positioned beneath the span elements.</p>

<h3>Animated Folds</h3>

<pre><code>.ribbon span {
    background:#fff;
    display:inline-block;
    line-height:3em;
    padding:0 1em;
    margin-top:0.5em;
    position:relative;

    -webkit-transition: background-color 0.2s, margin-top 0.2s;  /* Saf3.2+, Chrome */
    -moz-transition: background-color 0.2s, margin-top 0.2s;  /* FF4+ */
    -ms-transition: background-color 0.2s, margin-top 0.2s;  /* IE10 */
    -o-transition: background-color 0.2s, margin-top 0.2s;  /* Opera 10.5+ */
    transition: background-color 0.2s, margin-top 0.2s;
}

.ribbon a:hover span {
    background:#FFD204;
    margin-top:0;
}

.ribbon span:before {
    content: "";
    position:absolute;
    top:3em;
    left:0;
    border-right:0.5em solid #9B8651;
    border-bottom:0.5em solid #fff;
}

.ribbon span:after {
    content: "";
    position:absolute;
    top:3em;
    right:0;
    border-left:0.5em solid #9B8651;
    border-bottom:0.5em solid #fff;
}
</code></pre>

<p>A nifty trick for vertically centering text inside of an element is to set the line-height to be the desired height of the element, and remove any vertical padding. This will keep the height fixed and the text centered, even if the font-face, font-size, or font-weight changes.</p>

<p>The top-margin gives the span space to be animated while staying within the anchor element. The span is given a relative position so that it will be the positioning reference for it's absolutely positioned <code>:before</code> and <code>:after</code> pseudo-elements.</p>

<p>A CSS3 transition animates the transition between the span's normal state and it's hover state. Transitions are an experimental feature and are not yet part of the CSS3 specification.  As such, each browser has implemented transitions using their respective vendor prefix. The non-prefixed transition property is used under the assumption that, in the future, the property will be a part of the CSS specification.</p>

<p>The :before and :after pseudo-elements create the folded edges when hovering a link.  They are absolutely positioned underneath the span element, and will normally be hidden due to the anchor element having a hidden overflow.  The pseudo-elements contain only a bottom border and a left or right border. Since the borders are as thick as they are long (0.5 x 0.5) and are adjacent, it creates two triangles for us to apply a color to.  The bottom borders will be the same color as the ribbon, and the left or right borders will have the color of the folded edge.</p>

<h3>See The <a href="/demo/ribbon.html">Demo</a></h3>]]></description></item><item><title>jQuery Modal Tutorial</title><link>http://www.jacklmoore.com/notes/jquery-modal-tutorial</link><guid>http://www.jacklmoore.com/notes/jquery-modal-tutorial</guid><pubDate>Fri, 20 Jan 2012 12:00:00 z</pubDate><description><![CDATA[<h3>See The <a href='/demo/modal/modal2.html'>Demo</a></h3>

<h2>Drafting the HTML</h2>

<p>I like to create a rough draft just using HTML and CSS, leaving the scripting for last.  I'll write the HTML first to structure the modal, even though the final HTML will be generated by the script.</p>

<pre><code>&lt;div id='overlay'&gt;&lt;/div&gt;
&lt;div id='modal'&gt;
    &lt;div id='content'&gt;No JavaScript Yet!&lt;/div&gt;
    &lt;a href='#' id='close'&gt;close&lt;/a&gt;
&lt;/div&gt;
</code></pre>

<p>This modal will have two root elements: <code>#overlay</code> and <code>#modal</code>.  The overlay is going to be a semi-transparent layer that fills the visitor's viewport. This turns the modal into a focal point, and reduces focus for the rest of the page.</p>

<h2>The CSS</h2>

<pre><code>#overlay {
    position: fixed; 
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: #000;
    opacity: 0.5;
    filter: alpha(opacity=50);
}
</code></pre>

<p>The overlay has a fixed position that is relative to the visitor's viewport.  The 100% width and height refer to the viewport size, so we get complete coverage no matter what part of the page the visitor is actually viewing. Unfortunately, fixed position is not supported in iOS 4 or below.  IE8 and IE7 do not support opacity, so an alpha filter is used instead.</p>

<pre><code>#modal {
    position:absolute;
    background:url(tint20.png) 0 0 repeat;
    background:rgba(0,0,0,0.2);
    border-radius:14px;
    padding:8px;
}

#content {
    border-radius:8px;
    background:#fff;
    padding:20px;
}
</code></pre>

<p>The important thing here is that #modal will be absolutely positioned, the rest of the rules just provide a nice default appearance.</p>

<p>The RGBa background will give a black fill (0,0,0) at 20% opacity (0.2), which will overwrite the previous background property. IE8 and IE7 do not support RGBa, so they will continue to use the previous background property which uses a semi-transparent PNG background image.</p>

<p>I gave <code>#modal</code> a larger border-radius than <code>#content</code>.  This made a border that is natural looking and consistent in thickness.  IE8 and IE7 do not support border-radius and will instead display the normal square corners.</p>

<pre><code>#close {
    position:absolute;
    background:url(close.png) 0 0 no-repeat;
    width:24px;
    height:27px;
    display:block;
    text-indent:-9999px;
    top:-7px;
    right:-7px;
}
</code></pre>

<p>The close button is absolutely positioned relative #modal, since <code>#modal</code> is it's closest ancestor element with positioning.  Since I used an anchor element for the close button, it's default display of <code>inline</code> must be changed to <code>block</code> in order to apply a fixed width and height to it.  Text-indent moves the anchor's text offscreen so that it will not overlay the background image.</p>

<h3>See The <a href='/demo/modal/modal1.html'>Work In Progress</a></h3>

<h2>The Script</h2>

<p>I would like the modal to handle the following things:</p>

<ul>
<li>Create it's own HTML and append it to the document</li>
<li>Display specified content</li>
<li>Open on command</li>
<li>Close on command</li>
<li>Be positioned in the center of the viewport</li>
<li>Stay centered if the viewport is resized</li>
</ul>

<p>Let's stump out the function and variable names:</p>

<pre><code>var modal = (function(){
    var 
    method = {},
    $overlay,
    $modal,
    $content,
    $close;

    // Center the modal in the viewport
    method.center = function () {};

    // Open the modal
    method.open = function (settings) {};

    // Close the modal
    method.close = function () {};

    return method;
}());
</code></pre>

<p>Here we have a function that is immediately executed and returns an object containing the methods needed to control the modal.  This object is assigned to the modal variable.  The rest of the variables are references to their corresponding elements in the document.  Now lets fill in the missing code.</p>

<h3>Append The HTML</h3>

<pre><code>$overlay = $('&lt;div id="overlay"&gt;&lt;/div&gt;');
$modal = $('&lt;div id="modal"&gt;&lt;/div&gt;');
$content = $('&lt;div id="content"&gt;&lt;/div&gt;');
$close = $('&lt;a id="close" href="#"&gt;close&lt;/a&gt;');

$modal.hide();
$overlay.hide();
$modal.append($content, $close);

$(document).ready(function(){
    $('body').append($overlay, $modal);
});
</code></pre>

<p>This generates the same HTML structure used earlier in the guide, now created and added to the document by our script.</p>

<h3>Center Method</h3>

<pre><code>method.center = function () {
    var top, left;

    top = Math.max($(window).height() - $modal.outerHeight(), 0) / 2;
    left = Math.max($(window).width() - $modal.outerWidth(), 0) / 2;

    $modal.css({
        top:top + $(window).scrollTop(), 
        left:left + $(window).scrollLeft()
    });
};
</code></pre>

<p>Here we balance the distance between each side of the viewport and each side of the modal.  jQuery's .outerWidth() and .outerHeight() are used because borders and padding should also be factored in.  I used Math.max() so that I could be sure that no value returned would be less than 0.  This means that if the modal is larger than the visitor's viewport, it will be positioned in the top left of the viewport rather running beyond that where it could be potentially being inaccessible.  $(window).scrollTop() returns the position of the vertical scrollbar, which is the distance from the top of the document to the top of the viewport.  This needs to be added to account for any scrolling that has happened.</p>

<h3>Open Method</h3>

<pre><code>method.open = function (settings) {
    $content.append(settings.content);

    $modal.css({
        width: settings.width || 'auto', 
        height: settings.height || 'auto'
    })

    method.center();

    $(window).bind('resize.modal', method.center);

    $modal.show();
    $overlay.show();
};
</code></pre>

<p>The open method accepts an object of our settings.  It can contain three properties: content, width, height.  Content can be text, HTML, or an element/jQuery object.  We append the data from settings.content to #content, and give #modal a width and height if either was specified in the settings object.  Method.center() is called to center the modal in the viewport and is bound to the window's resize event.  This will cause the modal to re-center itself whenever the viewport changes size.  I made use of jQuery's <a href='http://docs.jquery.com/Namespaced_Events'>event namespacing</a> so that later, when we unbind the event, we can make sure not to disturb any other resize events that other scripts may have bound to the window.  The last thing we do is reveal #modal and #overlay.</p>

<h3>Close Method</h3>

<pre><code>method.close = function () {
    $modal.hide();
    $overlay.hide();
    $content.empty();
    $(window).unbind('resize.modal');
};
</code></pre>

<p>Here we hide the #modal and the #overlay and remove the content.  Then we unbind the resize event because there is no need for it when the modal is closed.  Outside of the method</p>

<h3>Close Button</h3>

<pre><code>$close.click(function(e){
    e.preventDefault();
    method.close();
});
</code></pre>

<p>The default action of the click event is canceled (the browser from redirecting to the link's href) by calling e.preventDefault(), then the close method is called.</p>

<h3>Examples Calling The Modal</h3>

<pre><code>modal.open({content: "Howdy"});

modal.open({content: "&lt;p&gt;Howdy&lt;/p&gt;"});

modal.open({content: $("&lt;p&gt;Howdy&lt;/p&gt;"), width: "500px", height: "200px"});

// Ajax
$.get('ajax.html', function(data){
    modal.open({content: data});
});
</code></pre>

<h3>See The <a href='/demo/modal/modal2.html'>Demo</a></h3>]]></description></item><item><title>jQuery Accordion Tutorial</title><link>http://www.jacklmoore.com/notes/jquery-accordion-tutorial</link><guid>http://www.jacklmoore.com/notes/jquery-accordion-tutorial</guid><pubDate>Wed, 18 Jan 2012 12:00:00 z</pubDate><description><![CDATA[<h3>First Version:</h3>

<pre><code>&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
    &lt;style&gt;
        * { margin:0; padding:0; } /* a simple reset */
        .head, li, h2 { margin-bottom:15px; }
        .head { display:block; }
        .content { display:none; }
    &lt;/style&gt;
    &lt;script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"&gt;&lt;/script&gt;
    &lt;script&gt;
        $(document).ready(function(){
            $('.head').click(function(e){
                e.preventDefault();
                $(this).closest('li').find('.content').slideToggle();
            });
        });
    &lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;ul&gt;
        &lt;li&gt;
            &lt;a href='#' class='head'&gt;Heading 1&lt;/a&gt;
            &lt;div class='content'&gt;Content 1
            &lt;/div&gt;
        &lt;/li&gt;
        &lt;li&gt;
            &lt;a href='#' class='head'&gt;Heading 2&lt;/a&gt;
            &lt;div class='content'&gt;Content 2&lt;/div&gt;
        &lt;/li&gt;
        &lt;li&gt;
            &lt;a href='#' class='head'&gt;Heading 3&lt;/a&gt;
            &lt;div class='content'&gt;Content 3&lt;/div&gt;
        &lt;/li&gt;
    &lt;/ul&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>

<h3>See the <a href="/demo/accordion.html">Demo</a></h3>

<h3>The Script</h3>

<p>The unordered list will be the structure for the accordion, with each list item being one of the panels.  I think documenting the code will make it easier to understand than trying to explain the process, so here is the same script broken up with comments:</p>

<pre><code>// Wait until the DOM is loaded, before trying to query the document
$(document).ready(function(){

    // select the .head elements, and bind an event handler to them
    $('.head').click(function(e){

        // prevent the default action of the click event
        // ie. prevent the browser from redirecting to the link's href
        e.preventDefault();

        // 'this' is the execution context of the event handler
        // it refers to the clicked .head element
        $(this)

        // Walk up the DOM tree to find the closest list item
        // It is the closest shared ancestor of both .head and .content
        .closest('li')

        // Search the list item for .content
        .find('.content')

        // Trigger the sliding animation on .content
        .slideToggle();
    });
});
</code></pre>

<h3>Problem 1: It's Jumpy</h3>

<p>The demo demonstrated that the first accordion's animation wasn't fluid at all.  jQuery miscalculated the height of the content ('.content') because jQuery gave it an absolute position before measuring the height.  This caused the dimensions to change.  Giving the content a fixed width and/or height would fix this, but that would be impractical for fluid layouts or content of varying size.  An alternative solution is to give the content's parent element a non-static position.  This will insure that the content is positioned relative to the parent, which constrains the content to the width and height we expect it to have.</p>

<pre><code>li { position:relative; }
</code></pre>

<h3>Problem 2: It's Still Jumpy</h3>

<p>There is a bit of a jump at the start of slideDown and end of slideUp from the browser <a href="http://www.w3.org/TR/CSS21/box.html#collapsing-margins">collapsing adjoining vertical margins</a>.  When the slideUp animation completes, jQuery will hide the element being animated.  This means there will no longer be an element in the document flow between the .head element's margin and the list item's margin, triggering a collapse.  This can be prevented if the margins are separated by padding, border, or clearance.  Here are a few examples:</p>

<ul>
<li><p>Use overflow:auto or overflow:hidden on the list item to achieve clearance. I recommend using hidden overflow as auto overflow can cause additional jumping:</p>

<pre><code>li { overflow:hidden; }
</code></pre></li>
<li><p>Or use a transparent border:</p>

<pre><code>li { border-bottom:1px solid transparent; }
</code></pre></li>
<li><p>Or use padding instead of margin:</p>

<pre><code>.head, li, h2 { padding-bottom:15px; }
</code></pre></li>
</ul>

<p>There is currently an <a href="http://bugs.jquery.com/ticket/7442">open ticket</a> about this on bugs.jquery.com.</p>

<h3>Problem 3: The Animation Queues Up</h3>

<p>Clicking on the <code>&lt;h2&gt;</code> two or more times in quick succession causes the animation to queue up.  Normally <a href="http://api.jquery.com/stop/">.stop()</a> is used in this situation, but that causes a major problem with <code>.slideUp()</code>.  When called,<code>.slideUp()</code> will record the current height as the height <code>.slideDown()</code> should return to.  If <code>.stop()</code> is called during the slideDown animation, an incomplete height will be recorded making the unrevealed content inaccessible until the document is reloaded.  One way to work around that is to only call <code>$.slideToggle()</code> if the content is not currently being animated.</p>

<pre><code>$('.head').click(function(e){
    e.preventDefault();
    $(this).closest('li').find('.content').not(':animated').slideToggle();
});
</code></pre>

<h3>Caching</h3>

<p>The results of <code>$(this).closest('li').find('.content')</code> could be cached so that the document doesn't have to be queried on each interaction.  A recommended practice, but probably not worth the extra code in this case since we have to create a closure to hold it.  The click event happens infrequently (or never if the user chooses not to interact with the accordion).  If we were binding to a high frequency event, such as mousemove, caching would be much more important.</p>

<pre><code>// .each() is used to create a closure to store a cache of the query.
$('.head').each(function(){
    var $content = $(this).closest('li').find('.content');
    $(this).click(function(e){
        e.preventDefault();
        $content.not(':animated').slideToggle();
    });
});
</code></pre>

<h3>See the <a href="/demo/accordion.html">Demo</a></h3>]]></description></item><item><title>Fixing IE's Opacity Inheritance</title><link>http://www.jacklmoore.com/notes/ie-opacity-inheritance</link><guid>http://www.jacklmoore.com/notes/ie-opacity-inheritance</guid><pubDate>Tue, 17 Jan 2012 12:00:00 z</pubDate><description><![CDATA[<h3>In Internet Explorer 7, 8, 9, non-static child elements do not inherit the opacity of the parent.</h3>

<div style='opacity:0.5; filter: alpha(opacity=50); padding:15px; height:60px; border:1px solid #999; margin-bottom:15px;'>
    All of this text should have a 50% opacity...
    <div style='position:relative;'>But this line displays at full opacity in IE8 and IE7.</div>
    <div style='position:absolute;'>And this line displays at full opacity in IE9, IE8 and IE7.</div>
</div>

<pre><code>&lt;div style='opacity: 0.5; filter: alpha(opacity=50);'&gt;
    All of this text should have a 50% opacity...
    &lt;div style='position: relative'&gt;But this line displays at full opacity in IE7 and IE8.&lt;/div&gt;
    &lt;div style='position: absolute'&gt;And this line displays at full opacity in IE7, IE8 and IE9.&lt;/div&gt;
&lt;/div&gt;
</code></pre>

<p>This bug is triggered when the child element has any position other than static, regardless of the parent's position value (static, fixed, absolute, or relative). IE9 only has a problem when the child element has a fixed or absolute position, and the parent element has a static position. Maddeningly, IE7 and IE8 have other opacity related bugs which may derail alternative approaches.</p>

<h3>Workarounds</h3>

<ul>
<li>IE9: Give the parent a non-static position.</li>
<li>IE8: Have the child inherit the filter style.</li>
<li>IE7: Have the child inherit the filter style and give the parent a non-static position.</li>
</ul>

<div style='opacity:0.5; filter: alpha(opacity=50); padding:15px; height:60px; border:1px solid #999; margin-bottom:15px; position:relative'>
    All of this text has 50% opacity...
    <div style='position:relative; filter: inherit;'>Including this line.</div>
    <div style='position:absolute; filter: inherit;'>And this line.</div>
</div>

<pre><code>&lt;div style='opacity: 0.5; filter: alpha(opacity=50); position: relative;'&gt;
    All of this text has 50% opacity...
    &lt;div style='position: relative; filter: inherit;'&gt;Including this line.&lt;/div&gt;
    &lt;div style='position: absolute; filter: inherit;'&gt;And this line.&lt;/div&gt;
&lt;/div&gt;
</code></pre>

<p>Alternatively, a new alpha filter could be set on the child elements.  This could be useful in situations where inheriting the parent's filters is undesirable.</p>

<pre><code>&lt;div style='opacity: 0.5; filter: alpha(opacity=50); position: relative'&gt;
    All of this text has 50% opacity...
    &lt;div style='position: relative; filter: alpha(opacity=50);'&gt;Including this line.&lt;/div&gt;
    &lt;div style='position: absolute; filter: alpha(opacity=50);'&gt;And this line.&lt;/div&gt;
&lt;/div&gt;
</code></pre>

<p>A caveat to having a filter on the child element is that IE9 will apply both the child's filter and the parent's filter and/or opacity.  The examples above effectively have a 25% opacity in IE9 (50% of 50%).  Use conditional CSS to target IE8 and lower when setting the child's alpha filter.</p>]]></description></item><item><title>jQuery Tabs Tutorial</title><link>http://www.jacklmoore.com/notes/jquery-tabs</link><guid>http://www.jacklmoore.com/notes/jquery-tabs</guid><pubDate>Fri, 23 Dec 2011 12:00:00 z</pubDate><description><![CDATA[<iframe class='demo' src='/demo/tabs.html' style=' height:180px;' frameborder='0'></iframe>

<h3>Writing the Markup</h3>

<p>Lets start by writing our markup as if our visitor doesn't even have JavaScript enabled.  Even if you do not wish to support users without JavaScript, it is still a good pattern to follow to exercise <a href="http://en.wikipedia.org/wiki/Separation_of_concerns">separation of concerns</a>.</p>

<pre><code>&lt;ul class='tabs'&gt;
    &lt;li&gt;&lt;a href='#tab1'&gt;Tab 1&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href='#tab2'&gt;Tab 2&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href='#tab3'&gt;Tab 3&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div id='tab1'&gt;
    &lt;p&gt;Hi, this is the first tab.&lt;/p&gt;
&lt;/div&gt;
&lt;div id='tab2'&gt;
    &lt;p&gt;This is the 2nd tab.&lt;/p&gt;
&lt;/div&gt;
&lt;div id='tab3'&gt;
    &lt;p&gt;And this is the 3rd tab.&lt;/p&gt;
&lt;/div&gt;
</code></pre>

<p>I used fragment identifiers (<code>#tab1</code>, <code>#tab2</code>, <code>#tab3</code>) for the href values in the navigation.  Each element containing a tab's content is given an ID that corresponds to a fragment identifier.  This way the links are semantic and continue to be functional even if the visitor has JavaScript disabled.</p>

<p>A nice side effect of using only a fragment identifier for the href value is that retrieving the value through jQuery's .attr() method will give us the exact selector we need to query the document for that tab's content, ie. <code>$('ul.tabs a').attr('href')</code> will return <code>#tab1</code>.</p>

<h3>Writing the jQuery</h3>

<p>Rather than describing the code, I am just going to include it with comments that explain each step.</p>

<pre><code>$('ul.tabs').each(function(){
    // For each set of tabs, we want to keep track of
    // which tab is active and it's associated content
    var $active, $content, $links = $(this).find('a');

    // Use the first link as the initial active tab
    $active = $links.first().addClass('active');
    $content = $($active.attr('href'));

    // Hide the remaining content
    $links.not(':first').each(function () {
        $($(this).attr('href')).hide();
    });

    // Bind the click event handler
    $(this).on('click', 'a', function(e){
        // Make the old tab inactive.
        $active.removeClass('active');
        $content.hide();

        // Update the variables with the new link and content
        $active = $(this);
        $content = $($(this).attr('href'));

        // Make the tab active.
        $active.addClass('active');
        $content.show();

        // Prevent the anchor's default click action
        e.preventDefault();
    });
});
</code></pre>

<p><a href="/demo/tabs.html">See the complete document</a>. I used jQuery's <a href="http://api.jquery.com/on/">.on()</a> method for event binding, so be sure to use jQuery 1.7 or higher.</p>]]></description></item><item><title>HTML5 Placeholder Attribute</title><link>http://www.jacklmoore.com/notes/form-placeholder-text</link><guid>http://www.jacklmoore.com/notes/form-placeholder-text</guid><pubDate>Tue, 8 Nov 2011 12:00:00 z</pubDate><description><![CDATA[<h2>Placeholder</h2>

<p>Placeholder text is a short example or hint text that is shown in a form field when the field is unfocused and has no input from the user.  Designers like to use placeholders to make forms smaller, as smaller things appear to be simpler.</p>

<form action='#' method='get' style='padding:15px 15px 0; margin-bottom:14px; background:#F4EFE9 url(/img/tiles/wood.png);'>
    <input type='text' name='demo-name' placeholder='Name' style='width:40%; background:#fff;'/><br/>
    <input type='text' name='demo-email' placeholder='Email Address' style='width:40%; background:#fff;'/><br/>
    <textarea name='demo-comment' placeholder='Message' style='width:95%; background:#fff;'></textarea><br/>
    <input type='submit' value='Submit' onclick='return false;'/>
</form>

<p>While the adding &amp; removing of placeholder text on field focus has long been accomplished through JavaScript, there is now a <a href="http://www.w3.org/TR/html5/common-input-element-attributes.html#attr-input-placeholder">placeholder attribute</a> in the HTML5 working draft.  Most modern browsers support the placeholder attribute and will automatically add/replace the placeholder text.  They will also automatically exclude the placeholder from being sent when the form is submitted.  However, versions of Internet Explorer prior to IE10 do not support the attribute.</p>

<pre><code>&lt;input type='text' name='email' placeholder='Email Address'/&gt;
</code></pre>

<h3>Supporting Older Browsers</h3>

<p>It is very easy to detect placeholder support (or lack of) and duplicate the effect with a bit of JavaScript for older browsers.</p>

<pre><code>&lt;script&gt;
    // placeholder polyfill
    $(document).ready(function(){
        function add() {
            if($(this).val() == ''){
                $(this).val($(this).attr('placeholder')).addClass('placeholder');
            }
        }

        function remove() {
            if($(this).val() == $(this).attr('placeholder')){
                $(this).val('').removeClass('placeholder');
            }
        }

        // Create a dummy element for feature detection
        if (!('placeholder' in $('&lt;input&gt;')[0])) {

            // Select the elements that have a placeholder attribute
            $('input[placeholder], textarea[placeholder]').blur(add).focus(remove).each(add);

            // Remove the placeholder text before the form is submitted
            $('form').submit(function(){
                $(this).find('input[placeholder], textarea[placeholder]').each(remove);
            });
        }
    });
&lt;/script&gt;
</code></pre>

<p>To enable styling, this script adds a class of 'placeholder' while the placeholder text is being displayed.</p>

<h3>Styling The Placeholder</h3>

<p>Since placeholder has yet to be standardized, styles are applied through vendor-specific prefixes.  Even though Opera 11 supports the placeholder attribute, it does not offer any way to style it at this time. It's a good idea to go ahead and specify at least the color property to normalize the color between browsers.  Otherwise, a default style will be provided which will vary from browser to browser.</p>

<pre><code>::-webkit-input-placeholder { color:#999; }
:-moz-placeholder { color:#999; }
:-ms-input-placeholder { color:#999; }
.placeholder { color:#999; }
</code></pre>

<p>Unfortunately, the rules can not be combined into a single statement as a browser will not recognize vendor-specific selectors from other browser makers, resulting in an invalid rule that prevents the styles from being applied.  John Catterfeld compiled a nifty <a href='http://blog.ajcw.com/2011/02/styling-the-html5-placeholder/'>list of CSS properties</a> can be applied to placeholders.</p>]]></description></item><item><title>NaturalWidth and NaturalHeight in IE</title><link>http://www.jacklmoore.com/notes/naturalwidth-and-naturalheight-in-ie</link><guid>http://www.jacklmoore.com/notes/naturalwidth-and-naturalheight-in-ie</guid><pubDate>Sun, 23 Oct 2011 12:00:00 z</pubDate><description><![CDATA[<h3>Actual width and height in modern browsers</h3>

<p>Modern browsers (including IE9) provide naturalWidth and naturalHeight properties to IMG elements.  These properties contain the actual, non-modified width and height of the image.</p>

<pre><code>var 
nWidth = document.getElementById('example').naturalWidth,
nHeight = document.getElementById('example').naturalHeight;
</code></pre>

<h3>Actual width and height in IE8 and IE7</h3>

<p>The naturalWidth and naturalHeight properties are not supported in IE8 or lower.  The height and width property will give the apparent width and height after stylesheet and inline styles, inline width and height attributes, and the display property of the image and the image's parent elements have been applied.  The simplest way to get the unmodified width and height is to create a new image element, and use it's width and height property.</p>

<pre><code>function getNatural (DOMelement) {
    var img = new Image();
    img.src = DOMelement.src;
    return {width: img.width, height: img.height};
}

var 
natural = getNatural(document.getElementById('example')),
nWidth = natural.width,
nHeight = natural.height;
</code></pre>

<h3>jQuery naturalWidth() and naturalHeight()</h3>

<p>Here is a short jQuery (any version) plugin that adds two methods: naturalWidth() and naturalHeight().  It uses branching to determine if naturalWidth and naturalHeight are supported by the browser.  If supported, the method just becomes a getter for the naturalWidth or naturalHeight property.  If not supported, the method creates a new unstyled image element and returns that element's actual width and height.</p>

<pre><code>// adds .naturalWidth() and .naturalHeight() methods to jQuery
// for retreaving a normalized naturalWidth and naturalHeight.
(function($){
  var
  props = ['Width', 'Height'],
  prop;

  while (prop = props.pop()) {
    (function (natural, prop) {
      $.fn[natural] = (natural in new Image()) ? 
      function () {
        return this[0][natural];
      } : 
      function () {
        var 
        node = this[0],
        img,
        value;

        if (node.tagName.toLowerCase() === 'img') {
          img = new Image();
          img.src = node.src,
          value = img[prop];
        }
        return value;
      };
    }('natural' + prop, prop.toLowerCase()));
  }
}(jQuery));

// Example usage:
var 
nWidth = $('img#example').naturalWidth(),
nHeight = $('img#example').naturalHeight();
</code></pre>]]></description></item><item><title>ColorBox with Flickr Feed</title><link>http://www.jacklmoore.com/notes/colorbox-with-json-or-flickr</link><guid>http://www.jacklmoore.com/notes/colorbox-with-json-or-flickr</guid><pubDate>Mon, 10 Oct 2011 12:00:00 z</pubDate><description><![CDATA[<h3>Step 1: Include jQuery and ColorBox</h3>

<p>Feel free to jump straight to <a href='/demo/flickr.html'>the demo</a> to view-source. We will be building off of this basic HTML5 document:</p>

<pre><code>&lt;!doctype html&gt;
&lt;html&gt;
    &lt;head&gt;
        &lt;link rel="stylesheet" href="colorbox.css" /&gt;
        &lt;script src="jquery.min.js"&gt;&lt;/script&gt;
        &lt;script src="jquery.colorbox-min.js"&gt;&lt;/script&gt;
        &lt;script&gt;
            // our code
        &lt;/script&gt;
    &lt;/head&gt;
    &lt;body&gt;
    &lt;/body&gt;
&lt;/html&gt;
</code></pre>

<h3>Step 2: Get Flickr's JSON data</h3>

<p>The first thing we will want to do is use jQuery to fetch the JSON object from Flickr's public feed.  We will use the data in that JSON object to create the markup for our gallery. The data set returned by the feed can be <a href='http://www.flickr.com/services/feeds/docs/photos_public/'>filtered by tags and can include multiple users</a>.  Properties for these can be added to the <code>params</code> object below, but this demo will just be using the default settings.</p>

<pre><code>var, params = {
    id: '68459092@N06', // my Flickr User ID
    format: 'json',
    jsoncallback: '?'
},
feedURL = 'http://api.flickr.com/services/feeds/photos_public.gne',
feedQuery = decodeURIComponent($.param(params));

$.getJSON(feedURL + '?' + feedQuery, buildLinks);
</code></pre>

<p>I recommend taking a moment to view the <a href='http://api.flickr.com/services/feeds/photos_public.gne?id=68459092@N06&amp;format=json&amp;jsoncallback=?' target='_blank'>raw JSON data</a>.  The <code>items</code> property contains an array of objects that contain all of the data needed to create the links and thumbnails.  The URL to the photo is found in the <code>media</code> object.  This URL is formatted to give the 'small' size of the photo.  We will have to alter this URL to give us a larger size to display in ColorBox and again to give us a smaller size to use for a thumbnail.  Fortunately we just have to exchange the <a href="http://www.flickr.com/services/api/misc.urls.html">size suffix</a> with the suffix for the size we want.</p>

<h3>Step 3: Build the Links</h3>

<p>Let's create the anchor elements, assign ColorBox to them, and add them to our document:</p>

<pre><code>function buildLinks (json) {
    var 
    photo,
    $links = $(), 
    $thumb,
    $anchor;

    while ( photo = json.items.pop() ){
        $anchor = $('&lt;a/&gt;').attr({
            // get the medium-large size photo
            href: photo.media.m.replace('_m', '_z'),
            title: photo.title
        });

        $thumb = $('&lt;img/&gt;').attr({
            // get the small-square size thumbnail photo
            src: photo.media.m.replace('_m', '_s'),
            alt: photo.title
        }).appendTo($anchor);

        $links = $links.add($anchor);
    }

    $links.colorbox({rel:'flickr', speed:0});

    // Wait until the DOM has loaded before trying to append to the body
    $(document).ready(function () {
        $('body').append($links);
    });
}
</code></pre>

<p><a href="/demo/flickr.html">View the demo</a> and see it all put together.</p>

<h3>Notes</h3>

<ul>
<li>I'm aware this code isn't the most efficient or robust, but hopefully it made for a clear demo.</li>
<li>Currently our thumbnails are in descending order by date.  To list the thumbnails in ascending order, replace <code>json.items.pop()</code> with <code>json.items.shift()</code>.</li>
</ul>]]></description></item><item><title>Threadless Reprint</title><link>http://www.jacklmoore.com/notes/tragedy-struck-on-threadless</link><guid>http://www.jacklmoore.com/notes/tragedy-struck-on-threadless</guid><pubDate>Wed, 5 Oct 2011 12:00:00 z</pubDate><description><![CDATA[<div style="background:#533C2C; margin-bottom:10px"><img src='/img/tragedy-struck-on-threadless.png' width='590' height='427' alt='My Threadless print' style="margin:auto; display:block;"/></div>

<p><a href="http://www.threadless.com/product/1051/Tragedy_Struck">Link</a></p>]]></description></item><item><title>Working with JavaScript click events</title><link>http://www.jacklmoore.com/notes/click-events</link><guid>http://www.jacklmoore.com/notes/click-events</guid><pubDate>Sat, 20 Aug 2011 12:00:00 z</pubDate><description><![CDATA[<h2>A Greedy Click Event</h2>

<pre><code>// Example of a typical click-event binding:
jQuery('a#example').click(function(e){
    console.log('click!');
    e.preventDefault();
});
</code></pre>

<p>Here the click event has been intercepted and the default behavior canceled to prevent the browser from being directed to a new location.  Depending on the situation, this may cancel more actions than intended.  <strong>A middle-button click or ctrl+click (open in new tab), shift+click (open in new window), or alt+click (download) would be canceled as well</strong>.</p>

<p>If the intention was to only cancel an unmodified left-click, then other mouse buttons and event modifiers should be filtered out.</p>

<h2>A Discriminating Click Event</h2>

<pre><code>$('a#example').mousedown(function(e){
    if (e.which == 1 &amp;&amp; !(e.shiftKey || e.altKey || e.metaKey)) {
        $(this).unbind('click.lc').bind('click.lc', function(event){
            console.log('click!');
            event.preventDefault();
        });
    }
});
</code></pre>

<p>This would be much more involved if it were not for jQuery normalizing the event object to W3C standards:</p>

<ul>
<li>Event.which is the normalized button identifier (left-click will be '1' for all browsers).</li>
<li>Event.metaKey is the normalized ctrl (for PC) and command (for MacOS) event modifier.</li>
<li>Event.preventDefault() is the normalized method for stopping the browser's default action.</li>
</ul>

<p>The reason to detect the mousedown seperately from the click event itself is that IE only provides button identification for mousedown and mouseup events.  There is no way to detect which mouse button was clicked from a click event object in IE.  Since the mousedown event does not necessarily preceed a click event, the click event handler should be unbound first to insure that it is not applied multiple times.  I namedspaced the event ('.lc' for 'left-click') so that any unrelated event handlers would not be unbound as well.</p>

<p>A <em>Good Enough</em> approach would be to simply ignore IE's lack of button identification:</p>

<pre><code>$('a#example').click(function(e){
    if (!(e.which &gt; 1 || e.shiftKey || e.altKey || e.metaKey)) {
        console.log('click!');
        e.preventDefault();
    }
});
</code></pre>

<p>This works perfectly for non-IE browsers because the lowest button identifier is 1, and that is for the left-mouse-button.  If e.which is greater than 1, then it had to have been from another mouse-button.  For click events, jQuery sets e.which to 0 for every mouse-button in IE.  Not being able to identify which mouse-button is not that important in most cases.  The right-mouse-button does not need to be identified because it does not generate a click event, it generates a contextmenu event.  In IE the default behavior of a middle-click on anchor elements with a valid non-fragment href property cannot be canceled, so there is no need to identify it for purposes of exclusion.</p>]]></description></item><item><title>JavaScript: working with URLs and GET</title><link>http://www.jacklmoore.com/notes/javascript-url-querystring-get</link><guid>http://www.jacklmoore.com/notes/javascript-url-querystring-get</guid><pubDate>Wed, 3 Aug 2011 12:00:00 z</pubDate><description><![CDATA[<p>I am frequently asked about how to deal with JavaScript that depends on parameters in a URL.  This topic has been exhaustively covered so there isn't anything new here.  MooTools, Prototype, and jQuery users should know that those libraries already have (better) serialize methods, such as jQuery's <a href='http://api.jquery.com/jQuery.param/'>param</a>.  Ben Alman wrote a much more sophisticated unserialize method called <a href='http://benalman.com/code/projects/jquery-bbq/examples/deparam/'>deparam</a> that is available as a jQuery plugin. However, I still felt like writing my own and hopefully someone will find it useful.</p>

<h3>Methods</h3>

<table>
  <tr>
    <td>URL.serialize(parameters)</td>
    <td>Accepts an object of parameters and returns a querystring.</td>
  </tr>
  <tr>
    <td>URL.unserialize(querystring)</td>
    <td>Accepts a querystring and returns an object of parameters.</td>
  </tr>
  <tr>
    <td>URL.parse(url)</td>
    <td>Accept any valid URL and breaks it into it's components, such as host, hash (fragment), and search (querystring).</td>
  </tr>
</table>

<h3>Usage</h3>

<pre><code>URL.serialize({name:'Tom', age:50, hobby:'fishing &amp; gardening'});
//  returns name=Tom&amp;age=50&amp;hobby=fishing%20%26%20gardening

URL.unserialize('name=Tom&amp;age=50&amp;hobby=fishing%20%26%20gardening');
//  returns {name:"Tom", age:"50", hobby:"fishing &amp; gardening"}

URL.parse('http://www.example.com:8080/blog/index.php?pageID=2&amp;query="parts"#top');
//  returns
//  {
//      file: "index.php",
//      hash: "#top",
//      host: "www.example.com:8080",
//      hostname: "www.example.com",
//      href: "http://www.example.com:8080/blog/index.php?pageID=2&amp;query="parts"#top",
//      params: {pageID:"2", query:"parts"},
//      pathname: "/blog/index.php",
//      port: "8080",
//      protocol: "http:",
//      search: "?pageID=2&amp;query=%22parts%22"
//  }
</code></pre>

<h3>Source</h3>

<pre><code>var URL = (function (a) {
    return {
        // create a querystring from a params object
        serialize: function (params) { 
            var key, query = [];
            for (key in params) {
                query.push(encodeURIComponent(key) + "=" + encodeURIComponent(params[key]));
            }
            return query.join('&amp;');
        },

        // create a params object from a querystring
        unserialize: function (query) {
            var pair, params = {};
            query = query.replace(/^\?/, '').split(/&amp;/);
            for (pair in query) {
                pair = query[pair].split('=');
                params[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);
            }
            return params;
        },

        parse: function (url) {
            a.href = url;
            return {
                // native anchor properties
                hash: a.hash,
                host: a.host,
                hostname: a.hostname,
                href: url,
                pathname: a.pathname,
                port: a.port,
                protocol: a.protocol,
                search: a.search,
                // added properties
                file: a.pathname.split('/').pop(),
                params: URL.unserialize(a.search)
            };
        }
    };
}(document.createElement('a')));
</code></pre>]]></description></item><item><title>Solving IE7 &amp; IE8 PNG Opacity Problems</title><link>http://www.jacklmoore.com/notes/ie-transparency-problems</link><guid>http://www.jacklmoore.com/notes/ie-transparency-problems</guid><pubDate>Mon, 18 Jul 2011 12:00:00 z</pubDate><description><![CDATA[<h2>PNG Alpha-transparencies</h2>

<pre><code>/* Normal CSS background using an PNG with an alpha transparency */
#demo {
    background:url(ie8-logo.png) 0 0 no-repeat;
}
</code></pre>

<p>IE7 and IE8 have native PNG support for alpha-transparencies, but it falls to pieces as soon as opacity comes into the picture.  When setting any value for opacity, even 100% (ie. <code>filter: alpha(opacity = 100)</code>), IE fills in the alpha-transparency of the PNG with a pure black fill.  This is sometimes refered to as a 'black halo'.  The alpha filter can be removed at any time to remove the fill and restore the alpha transparency, but supporting both requires using more of IE's propriatary filters.  All of the follow examples should be placed in a IE-targeted <a href="http://www.quirksmode.org/css/condcom.html">conditional comment</a>.</p>

<h3>Screenshot</h3>

<p><img src="/img/alpha-demo.png" alt="" title="" /></p>

<h3>Gradient filter fix</h3>

<p>This is a great little hack that avoids the drawbacks associated with using AlphaImageLoader.  The caveat is that it does not work for IE6, and the PNG may need to be tweaked a bit for it to display correctly.</p>

<pre><code>#demo {
    background:url(ie8-logo.png) 0 0 no-repeat;
    filter: progid:DXImageTransform.Microsoft.gradient(
        startColorstr=#00FFFFFF, endColorstr=#00FFFFFF
    );
}
</code></pre>

<p>ColorBox uses this technique for alpha channel support in IE8 and IE7.  Credit for this technique goes to <a href="http://www.sitepoint.com/forums/javascript-15/jquery-fadein-fadeout-transparent-png-ie7-chrome-590295.html">Dan Tello</a>, and to <a href="https://github.com/Lukom">Lukom</a> for bringing it to my attention.</p>

<h3>AlphaImageLoader filter fix</h3>

<pre><code>#demo {
    background: transparent;
    filter:
    progid:DXImageTransform.Microsoft.AlphaImageLoader(src=ie8-logo.png,sizingMethod='crop');
}
</code></pre>

<p>This is a less robust solution than the gradient filter, however it works well and is supported for IE6-IE8.  The AlphaImageLoader filter displays an image between the background and the content.</p>

<p><strong>It is treated like an image element and not a CSS background-image, so it loses CSS properties like background-position and background-repeat.  Also, it's src is relative to the current HTML document unlike a CSS background-image which path is relative to the CSS document.</strong>  An absolute path or path that is relative to the root can be used to avoid some of the document to document path confusion.  A CSS expression can be used to create a path that is relative to the CSS document as having paths relative to the HTML document can impractical, especially for code that is distributed or reuable.</p>

<pre><code>#demo {
    background:url(ie8-logo.png) 0 0 no-repeat;
    behavior:
    expression(this.src = this.src ?
        this.src : this.currentStyle.backgroundImage.split('"')[1],
        this.style.background = "none",
    this.style.filter =
        "progid:DXImageTransform.Microsoft.AlphaImageLoader(src="
        + this.src + ",sizingMethod='crop')");
}
</code></pre>

<p>This is how ColorBox enables PNG alpha-transparency support in IE6.  Using CSS expressions are not supported in IE8 and their use is discouraged in general, but IE6 users have limited options here.</p>

<h2>ClearType Issues</h2>

<p>IE7 &amp; IE8 lose ClearType whenever there an opacity filter is applied (ie. <code>filter: alpha(opacity=50)</code>).  It even happens when the opacity is set to 100%.  There are a couple of things that can be done to improve the situation. 1. Use a background fill if possible.  2. Remove the filter in situations where it would be at 100%.  For example, if you animated an element from having 0 opacity to having 100% opacity.</p>

<p><img src="/img/cleartype.png" alt="" title="" /></p>

<h2>Opacity Inheritance</h2>

<p>IE7, IE8, and IE9 all have some sort of defective <a href="/notes/ie-opacity-inheritance">opacity inheritance</a>.</p>]]></description></item><item><title>JavaScript: Slice, Substring, or Substr?</title><link>http://www.jacklmoore.com/notes/substring-substr-slice-javascript</link><guid>http://www.jacklmoore.com/notes/substring-substr-slice-javascript</guid><pubDate>Sat, 25 Jun 2011 12:00:00 z</pubDate><description><![CDATA[<p>In JavaScript, substrings are primarily extracted through one of following String methods:
<a href="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/slice">slice</a>, 
<a href="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/substring">substring</a>, 
<a href="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/substr">substr</a>.</p>

<pre><code>// slice 
// syntax: string.slice(start [, stop])
"Good news, everyone!".slice(5,9); // extracts 'news'

// substring 
// syntax: string.substring(start [, stop])
"Good news, everyone!".substring(5,9); // extracts 'news'

// substr
// syntax: string.substr(start [, length])
"Good news, everyone!".substr(5,4); // extracts 'news'
</code></pre>

<p>All three of these methods take in a start index and an optional stop index (or length) parameter, but they differ in some important ways:</p>

<ul>
<li>substr can give inconsistent results.  If the starting index is negative, substr will either return the whole string (Internet Explorer) or extract from the end of the string (other browsers).</li>
<li>substring swaps it's parameters if the starting index is greater than the stopping index (start &gt; stop).</li>
<li>substring returns the entire string if the starting index is negative.</li>
<li>slice extracts from the end of the string if the starting index is negative.<br/><code>Good news, everyone!".slice(-4); // extracts 'one!'</code></li>
</ul>

<p>Since all three methods have <a href="http://jsperf.com/substring-extraction-methods-substring-substr-slice">roughly equivalent performance</a>, my preference is to use slice.  It supports extracting from the end of the string and I feel that returning an empty string when start index &gt; stop follows the <a href="http://en.wikipedia.org/wiki/Principle_of_least_astonishment">principle of least surprise</a> better than substring's swapping of parameters. I avoid substr because of the browser inconsistency.</p>]]></description></item></channel></rss>
