<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>IanLunn.co.uk</title>
	<atom:link href="http://www.ianlunn.co.uk/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.ianlunn.co.uk/blog</link>
	<description>Web Design &#38; Development</description>
	<lastBuildDate>Sat, 12 May 2012 08:13:04 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Concerns About Opera Rendering Webkit Properties</title>
		<link>http://www.ianlunn.co.uk/blog/articles/concerns-about-opera-rendering-webkit-properties/</link>
		<comments>http://www.ianlunn.co.uk/blog/articles/concerns-about-opera-rendering-webkit-properties/#comments</comments>
		<pubDate>Sat, 28 Apr 2012 10:15:28 +0000</pubDate>
		<dc:creator>Ian Lunn</dc:creator>
				<category><![CDATA[Articles]]></category>

		<guid isPermaLink="false">http://www.ianlunn.co.uk/blog/?p=2838</guid>
		<description><![CDATA[<strong>12th May 2012</strong>: Having looked into issue 1 further, it appears that the Experimental Opera Mobile Emulator is converting transition events to lowercase, which is the reason jQuery doesn't understand the oTransitionEnd event. Please see this <a href="http://jsfiddle.net/ianlunn/DBfze/" title="jsFiddle Example">jsFiddle example</a> for more information.

<strong>11th May 2012</strong>: Paul Irish <a href="http://www.youtube.com/watch?v=qiJMMDEBm0E">posted his thoughts regarding these issues</a>]]></description>
			<content:encoded><![CDATA[<p>In February, Opera announced they were planning on rendering some Webkit prefixed properties in their Opera browser. Yesterday, they released further details on this, along with an experimental build of Opera Mobile Emulator that renders Webkit prefixed properties.</p>

<p>If you&#8217;d like to know why they are doing this and how it will affect you as a developer, I encourage you to take a look at <a href="http://dev.opera.com/articles/view/opera-mobile-emulator-experimental-webkit-prefix-support/">Opera Mobile Emulator build with experimental WebKit prefix support</a>.</p>

<p>When Opera first made this announcement, I wrote <a href="http://www.ianlunn.co.uk/blog/articles/vendor-prefixing-standing-up-for-developers/">Vendor Prefixing: Standing Up for Developers</a>, where I explained that it wasn&#8217;t just developers who should be taking the blame for vendor prefixes not being implemented properly. I also mentioned that I&#8217;ve had a lot of difficulties with my personal project <a href="http://www.sequencejs.com/">Sequence.js</a>, due to an Opera bug.</p>

<p>I&#8217;ve been awaiting Opera&#8217;s post regarding exactly which Webkit prefixed properties they would render and as I anticipated, my personal project no longer works due to these changes. What&#8217;s more, they may cause issues for other websites too.</p>

<p>In this post, I will address concerns I have regarding this move and provide code examples that I believe could prove to cause trouble for Opera in the long run.</p>

<p><span id="more-2838"></span></p>

<h2>Issue 1 &#8211; jQuery Doesn&#8217;t Bind transitionEnd Events</h2>

<p><a href="http://www.sequencejs.com/">Sequence.js</a>, is a CSS3 transition based slider. It relies on transitionEnd events to be able to time the changing of slides within a slideshow.</p>

<p>In Opera Mobile Emulator Experimental, if you&#8217;re using jQuery to bind events to transitionEnd, those events, whether prefixed or non-prefixed, will no longer work:</p>

<pre><code>$(document).bind("webkitTransitionEnd oTransitionEnd", function(){
    alert("transition ended");
});
</code></pre>

<p>See a demo here: <a href="http://jsfiddle.net/5vrUP/">JSFiddle: transitionEnd Issue</a></p>

<p>I also tested binding these events in standalone JavaScript which does work, so clearly this is an issue with jQuery. I am unfamiliar with the jQuery source, so hopefully others can expand on why this is happening (or not happening as the case may be). Whilst not technically a fault with the Opera browser, existing applications that rely on these jQuery events may no longer work.</p>

<p><strong>Update</strong>: You can find the JS binding test <a href="http://jsfiddle.net/sZguZ/" title="JS Binding Test">here</a>.</p>

<p><strong>Update 12th May 2012</strong>: Having looked into this a little further, it appears the Experimental Opera Mobile Emulator is converting transition events to lowercase. So, oTransitionEnd becomes otransitionend. A workaround is to bind the lowercase version in jQuery, <a href="http://jsfiddle.net/ianlunn/DBfze/" title="jsFiddle Example">demonstrated here</a>.</p>

<h2>Issue 2 &#8211; Modernizr Returns the Webkit Prefixed Property in Opera</h2>

<p>Modernizr is used to query the features of a browser, allowing a developer to write fallbacks in the case of a browser not supporting a particular feature.</p>

<pre><code>alert(Modernizr.prefixed('transition'));​
</code></pre>

<p>See a demo here: <a href="http://jsfiddle.net/ianlunn/UCWnp/">JSFiddle: Modernizr Prefixed Issue</a></p>

<p>The above code in a Webkit browser, returns &#8220;WebkitTransition&#8221;. Now that the experimental Opera supports Webkit transitions, this query returns &#8220;WebkitTransition&#8221; too. Is this a problem? Yes. </p>

<p>As Opera mention in their post, when using prefixed properties in CSS they&#8217;ve chosen to respect the cascade, allowing a developer to place the property they want Opera to rely on below others in the rule set. If you want the Opera prefix to take precedence, place it after the Webkit prefix and vice versa. With Modernizr.prefixed(), you don&#8217;t have that choice. You just get &#8220;WebkitTransition&#8221;. You may want to treat Opera differently to a Webkit browser based on this result, but you no longer get the choice. Issue 3 supports this.</p>

<p>Again, this isn&#8217;t directly an issue with Opera but it does effect existing tools and may cause more issues for developers&#8230;even the responsible ones.</p>

<h2>Issue 3 &#8211; Opera Doesn&#8217;t Return the Transition Duration Via JavaScript</h2>

<p>This issue doesn&#8217;t just exist in the experimental Opera Mobile but it&#8217;s previous versions and the upcoming Opera 12, and is only made worse in the experimental version.</p>

<pre><code>transDuration = $("#menu").css("-o-transition-duration");
</code></pre>

<p>See a demo here: <a href="http://jsfiddle.net/ianlunn/76Les/">JSFiddle: Transition Duration Returns an Empty Value</a></p>

<p><a href="http://my.opera.com/community/forums/topic.dml?id=1145422">Opera Bug Report</a></p>

<p>When getting the transition duration of an element via jQuery or JavaScript, an empty value is returned.</p>

<p>This isn&#8217;t a result of Opera rendering Webkit properties but it does mean that the issue can no longer be avoided via querying the browsers features and serving a workaround, as mentioned in issue 2.</p>

<h2>Promoting Laziness and Punishing the Responsible</h2>

<p>I call myself a responsible developer. When developing <a href="http://www.sequencejs.com/">Sequence.js</a>, I consider all browsers and although it uses cutting edge technology, I make sure it works in older browsers too. When I came across issue 3 in Opera, I spent two days working out what the issue was and writing a workaround for it because I wanted to support Opera. I am certainly going to have to spend more time working on the project to get it working in future versions of Opera too, should this experimental approach become reality.</p>

<p>I&#8217;d like to point out that I have nothing against Opera but do I agree with this move? It&#8217;s difficult to say. I understand that they want to fix the issues created by lazy developers but at the same time, it seems that laziness is being further promoted.</p>

<p>Tweets such as:</p>

<pre><code>"I don't include the -o- prefix because I don't test in Opera because it accounts for 0.3% of our visitors. Not because I'm lazy or inept."
</code></pre>

<p>And:</p>

<pre><code>"I totally see why Opera is doing this. I'm bad at using the -o prefix, if they have parity with webkit then go for it."
</code></pre>

<p>Show that some developers are, to be frank, stupid, and in the case of the latter, encouraged to be stupid. If you can type -webkit-, then you can type -o-. How can you be &#8220;bad&#8221; at that? Does taking a couple of seconds to write an extra line (or run your whole stylesheet through <a href="http://www.prefixr.com/">Prefixr</a>) equate to the trouble your visitors may face because you didn&#8217;t include an extra prefix? Even if you&#8217;re not going to test in Opera, by not including the -o- prefix, your site will be more broken that what it is if you do include it but not test.</p>

<p>With the issues I&#8217;ve mentioned above, it seems like it&#8217;s not just laziness that is being encouraged but the responsible are being punished at the same time.</p>

<p>This isn&#8217;t about developers though. It&#8217;s supposed to be about the users. Bridging the gap so users don&#8217;t have to suffer. This I completely agree with, although the way in which Opera have approached it, I&#8217;m not so sure about.</p>

<p>They explain that they took the top 10,000 sites and analysed what -webkit- prefixed properties were used without fallback, then acted based on those findings. I think this should be reconsidered. Does Opera (or any browser for that matter) really need to support transitions? Do they benefit the user or subtract from an experience should they not be implemented? </p>

<p>Let&#8217;s not contradict the purpose of making this difficult move. This shouldn&#8217;t be about keeping up with the competition. I&#8217;d like to see Opera provide cases where a site is broken because an -o- prefix or the official property has been omitted, justifying the need to support the -webkit- one. </p>

<p>Opera, you&#8217;re being closely watched by other browsers that may want to make this move too, let&#8217;s get it right from the beginning.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ianlunn.co.uk/blog/articles/concerns-about-opera-rendering-webkit-properties/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Sequence.js Launch! The Unique CSS3 Powered Slider</title>
		<link>http://www.ianlunn.co.uk/blog/articles/sequence-js-launch/</link>
		<comments>http://www.ianlunn.co.uk/blog/articles/sequence-js-launch/#comments</comments>
		<pubDate>Tue, 14 Feb 2012 17:24:30 +0000</pubDate>
		<dc:creator>Ian Lunn</dc:creator>
				<category><![CDATA[Articles]]></category>

		<guid isPermaLink="false">http://www.ianlunn.co.uk/blog/?p=2821</guid>
		<description><![CDATA[Today I launched a jQuery plugin I&#8217;ve been working on for the last few months. It&#8217;s a slider plugin call Sequence and it&#8217;s unlike any other. Sequence doesn&#8217;t work out of the box. That sounds bad right? Usually when you &#8230;]]></description>
			<content:encoded><![CDATA[<p>Today I launched a jQuery plugin I&#8217;ve been working on for the last few months. It&#8217;s a slider plugin call <a href="http://www.sequencejs.com/">Sequence</a> and it&#8217;s unlike any other.</p>

<p><span id="more-2821"></span></p>

<p><a href="http://www.sequencejs.com/">Sequence</a> doesn&#8217;t work out of the box. That sounds bad right? Usually when you install a slider plugin, it looks and functions pretty much the same across however many sites it&#8217;s installed on. Not Sequence!</p>

<p>Not a single installation of Sequence ever has to be the same. Using only CSS3, you can style not just the looks of your website&#8217;s slider but it&#8217;s transitions too. Take a look at some of the demos:</p>

<p><a href="http://www.sequencejs.com/themes/modern-slide-in/" title="Sequence Theme - Modern Slide In"><img src="http://www.ianlunn.co.uk/blog/wp-content/uploads/2012/02/sequence-modern.jpg" alt="Sequence Theme - Modern Slide In" title="sequence-modern" width="590" height="364" class="aligncenter size-full wp-image-2823" /></a></p>

<p><a href="http://www.sequencejs.com/themes/sliding-horizontal-parallax" title="Sequence Theme - Sliding Horizontal Parallax"><img src="http://www.ianlunn.co.uk/blog/wp-content/uploads/2012/02/sequence-sliding.jpg" alt="Sequence Theme - Sliding Horizontal Parallax" title="sequence-sliding" width="590" height="369" class="aligncenter size-full wp-image-2824" /></a></p>

<p><a href="http://www.sequencejs.com/themes/apple-style/" title="Sequence Theme - Apple Style"><img src="http://www.ianlunn.co.uk/blog/wp-content/uploads/2012/02/sequence-apple.jpg" alt="Sequence Theme - Apple Style" title="sequence-apple" width="596" height="360" class="aligncenter size-full wp-image-2822" /></a></p>

<p>You can achieve an infinite amount of styles, transitions and effects using the latest web technologies. Rotate, fade, skew, 3D transform, parallax effects, you name it. Finally&#8230;you have creative freedom but still all the functionality you expect from a slider plugin.</p>

<p>Sequence also supports touch devices and responsive designs. It&#8217;s not just about the cool stuff though. Sequence also works in browsers that don&#8217;t support CSS3 using graceful fallbacks that can also be customised.</p>

<p><a href="http://www.sequencejs.com/">Sequence</a> is an open source project, so if you have feedback or would like to collaborate, follow the project on <a href="https://github.com/IanLunn/Sequence">GitHub</a>.</p>

<p>I&#8217;ll be posting a tutorial very soon to demonstrate how you can use Sequence to make your own slider theme.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ianlunn.co.uk/blog/articles/sequence-js-launch/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Vendor Prefixing: Standing Up for Developers</title>
		<link>http://www.ianlunn.co.uk/blog/articles/vendor-prefixing-standing-up-for-developers/</link>
		<comments>http://www.ianlunn.co.uk/blog/articles/vendor-prefixing-standing-up-for-developers/#comments</comments>
		<pubDate>Thu, 09 Feb 2012 11:16:38 +0000</pubDate>
		<dc:creator>Ian Lunn</dc:creator>
				<category><![CDATA[Articles]]></category>

		<guid isPermaLink="false">http://www.ianlunn.co.uk/blog/?p=2810</guid>
		<description><![CDATA[Today I came across Bruce Lawson&#8217;s article regarding vendor prefixes and the possibility that Opera, Mozilla and Microsoft will begin to implement -webkit CSS properties within their own browsers. Their argument in my opinion is justifiable; too many developers are &#8230;]]></description>
			<content:encoded><![CDATA[<p>Today I came across <a href="http://www.brucelawson.co.uk/2012/vendor-prefixes-mobile-monoculture/">Bruce Lawson&#8217;s article</a> regarding vendor prefixes and the possibility that Opera, Mozilla and Microsoft will begin to implement -webkit CSS properties within their own browsers.</p>

<p>Their argument in my opinion is justifiable; too many developers are only targeting WebKit browsers, often leaving anything other than WebKit either with a lesser experience, or worse, completely neglected and broken. By parsing -webkit CSS properties, non WebKit browsers will be able to bridge the gaps left behind by developers that haven&#8217;t done their job as well as they should/could.</p>

<p>In the articles I have read regarding this, the blame seems to be resting entirely on the shoulders of developers which I think is unfair. Shouldn&#8217;t we question why developers haven&#8217;t taken the time to develop cross browser features?</p>

<p><span id="more-2810"></span></p>

<p>In response to Bruce Lawson&#8217;s article, <a href="https://twitter.com/#!/wilto/status/166902077333848066">Mat &#8220;Wilto&#8221; Marquis tweets</a>:</p>

<blockquote>
  <p>Don’t say I didn’t warn you, makers of “iPhone websites” the world over.</p>
</blockquote>

<p>Whilst I don&#8217;t deny there is a side-blinders culture of developing for WebKit only, there are legitimate and realistic reasons for not considering other browser prefixes, of which, in some cases, the browser vendors themselves should take their fair share of blame.</p>

<p>For as long as I have been educated in the matter of cross browser compatibility, I have made every effort to make whatever I am devloping work in all browsers. I say this with a tear of frustration in my eye and a bead of sweat on my frow: cross browser compatibility is difficult!</p>

<p>Co-chairman of the W3X CSS Working Group, Daniel Glazman, writes in a <a href="http://www.glazman.org/weblog/">call for action</a>:</p>

<blockquote>
  <p>I am asking all the Web Authors community to stop designing web sites for WebKit only, in particular when adding support for other browsers is only a matter of adding a few extra prefixed CSS properties.</p>
</blockquote>

<p>Unfortunately, in many instances, Daniel Glazman&#8217;s statement just isn&#8217;t true. In a personal project I am currently working on, I spent two days developing a workaround for Opera because I wasn&#8217;t able to <a href="http://my.opera.com/community/forums/topic.dml?id=1145422">get the value of any of its vendor prefixed properties via JavaScript</a>. If it were a client project, my schedule would have been knocked off by two days and I&#8217;d be left with the decision of charging the client extra or taking the hit myself for a bug that was unforseen. I spent these extra two days developing a workaround because I believe in cross browser compatibility. Would all clients be so concerned about cross browser compatibility in a browser that doesn&#8217;t have the biggest market share?</p>

<p>I&#8217;m not just pointing a finger at Opera here and I don&#8217;t agree with ignoring a browser because it&#8217;s market share is smaller (but unfortunately clients often do), it&#8217;s merely a recent experience I had that demonstrates the difficulties developers have to face when dealing with multiple browsers.</p>

<p>Are browser vendors truly aware of their responsibility too? One bug in a browser turns into x number of bugs across x number of websites.</p>

<p>As developers we are being asked to develop cross browser compatible websites with technology that is not cross browser itself. In my experience, WebKit has the most accurate implementation of the specifications I use to build for the web. It is to be expected that a specification still in draft is not perfectly implemented across all browsers but it too should be expected that developers (and in particular their clients) cannot spend extra time and money developing different implementations of the same outcome.</p>

<p>I am not just passing the blame back to browser vendors. It is true that a lot of developers are ignorant towards browsers beyond WebKit powered ones but there are a lot of developers trying to do the right thing too, no matter how hard their job can be.</p>

<p>As far as a solution is concerned, I think Daniel Glazman is on the right track:</p>

<blockquote>
  <p>The rule should be this one: if the CSS parser encounters a prefixed property for another browser, honour that property as if it were prefixed for us UNLESS an unprefixed or prefixed for us valid declaration for that property was already set. That would drastically reduce the problems on the Web.</p>
</blockquote>

<p>This coupled with the automatic update of all browsers makes sense to me.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ianlunn.co.uk/blog/articles/vendor-prefixing-standing-up-for-developers/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>AJAX Search Suggest (WeAreHunted.com Style)</title>
		<link>http://www.ianlunn.co.uk/blog/code-tutorials/ajax-search-suggest-wearehunted/</link>
		<comments>http://www.ianlunn.co.uk/blog/code-tutorials/ajax-search-suggest-wearehunted/#comments</comments>
		<pubDate>Thu, 22 Dec 2011 11:49:45 +0000</pubDate>
		<dc:creator>Ian Lunn</dc:creator>
				<category><![CDATA[Code Tutorials]]></category>

		<guid isPermaLink="false">http://www.ianlunn.co.uk/blog/?p=2771</guid>
		<description><![CDATA[WeAreHunted.com is a music website with some great functionality that makes it unique yet highly usable. In particular, I find the way in which a user can search the site to be very intuitive and it opens up the process &#8230;]]></description>
			<content:encoded><![CDATA[<p><a href="http://wearehunted.com" title="We Are Hunted">WeAreHunted.com</a> is a music website with some great functionality that makes it unique yet highly usable. In particular, I find the way in which a user can search the site to be very intuitive and it opens up the process to be a lot more useful. The site uses the full browser window to present the user with suggestions that closely match what they are looking for. In this month&#8217;s tutorial, we&#8217;re going to create <a href="http://www.ianlunn.co.uk/demos/ajax-search-suggest-wearehunted/" title="AJAX Search Suggest (WeAreHunted.com Style)">our own version</a> of <a href="http://wearehunted.com" title="We Are Hunted">WeAreHunted.com&#8217;s</a> full screen search suggestion feature using jQuery, AJAX and PHP.</p>

<p><span id="more-2771"></span></p>

<h2>Getting Started</h2>

<p>To recreate the search suggest feature, we&#8217;re going to use jQuery and a small amount of PHP to query the server for search terms. To allow these two scripts to communicate, we&#8217;ll make use of AJAX &#8212; passing a string containing the search term from jQuery to PHP. The PHP will then return a string containing the results. We&#8217;ll make use of JSON (JavaScript Object Notation) so our search terms/results are well formatted and easily encoded/decoded between these two technologies.</p>

<p>Note that for the sake of simplicity, we&#8217;re going to use a PHP file with some search terms in it that we&#8217;ll pretend are actual results. In the real world, you&#8217;d query a database.</p>

<h2>The HTML</h2>

<p>Let&#8217;s begin by creating the interface itself. Quite simply, to launch the search feature, we just need a search button, like so:</p>

<pre><code>&lt;div id="search"&gt;
    Search
    &lt;img src="images/bt-search.jpg" alt="Search" /&gt;
&lt;/div&gt;
</code></pre>

<p>We&#8217;ve given the div an ID of &#8220;search&#8221; which will allow us to add a click event to it in the jQuery later on.</p>

<p>When the user clicks the search button, we&#8217;ll open an overlay that sits on top of the rest of the page. </p>

<pre><code>&lt;div id="search-overlay"&gt;
    &lt;h2&gt;Begin typing to search&lt;/h2&gt;
    &lt;div id="close"&gt;X&lt;/div&gt;
    &lt;form&gt;
        &lt;input id="hidden-search" type="text" autocomplete="off" /&gt;
        &lt;input id="display-search" type="text" autocomplete="off" readonly="readonly" /&gt;
    &lt;/form&gt;

    &lt;div id="results"&gt;
        &lt;h2 class="artists"&gt;Artists&lt;/h2&gt;
        &lt;ul id="artists"&gt;&lt;/ul&gt;
    &lt;/div&gt;
&lt;/div&gt;
</code></pre>

<p>Again, we&#8217;ve given the containing div an ID to allow us to interact with it via jQuery. We&#8217;ve also added another div with the ID of &#8220;close&#8221;, which, you guessed it, will close the overlay when clicked.</p>

<p>The search overlay also contains a form with not one, but two input boxes.  Why? As <a href="http://wearehunted.com" title="We Are Hunted">WeAreHunted.com</a> is a very visual site, they&#8217;ve gone to a lot of effort to make the site appear exactly as they want, meaning a small amount of trickery using two search input boxes to remove the blinking cursor from the input box. We&#8217;ll go into greater detail on this in the <a href="#the-css">The CSS</a>.</p>

<p>We also have a &#8220;results&#8221; div within the overlay that contains a list of the terms that match the users search query.</p>

<pre><code>&lt;script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="scripts/ajax-search-suggest.js"&gt;&lt;/script&gt;
&lt;link rel="stylesheet" type="text/css" media="screen" href="css/styles.css" /&gt;
</code></pre>

<p>Finally for the HTML, we need to reference the jQuery library (hosted via Google), and the jQuery and CSS files we&#8217;ll be creating shortly.</p>

<h2><a id="the-css" name="the-css">The CSS</a></h2>

<p>To begin, we&#8217;ll style the search button (the div with an ID of &#8220;search&#8221;):</p>

<pre><code>#search{
    background: #d3d3d3;
    cursor: pointer;
    font-size: 24px;
    font-weight: bold;
    text-transform: uppercase;
    padding: 20px 2%;
    width: 96%;
}
</code></pre>

<p>Obviously, you can style your search button however you want &#8212; none of the above CSS is required for the script to work correctly.</p>

<p>The overlay that will appear when we click the search button is styled like so:</p>

<pre><code>#search-overlay{
    background: black;
    background: rgba(0,0,0,0.85);
    color: white;
    display: none;
    font-size: 24px;
    height: 100%;
    padding: 20px;
    position: fixed;
    width: 100%;
}
</code></pre>

<p>Let&#8217;s take a look at this a little closer. We&#8217;ve given the overlay a background colour of black but also specified an RGBA background too. So, in newer browsers the background will appear black (RGB: 0, 0, 0) but also have an alpha opacity of 0.85 and the page behind the overlay still shows through slightly. Older browsers will simply show a solid black background.</p>

<p>The overlay has a position of &#8220;fixed&#8221; which means it will also appear within the viewport and the height/width of 100% makes sure it covers the whole viewport. Also note that we&#8217;ve set the overlay not to show using &#8220;display: none&#8221;. We&#8217;ll change this in the jQuery when a user hits the search button so it becomes visibile.</p>

<p>Now, let&#8217;s take a look at those two input boxes and understand why we need two of them:</p>

<pre><code>&lt;input id="hidden-search" type="text" autocomplete="off" /&gt;
&lt;input id="display-search" type="text" autocomplete="off" readonly="readonly" /&gt;
</code></pre>

<p>If you click on an input box in a browser, you&#8217;ll notice a blinking text cursor. This is something <a href="http://wearehunted.com" title="We Are Hunted">WeAreHunted.com</a> appear not to have wanted. Unfortunately, there&#8217;s not a CSS property we can simply apply to make it go away, so instead, we need to use two input boxes. One input box will be hidden off screen (&#8220;hidden-search&#8221;) which is where the user will type, and the second input box (&#8220;display-search&#8221;) will mirror the contents of the first box. However, the second box is set to &#8220;readonly&#8221; in the HTML, meaning the blinking cursor is removed. Each input box also turns off &#8220;autocomplete&#8221; to prevent previous search queries from appearing in a list below.</p>

<p>Let&#8217;s hide the &#8220;hidden-search&#8221; input box in the CSS:</p>

<pre><code>#hidden-search{
    left: -10000px;
    position: absolute;
}
</code></pre>

<p>Here we set the input boxes position to absolute and -10000px. This will place the box way over to the left, a long way from the viewport, where the user can&#8217;t see it.</p>

<pre><code>#display-search{
    background: none;
    border: none;
    color: white;
    font-size: 60px;
    margin: 25px 0 0 0;
    width: 960px;
}
</code></pre>

<p>Now we can style the mirrored search input box. Nothing special is required here other than simple styling.</p>

<p>Our demo also contains a close button which is styled like so:</p>

<pre><code>#close{
    cursor: pointer;
    position: fixed;
    right: 20px;
    top: 20px;
}
</code></pre>

<p>The only other notable styles are for the results list:</p>

<pre><code>#results{
    display: none;
    width: 300px;
}
</code></pre>

<p>As we did with the overlay, we&#8217;ll hide the results list until we need it, using &#8220;display: none&#8221;.</p>

<h2>The jQuery</h2>

<p>Now we have our interface set up, let&#8217;s start adding the functionality using jQuery.</p>

<h3>Showing/Hiding the Overlay</h3>

<pre><code>$(document).ready(function(){ 
    //...
}
</code></pre>

<p>We will wrap the code in jQuery&#8217;s document ready function. This will initiate as soon as the HTML and CSS has rendered (and the page is ready).</p>

<p>Once the document is ready, we&#8217;ll select some of the elements that will be used more than once; the two input boxes, the search overlay and the list of artists:</p>

<pre><code>var $hiddenSearch = $("#hidden-search"),
    $displaySearch = $("#display-search"),
    $searchOverlay = $("#search-overlay"),
    $artistsList = $("#artists");
</code></pre>

<p>Note that we&#8217;re saving these selectors to variables to improve performance (it&#8217;s good practice to save a selector you will use more than once).</p>

<p>Now we add our first click event to the search button:</p>

<pre><code>$("#search").click(function(){
    $searchOverlay.show();
    $hiddenSearch.focus();
});
</code></pre>

<p>When the &#8220;search&#8221; button is clicked, the &#8220;search-overlay&#8221; is shown (the CSS is changed from &#8220;display: none&#8221; to &#8220;display: block&#8221;) and we give the input box with ID of &#8220;hidden-search&#8221; focus. &#8220;Giving focus&#8221; is what happens when a user clicks on an input box &#8212; that box now has focus and the user can begin typing in it. Here we&#8217;re controlling the focus ourselves so as soon as the search button is clicked, the user can begin typing. Remember that the &#8220;hidden-search&#8221; input box is hidden off-screen so it&#8217;s very important we apply the focus because the user isn&#8217;t able to click the box themselves.</p>

<pre><code>$("#search-overlay").click(function(event){
    $hiddenSearch.focus();
    if(event.target.id == "search-overlay" || event.target.id == "close"){
        $hiddenSearch.blur();
        $(this).animate({"opacity": 0}, 500, function(){
            $(this).hide().css("opacity", 1); 
        });
    }
});
</code></pre>

<p>We want the &#8220;search-overlay&#8221; to close when clicked, but not in all cases. When applying click events in jQuery or JavaScript, the element it&#8217;s applied to also listens to click events on its child elements. In this case, the &#8220;search-overlay&#8221; will have quite a few children; the close button, the input boxes and the list of results. The close button should obviously close the &#8220;search-overlay&#8221; when clicked, but we don&#8217;t want the input boxes or results list to close the search overlay.</p>

<p>A child notifying it&#8217;s parent of an event is called &#8220;bubbling&#8221; or &#8220;propagation&#8221;. As we want to be selective about which elements &#8220;bubble&#8221; we can pass the event parameters into the function and query those parameters, like so:</p>

<pre><code>$("#search-overlay").click(function(event){
    //...
    if(event.target.id == "search-overlay" || event.target.id == "close"){
        //...
    }
}
</code></pre>

<p>By passing the <em>event</em>, we can query exactly which element or child element is being clicked. Here we&#8217;ve set up an if statement to determine whether the element being click is either the &#8220;search-overlay&#8221; or &#8220;close&#8221; button.</p>

<p>Now we can put all of our code to be executed when these two elements are clicked, into that if statement:</p>

<pre><code>$hiddenSearch.blur();
$(this).animate({"opacity": 0}, 500, function(){
    $(this).hide().css("opacity", 1); 
});
</code></pre>

<p>So, if the &#8220;search-overlay&#8221; or &#8220;close&#8221; button are clicked, we remove the focus from the &#8220;hidden-search&#8221; input by using .blur(). We then fade out the &#8220;search-overlay&#8221; and hide it.</p>

<p>Note that before we used the if statement to determine what element was being clicked, we added the focus to the &#8220;hidden-search&#8221; input again:</p>

<pre><code>$hiddenSearch.focus();
</code></pre>

<p>This is to make sure that if the user was clicking on an element that didn&#8217;t hide the &#8220;search-overlay&#8221;, the &#8220;hidden-search&#8221; input would still have focus (overriding whatever element the browser tried to apply focus to when the user clicked on the page).</p>

<h3>Key Events</h3>

<p>For our demo, we will use the &#8220;keydown&#8221; event, meaning whenever a user pushes down on a keyboard key, we can trigger our AJAX call to the PHP script, as well as dealing with the two input boxes we&#8217;ve created.</p>

<pre><code>$hiddenSearch.keydown(function(e){
    //...
}
</code></pre>

<p>Note for this keydown event &#8212; like the click event on the &#8220;search-overlay&#8221; &#8212; we&#8217;re passing the event into the function (this time I&#8217;ve called it &#8220;e&#8221; just for speeding up writing the following code, and in real world code, I&#8217;d call it &#8220;e&#8221; consistently &#8212; although that&#8217;s personal preference, the choice is yours).</p>

<pre><code>currentQuery = $displaySearch.val();
</code></pre>

<p>As soon as the user hits a key on their keyboard, we&#8217;re going to grab the query they&#8217;ve typed into the &#8220;display-search&#8221; input box and save it as a variable called &#8220;currentQuery&#8221;.</p>

<p>Now to make use of that event we passed into the function&#8230;</p>

<pre><code>if(e.keyCode == 8){
    //...
}
</code></pre>

<p>Here we get the keyCode from the event (&#8220;e&#8221;). Each key has a value, in the case of the above code, 8 is the backspace key. See this <a href="http://www.cambiaresearch.com/articles/15/javascript-char-codes-key-codes">reference sheet</a> for a list of key codes. So, this if statement is checking to see if the user has hit the backspace key (and is trying to delete whatever is contained in the input box).</p>

<p>Let&#8217;s skip what code is triggered when the backspace key is pressed for the moment and take a look at what happens when the user hits the alphanumberic keys (A &#8211; Z, 0 &#8211; 9):</p>

<pre><code>if(e.keyCode == 8){
    //...when the user hits the backspace key (we'll write this functionality shortly)  
}else if(e.keyCode == 32 || (e.keyCode &gt;= 65 &amp;&amp; e.keyCode &lt;= 90) || (e.keyCode &gt;= 48 &amp;&amp; e.keyCode &lt;= 57)){
    latestQuery = currentQuery + String.fromCharCode(e.keyCode);
    displaySearch.val(latestQuery);
    updateResults(latestQuery);
}
</code></pre>

<p>Key codes 32, 65 &#8211; 90 and 48 &#8211; 57 are the space bar, alphabetic keys A &#8211; Z, and numeric keys 0 &#8211; 9. Whenever the user hits one of these keys, we add the value of that key to the end of whatever the user has already added to the search input box, like this:</p>

<pre><code>latestQuery = currentQuery + String.fromCharCode(e.keyCode);
</code></pre>

<p>If the user has so far typed &#8220;AC&#8221;, when they hit the next key (&#8220;D&#8221; for example), the &#8220;currentQuery&#8221; is &#8220;AC&#8221; and the &#8220;String.fromCharCode(e.keyCode)&#8221; is &#8220;D&#8221;, making the latestQuery &#8220;ACD&#8221;.</p>

<p>&#8220;e.keyCode&#8221; will return the value of the key and by using &#8220;String.fromCharCode()&#8221;, we can turn that value in the actual key being pressed.</p>

<pre><code>$displaySearch.val(latestQuery);
</code></pre>

<p>For each key the user hits, we construct their query &#8220;latestQuery&#8221; and add it into the &#8220;display-search&#8221; input box.</p>

<p>When using key events and determining what keys the user is hitting, you usually don&#8217;t have to construct the contents and add it into the input box yourself, but remember we&#8217;re having to hack the input boxes a little because we wanted to remove the blinking text cursor.</p>

<p>Finally for the alphanumeric key down event, we have this last line of code:</p>

<pre><code>updateResults(latestQuery);
</code></pre>

<p>This is the final function in our keycode event that passes the &#8220;lastestQuery&#8221; to the PHP to try and find a match for the users query. Let&#8217;s return to the backspace key event before going into that:</p>

<pre><code>if(e.keyCode == 8){
    latestQuery = currentQuery.substring(0, currentQuery.length - 1);
    $displaySearch.val(latestQuery);
    updateResults(latestQuery);
}
</code></pre>

<p>Now we know how the alaphanumeric keys work, this should look familiar. On the first line, we construct the &#8220;latestQuery&#8221; again but this time, when the user hits the backspace key, we remove the last character from the latest query. Once that&#8217;s done, we update the &#8220;display-search&#8221; input box again and trigger the &#8220;updateResults&#8221; function to return results for the user.</p>

<h3>Returning Results using AJAX</h3>

<p>Let&#8217;s take a look at the &#8220;updateResults&#8221; function now, which is triggered whenever the user alters the contents of the input box:</p>

<pre><code>function updateResults(latestQuery){
    if(latestQuery.length &gt; 0){
        //...
    }
}else{
    $artistsList.html("&lt;li&gt;No results&lt;/li&gt;");
}
</code></pre>

<p>First and foremost, we make sure the user has actually entered a query by checking its length. If they haven&#8217;t, we update the artists list to show there weren&#8217;t any results. The &#8220;updateResults&#8221; function will only execute when the user has pressed a key so the only time the &#8220;latestQuery&#8221; length won&#8217;t be above 0 is when the user has completely deleted their query.</p>

<p>Now here&#8217;s where we use AJAX and start communicating with the PHP script:</p>

<pre><code>if(latestQuery.length &gt; 0){
    $.post("auto-suggest.php", {latestQuery: latestQuery}, function(data){
        //...do stuff with the returned results
    });
}
</code></pre>

<p>We&#8217;re posting to the PHP script &#8220;auto-suggest.php&#8221; (which we&#8217;ll look at the contents of shortly) the &#8220;latestQuery&#8221; variable which contains the users search query. We then trigger a function which passes the &#8220;data&#8221; or the result that is returned from the &#8220;auto-suggest.php&#8221; script. Within that function we will update and modify the results list based on that new result which we&#8217;ll write shortly, but for now, let&#8217;s follow the flow of the code and take a look at the PHP.</p>

<h2>The PHP</h2>

<p>The php file &#8220;auto-suggest.php&#8221; exists on the server. For the sake of this demo, we&#8217;re going to include a list of static results to query but in the real world, you&#8217;d connect to and query a database.</p>

<pre><code>&lt;?php
    include ("test-data.php");
    //...
?&gt;
</code></pre>

<p>The test data looks like this:</p>

<pre><code>$data = array(
    "ABBA" =&gt; "?search=ABBA",
    "ACDC" =&gt; "?search=ACDC",
    //...and so on
    );
</code></pre>

<p>Each result is made up of a term (&#8220;ABBA&#8221;) and a URL (&#8220;?search=ABBA&#8221;). By including the &#8220;test-data.php&#8221; file, we can now query the list of artists from our main PHP file &#8220;auto-suggest.php&#8221;.</p>

<pre><code>include ("test-data.php");
if(isset($_POST['latestQuery'])){
    //...
}
</code></pre>

<p>So once our data is included, we can test to see if the &#8220;latestQuery&#8221; variable has been posted to the PHP script (and it will have been via AJAX).</p>

<pre><code>$latestQuery = $_POST['latestQuery'];
$latestQueryLength = strlen($latestQuery);
$result = array();
</code></pre>

<p>To make things a little easier to read, we&#8217;ll turn that posted &#8220;latestQuery&#8221; into a PHP variable and count how many characters make up that query.</p>

<p>It&#8217;s possible &#8212; particularly in a real world application &#8212; that the user&#8217;s query will return more than one result so we&#8217;ve also set up an array by the name of &#8220;result&#8221;, that can hold multiple terms that match the user&#8217;s query.</p>

<pre><code>foreach($data as $name =&gt; $url){
    if (substr(strtolower($name),0,$latestQueryLength) == strtolower($latestQuery)){
        $result[$name] = $url;
    }
}
</code></pre>

<p>Now, for each item in our list of test data, we&#8217;re going to break up the item into variables, one for the term (&#8220;ABBA&#8221;), the other for its URL (&#8220;?search=ABBA&#8221;). We&#8217;ll also use an if statement to determine if the users query is contained within that term. If there is a match, we store the term and its URL within the results array. The term is used as the key and the URL its value, like so:</p>

<pre><code>ABBA : "?search=ABBA"
</code></pre>

<p>Once the loop that matches queries to terms is complete, we finally &#8220;echo&#8221; the result array after encoding it as JSON:</p>

<pre><code>echo json_encode($result);
</code></pre>

<p>&#8220;Echoing&#8221; the result returns it back to the jQuery script. By encoding it as JSON, we turn the whole array into a string which is easily passed between the PHP and jQuery via AJAX. If this seems a little overwhelming, imagine the jQuery and PHP scripts being the start and end points of a journey, AJAX is the road between the two points and JSON is the vehicle &#8212; containined within is the message we need to deliver between the two.</p>

<h2>Back to the jQuery</h2>

<p>PHP has now done it&#8217;s job and returned either an empty string (no matching terms), or a string containing atleast one matching term.</p>

<pre><code>if(data.length &gt; 0){
    data = $.parseJSON(data);
    //...code to output results
}else{
    $artistsList.html("&lt;li&gt;No results&lt;/li&gt;");
}
</code></pre>

<p>Here we determine if the PHP script returned a result or not by checking its length. When we &#8220;echoed&#8221; the results from the PHP script, we converted them to JSON.</p>

<p>If there isn&#8217;t a result, we add &#8220;No results&#8221; to the list of results. If there is atleast one result, we parse the JSON &#8212; turning it into a JavaScript object &#8212; and save that into a variable.</p>

<p>Let&#8217;s assume the user has so far typed &#8220;AC&#8221;. Querying the test data, PHP will return two results, which when parsed will look like this:</p>

<pre><code>{ACDC : "?search=ACDC", Ace of Spades : "?search=AceOfSpades"}
</code></pre>

<p>We can now use this string to output and update the results list.</p>

<pre><code>$("#artists li").remove(":contains('No results')");
$("#results").show();
</code></pre>

<p>Firstly, we do some housework. In case the results list is already showing &#8220;No results&#8221;, we&#8217;ll remove that from the list. In the CSS, we also hid the results list, so if that is yet to be displayed, we&#8217;ll change its CSS from &#8220;display: none&#8221;, to &#8220;display: block&#8221;.</p>

<pre><code>previousTerms = new Array();                    
</code></pre>

<p>Now, an easy way to update the list of results would be to clear the list everytime a  new result is returned and populate it again. This causes some undesirable flashing during the refreshing of the list though. Instead, what we&#8217;re going to do, is create an array of terms, called &#8220;previousTerms&#8221;. We will then compare the previous terms (the ones currently being displayed) with the new ones returned from the PHP script.</p>

<pre><code>$("#artists li").each(function(){
    previousTerms.push($(this).text());
});
</code></pre>

<p>For each list item in the list of results, we will add the text from that item, to the &#8220;previousTerms&#8221; array.</p>

<p>Let&#8217;s continue with our example; the user has so far typed &#8220;AC&#8221; and the PHP script has returned results. We&#8217;ll also assume that the list of results has so far shown each result for the query &#8220;A&#8221;. So the results we are yet to display, look like this:</p>

<pre><code>{ACDC : "?search=ACDC", Ace of Spades : "?search=AceOfSpades"}
</code></pre>

<p>And the &#8220;previousTerms&#8221; array looks like this:</p>

<pre><code>["ABBA" , "ACDC, "Ace of Spades"]
</code></pre>

<p>As we&#8217;re not just going to clear the whole list of results and output the new ones, we need to compare the new terms with the previous terms.</p>

<pre><code>keepTerms = new Array();
</code></pre>

<p>Let&#8217;s create a new array that will hold only the terms we want to keep.</p>

<pre><code>for(term in data){
    url = data[term];
    if($.inArray(term, previousTerms) === -1){
        $artistsList.prepend('&lt;li&gt;&lt;a href="'+url+'" title="'+term+'"&gt;'+term+'&lt;/a&gt;&lt;/li&gt;');
    }else{
        keepTerms.push(term);
    }               
}
</code></pre>

<p>Now we can begin breaking up that string of returned results. &#8220;term&#8221; itself is the key (the name of the artists) and &#8220;data[term]&#8221; is the value (the URL). For each key/value pair, we&#8217;re going to compare the term with the terms in the &#8220;previousTerms&#8221; array. If it isn&#8217;t in the array, we add the term to the list of results (wrapped in a little bit of HTML to create the link). If it <em>is</em> in the &#8220;previousTerms&#8221; array (and is already being displayed), we&#8217;ll add it to the &#8220;keepTerms&#8221; array.</p>

<p>We&#8217;re almost there! Before we write the final step &#8211;removing the terms from the results list that no longer match the latest returned results &#8212; we need to make sure the AJAX is keeping up with the users speed of typing.</p>

<p>One thing to note about sending lots of querires off to a server based script is that it takes time for that to happen. We&#8217;re sending a request every time the user hits a key, which means they&#8217;re most likely changing the query quicker than the AJAX can return results. To make sure the most current result is being displayed for the most recent query, we&#8217;ll use another if statement:</p>

<pre><code>if(data == "" || (keepTerms.length == 0 &amp;&amp; (previousTerms.length != 0 || $displaySearch.val() == ""))){
    $artistsList.html("&lt;li&gt;No results&lt;/li&gt;");
}else{  
    //...code to execute removal of irrelavent results
}
</code></pre>

<p>In any of these instances, we want to show &#8220;no results&#8221;:</p>

<ul>
<li>the PHP script has returned no results, or</li>
<li>the &#8220;keepTerms&#8221; array is empty, and:

<ul>
<li>the &#8220;previousTerms&#8221; array is not empty, or</li>
<li>the search input box is empty</li>
</ul></li>
</ul>

<p>If you remove this if statement from the code and quickly change the query, you&#8217;ll see that the returned results do not always reflect the most current query. This final if statement rectifies that issue.</p>

<p>So, providing none of the above are true and there <em>are</em> results to show, we can execute the last bit of code.</p>

<p>We have two final arrays to compare, the &#8220;previousTerms&#8221; (those being displayed currently), and &#8220;keepTerms&#8221; (only the ones that are now relevant).</p>

<p>Again, let&#8217;s take a look at our example. The user has queried &#8220;AC&#8221; so far, and previously we displayed results for the query &#8220;A&#8221;. &#8220;The previousTerms&#8221; array looks like this:</p>

<pre><code>["Ace of Spades", "ACDC", "ABBA"]
</code></pre>

<p>And the &#8220;keepTerms&#8221; array like this:</p>

<pre><code>["Ace of Spades", "ACDC"]
</code></pre>

<p>By comparing these two arrays, we can single out the terms that no longer match the returned terms and remove them:</p>

<pre><code>for(term in previousTerms){
    if($.inArray(previousTerms[term], keepTerms) === -1){
        $("#artists li").filter(function(){
            return $(this).text() == previousTerms[term]
        }).remove();
    }
}
</code></pre>

<p>For each term in the &#8220;previousTerms&#8221; array, we determine if that term also exists in the &#8220;keepTerms&#8221; array, if it doesn&#8217;t, find it in the list of results and remove it.</p>

<h2>Conclusion</h2>

<p>As mentioned previously, this demo queries a simple array of test data &#8212; in the real world, you&#8217;d query a database and could use better matching algorithms provided by SQL.</p>

<p>If you plan on using this in a real world application, I&#8217;d also recommend taking performance considerations further. It may be a good idea to limit the number of results returned as well as constructing the list of results in a variable so they can be outputted as one instead of using jQuery to output each list item individually.</p>

<p>This code could be quickly adapted to consider those real world factors and hopefully it&#8217;s helped you to understand how simple it is to get jQuery and PHP to communicate with each other via AJAX.</p>

<p>Remember you can <a href="http://www.ianlunn.co.uk/demos/ajax-search-suggest-wearehunted/">view the demo here</a>, <a href="http://www.ianlunn.co.uk/demos/ajax-search-suggest-wearehunted/ajax-search-suggest-wearehunted-style.zip">download the code here</a>, <a href="https://github.com/IanLunn/AJAX-Search-Suggest--WeAreHunted.com-Style-/">fork AJAX Search Suggest (WeAreHunted.com style)</a> on GitHub, or comment/ask a question below.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ianlunn.co.uk/blog/code-tutorials/ajax-search-suggest-wearehunted/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Going Freelance: One Year In</title>
		<link>http://www.ianlunn.co.uk/blog/freelance-diary/going-freelance-one-year-in/</link>
		<comments>http://www.ianlunn.co.uk/blog/freelance-diary/going-freelance-one-year-in/#comments</comments>
		<pubDate>Fri, 11 Nov 2011 13:45:32 +0000</pubDate>
		<dc:creator>Ian Lunn</dc:creator>
				<category><![CDATA[Freelance Diary]]></category>

		<guid isPermaLink="false">http://www.ianlunn.co.uk/blog/?p=2714</guid>
		<description><![CDATA[Today my business is one year old and I&#8217;m still here to tell the tale! I&#8217;m returning to my &#8220;Going Freelance&#8221; diary to discuss my year, hopefully to give you some helpful pointers and insights into the web design business &#8230;]]></description>
			<content:encoded><![CDATA[<p>Today my business is one year old and I&#8217;m still here to tell the tale! I&#8217;m returning to my &#8220;<a href="http://www.ianlunn.co.uk/blog/category/freelance-diary/">Going Freelance</a>&#8221; diary to discuss my year, hopefully to give you some helpful pointers and insights into the web design business (and self employment in general) as well as to help myself by going over what I&#8217;ve spent the year doing, what I&#8217;ve learnt and how I will approach freelance life next year.</p>

<p><span id="more-2714"></span></p>

<h2>What I&#8217;ve Been Doing This Year</h2>

<h3>Starting and Maintaining a Business</h3>

<p><a href="http://www.ianlunn.co.uk/">Ian Lunn Design</a> officially opened for business November 11th 2010 but I started planning and preparing in August 2010.  I didn&#8217;t get my first job until December but thankfully, ever since then work has rolled in steadily.</p>

<p>I feel quite lucky to have got early clients that I can proudly say I am still doing work for today. In fact, looking back, I really haven&#8217;t had a huge number of clients but the ones I have had, I&#8217;ve formed a good relationship with and they&#8217;ve continued to come back to me with new projects.</p>

<p>All of my work this past year has been remote. I&#8217;ve worked with people in America, Australia and the UK which completely went against my business plan. My original plan was to start off with local clients, build a name for myself and then hopefully take on clients over the Internet. I wanted to take on clients over the Internet because I felt they would be more tech savvy and I could get my hands on more creative and complex projects. This is important to note if you&#8217;re starting out as a freelance web designer: don&#8217;t just take on any projects that come along, decide what work you feel you would like to do and aim to take on those type of projects. I&#8217;ll come to this later on when I talk about blogging.</p>

<p>Being able to take on Internet based clients has been great and is something that happened quicker than expected. I&#8217;ve already worked for some well known clients along side web professionals I have a lot of respect for.</p>

<p>Maintaining a business was something completely new to me. I&#8217;ve never worked for myself before although I&#8217;ve actually found the experience quite enjoyable. I like to learn (any subject) and there&#8217;s a lot to learn about running your own business. As mentioned in previous diary entries, <a href="http://www.businesslink.gov.uk/bdotg/action/home">Business Link</a> were a big help to me and pointed me in the right direction. I have been using <a href="http://fre.ag/3l9vxdou">FreeAgent</a> for accounting and admin, which is a truly amazing service. I consider where my business would be today if I hadn&#8217;t of used that.</p>

<h3>Blogging</h3>

<p>Blogging is something I started in August 2010 as soon as I knew I was going to become self employed. It has probably been the catalyst for this year&#8217;s successes but also my biggest regret.</p>

<p>I decided to start blogging based on the success and recommendation of <a href="http://www.blog.spoongraphics.co.uk/">Chris Spooner</a> &#8212; who now blogs full-time.</p>

<p>I didn&#8217;t initially get much success from my blogging. Stats in Google Analytics were starting to increase but I wasn&#8217;t getting any comments and nobody was getting in touch regarding potential projects. I quickly realised that writing a post each week was way too much work (especially when creating a demo or graphical piece to go along with that post). For a while I managed to post every fornight.</p>

<p>I started chatting to a few people via <a href="http://www.twitter.com/IanLunn">Twitter</a> that had read my &#8220;Going Freelance&#8221; series and as I watched Google Analytics, it became clear that my <a href="http://www.ianlunn.co.uk/blog/category/code-tutorials/">JavaScript tutorials</a> were starting to be of interest to people.</p>

<p>I eventually decided to make a big change and solely concentrate on <a href="http://www.ianlunn.co.uk/blog/category/code-tutorials/">JavaScript tutorials</a> for my blog. Why? Because they were getting the most interest out of all the posts. This led me to make quite a big decision about my career in general which I&#8217;ll come to shortly.</p>

<p>My post about creating a <a href="http://www.ianlunn.co.uk/blog/code-tutorials/bbc-news-jquery-map/">jQuery map</a> interested somebody who found the post via Google and they eventually became the first client achieved from my blog.</p>

<p>I continued writing tutorials &#8212; which is also a great opportunity for you to improve your own knowledge, I may add &#8212; and eventually wrote my recreation of the <a href="http://www.ianlunn.co.uk/blog/code-tutorials/recreate-nikebetterworld-parallax/">Nike Better World parallax effect</a>. This post was probably online for about 3 months before it started getting popular. I&#8217;ve since received a lot of work from that tutorial.</p>

<p>As mentioned earlier, when working for yourself, you have a lot of freedom and can choose what work you take on. Blogging is the perfect way to stand out and show people what you&#8217;re capable of doing. Write about the work you love, and people will approach you with project proposals of a similar nature. Not only that, but blogging is a chance for you to improve your own knowledge of a subject and writing about something you may think you know, always reveals something you didn&#8217;t!</p>

<p>So, blogging has got me some great projects and work that I&#8217;ve really enjoyed. Because I write tutorials though, it takes up a lot of time and when I started getting really busy, blogging was the first thing I had to drop.</p>

<p>Deciding not to blog is something I&#8217;ve really regretted and I will try my hardest next year to get back into it, especially as it&#8217;s so important for increasing exposure and getting new and interesting work.</p>

<h2>Feelings Toward Freelance Life</h2>

<p>Freelancing/self employment is harder than I thought it would be but more rewarding too. It&#8217;s naive to think that when you work for yourself, you can just wake up one morning and decide to play video games instead of work &#8212; but I did! Maybe I&#8217;m the type of person to worry a lot but whenever I&#8217;m not working during 9 &#8211; 5, I feel guilty. Perhaps that&#8217;s what got me through my first year though &#8212; I&#8217;ve cared about my business and the relationship with my clients so I&#8217;ve given everything I&#8217;ve got, that has meant a lot more of my time than just 9 &#8211; 5, and my personal life has changed quite a bit too.</p>

<p>When I started freelancing, I made the decision to stop playing video games so I wouldn&#8217;t be distracted by the &#8220;quick&#8221; game at lunch. It turned out I dropped a lot more than this hobby though. I found I had no time for growing veg in the spring and summer (something I like to do), and time spent with my girlfriend had to become a little more scheduled. I was generally not doing minor stuff because I thought it was time wasted &#8212; like sitting in an armchair, looking out the window, eating crisps &#8212; and I got a little too strict on myself. Towards the end of this first year though, I realised that personal life and wasting time eating crisps is important. To quote Bertrand Russell: &#8220;The time you enjoy wasting is not wasted time&#8221;.</p>

<p>About 4 months into self employment, I went for an interview for a permanent job. I was in two minds whether to go or not. I was yet to make money consistently in my self employment. I was offered the job but eventually turned it down based on the fact that I had taken the leap into self employment and I&#8217;d be disappointed if I didn&#8217;t see it through. Only a few weeks after turning the role down, I got a big client. I earnt a good amount of money but more importantly, the potential of self employment presented itself. I&#8217;m so glad I continued.</p>

<p>I still talk to companies and agencies regarding potential work simply because a job interview is a great opportunity to have people listen to you talk about yourself and how good you think you are! Don&#8217;t miss opportunities like this; you get to meet new people in a similar field, improve your interview skills and if you don&#8217;t want the job, you get to say no &#8212; which is a very powerful thing!</p>

<p>Saying no is scary, especially in the early days when you need to earn money, but don&#8217;t underestimate its power. Saying no doesn&#8217;t mean that a situation won&#8217;t have an outcome; it means you feel confident in your position, you know what you want  and won&#8217;t take anything less. It helps you and the people you interact with to understand who you are and what you do &#8212; knowing and making clear your limits defines you as a person.</p>

<p>I also defined myself as a professional &#8212; finally! I studied Internet Technology at university and when my career started, I ended up in more of a designers position. I&#8217;ve always been an &#8220;all-rounder&#8221; that can design, develop and market a website. I feel I have a strong level in all three but to really be successful and set yourself apart, you need to truly excel in one. My blog helped me with this decision, it was clear that people were more interested in my JavaScript tutorials and I felt more comfortable and happier writing them. I asked around and people saw me as a front end developer more than anything else. I made the leap and I&#8217;m glad I did. I&#8217;ve been able to learn so much more by just concentrating on one profession.</p>

<h2>Feelings Toward the Year</h2>

<h3>Pleased About</h3>

<p>I woke up this morning super excited to start geeking out in the statistics of my business. I&#8217;ve finally completed a year and jumped at the chance to gather up lots of different stats.</p>

<p>Financially, for a first year, I am very pleased. I earnt more than I have ever done in employment and I also earnt more than what was on offer for the job I turned down so gladly I can say I <em>did</em> make the right decision there.</p>

<p>My blog &#8212; despite the fact I have neglected it &#8212; has achieved over 10,000 visitors a month for the last few months with an average read time of over two and a half minutes &#8212; the latter being more important to me as it shows my content is valuable to people.</p>

<p>So, as it was my first year, everything has gone from zero to a reasonable figure that can be built on next year and at some point before the end of the year, I plan to work out some targets I&#8217;d like to reach this time next year. It&#8217;s more fun when you have stats to compare and beat!</p>

<p>Possibly the biggest plus-point of self employment is the fact you get to choose what work you want to take on and what you learn. I have learnt so much this year! I&#8217;ve dedicated a big amount of my time to personal projects and really got to grips with new technologies such as HTML5 (including the APIs), CSS3 and jQuery. I could never have learnt so much in a full time position.</p>

<h3>Regrets</h3>

<p>As already mentioned, the fact I neglected my blog when I got too busy is my biggest regret. That might not sound so bad but my blog really increased my exposure and won me a lot of work. Looking at my stats, I also consider how impressive they might be if I was able to blog on a regular basis.</p>

<p>Second to this, would probably be procrastination. I guess it&#8217;s a natural thing for a person to procrastinate, so maybe it shouldn&#8217;t be regretted but I certainly did a lot of it when I didn&#8217;t have work to complete &#8212; more so than in full time employment.</p>

<p>The problem with working from home is the distractions. I removed video games, as mentioned previously, but the fact I was at home and didn&#8217;t really seperate home life from work life had an impact. When I say I procrastinated, I don&#8217;t mean I spent half the day watching TV, I was at my computer, but checking Facebook/Twitter and day dreaming became a big distraction and the most difficult thing was just getting started and motivated.</p>

<p>I haven&#8217;t quite yet worked out how to better get into a productive state of mind &#8212; I think jumping straight into whatever it is you want to do is probably the only way &#8212; but I did find that managing tasks around my mood helped. For example, if I started coding but found that I was spending more time tweeting and watching videos of cats on YouTube, I&#8217;d stop that task and move onto another that maybe didn&#8217;t require as much concentration. I might have done my accounting, sent emails etc and waited for the next day where hopefully, I&#8217;d be in the right state of mind to stare at code all day. Ironically, I find I code best in a hazy &#8220;I&#8217;m not here today&#8221; type of mood &#8212; but that&#8217;s for a different blog post!</p>

<p>Another minor gripe I have and feel bitter enough about to mention is Thomson Local. I&#8217;ll keep it short! Thomson Local are a business directory that I signed up with to get my business details in their printed book as well as online. I paid around £350 for the year. I didn&#8217;t get a single phone call regarding potential work but I did get a hell of a lot of calls from companies that Thomson Local had sold my details to. So, I paid £350 to Thomson Local so they could make more money out of selling my details. Their sales team are also liars and very unhelpful. Don&#8217;t go with them.</p>

<h2>What I&#8217;ve Learnt</h2>

<p>I love to learn, not just web related subjects but absolutely everything. I&#8217;ve already mentioned that I spent a lot of time learning HTML5, CSS3 and jQuery but I&#8217;ve also learnt a lot about myself, general life skills as well as dealing with clients.</p>

<p>Self employment throughs a hell of a lot of stuff your way, you&#8217;ll be the &#8220;web professional&#8221; you set out to be but also an accountant, a project manager, a client liasion manager, a receptionist (turning away a lot of sales calls), a marketeer, and a tea boy/girl.</p>

<p>I was again, naive in my approach to self employment. The amount of time spent just getting a project started is way more than I expected. Talking to a client, telling them about how you operate, writing contracts, sending quotes and invoices is a big job and it can get a little frustrating at times but it&#8217;s something you must do and do well because it&#8217;s the foundation for your business.</p>

<p>I think these types of jobs I will continue to learn and get better at for a long time to come.</p>

<p>Some quick tips regarding this:</p>

<ul>
<li>Do your accounts weekly and don&#8217;t forget. Doing them often means you&#8217;ll only need to spend an hour or two a week rather than waiting a few months and spending days struggling to remember what a particular transaction was.</li>
<li>If you have a client that keeps sending you little jobs (the ones that make you feel like your losing money because of the formalities involved with starting new projects), let them know it&#8217;s cost effective for you both to build up those little jobs into a bigger project. If it&#8217;s not an urgent task, they&#8217;ll be happy to wait a few weeks and save some money.</li>
<li>Your contract is an evolving document, change it often to meet evolving technologies as well as to match the specific tasks for a project. If a client raises a concern because something isn&#8217;t clear, change it in your overall template so it applies to all future contracts. Get your contract read over by the company you&#8217;ve chosen for professional indemnity insurance too.</li>
<li>Invest in software packages that will help with these tasks. For accounting, I recommend <a href="http://fre.ag/3l9vxdou">FreeAgent</a> and for project management, <a href="http://basecamphq.com/">BaseCamp</a>. I also use <a href="http://www.echosign.com/">eSign</a> to send out contracts that can be signed digitally.</li>
<li>Send out questionnaires to your clients after a project is signed off to ask them for feedback. Set up a questionnaire on <a href="https://docs.google.com/">Google Docs</a> and send it out via <a href="http://mailchimp.com/">MailChimp</a>, all for free!</li>
</ul>

<h2>Plans for Next Year</h2>

<h3>To Beat this Year in Every Way</h3>

<p>I want to earn more, learn more, and better improve my exposure.</p>

<h3>Release Personal Projects</h3>

<p>This year I worked on a lot of personal projects. I guess the tutorials and demos on my blog could be classed as personal projects but aside from those, I didn&#8217;t actually finish any other personal projects despite starting quite a few.</p>

<p>Very early on, I started working on a novelty site with a friend that looked at your Twitter account and gave you a score based on how nerdy you were. This unfortunately, I don&#8217;t think will ever be released as I have too many other personal projects I want to complete before that.</p>

<p>Right now, I am working on a jQuery slideshow that uses CSS3 animations. I am very excited about this as it is a plugin that is very easy to use but can be customized greatly. I expect to see lots of creative uses for it. I aim to release this before 2012.</p>

<p>Another project I am working on is a very small jQuery plugin and browser extension. It is based on an idea I implemented for <a href="https://developer.mozilla.org/en-US/demos/devderby/2011/august/">Mozilla&#8217;s Dev Derby</a> (which I came 3rd for!). I hope it will spur browser vendors to eventually build its functionality straight into their browsers.</p>

<p>Finally, I&#8217;m working on a game utilising JavaScript and HTML5s Canvas API. I plan to break this down into stages of development and create a series of tutorials on my blog. Currently the game is in a very basic form, allowing for player movement and randomly generated falling objects that the player must catch.</p>

<h3>To Take on More Great Clients with Interesting Projects</h3>

<p>For my first year, I&#8217;ve already taken on some amazing clients and projects. Next year, I&#8217;d like to do the same and take on interactive projects that make use of HTML5, CSS3 and JavaScript.</p>

<h2>Conclusion</h2>

<p>Having written this post, I am very excited for next year. I made the right decision by &#8220;Going Freelance&#8221;. Not only did I exceed my expectations regarding the type of work and clients I&#8217;d take on but I&#8217;ve also had a lot of time to spend learning and working on my own projects.</p>

<p>I&#8217;ve dedicated a lot of time to my first year but it&#8217;s paid off and I&#8217;m now in a position to be able to step back, take a look at what I&#8217;ve achieved and improve upon it next year.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ianlunn.co.uk/blog/freelance-diary/going-freelance-one-year-in/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>

