<?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>AHdevelopment</title>
	<atom:link href="http://www.ahdev.co.uk/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.ahdev.co.uk</link>
	<description>Tutorials, Tips and Resources</description>
	<lastBuildDate>Mon, 07 Jun 2010 08:00:22 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Browser Detection using ASP.Net</title>
		<link>http://www.ahdev.co.uk/tutorials/aspnet/2010/06/07/browser_detection_using_aspnet/</link>
		<comments>http://www.ahdev.co.uk/tutorials/aspnet/2010/06/07/browser_detection_using_aspnet/#comments</comments>
		<pubDate>Mon, 07 Jun 2010 08:00:22 +0000</pubDate>
		<dc:creator>Alan Holmes</dc:creator>
				<category><![CDATA[ASP.Net]]></category>
		<category><![CDATA[Browser Detection]]></category>
		<category><![CDATA[HttpBrowserCapabilities]]></category>
		<category><![CDATA[Server-Side]]></category>

		<guid isPermaLink="false">http://www.ahdev.co.uk/?p=217</guid>
		<description><![CDATA[This tutorial will look at using ASP.Net's HttpBrowserCapabilities to detect the browser name and version.]]></description>
			<content:encoded><![CDATA[<h2>The Idea</h2>
<p>There are numerous scripts out there for detecting the browser via JavaScript, however, what about when you want to know the browser in your server-side code? You may ask why? The reasons are many, including page stats, browser based dynamic content, etc. </p>
<p>My personal reason for looking into this, is displaying an unsupported browser message (such as YouTube does for older browsers), within a website Content Management System (CMS), so that you can ensure users are using a browser that will allow them to use the full functionality of the CMS. Again, this could be done by JavaScript, but I required a server-side solution.</p>
<h2>The Solution</h2>
<p>In this tutorial, we will be creating a demo that will display message to users telling them if there browser is supported, and if it is not, then it will display a list of browsers that are, you can view a <a href="http://demo.ahdev.co.uk/ASPnet_Browser_Detection/" target="_blank">demo here</a>.</p>
<p>In this example, only Firefox 3+ and IE8+ will be accepted as supported browsers (just to make it possible to see the result for unsupported browsers in Google Chrome, Safari and Opera), but it can be easily changed to allow other browsers.</p>
<h3>The Code</h3>
<p>For this tutorial we will be using ASP.Net&#8217;s <em><strong>HttpBrowserCapabilities</strong></em> facility to get the browser details. Let me start out by saying, I know that this has some limits, one being that it cannot differentiate Google Chrome from Safari, but it does my needs which is why I am using it.</p>
<p>Firstly, lest set the variables that we will be using to store the Browser details</p>
<pre class="brush:vb">
Dim httpRequest As HttpBrowserCapabilities = Request.Browser 'Gets the browser details

Dim strBrowserName as string = "" 'Browser Name
Dim strBrowserVersion as string = httpRequest.Version 'Version Number
Dim intMajorVersion as integer = httpRequest.MajorVersion 'Major Version Number
Dim boolSupportedBrowser as boolean = false 'Is this a supported browser
</pre>
<p>Next, I wanted to have some better names, than provided by <strong><em>httpRequest.Browser</em></strong>, so I used a <strong><em>select case</em></strong> statement to get these names. In this process we will also be setting the value for <strong><em>boolSupportedBrowser</em></strong>.</p>
<pre class="brush:vb">
'Set the name, and whether the browser is supported
Select Case lcase(httpRequest.Browser)

	Case "ie"
		strBrowserName = "Internet Explorer"
		if intMajorVersion >= 8 then
			boolSupportedBrowser = true
		end if 'if intMajorVersion >= 8 then

	Case "firefox", "mozilla"
		strBrowserName = "Mozilla Firefox"
		if intMajorVersion >= 3 then
			boolSupportedBrowser = true
		end if 'if intMajorVersion >= 3 then

	Case "applemac-safari"
		strBrowserName = "Safari/Google Chrome"
		boolSupportedBrowser = false

	Case "opera"
		strBrowserName = "Opera"
		boolSupportedBrowser = false

	Case Else
	   strBrowserName = "Unknown Browser"
	   boolSupportedBrowser = false

End Select 'Select Case lcase(httpRequest.Browser)
</pre>
<p>You will notice that under IE and Firefox, we only set <strong><em>boolSupportedBrowser</em></strong> to true if the Major version matches the criteria.</p>
<h3>The Message</h3>
<p>Now that we have all the settings that we need, we can display the message. By using the ASP.Net code tags <strong><em>&lt;% %&gt;</em></strong> we can include the variables set above, to include the browser name, and what content to display.</p>
<pre class="brush:xml">
&lt;div id="BrowserSupport"&lt;% if not boolSupportedBrowser then %&gt;class="Unsupported"&lt;% end if %&gt;&gt;
	&lt;div class="Message"&gt;
	&lt;% if boolSupportedBrowser then %&gt;
		&lt;strong&gt;Congratulations&lt;/strong&gt; your browser, &lt;em&gt;&lt;%=strBrowserName &#038; " " &#038; strBrowserVersion%&gt;&lt;/em&gt;, is supported
	&lt;% else 'if boolSupportedBrowser then %&gt;
		&lt;strong&gt;&lt;%=strBrowserName &#038; " " &#038; strBrowserVersion%&gt;&lt;/strong&gt; is not a supported browser

		&lt;br /&gt;Please upgrade to one of the following:
	&lt;% end if 'if boolSupportedBrowser then %&gt;
	&lt;/div&gt;
	&lt;% if not boolSupportedBrowser then %&gt;
	&lt;div class="Supported"&gt;
		&lt;div class="Browser IE"&gt;&lt;a href="http://www.microsoft.com/windows/internet-explorer/default.aspx" target="_blank" title="Get Internet Explorer 8"&gt;Internet Explorer 8&lt;/a&gt;&lt;/div&gt;

		&lt;div class="Browser Firefox"&gt;&lt;a href="http://www.mozilla.com" target="_blank" title="Get Mozilla Firefox"&gt;Mozilla Firefox&lt;/a&gt;&lt;/div&gt;
		&lt;div class="clear"&gt;&lt;/div&gt;
	&lt;/div&gt;
	&lt;% end if 'if not boolSupportedBrowser then %&gt;
&lt;/div&gt;
</pre>
<h3>Finally</h3>
<p>And finally, the CSS used for this demo.</p>
<pre class="brush:css">
#BrowserSupport{
	background: #D2FFD3;
	border:1px solid #00CC00;
	color:#00CC00;
	font:10pt Arial, Helvetica, sans-serif;
	padding:10px;
	text-align:center;
	width:505px;
}

#BrowserSupport.Unsupported{
	background: #FFDFDF;
	border-color: #FF0000;
	color:#FF0000;
}

.Supported{
	padding-top:10px;
}

.Supported .Browser{
	float:left;
	margin-left:5px;
}

.Supported .Browser.IE{
	margin-left:0px;
}

.Supported .Browser a{
	background:#FFFFFF;
	border:1px solid #999999;
	color:#000000;
	display:block;
	font-size:7pt;
	font-weight:bold;
	height:15px;
	padding-top:80px;
	text-decoration:none;
	width:95px;
}

.Supported .Browser.IE a{
	background:#FFFFFF url(../images/IE.png) top center no-repeat;
}

.Supported .Browser.Firefox a{
	background:#FFFFFF url(../images/Firefox.png) top center no-repeat;
}

#BrowserSupport, .Supported .Browser a{
	-moz-border-radius :6px;
	-webkit-border-radius: 6px;
	-khtml-border-radius: 6px;
}

.clear{
	clear:both;
	font-size:0px;
	height:0px;
	overflow:hidden;
}
</pre>
<p>Your messages should look something Like (if you are viewing in IE or Opera, then you will not have curved borders, as they do not support the <strong><em>border-radius</em></strong> css):</p>
<div class="ImageBox" style="width: 533px;"><img title="Message for a supported browser" src="http://images.ahdev.co.uk/articles/BrowserDetection_Supported.jpg" alt="Message for a supported browser" width="527" height="38" /><span>Message for a supported browser.</span></div>
<div class="ImageBox" style="width: 533px;"><img title="Message for a unsupported browser" src="http://images.ahdev.co.uk/articles/BrowserDetection_Unsupported.jpg" alt="Message for a unsupported browser" width="527" height="161" /><span>Message for a unsupported browser.</span></div>
<h2>Compatibility, Conclusion and Download</h2>
<p>This script has been tested in IE7, Firefox 3.5.3, Google Chrome 4.1.2, Safari 4.0.5 and Opera 10.53, all on a windows platform. This technique will allow you to do a number of things, either to display a message for unsupported browser, as in this demo, or to show different content based on browser. </p>
<p>The only drawback at present, is that Google Chrome is not recognised as a separate browser, it is recognised as Safari.</p>
<p>Also, please be aware that <strong><em>httpRequest.Version</em></strong> and <strong><em>httpRequest.MajorVersion</em></strong> may not return the value you expect. For example, I use Opera 10.53, but it returns 9.80 as the version number.</p>
<div class="DownloadButton Center"><a title="Download the files for this demo" href="http://static.ahdev.co.uk/downloads/ASPnet_Browser_Detection.zip">Download Demo Files</a></div>
<p>Any feedback or improvements are welcome.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ahdev.co.uk/tutorials/aspnet/2010/06/07/browser_detection_using_aspnet/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ASP.Net Data Reader Paging with Page Numbers</title>
		<link>http://www.ahdev.co.uk/tutorials/aspnet/2010/06/02/aspnet_data_reader_paging_with_page_numbers/</link>
		<comments>http://www.ahdev.co.uk/tutorials/aspnet/2010/06/02/aspnet_data_reader_paging_with_page_numbers/#comments</comments>
		<pubDate>Wed, 02 Jun 2010 08:00:10 +0000</pubDate>
		<dc:creator>Alan Holmes</dc:creator>
				<category><![CDATA[ASP.Net]]></category>
		<category><![CDATA[Data Reader]]></category>
		<category><![CDATA[Page Numbers]]></category>
		<category><![CDATA[Paging]]></category>

		<guid isPermaLink="false">http://www.ahdev.co.uk/?p=208</guid>
		<description><![CDATA[This Tutorial will explain how to create paging in ASP.Net. As well as create the standard next and previous links, it will also output page numbers.]]></description>
			<content:encoded><![CDATA[<h2>The Idea</h2>
<p>I recently wrote an article for <a href="http://www.ahdev.co.uk/tutorials/asp/2010/05/26/asp_recordset_paging_with_page_numbers/">creating paging with numbers for ASP</a>. I have now converted this into ASP.Net code, which can be found below. It uses the same ideas and structure as the ASP version, so for further details, <a href="http://www.ahdev.co.uk/tutorials/asp/2010/05/26/asp_recordset_paging_with_page_numbers/">read here</a>, I shall only be providing the code in this article.</p>
<h2>The Code</h2>
<pre class="brush:vb">
'Default Paging Values
Dim intTotalRecords as Integer = 0	'Total Records
Dim intNumPages as Integer = 0		'Number of pages
Dim intPageSize as Integer = -1		'Amount per page, -1 means all
Dim intPageNumber as Integer = 1	'The current page to display

'News Table Values
Dim strFrom as String = "Tbl_News"
Dim strPrimKey as String = "fldNewsID"
Dim strColumns as String = "fldNewsID, fldTitle, fldAbstract, fldDate"
Dim strWhere as String = ""
Dim strOrderBy as String = "fldDate desc"

'Get the current page number from the querystring
Dim intCurPage as Integer = 1
if (trim(request("p")) &lt;&gt; "") and (isnumeric(request("p"))) then
	intCurPage = request("p")
end if 'if (trim(request("p")) &lt;&gt; "") and (isnumeric(request("p"))) then

'Calls the function to set the current paging values
SetPagingValues(5, intCurPage, strFrom, strPrimKey, strWhere)

'calls the function to get the paged sql
strSQL = CreatePagedSQL(strFrom, strPrimKey, strColumns, strWhere, strOrderBy)

'Get the records from the database
Dim dtrNewsList As SqlDataReader
dtrNewsList = getDTR(strSQL)

If dtrNewsList.HasRows Then
	While dtrNewsList.Read()
		response.Write("&lt;div class=""NewsList""&gt;")
		response.Write("&lt;span class=""Title""&gt;" &#038; dtrNewsList("fldTitle").ToString &#038; "&lt;/span&gt;")
		response.Write("&lt;span class=""Date""&gt;" &#038; dtrNewsList("fldDate").ToString &#038; "&lt;/span&gt;")
		response.Write("&lt;span class=""Abstract""&gt;" &#038; dtrNewsList("fldAbstract").ToString &#038; "&lt;/span&gt;")
		response.Write("&lt;/div&gt;")
	End While 'While dtrNewsList.Read()
End If 'If dtrNewsList.HasRows Then

'close the object
dtrNewsList.Close()
dtrNewsList = Nothing

'Function to fill the data reader
Public Function getDTR(ByVal sql As String) As SqlDataReader
	Dim sqlConn As SqlConnection
	Dim cmdTemp As SqlCommand
	Dim dtr As SqlDataReader

	'create connection
	sqlConn = New SqlConnection("Database Connection String")

	'get data from database
	cmdTemp = New SqlCommand(sql, sqlConn)
	sqlConn.Open()
	dtr = cmdTemp.ExecuteReader(CommandBehavior.CloseConnection)

	'Write to log file
	objErrors.Log(strErrorLocation, strError)
	dtr = Nothing

	'return data reader
	Return dtr
End Function 'Public Function getDTR(ByVal sql As String) As SqlDataReader

Sub SetPagingValues(intTempPageSize, intTempPageNumber, strFrom, strPrimKey, strWhere)
	Dim strSQLCount as String = ""
	Dim sngTempNumPages as Integer = 0
	Dim intTempNumPages as Integer = 1
	Dim dtrSQLCount As SqlDataReader

	'Set the Page Size (number of records to show per page)
	If (Trim(intTempPageSize) &lt;&gt; "") And (isnumeric(intTempPageSize)) Then
		intPageSize = intTempPageSize
	Else 'If (Trim(intTempPageSize) &lt;&gt; "") And (isnumeric(intTempPageSize)) Then
		'not valid number, so set to -1
		'IE all records
		intPageSize = -1
	End If 'If (Trim(intTempPageSize) &lt;&gt; "") And (isnumeric(intTempPageSize)) Then

	'Set the page number (the current page being viewed)
	If (Trim(intTempPageNumber) &lt;&gt; "") And (isnumeric(intTempPageNumber)) Then
		intPageNumber = intTempPageNumber
	Else 'If (Trim(intTempPageNumber) &lt;&gt; "") And (isnumeric(intTempPageNumber)) Then
		'if not a valid number, set page number to 1
		intPageNumber = 1
	End If 'If (Trim(intTempPageNumber) &lt;&gt; "") And (isnumeric(intTempPageNumber)) Then

	'SQL to get the total number of records in table
	strSQLCount = "SELECT Count(*) As RecCount From " &#038; strFrom &#038; " WHERE (1=1) "

	'If given add the where clause
	If Trim(strWhere) &lt;&gt; "" Then
		strSQLCount = strSQLCount &#038; " AND " &#038; strWhere
	End If 'If Trim(strWhere) &lt;&gt; "" Then

	'open the sql into a DTR
	dtrSQLCount = getDTR(strSQLCount)

	'Set the total records value
	If dtrSQLCount.HasRows Then
		dtrSQLCount.Read()
		intTotalRecords = dtrSQLCount("RecCount")
	Else 'If dtrSQLCount.HasRows Then
		intTotalRecords = 0
	End If 'If dtrSQLCount.HasRows Then

	'close the DTR
	dtrSQLCount.Close()
	dtrSQLCount = Nothing

	'if Total Records and Page size is greater than 0
	'then work out the number of pages
	If (intTotalRecords &gt; 0) And (intPageSize &gt; 0) Then
		sngTempNumPages = intTotalRecords / intPageSize
		intTempNumPages = RoundUp(sngTempNumPages)
	Else 'If (intTotalRecords &gt; 0) And (intPageSize &gt; 0) Then
		intTempNumPages = 1
	End If 'If (intTotalRecords &gt; 0) AND (intPageSize &gt; 0) Then

	'set the num pages
	intNumPages = intTempNumPages

	'if Page number is greater than number of pages, then set to
	'number of pages
	If cint(intPageNumber) &gt; cint(intNumPages) Then
		intPageNumber = intNumPages
	End If 'If intPageNumber &gt; intNumPages Then
End Sub 'Sub SetPagingValues(intTempPageSize, intTempPageNumber, strFrom, strPrimKey, strWhere)

Function CreatePagedSQL(strFrom, strPrimKey, strColumns, strWhere, strOrderBy)
	'Returns paged dataset for supplied SQL, broken down into sections
	Dim strSQL as String = ""
	Dim strTopRecords as String = ""
	Dim intIgnoreRecs as Integer = 0
	Dim strPagedWhere as String = " WHERE (1=1) "

	'Create where clause
	If Trim(strWhere) &lt;&gt; "" Then
		strPagedWhere += " AND " &#038; strWhere
	End If 'If Trim(strPagedWhere) &lt;&gt; "" Then

	'create Order clause
	If Trim(strOrderBy) &lt;&gt; "" Then
		strOrderBy = " ORDER BY " &#038; strOrderBy
	End If 'If Trim(strOrderBy) &lt;&gt; "" Then

	'set how many records to get
	If intPageSize &gt; 0 Then
		strTopRecords = " TOP " &#038; intPageSize
	End If 'If intPageSize &gt; 0 Then

	'if not on page one, set the number of records to ignore
	If (intNumPages &gt; 1) And (intPageNumber &gt; 1) Then
		intIgnoreRecs = intPageSize * (intPageNumber - 1)
		strPagedWhere += " AND " &#038; strPrimKey &#038; " NOT IN (SELECT TOP " &#038; intIgnoreRecs &#038; " " &#038; strPrimKey &#038; " FROM " &#038; strFrom &#038; " " &#038; strPagedWhere &#038; " " &#038; strOrderBy &#038; ")"
	End If 'If (intNumPages &gt; 1) And (intPageNumber &gt; 1) Then

	'create sql
	strSQL = "SELECT " &#038; strTopRecords &#038; " " &#038; strColumns &#038; " FROM " &#038; strFrom &#038; " " &#038; strPagedWhere &#038; " " &#038; strOrderBy

	'return the sql
	CreatePagedSQL = strSQL
end function 'Function CreatePagedSQL(strFrom, strPrimKey, strColumns, strWhere, strOrderBy)

Function CreatePagingLinks(strTempAction)
	Dim strPaging as String = ""
	Dim strCurAction as String = ""

	'only display if there is more than one page
	If (intNumPages &gt; 1) Then
		'open the paging
		strPaging += "&lt;div class=""Paging"" &gt;"
		strPaging += "&lt;span class=""label"" &gt;page:&lt;/span&gt;"

		'if not the first page, add the previous link
		If intPageNumber &gt; 1 Then
			strCurAction = Replace(strTempAction, "{PageNo}", intPageNumber - 1)
			strPaging += "&lt;a class=""Previous"" href=""" &#038; strCurAction &#038; """ title=""Go to the previous page"" &gt;&laquo; Previous&lt;/a&gt;"
		End If 'If intPageNumber &gt; 1 Then

		'loop through and add the page numbers
		For i = 1 To intNumPages

			'set current action
			strCurAction = Replace(strTempAction, "{PageNo}", i)

			strPaging += "&lt;a href=""" &#038; strCurAction &#038; """ "

			'if this is the current page, mark as active
			If cint(i) = cint(intPageNumber) Then
				strPaging += " class=""Active"" "
			End If 'If i = intPageNumber Then

			strPaging += " title=""Go to Page " &#038; i &#038; """&gt;" &#038; i &#038; "&lt;/a&gt; "
		Next 'For i = 1 To intNumPages

		'if not the last page, show the next link
		If cint(intPageNumber) &lt; cint(intNumPages) Then
			strCurAction = Replace(strTempAction, "{PageNo}", intPageNumber + 1)
			strPaging += "&lt;a class=""Next"" href=""" &#038; strCurAction &#038; """ title=""Go to the next page"" &gt;Next &raquo;&lt;/a&gt;"
		End If 'If cint(intPageNumber) &lt; cint(intNumPages) Then

		'close the paging
		strPaging += "&lt;div class=""clear"" &gt;&lt;/div&gt;"
		strPaging += "&lt;/div&gt;"
	End If 'If (intNumPages &gt; 1) Then

	'return paging links
	CreatePagingLinks = strPaging
End Function 'Function CreatePagingLinks(strTempAction)

Function RoundUp(intNum)
	'Rounds up the given number
	If (intNum - Fix(intNum) &lt;&gt; 0) Then
		RoundUp = Fix(intNum) + 1
	Else 'If (intNum - Fix(intNum) &lt;&gt; 0) Then
		RoundUp = intNum
	End If 'If (intNum - Fix(intNum) &lt;&gt; 0) Then
end function 'Function RoundUp(intNum)
</pre>
<h2>Conclusion</h2>
<p>As well as giving the user easier controls to navigation through the pages, this code should also put less strain on your database, and also should result in quicker load times for you pages.</p>
<p>Any feedback or improvements are welcome.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ahdev.co.uk/tutorials/aspnet/2010/06/02/aspnet_data_reader_paging_with_page_numbers/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ASP Recordset Paging with Page Numbers</title>
		<link>http://www.ahdev.co.uk/tutorials/asp/2010/05/26/asp_recordset_paging_with_page_numbers/</link>
		<comments>http://www.ahdev.co.uk/tutorials/asp/2010/05/26/asp_recordset_paging_with_page_numbers/#comments</comments>
		<pubDate>Wed, 26 May 2010 08:00:10 +0000</pubDate>
		<dc:creator>Alan Holmes</dc:creator>
				<category><![CDATA[ASP]]></category>
		<category><![CDATA[Page Numbers]]></category>
		<category><![CDATA[Paging]]></category>
		<category><![CDATA[Recordset]]></category>

		<guid isPermaLink="false">http://www.ahdev.co.uk/?p=204</guid>
		<description><![CDATA[This Tutorial will explain how to create paging in ASP. As well as create the standard next and previous links, it will also output page numbers.]]></description>
			<content:encoded><![CDATA[<h2>The Idea</h2>
<p>You&#8217;ll be hard pressed to find a dynamic website these days that doesn&#8217;t make use of paging in some way or form, especially on list pages such as Products, News, etc. For a long time, I used the in built server behaviours in Dreamweaver, which suited most purposes, as they provided working previous, next, first and last links. </p>
<p>Problems started however as pages got more complex, and for unknown reasons the generated code would work on some sections and not others, even despite the code being the same. This combined with the issues that came with recordsets containing more and more data, I needed to look for an alternative, and more efficient solution.</p>
<h2>The Solution</h2>
<p>After much searching, I found that the general consensus, for more efficient paging, is to retrieve only the required amount of records from the database, so have 1000 records, then you only get the 50 that you are wanting to display at that time. This will require a little more planning when constructing your code and SQL statements, but will save a lot of load on your database, as you will not be requesting 1000 records on every page load.</p>
<p>In this tutorial, a sample news list page will be created, you can view a <a href="http://demo.ahdev.co.uk/ASP_Recordset_Paging_with_Numbers/" target="_blank">demo here</a>.</p>
<h3>The Required SQL</h3>
<p>Firstly, lets have a look at SQL that we need to retrieve the records, the first is for the first page of records, and the second is to return the second page of results. What the second statement does, is return the top 5 results, after ignoring the first 5 records, and then on following pages we would ignore 10, 15, 20 and so forth records.</p>
<pre class="brush:sql">
/* SQL request for the first page of records */
SELECT top 5 fldNewsID, fldTitle, fldAbstract, fldDate FROM Tbl_News ORDER BY fldDate desc

/* SQL request for the second page of records */
SELECT TOP 5 fldNewsID, fldTitle, fldAbstract, fldDate FROM Tbl_News WHERE (1=1) AND fldNewsID NOT IN (SELECT TOP 5 fldNewsID FROM Tbl_News WHERE (1=1) ORDER BY fldDate desc) ORDER BY fldDate desc
</pre>
<h3>The ASP Functions</h3>
<p>We shall be creating a function that will generate these statements for us, but first there are values that need to be set in order to set these values correctly.</p>
<pre class="brush:vb">
'Default Paging Values
intTotalRecords = 0	'Total Records
intNumPages = 0		'Number of pages
intPageSize = -1	'Amount per page, -1 means all
intPageNumber = 1	'The current page to display

'News Table Values
strFrom = "Tbl_News"
strPrimKey = "fldNewsID"
strColumns = "fldNewsID, fldTitle, fldAbstract, fldDate"
strWhere = ""
strOrderBy = "fldDate desc"

'Get the current page number from the querystring
intCurPage = 1
if (trim(request("p")) <> "") and (isnumeric(request("p"))) then
	intCurPage = request("p")
end if 'if (trim(request("p")) <> "") and (isnumeric(request("p"))) then

'Calls the function to set the current paging values
SetPagingValues 5, intCurPage, strFrom, strPrimKey, strWhere
</pre>
<p>Having set some presents, and gotten the current page number from the querystring, we call a function <strong><em>SetPagingValues</em></strong> that will take these details, and then set the Total Records and Number of Pages so that the paged SQL can be created properly.</p>
<pre class="brush:vb">
Sub SetPagingValues(intTempPageSize, intTempPageNumber, strFrom, strPrimKey, strWhere)
	strSQLCount = ""
	sngTempNumPages = 0
	intTempNumPages = 1

	'Set the Page Size (number of records to show per page)
	If (Trim(intTempPageSize) <> "") And (isnumeric(intTempPageSize)) Then
		intPageSize = intTempPageSize
	Else 'If (Trim(intTempPageSize) <> "") And (isnumeric(intTempPageSize)) Then
		'not valid number, so set to -1
		'IE all records
		intPageSize = -1
	End If 'If (Trim(intTempPageSize) <> "") And (isnumeric(intTempPageSize)) Then

	'Set the page number (the current page being viewed)
	If (Trim(intTempPageNumber) <> "") And (isnumeric(intTempPageNumber)) Then
		intPageNumber = intTempPageNumber
	Else 'If (Trim(intTempPageNumber) <> "") And (isnumeric(intTempPageNumber)) Then
		'if not a valid number, set page number to 1
		intPageNumber = 1
	End If 'If (Trim(intTempPageNumber) <> "") And (isnumeric(intTempPageNumber)) Then

	'SQL to get the total number of records in table
	strSQLCount = "SELECT Count(*) As RecCount From " &#038; strFrom &#038; " WHERE (1=1) "

	'If given add the where clause
	If Trim(strWhere) <> "" Then
		strSQLCount = strSQLCount &#038; " AND " &#038; strWhere
	End If 'If Trim(strWhere) <> "" Then

	'open the sql
	Set objCmd = Server.CreateObject("ADODB.Command")
	objCmd.ActiveConnection = strConnectionString

	objCmd.CommandText = strSQLCount
	set rsRecCount = objCmd.Execute 

	'Set the total records value
	If not rsRecCount.eof Then
		intTotalRecords = rsRecCount("RecCount")
	Else 'If not rsRecCount.eof Then
		intTotalRecords = 0
	End If 'If not rsRecCount.eof Then

	'close the count
	set rsRecCount = nothing

	'close the connection
	objCmd.ActiveConnection = nothing
	Set objCmd = nothing

	'if Total Records and Page size is greater than 0
	'then work out the number of pages
	If (intTotalRecords > 0) And (intPageSize > 0) Then
		sngTempNumPages = intTotalRecords / intPageSize
		intTempNumPages = RoundUp(sngTempNumPages)
	Else 'If (intTotalRecords > 0) And (intPageSize > 0) Then
		intTempNumPages = 1
	End If 'If (intTotalRecords > 0) AND (intPageSize > 0) Then

	'set the num pages
	intNumPages = intTempNumPages

	'if Page number is greater than number of pages, then set to
	'number of pages
	If cint(intPageNumber) > cint(intNumPages) Then
		intPageNumber = intNumPages
	End If 'If intPageNumber > intNumPages Then
End Sub 'Sub SetPagingValues(intTempPageSize, intTempPageNumber, strFrom, strPrimKey, strWhere)

Function RoundUp(intNum)
	'Rounds up the given number
	If (intNum - Fix(intNum) <> 0) Then
		RoundUp = Fix(intNum) + 1
	Else 'If (intNum - Fix(intNum) <> 0) Then
		RoundUp = intNum
	End If 'If (intNum - Fix(intNum) <> 0) Then
end function 'Function RoundUp(intNum)
</pre>
<p>The <strong><em>RoundUp</em></strong> is simply used to ensure that we have the correct number of pages. As the number of pages is calculated by Total Records/Amount Per page, it is quite possible that the answer could contain a decimal, such as 3.5, in this case, we need to ensure that the next full number (in this case 4) is used.</p>
<p>Now that we have all the variables set correctly, we can call the function to create the SQL statement.</p>
<pre class="brush:vb">
'calls the function to get the paged sql
strSQL = CreatePagedSQL(strFrom, strPrimKey, strColumns, strWhere, strOrderBy)

Function CreatePagedSQL(strFrom, strPrimKey, strColumns, strWhere, strOrderBy)
	'Returns paged dataset for supplied SQL, broken down into sections
	strSQL = ""
	strTopRecords = ""
	intIgnoreRecs = 0
	strPagedWhere = " WHERE (1=1) "

	'Create where clause
	If Trim(strWhere) <> "" Then
		strPagedWhere = strPagedWhere &#038; " AND " &#038; strWhere
	End If 'If Trim(strPagedWhere) <> "" Then

	'create Order clause
	If Trim(strOrderBy) <> "" Then
		strOrderBy = " ORDER BY " &#038; strOrderBy
	End If 'If Trim(strOrderBy) <> "" Then

	'set how many records to get
	If intPageSize > 0 Then
		strTopRecords = " TOP " &#038; intPageSize
	End If 'If intPageSize > 0 Then

	'if not on page one, set the number of records to ignore
	If (intNumPages > 1) And (intPageNumber > 1) Then
		intIgnoreRecs = intPageSize * (intPageNumber - 1)
		strPagedWhere = strPagedWhere &#038; " AND " &#038; strPrimKey &#038; " NOT IN (SELECT TOP " &#038; intIgnoreRecs &#038; " " &#038; strPrimKey &#038; " FROM " &#038; strFrom &#038; " " &#038; strPagedWhere &#038; " " &#038; strOrderBy &#038; ")"
	End If 'If (intNumPages > 1) And (intPageNumber > 1) Then

	'create sql
	strSQL = "SELECT " &#038; strTopRecords &#038; " " &#038; strColumns &#038; " FROM " &#038; strFrom &#038; " " &#038; strPagedWhere &#038; " " &#038; strOrderBy

	'return the sql
	CreatePagedSQL = strSQL
end function 'Function CreatePagedSQL(strFrom, strPrimKey, strColumns, strWhere, strOrderBy)
</pre>
<p>We now have our SQL statement, so we can now use it to output the selected records.</p>
<pre class="brush:vb">
'Open a command oject for connections to the database
Set objCommand = Server.CreateObject("ADODB.Command")
objCommand.ActiveConnection = strConnectionString

'Get the records from the database
objCommand.CommandText = strSQL
set rsNewsList = objCommand.Execute 

'Loop through the recordset and output the data
while not rsNewsList.eof

	response.Write("&lt;div class=""NewsList""&gt;")
	response.Write("&lt;span class=""Title""&gt;" &#038; rsNewsList("fldTitle") &#038; "&lt;/span&gt;")
	response.Write("&lt;span class=""Date""&gt;" &#038; rsNewsList("fldDate") &#038; "&lt;/span&gt;")
	response.Write("&lt;span class=""Abstract""&gt;" &#038; rsNewsList("fldAbstract") &#038; "&lt;/span&gt;")
	response.Write("&lt;/div&gt;")

rsNewsList.movenext
wend

'Output the numbered paging links
response.write(CreatePagingLinks("default.asp?p={PageNo}"))

'empty the recordset
Set rsNewsList = nothing

'close the command object
objCommand.ActiveConnection = nothing
Set objCommand = nothing
</pre>
<p>And the final step is to output the paging links, by creating the function <strong><em>CreatePagingLinks</em></strong> (called on line 22).</p>
<pre class="brush:vb">
Function CreatePagingLinks(strTempAction)
	strPaging = ""
	strCurAction = ""

	'only display if there is more than one page
	If (intNumPages &gt; 1) Then
		'open the paging
		strPaging = strPaging &#038; "&lt;div class=""Paging"" &gt;"
		strPaging = strPaging &#038; "&lt;span class=""label"" &gt;page:&lt;/span&gt;"

		'if not the first page, add the previous link
		If intPageNumber &gt; 1 Then
			strCurAction = Replace(strTempAction, "{PageNo}", intPageNumber - 1)
			strPaging = strPaging &#038; "&lt;a class=""Previous"" href=""" &#038; strCurAction &#038; """ title=""Go to the previous page"" &gt;&laquo; Previous&lt;/a&gt;"
		End If 'If intPageNumber &gt; 1 Then

		'loop through and add the page numbers
		For i = 1 To intNumPages

			'set current action
			strCurAction = Replace(strTempAction, "{PageNo}", i)

			strPaging = strPaging &#038; "&lt;a href=""" &#038; strCurAction &#038; """ "

			'if this is the current page, mark as active
			If cint(i) = cint(intPageNumber) Then
				strPaging = strPaging &#038; " class=""Active"" "
			End If 'If i = intPageNumber Then

			strPaging = strPaging &#038; " title=""Go to Page " &#038; i &#038; """&gt;" &#038; i &#038; "&lt;/a&gt; "
		Next 'For i = 1 To intNumPages

		'if not the last page, show the next link
		If cint(intPageNumber) &lt; cint(intNumPages) Then
			strCurAction = Replace(strTempAction, "{PageNo}", intPageNumber + 1)
			strPaging = strPaging &#038; "&lt;a class=""Next"" href=""" &#038; strCurAction &#038; """ title=""Go to the next page"" &gt;Next &raquo;&lt;/a&gt;"
		End If 'If cint(intPageNumber) &lt; cint(intNumPages) Then

		'close the paging
		strPaging = strPaging &#038; "&lt;div class=""clear"" &gt;&lt;/div&gt;"
		strPaging = strPaging &#038; "&lt;/div&gt;"
	End If 'If (intNumPages &gt; 1) Then

	'return paging links
	CreatePagingLinks = strPaging
End Function 'Function CreatePagingLinks(strTempAction)
</pre>
<h3>The Full ASP Code</h3>
<p>And thats it, the full code needed to create recordset paging with page numbers, below is the full code:</p>
<pre class="brush:vb">
strConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=Path to your database location\Private\News_Example.mdb"

'Default Paging Values
intTotalRecords = 0	'Total Records
intNumPages = 0		'Number of pages
intPageSize = -1	'Amount per page, -1 means all
intPageNumber = 1	'The current page to display

'News Table Values
strFrom = "Tbl_News"
strPrimKey = "fldNewsID"
strColumns = "fldNewsID, fldTitle, fldAbstract, fldDate"
strWhere = ""
strOrderBy = "fldDate desc"

'Get the current page number from the querystring
intCurPage = 1
if (trim(request("p")) &lt;&gt; "") and (isnumeric(request("p"))) then
	intCurPage = request("p")
end if 'if (trim(request("p")) &lt;&gt; "") and (isnumeric(request("p"))) then

'Calls the function to set the current paging values
SetPagingValues 5, intCurPage, strFrom, strPrimKey, strWhere

'calls the function to get the paged sql
strSQL = CreatePagedSQL(strFrom, strPrimKey, strColumns, strWhere, strOrderBy)

'Open a command oject for connections to the database
Set objCommand = Server.CreateObject("ADODB.Command")
objCommand.ActiveConnection = strConnectionString

'Get the records from the database
objCommand.CommandText = strSQL
set rsNewsList = objCommand.Execute 

'Loop through the recordset and output the data
while not rsNewsList.eof

	response.Write("&lt;div class=""NewsList""&gt;")
	response.Write("&lt;span class=""Title""&gt;" &#038; rsNewsList("fldTitle") &#038; "&lt;/span&gt;")
	response.Write("&lt;span class=""Date""&gt;" &#038; rsNewsList("fldDate") &#038; "&lt;/span&gt;")
	response.Write("&lt;span class=""Abstract""&gt;" &#038; rsNewsList("fldAbstract") &#038; "&lt;/span&gt;")
	response.Write("&lt;/div&gt;")

rsNewsList.movenext
wend

'Output the numbered paging links
response.write(CreatePagingLinks("default.asp?p={PageNo}"))

'empty the recordset
Set rsNewsList = nothing

'close the command object
objCommand.ActiveConnection = nothing
Set objCommand = nothing

Sub SetPagingValues(intTempPageSize, intTempPageNumber, strFrom, strPrimKey, strWhere)
	strSQLCount = ""
	sngTempNumPages = 0
	intTempNumPages = 1

	'Set the Page Size (number of records to show per page)
	If (Trim(intTempPageSize) &lt;&gt; "") And (isnumeric(intTempPageSize)) Then
		intPageSize = intTempPageSize
	Else 'If (Trim(intTempPageSize) &lt;&gt; "") And (isnumeric(intTempPageSize)) Then
		'not valid number, so set to -1
		'IE all records
		intPageSize = -1
	End If 'If (Trim(intTempPageSize) &lt;&gt; "") And (isnumeric(intTempPageSize)) Then

	'Set the page number (the current page being viewed)
	If (Trim(intTempPageNumber) &lt;&gt; "") And (isnumeric(intTempPageNumber)) Then
		intPageNumber = intTempPageNumber
	Else 'If (Trim(intTempPageNumber) &lt;&gt; "") And (isnumeric(intTempPageNumber)) Then
		'if not a valid number, set page number to 1
		intPageNumber = 1
	End If 'If (Trim(intTempPageNumber) &lt;&gt; "") And (isnumeric(intTempPageNumber)) Then

	'SQL to get the total number of records in table
	strSQLCount = "SELECT Count(*) As RecCount From " &#038; strFrom &#038; " WHERE (1=1) "

	'If given add the where clause
	If Trim(strWhere) &lt;&gt; "" Then
		strSQLCount = strSQLCount &#038; " AND " &#038; strWhere
	End If 'If Trim(strWhere) &lt;&gt; "" Then

	'open the sql
	Set objCmd = Server.CreateObject("ADODB.Command")
	objCmd.ActiveConnection = strConnectionString

	objCmd.CommandText = strSQLCount
	set rsRecCount = objCmd.Execute 

	'Set the total records value
	If not rsRecCount.eof Then
		intTotalRecords = rsRecCount("RecCount")
	Else 'If not rsRecCount.eof Then
		intTotalRecords = 0
	End If 'If not rsRecCount.eof Then

	'close the count
	set rsRecCount = nothing

	'close the connection
	objCmd.ActiveConnection = nothing
	Set objCmd = nothing

	'if Total Records and Page size is greater than 0
	'then work out the number of pages
	If (intTotalRecords &gt; 0) And (intPageSize &gt; 0) Then
		sngTempNumPages = intTotalRecords / intPageSize
		intTempNumPages = RoundUp(sngTempNumPages)
	Else 'If (intTotalRecords &gt; 0) And (intPageSize &gt; 0) Then
		intTempNumPages = 1
	End If 'If (intTotalRecords &gt; 0) AND (intPageSize &gt; 0) Then

	'set the num pages
	intNumPages = intTempNumPages

	'if Page number is greater than number of pages, then set to
	'number of pages
	If cint(intPageNumber) &gt; cint(intNumPages) Then
		intPageNumber = intNumPages
	End If 'If intPageNumber &gt; intNumPages Then
End Sub 'Sub SetPagingValues(intTempPageSize, intTempPageNumber, strFrom, strPrimKey, strWhere)

Function CreatePagedSQL(strFrom, strPrimKey, strColumns, strWhere, strOrderBy)
	'Returns paged dataset for supplied SQL, broken down into sections
	strSQL = ""
	strTopRecords = ""
	intIgnoreRecs = 0
	strPagedWhere = " WHERE (1=1) "

	'Create where clause
	If Trim(strWhere) &lt;&gt; "" Then
		strPagedWhere = strPagedWhere &#038; " AND " &#038; strWhere
	End If 'If Trim(strPagedWhere) &lt;&gt; "" Then

	'create Order clause
	If Trim(strOrderBy) &lt;&gt; "" Then
		strOrderBy = " ORDER BY " &#038; strOrderBy
	End If 'If Trim(strOrderBy) &lt;&gt; "" Then

	'set how many records to get
	If intPageSize &gt; 0 Then
		strTopRecords = " TOP " &#038; intPageSize
	End If 'If intPageSize &gt; 0 Then

	'if not on page one, set the number of records to ignore
	If (intNumPages &gt; 1) And (intPageNumber &gt; 1) Then
		intIgnoreRecs = intPageSize * (intPageNumber - 1)
		strPagedWhere = strPagedWhere &#038; " AND " &#038; strPrimKey &#038; " NOT IN (SELECT TOP " &#038; intIgnoreRecs &#038; " " &#038; strPrimKey &#038; " FROM " &#038; strFrom &#038; " " &#038; strPagedWhere &#038; " " &#038; strOrderBy &#038; ")"
	End If 'If (intNumPages &gt; 1) And (intPageNumber &gt; 1) Then

	'create sql
	strSQL = "SELECT " &#038; strTopRecords &#038; " " &#038; strColumns &#038; " FROM " &#038; strFrom &#038; " " &#038; strPagedWhere &#038; " " &#038; strOrderBy

	'return the sql
	CreatePagedSQL = strSQL
end function 'Function CreatePagedSQL(strFrom, strPrimKey, strColumns, strWhere, strOrderBy)

Function CreatePagingLinks(strTempAction)
	strPaging = ""
	strCurAction = ""

	'only display if there is more than one page
	If (intNumPages &gt; 1) Then
		'open the paging
		strPaging = strPaging &#038; "&lt;div class=""Paging"" &gt;"
		strPaging = strPaging &#038; "&lt;span class=""label"" &gt;page:&lt;/span&gt;"

		'if not the first page, add the previous link
		If intPageNumber &gt; 1 Then
			strCurAction = Replace(strTempAction, "{PageNo}", intPageNumber - 1)
			strPaging = strPaging &#038; "&lt;a class=""Previous"" href=""" &#038; strCurAction &#038; """ title=""Go to the previous page"" &gt;&laquo; Previous&lt;/a&gt;"
		End If 'If intPageNumber &gt; 1 Then

		'loop through and add the page numbers
		For i = 1 To intNumPages

			'set current action
			strCurAction = Replace(strTempAction, "{PageNo}", i)

			strPaging = strPaging &#038; "&lt;a href=""" &#038; strCurAction &#038; """ "

			'if this is the current page, mark as active
			If cint(i) = cint(intPageNumber) Then
				strPaging = strPaging &#038; " class=""Active"" "
			End If 'If i = intPageNumber Then

			strPaging = strPaging &#038; " title=""Go to Page " &#038; i &#038; """&gt;" &#038; i &#038; "&lt;/a&gt; "
		Next 'For i = 1 To intNumPages

		'if not the last page, show the next link
		If cint(intPageNumber) &lt; cint(intNumPages) Then
			strCurAction = Replace(strTempAction, "{PageNo}", intPageNumber + 1)
			strPaging = strPaging &#038; "&lt;a class=""Next"" href=""" &#038; strCurAction &#038; """ title=""Go to the next page"" &gt;Next &raquo;&lt;/a&gt;"
		End If 'If cint(intPageNumber) &lt; cint(intNumPages) Then

		'close the paging
		strPaging = strPaging &#038; "&lt;div class=""clear"" &gt;&lt;/div&gt;"
		strPaging = strPaging &#038; "&lt;/div&gt;"
	End If 'If (intNumPages &gt; 1) Then

	'return paging links
	CreatePagingLinks = strPaging
End Function 'Function CreatePagingLinks(strTempAction)

Function RoundUp(intNum)
	'Rounds up the given number
	If (intNum - Fix(intNum) &lt;&gt; 0) Then
		RoundUp = Fix(intNum) + 1
	Else 'If (intNum - Fix(intNum) &lt;&gt; 0) Then
		RoundUp = intNum
	End If 'If (intNum - Fix(intNum) &lt;&gt; 0) Then
end function 'Function RoundUp(intNum)
</pre>
<h3>Styling</h3>
<p>Finally, some CSS just to make the sample easier to visualise.</p>
<pre class="brush:css">.NewsList{
	border:1px solid #000000;
	margin-bottom:10px;
	padding:5px;
	width:500px;
}

.NewsList .Title{
	font:bold 12pt Arial, Helvetica, sans-serif;
}

.NewsList .Date{
	font:italic 8pt Arial, Helvetica, sans-serif;
	padding-left:10px;
}

.NewsList .Abstract{
	font:10pt Arial, Helvetica, sans-serif;
	display:block;
}

.Paging .label{
	display:block;
	float:left;
	padding:3px;
	margin:0px 0px 2px 0px;
	color:#999999;
}

.Paging a{
	display:block;
	float:left;
	border:1px solid #999999;
	padding:2px;
	margin:0px 0px 2px 2px;
	text-align:right;
	width:16px;
	text-decoration:none;
	color:#999999;
}

.Paging a:hover{
	border:1px solid #000000;
	color:#000000;
}

.Paging a.Active{
	border:1px solid #000000;
	color:#000000;
}

.Paging a.Previous, .Paging a.Next{
	width:auto;
	padding:2px 4px;
}</pre>
<h2>Conclusion and Download</h2>
<p>As well as giving the user easier controls to navigation through the pages, this code should also put less strain on your database, and also should result in quicker load times for you pages.</p>
<div class="DownloadButton Center"><a title="Download the files for this demo" href="http://static.ahdev.co.uk/downloads/ASP_Recordset_Paging_with_Numbers.zip">Download Demo Files</a></div>
<p>Any feedback or improvements are welcome.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ahdev.co.uk/tutorials/asp/2010/05/26/asp_recordset_paging_with_page_numbers/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Useful Styling Techniques Introduced in CSS3</title>
		<link>http://www.ahdev.co.uk/tutorials/htmlcss/2010/05/19/useful_styling_techniques_introduced_in_css3/</link>
		<comments>http://www.ahdev.co.uk/tutorials/htmlcss/2010/05/19/useful_styling_techniques_introduced_in_css3/#comments</comments>
		<pubDate>Wed, 19 May 2010 08:00:30 +0000</pubDate>
		<dc:creator>Alan Holmes</dc:creator>
				<category><![CDATA[HTML/CSS]]></category>
		<category><![CDATA[border-radius]]></category>
		<category><![CDATA[box-shadow]]></category>
		<category><![CDATA[CSS3]]></category>
		<category><![CDATA[text-shadow]]></category>
		<category><![CDATA[word-wrap]]></category>

		<guid isPermaLink="false">http://www.ahdev.co.uk/?p=185</guid>
		<description><![CDATA[With the introduction of CSS3, comes some new, very useful styling abilities, including border-radius, which can be used to create rounded borders, like those seen in the WordPress admin menus, buttons and tables.]]></description>
			<content:encoded><![CDATA[<h2>CSS3 Techniques</h2>
<p>Although all CSS3 techniques are not yet full supported (well, to be honest, not supported in Internet Explorer, surprise surprise), there are some useful techniques that are worth knowing about now, and currently (on my personal tests), work in Firefox 3.6.3, Google Chrome 4.1.2 and Safari 4.0.5, but are also said to work in Konqueror and Opera.</p>
<p>Here we shall be looking at four techniques in particular, border-radius, box-shadow, text-shadow and word-wrap.</p>
<h2>Border-Radius</h2>
<p><strong><em>Border-Radius</em></strong> will allow you to create round corners, without the need to use images. You can add it to all, or specific corners, buy using the following:</p>
<pre class="brush:css">
/* Round all corners */
-moz-border-radius:10px;
-webkit-border-radius: 10px;
-khtml-border-radius: 10px;

/* Round top left corner */
-moz-border-radius-topleft :10px;
-webkit-border-top-left-radius: 10px;
-khtml-border-top-left-radius: 10px;
</pre>
<p>This technique works in Firefox 3.6.3, Google Chrome 4.1.2 and Safari 4.0.5, you can view a <a href="http://demo.ahdev.co.uk/CSS3_Techniques/border-radius.html" target="_blank">demo here</a>. For those using an unsupported browser, a screen shot is below:</p>
<div class="ImageBox" style="width: 408px;"><img src="http://images.ahdev.co.uk/articles/BorderRadius.jpg" alt="Border-Radius" width="402" height="94" /><span> Screen shot of Border-Radius in use.</span></div>
<h2>Box-Shadow</h2>
<p><strong><em>Box-Shadow</em></strong> will apply a drop shadow to the box. It takes three lengths and a colour as its attributes, the lengths are as follows:</p>
<ul>
<li>The horizontal offset, positive means the shadow will be on the right, a negative offset will put the shadow on the left</li>
<li>The vertical offset, a positive one means the shadow will be below the box, a negative one means the shadow will be above the box</li>
<li>The blur radius, if set to 0 the shadow will be sharp, the higher the number, the more blurred it will be</li>
</ul>
<p>Use the following css to add a shadow:</p>
<pre class="brush:css">
-moz-box-shadow: 10px 10px 5px #888;
-webkit-box-shadow: 10px 10px 5px #888;
-khtml-box-shadow: 10px 10px 5px #888;
</pre>
<p>This technique works in Firefox 3.6.3, Google Chrome 4.1.2 and Safari 4.0.5, you can view a <a href="http://demo.ahdev.co.uk/CSS3_Techniques/box-shadow.html" target="_blank">demo here</a>. For those using an unsupported browser, a screen shot is below:</p>
<div class="ImageBox" style="width: 408px;"><img src="http://images.ahdev.co.uk/articles/Boxshadow.jpg" alt="Box-Shadow" width="402" height="56" /><span> Screen shot of Box-Shaodw in use.</span></div>
<h2>Text-Shadow</h2>
<p><strong><em>Text-Shadow</em> </strong>will apply a drop shadow to text. It takes three lengths and a colour as its attributes, the lengths are as follows:</p>
<ul>
<li>The horizontal offset, positive means the shadow will be on the right, a negative offset will put the shadow on the left</li>
<li>The vertical offset, a positive one means the shadow will be below the box, a negative one means the shadow will be above the box</li>
<li>The blur radius, if set to 0 the shadow will be sharp, the higher the number, the more blurred it will be</li>
</ul>
<p>Use the following css to add a shadow:</p>
<pre class="brush:css">
text-shadow: 2px 2px 2px #333;
</pre>
<p>This technique works in Firefox 3.6.3, Google Chrome 4.1.2 and Safari 4.0.5, you can view a <a href="http://demo.ahdev.co.uk/CSS3_Techniques/text-shadow.html" target="_blank">demo here</a>. For those using an unsupported browser, a screen shot is below:</p>
<div class="ImageBox" style="width: 408px;"><img src="http://images.ahdev.co.uk/articles/textshadow.jpg" alt="Text-Shadow" width="402" height="27" /><span> Screen shot of Text-Shaodw in use.</span></div>
<h2>Word-Wrap</h2>
<p><strong><em>Word-wrap</em></strong> allows long words to be wrapped within a box, making the word flow onto the next line. It has two possible values, <strong><em>normal</em></strong> and <strong><em>break-word</em></strong>.</p>
<p>Using <strong><em>break-word</em></strong> you will be able to force long words to be spread across multiple lines.</p>
<p>Use the following css to add a shadow:</p>
<pre class="brush:css">
word-wrap:break-word;
</pre>
<p>This technique works in IE7, Firefox 3.6.3, Google Chrome 4.1.2 and Safari 4.0.5, you can view a <a href="http://demo.ahdev.co.uk/CSS3_Techniques/word-wrap.html" target="_blank">demo here</a>. For those using an unsupported browser, a screen shot is below:</p>
<div class="ImageBox" style="width: 408px;"><img src="http://images.ahdev.co.uk/articles/wordwrap.jpg" alt="Word-Wrap" width="402" height="179" /><span> Screen shot of Word-Wrap in use.</span></div>
<h2>Compatibility, Conclusion and Download</h2>
<p>These techniques have been tested in IE7, Firefox 3.6.3, Google Chrome 4.1.2 and Safari 4.0.5, all on a windows platform. Please refer to each example as to which browsers they do work in. These are very useful techniques, and can save a lot of time, as they are much simpler than trying to reproduce the same results with images. All we need now is for Microsoft to pick up these techniques an include them in Internet Explorer, so that they can be used without needing to provide alternatives just for IE.</p>
<div class="DownloadButton Center"><a title="Download the files for this demo" href="http://static.ahdev.co.uk/downloads/CSS3_Techniques.zip">Download Demo Files</a></div>
<p>Any feedback or improvements are welcome.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ahdev.co.uk/tutorials/htmlcss/2010/05/19/useful_styling_techniques_introduced_in_css3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Dependant Drop Downs Using Ajax</title>
		<link>http://www.ahdev.co.uk/tutorials/ajax_javascript/2010/05/12/dependant_drop_downs_using_ajax/</link>
		<comments>http://www.ahdev.co.uk/tutorials/ajax_javascript/2010/05/12/dependant_drop_downs_using_ajax/#comments</comments>
		<pubDate>Wed, 12 May 2010 08:00:09 +0000</pubDate>
		<dc:creator>Alan Holmes</dc:creator>
				<category><![CDATA[Ajax/JavaScript]]></category>
		<category><![CDATA[Ajax]]></category>
		<category><![CDATA[Dependant Drop Downs]]></category>
		<category><![CDATA[Select Menu]]></category>

		<guid isPermaLink="false">http://www.ahdev.co.uk/?p=192</guid>
		<description><![CDATA[This tutorial will explain how to create dependant/cascading drop down menus, using Ajax to retrieve the options for the sub menus.]]></description>
			<content:encoded><![CDATA[<h2>The Idea</h2>
<p>Probably one of the most common needs for drop down menus (select menus), is to have multiple depending drop downs, an example of this could be cars, having makes and models. The requirement, is that when a user selects a value in the first drop down, the second drop down is then filled with corresponding data.</p>
<p>In the past, this was solved by submitting the page on each selection, and although this solves the problem quite well, it is far from ideal. With this method the whole page would have to be loaded every time the user selects a value (specifically if the data is to be retrieved from a database), not only meaning a slower experience for the user (and possibly a higher server usage), but also extra coding would be needed to ensure the rest of the users entries are remembered (enough though that is already likely to be in place for server side validation).</p>
<p>With the usage of JavaScript becoming more common, and the arrival of Ajax (asynchronous JavaScript and XML), comes a far better solution, and certainly a more user friendly solution. Using Ajax, we can send a request to the server to get the data, and then display in the in second drop down menu, without the user seeing anything happening.</p>
<h2>The Solution</h2>
<p>In this tutorial, we will be creating a demo that will use car make and models to illustrate the use of Ajax to meet these needs, you can view a <a href="http://demo.ahdev.co.uk/Ajax_Dependant_Drop_Down/" target="_blank">demo here</a>.</p>
<h3>The Form</h3>
<p>Firstly, lets create the form, with the needed. For this sample, we will be using just a few cars and models for each, that will not be retrieved from the database (though it can simply be altered to make so).</p>
<p>As you can see, only the Make menu has any values, the Model will be filled upon selection of a Make.</p>
<pre class="brush:xml">&lt;form&gt;
	&lt;select id="CarMake" name="CarMake" onchange="GetModels();"&gt;
		&lt;option value=""&gt; -- Please Select -- &lt;/option&gt;
		&lt;option value="Audi"&gt;Audi&lt;/option&gt;
		&lt;option value="BMW"&gt;BMW&lt;/option&gt;
		&lt;option value="Ford"&gt;Ford&lt;/option&gt;
	&lt;/select&gt;
	&lt;select id="CarModel" name="CarModel"&gt;
		&lt;option value=""&gt; -- Please Select -- &lt;/option&gt;
	&lt;/select&gt;
&lt;/form&gt;</pre>
<h3>The Ajax</h3>
<p>That&#8217;s the easy part done with, now onto the Ajax. Firstly we need to create the XmlHttpRequest Object that will be used to retrieve the data.</p>
<pre class="brush:javascript">//Our XmlHttpRequest object to get the models
var xmlModels = getXmlHttpRequestObject();

//Gets the browser specific XmlHttpRequest Object
function getXmlHttpRequestObject() {
	if (window.XMLHttpRequest) {
		return new XMLHttpRequest();
	}else if(window.ActiveXObject) {
		return new ActiveXObject("Microsoft.XMLHTTP");
	}
}</pre>
<p>Now we will create the <strong><em>GetModels</em></strong> that is called when a change is made to the Car Make drop down. This function will get the current selected value of the Car Make drop down, and then make a call to an ASP page, which will process the make and return the relevant models.</p>
<pre class="brush:javascript">function GetModels(){

	//Get the Car Make
	sltCarMake = document.getElementById("CarMake");
	strCarMake = sltCarMake.options[sltCarMake.selectedIndex].value;

	//URL to get the models from, the timestamp is to ensure that
	//each request is fresh, and not cached
	//(especially if data is from the database)
	var timestamp = Number(new Date());
	var url='models.asp?Make=' + strCarMake + '&#038;ts=' + timestamp

	//The Ajax Request, the response is handled in the function Models_Handle
	xmlModels.open("GET", url, true);
	xmlModels.onreadystatechange = Models_Handle;
	xmlModels.send(null);
}</pre>
<p>Now that we have the data, we need to process it, and that is done by the <strong><em>Models_Handle</em></strong> function, which is take the data, and split it into an array, which is then entered into the drop down menu.</p>
<pre class="brush:javascript">
function Models_Handle(){
	if (xmlModels.readyState == 4) {
		//Get the Response
		var strResponse = xmlModels.responseText

		//Car Model object
		sltCarModel = document.getElementById("CarModel");

		//reset select menu to default
		sltCarModel.options.length=0;
		sltCarModel.options[0] = new Option(" -- Please Select -- ","");

		if (strResponse != ""){

			//Split response into array
			var arrResponse = strResponse.split("||");	

			var arrLen = arrResponse.length;
			var intPos = 0;
			for(i=0;i&lt;arrLen;i++){
				sltCarModel.options[i + 1] = new Option(arrResponse[i],arrResponse[i]);
			}
		}
	}
}</pre>
<h3>The ASP Page</h3>
<p>All that is left to create is the ASP page to return the data. In this sample we will be using some hard coded values, but you can simply replace this with some database driven code to output the same results.</p>
<pre class="brush:vb">
strCarMake = request("Make")
strCarModels = ""

select case lcase(strCarMake)

	case "audi"
		strCarModels = "A1||A2||A3||A4||A5"
	case "bmw"
		strCarModels = "Series 1||Series 3||Series 5||Series 6||Series 7"
	case "ford"
		strCarModels = "Ka||Fiesta||Focus||Focus RS||Mondeo"

end select

response.Write(strCarModels)</pre>
<h2>Compatibility, Conclusion and Download</h2>
<p>This script has been tested in IE7 (though should also work in IE6), Firefox 3.5.3, Google Chrome 4.1.2 and Safari 4.0.5, all on a windows platform. This is a very useful technique, which can easily be altered to fill several dependant drop downs. The Ajax technique can also be used retrieve data for other form elements, and to get &#8216;dynamic&#8217; content for web pages.</p>
<div class="DownloadButton Center"><a title="Download the files for this demo" href="http://static.ahdev.co.uk/downloads/Ajax_Dependant_Drop_Down.zip">Download Demo Files</a></div>
<p>Any feedback or improvements are welcome.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ahdev.co.uk/tutorials/ajax_javascript/2010/05/12/dependant_drop_downs_using_ajax/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Navigation Tabs using &#8216;Sliding Doors&#8217; Method</title>
		<link>http://www.ahdev.co.uk/tutorials/htmlcss/2010/03/05/navigation_tabs_using_sliding_doors_method/</link>
		<comments>http://www.ahdev.co.uk/tutorials/htmlcss/2010/03/05/navigation_tabs_using_sliding_doors_method/#comments</comments>
		<pubDate>Fri, 05 Mar 2010 08:00:47 +0000</pubDate>
		<dc:creator>Alan Holmes</dc:creator>
				<category><![CDATA[HTML/CSS]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[CSS Sprites]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[Navigation]]></category>
		<category><![CDATA[Sliding Doors]]></category>
		<category><![CDATA[Tabs]]></category>

		<guid isPermaLink="false">http://www.ahdev.co.uk/?p=33</guid>
		<description><![CDATA[This tutorial will explain how to create navigational tabs, like those seen on play.com, using the 'Sliding Doors' method.]]></description>
			<content:encoded><![CDATA[<h2>The Idea</h2>
<p>Tabs have been used for navigation for many years, and this has generally been done by using an image, either as a background, or using the &lt;img&gt; tag. The main disadvantage to this method is that each tab must be the exact same size (thus having varying degrees of &#8216;padding&#8217; for the text), or needing a different image for each tab. This will cause problems, either when adding a new tab, or should the tab text be too long.</p>
<p>There is one popular css method, know as &#8216;Sliding Doors&#8217;, combined with &#8216;<a title="View article on CSS Sprites" href="/tutorials/htmlcss/2010/03/02/css_sprites/">CSS Sprite Images</a>&#8216;, that allows for the use of a single image to be used for tabs of any width <em>(Note: Depending on the width of the tab image)</em>. Using these two methods, we will reproduce an effect similar to the navigation on <a href="http://www.play.com" target="_blank">Play.com</a>.</p>
<h2>The Solution</h2>
<p>We will be creating navigation that will look as below, you can view a <a href="http://demo.ahdev.co.uk/Sliding_Door_Tabs/" target="_blank">demo here</a>.</p>
<div class="ImageBox" style="width: 414px;"><img title="Navigation Tabs, using sliding door method, with normal, hover and current states" src="http://images.ahdev.co.uk/articles/SlidingDoorTabsEndResult.jpg" alt="Navigation Tabs, using sliding door method, with normal, hover and current states" width="408" height="25" /><span>Navigation Tabs, using sliding door method, with normal, hover and current states.</span></div>
<h3>Tab Image</h3>
<div class="ImageBox Right"><img src="http://demo.ahdev.co.uk/Sliding_Door_Tabs/images/Tabs.jpg" border="0" alt="Navigation Tabs" width="246" height="75" /><span><strong>Top:</strong> Normal, <strong>Middle:</strong> Hover, <strong>Bottom:</strong> Current</span></div>
<p>This is the single image that will be used in creating the navigation. It contains three different tabs. The grey will be used for the normal state of the navigation, the blue will be used for the hover state, and the orange will be used for the &#8220;current&#8221; page.</p>
<h3>HTML</h3>
<p>Firstly lets look at the HTML for our navigation. This is what a typical navigation might look like (as you can see each link will be a different length):</p>
<pre class="brush:xml">&lt;div class="MainNavigation"&gt;
	&lt;ul&gt;
		&lt;li&gt;&lt;a href="#"&gt;Home&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="#"&gt;Services&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="#"&gt;Portfolio&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="#"&gt;Testimonials&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="#"&gt;Contact Us&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;
&lt;/div&gt;</pre>
<p>Now we add a few extra parts to the HTML, which will result in the following:</p>
<pre class="brush:xml">&lt;div class="MainNavigation"&gt;
	&lt;ul&gt;
		&lt;li&gt;&lt;a href="#" class="current"&gt;&lt;span&gt;Home&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="#"&gt;&lt;span&gt;Services&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="#"&gt;&lt;span&gt;Portfolio&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="#"&gt;&lt;span&gt;Testimonials&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="#"&gt;&lt;span&gt;Contact Us&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;
&lt;/div&gt;</pre>
<p>You will see that I have added <strong><em>class=&#8221;current&#8221;</em></strong> to the home link, this will be used to change the style of the current page. I have also added <em><strong>&lt;span&gt;&lt;/span&gt;</strong></em> to each link, as this is needed for adding the background image, I will explain why later.</p>
<h3>CSS</h3>
<p>Firstly, lets create the CSS to convert the navigation from a list into a horizontal menu.</p>
<pre class="brush:css">.MainNavigation, .MainNavigation ul, .MainNavigation ul li{
	font:bold 10pt Arial, Helvetica, sans-serif;
	margin:0px;
	padding:0px;
}

.MainNavigation ul li{
	float:left;
	list-style-type:none;
}

.MainNavigation ul li a{
	color:#333333;
	display:block; /* Important - without this the technique will not work */
	float:left;
	margin:0px 2px; /*tides the navigation up by adding space between each */
	text-decoration:none;
}

.MainNavigation ul li a span{
	display:block; /* Important - without this the technique will not work */
}</pre>
<p>Now that is out of the way, lets look at adding the tab image to the links. This is where the <strong><em>&lt;span&gt;</em></strong> tags, that we added earlier, come into place. The <strong><em>Background-image</em></strong> property of CSS only allows for one image to be attached to any element, so by adding the background image to the links, we would achieve the following:</p>
<div class="ImageBox" style="width: 414px;"><img title="Navigation Tabs, without using spans" src="http://images.ahdev.co.uk/articles/SlidingDoorNoSpans.jpg" alt="Navigation Tabs, without using spans" width="408" height="25" /><span>Navigation Tabs, without adding spans.</span></div>
<p>By adding the <strong><em>&lt;span&gt;</em></strong> tags, we give ourselves two elements to add the image to. So lets look at the CSS for doing this:</p>
<pre class="brush:css">/* Make the image available to both the link, and the span */
.MainNavigation ul li a, .MainNavigation ul li a span{
	background:#ffffff url(../images/Tabs.jpg) no-repeat;
}

/* Add the following to the relevant classes */
.MainNavigation ul li a{
	background-position:0 0;
	padding:0px 0px 0px 10px;
}

.MainNavigation ul li a span{
	background-position:100% 0;
	height:20px; /* Height of tab, minus the top &amp; bottom paddings */
	padding:5px 10px 0px 0px;
}</pre>
<p>As we are using <a title="View article on CSS Sprites" href="/tutorials/htmlcss/2010/03/02/css_sprites/">CSS Sprites</a> in this tutorial, we attach the image once, and then use <em><strong>background-position</strong></em> to determine which part of the image to use. You add two figures to <em><strong>background-position</strong></em> (either as pixels or percentages), the first gives the position on the x-axis and the second gives the position on the y-axis (the starting point is the top left corner of the image).</p>
<p>For the link, we need to show from the top left (this part isn&#8217;t absolutely needed, but I always add it for consistency), so we add <em><strong>background-position:0 0;</strong></em>. To make sure that this image is not fully overflowed by the span&#8217;s image, we need to add some padding on the link, as you can see by <strong><em>padding:0px 0px 0px 10px;</em></strong> I have added 10px to the left (adjust this according to your required padding, I am adding 10px to the left and right of the tab).</p>
<p>For the span, we need to show from the top right of the image, this is achieved by <em><strong>background-position:100% 0;</strong></em>.  We then add 10px to the right padding for this, which will now create the full tab. To tidy up the tab, and make the text align in the middle, we add <em><strong>height:20px;</strong></em> and <em><strong>padding:5px 10px 0px 0px;</strong></em>. Adding the 5px padding to the top will align the text in the middle. The height is added to make sure the full tab is displayed (this is calculated by taking the height of the tab, and reducing it by the top and bottom padding).</p>
<p>Your tabs should now look as follows:</p>
<div class="ImageBox" style="width: 414px;"><img title="Navigation Tabs, using sliding door method" src="http://images.ahdev.co.uk/articles/SlidingDoorTabs.jpg" alt="Navigation Tabs, using sliding door method" width="408" height="25" /><span>Navigation Tabs, using sliding door method.</span></div>
<h3>Hover and Current States</h3>
<p>The Final step is to add the hover and current states. Add the following styles to do this:</p>
<pre class="brush:css">.MainNavigation ul li a:hover{
	background-position:0 -25px;
	color:#ffffff;
}

.MainNavigation ul li a:hover span{
	background-position:100% -25px;
}

.MainNavigation ul li a.current, .MainNavigation ul li a.current:hover{
	background-position:0 -50px;
	color:#ffffff;
}

.MainNavigation ul li a.current span, .MainNavigation ul li a.current:hover span{
	background-position:100% -50px;
}</pre>
<p>Your tabs should now be the same as our intended final result:</p>
<div class="ImageBox" style="width: 414px;"><img title="Navigation Tabs, using sliding door method, with normal, hover and current states" src="http://images.ahdev.co.uk/articles/SlidingDoorTabsEndResult.jpg" alt="Navigation Tabs, using sliding door method, with normal, hover and current states" width="408" height="25" /><span>Navigation Tabs, using sliding door method, with normal, hover and current states.</span></div>
<h2>Final Code</h2>
<h3>HTML</h3>
<pre class="brush:xml">&lt;div class="MainNavigation"&gt;
	&lt;ul&gt;
		&lt;li&gt;&lt;a href="#" class="current"&gt;&lt;span&gt;Home&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="#"&gt;&lt;span&gt;Services&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="#"&gt;&lt;span&gt;Portfolio&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="#"&gt;&lt;span&gt;Testimonials&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="#"&gt;&lt;span&gt;Contact Us&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;
&lt;/div&gt;</pre>
<h3>CSS</h3>
<pre class="brush:css">.MainNavigation, .MainNavigation ul, .MainNavigation ul li{
	font:bold 10pt Arial, Helvetica, sans-serif;
	margin:0px;
	padding:0px;
}

.MainNavigation ul li{
	float:left;
	list-style-type:none;
}

/* Make the image available to both the link, and the span */
.MainNavigation ul li a, .MainNavigation ul li a span{
	background:#ffffff url(../images/Tabs.jpg) no-repeat;
}

.MainNavigation ul li a{
	background-position:0 0;
	color:#333333;
	cursor:pointer; /* Added to make sure pointer shows in IE, as the span seems to alter this */
	display:block; /* Important - without this the technique will not work */
	float:left;
	margin:0px 2px; /*tides the navigation up by adding space between each */
	padding:0px 0px 0px 10px;
	text-decoration:none;
}

.MainNavigation ul li a span{
	background-position:100% 0;
	display:block; /* Important - without this the technique will not work */
	height:20px; /* Height of tab, minus the top &amp; bottom paddings */
	padding:5px 10px 0px 0px;
}

.MainNavigation ul li a:hover{
	background-position:0 -25px;
	color:#ffffff;
}

.MainNavigation ul li a:hover span{
	background-position:100% -25px;
}

.MainNavigation ul li a.current, .MainNavigation ul li a.current:hover{
	background-position:0 -50px;
	color:#ffffff;
}

.MainNavigation ul li a.current span, .MainNavigation ul li a.current:hover span{
	background-position:100% -50px;
}</pre>
<h2>Compatibility, Conclusion and Download</h2>
<p>This script has been tested in IE7 (though should also work in IE6), Firefox 3.5.3, and Google Chrome 4.0.2, all on a windows platform. This is a very useful technique, which can used for tabs, buttons, and most things where two backgrounds might be needed.</p>
<div class="DownloadButton Center"><a title="Download the files for this demo" href="http://static.ahdev.co.uk/downloads/Sliding_Door_Tabs.zip">Download Demo Files</a></div>
<p>Any feedback or improvements are welcome.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ahdev.co.uk/tutorials/htmlcss/2010/03/05/navigation_tabs_using_sliding_doors_method/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>CSS Sprites</title>
		<link>http://www.ahdev.co.uk/tutorials/htmlcss/2010/03/02/css_sprites/</link>
		<comments>http://www.ahdev.co.uk/tutorials/htmlcss/2010/03/02/css_sprites/#comments</comments>
		<pubDate>Tue, 02 Mar 2010 08:00:00 +0000</pubDate>
		<dc:creator>Alan Holmes</dc:creator>
				<category><![CDATA[HTML/CSS]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[CSS Sprites]]></category>
		<category><![CDATA[HTML]]></category>

		<guid isPermaLink="false">http://www.ahdev.co.uk/?p=124</guid>
		<description><![CDATA[This tutorial will explain what CSS Sprites are, why you should use them, and more importantly how to use them.]]></description>
			<content:encoded><![CDATA[<h2>What are CSS Sprites?</h2>
<p>When many people think of sprites, they generally thing of a single small image (usually of old computer game characters), however, here we are referring to &#8216;CSS Sprites&#8217;, which is something quite different. A CSS Sprite is the combination of a number of images into one large one, which are then accessed using the <strong><em>background-position</em></strong> property of CSS.</p>
<h2>Why should I use CSS Sprites?</h2>
<p>You might be thinking that CSS Sprites sounds like more hassle than its worth, and that it&#8217;s quicker to use &#8217;sliced&#8217; images in your website. The that might be the case for building your website, but when loading your website (which lets face it, is the important issue), the less images you have the better. The reason for this, is that each image request has a separate HTTP-Request, and the more of those the longer load time you are likely to have. For more information on this, check out the following article from the Yahoo Developer Network:</p>
<blockquote cite="http://developer.yahoo.com/performance/rules.html"><p>80% of the end-user response time is spent on the front-end. Most of this time is tied up in downloading all the components in the page: images, stylesheets, scripts, Flash, etc. Reducing the number of components in turn reduces the number of HTTP requests required to render the page. This is the key to faster pages. <span class="ContinueReading">[<a title="Continue reading: Best Practices for Speeding Up Your Web Site" href="http://developer.yahoo.com/performance/rules.html" target="_blank">Continue Reading</a>]</span><br />
<cite>Best Practices for Speeding Up Your Web Site, <strong>Yahoo Developer Network</strong></cite></p></blockquote>
<h2>How will I benefit from CSS Sprites?</h2>
<p>To show the difference that CSS sprites can make, I have created two basic examples, one using <a title="View example using CSS Sprites" href="http://demo.ahdev.co.uk/CSS_Sprites/sprite.html" target="_blank">CSS Sprites</a>, and one using <a title="View example using individual images" href="http://demo.ahdev.co.uk/CSS_Sprites/without.html" target="_blank">individual images</a>.</p>
<table class="DataTable" border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<th width="54%" align="left" valign="top" class="TopLeftBorder"></th>
<th width="23%" align="center" valign="top">Individual Images</th>
<th width="23%" align="center" valign="top" class="TopRightBorder">CSS Sprites</th>
</tr>
<tr>
<th align="left" valign="top">No Images</th>
<td align="center" valign="top">4</td>
<td align="center" valign="top">1</td>
</tr>
<tr>
<th align="left" valign="top">Http Requests <span>(Including Html and Css Documents)</span></th>
<td align="center" valign="top">6</td>
<td align="center" valign="top">3</td>
</tr>
<tr>
<th align="left" valign="top">Total Size <span>(HTML, CSS, Images &amp; Headers)</span></th>
<td align="center" valign="top">8741 bytes (8.54K)</td>
<td align="center" valign="top">7654 bytes (7.47K)</td>
</tr>
<tr>
<th align="left" valign="top" class="BottomLeftBorder">Download Times <span>(seconds @ 56K)</span></th>
<td align="center" valign="top">2.94</td>
<td align="center" valign="top" class="BottomRightBorder">2.13</td>
</tr>
<tr>
<td class="Summary" colspan="3" valign="top">Summary of stats, using <a title="Web Page Analyzer by websiteoptimization.com" href="http://www.websiteoptimization.com/services/analyze/" target="_blank">Web Page Analyzer</a></td>
</tr>
</tbody>
</table>
<p>As you can see from the table above, the CSS Sprite version has less HTTP requests, and a lower total size. This is as a result of the single image being smaller (in file size) than the 4 separate ones, but also, due to one requesting one header instead of four for images.</p>
<p>You may feel that the saving is not worth the extra work of Sprites, and on very low traffic sites, I would agree (though still use them), but once you start getting higher traffic, you will really start saving the bandwidth. Also, bare in mind that this is a very basic example, and more complex designs will likely use more images, and with this, CSS sprites can become more useful.</p>
<h2>How do I use CSS Sprites?</h2>
<p>Finally, we get to the point of this article, how to use CSS Sprites. I have taken four icons (from this <a title="View icon set from pixel-mixer.com" href="http://pixel-mixer.com/basic_set/" target="_blank">basic set</a>), and combined them into one image. <a href="http://demo.ahdev.co.uk/CSS_Sprites/images/sprite.jpg" target="_blank" title="View the Sprite image for this demo">View Here</a></p>
<h3>HTML</h3>
<p>Here is the basic HTML that we will be using in this example.</p>
<pre class="brush:xml">&lt;ul class="Nav"&gt;
	&lt;li class="Home"&gt;&lt;a href="#"&gt;Home&lt;/a&gt;&lt;/li&gt;
	&lt;li class="Events"&gt;&lt;a href="#"&gt;Events&lt;/a&gt;&lt;/li&gt;
	&lt;li class="Cart"&gt;&lt;a href="#"&gt;Cart&lt;/a&gt;&lt;/li&gt;
	&lt;li class="Contact"&gt;&lt;a href="#"&gt;Contact Us&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</pre>
<h3>CSS</h3>
<p>Lets first take a look at the css we would use, should we be using individual images.</p>
<pre class="brush:css">
.Nav, .Nav li{
	margin:0px;
	padding:0px;
}

.Nav li{
	float:left;
	list-style-type:none;
}

.Nav li a{
	background:top left no-repeat;
	display:block;
	float:left;
	font:bold 120% Arial, Helvetica, sans-serif;
	height:44px;
	margin-right:40px;
	padding:20px 0px 0px 70px;
	text-decoration:none;
}

.Nav li.Home a{
	background-image: url(../images/home.jpg);
}

.Nav li.Events a{
	background-image: url(../images/events.jpg);
}

.Nav li.Cart a{
	background-image: url(../images/Cart.jpg);
}

.Nav li.Contact a{
	background-image: url(../images/contact.jpg);
}
</pre>
<p>Each class is used to identify which image is to be used. Now, to change this css to use the single sprite image we have created.</p>
<pre class="brush:css">
.Nav li a{
	background:url(../images/sprite.jpg) no-repeat;
}

.Nav li.Home a{
	background-position:0 0;
}

.Nav li.Events a{
	background-position:0 -64px;
}

.Nav li.Cart a{
	background-position:0 -128px;
}

.Nav li.Contact a{
	background-position:0 -192px;
}
</pre>
<p>As you can see, there is very little difference in the amount of code needed. All that is needed is to call the image once, on the link <strong><em>background:url(../images/sprite.jpg) no-repeat;</em></strong>, and using the classes to identify the position to use in the image. The position is calculated from the top left of the image, thus <strong><em>.Home</em></strong> is <strong><em>background-position:0 0;</em></strong>. This first number represents the position on the x-axis, and the second number represents the position on the y-axis.</p>
<h2>Some Restrictions</h2>
<p>As with everything, CSS Sprites have certain restrictions, and have a limit to what they can be used for. The main issue is repeating backgrounds. Although you can do repeats with Sprites, it is far trickier than using separate images for these, and you will often end up displaying parts of the sprites that you do not wish to.</p>
<h2>Other Examples</h2>
<p>Below is a list of popular sites that use sprite images, which are more complex than the demos given:</p>
<ul>
<li><a title="Play.com" href="http://www.play.com/" target="_blank">Play.com</a> <em>- <a title="View Play.com Sprite image" href="http://images.play.com/SiteCSS/Play/Live2/2010022401/css/sprites/core-site.gif" target="_blank">Sprite Image</a></em></li>
<li><a title="Facebook" href="http://www.facebook.com" target="_blank">Facebook</a> <em>- <a title="View Facebook Sprite image" href="http://b.static.ak.fbcdn.net/rsrc.php/z3O30/hash/3wq3vjh4.png" target="_blank">Sprite Image</a></em></li>
<li><a title="Google" href="http://www.google.co.uk" target="_blank">Google</a> <em>- <a title="View Google Sprite image" href="http://www.google.co.uk/images/nav_logo7.png" target="_blank">Sprite Image</a></em></li>
</ul>
<h2>Compatibility, Conclusion and Download</h2>
<p>This script has been tested in IE7 (though should also work in IE6), Firefox 3.5.3, and Google Chrome 4.0.2, all on a windows platform. CSS Sprites can be very useful, and once the method is understood, easy to implement.</p>
<div class="DownloadButton Center"><a title="Download the files for this demo" href="http://static.ahdev.co.uk/downloads/CSS_Sprites.zip">Download Demo Files</a></div>
]]></content:encoded>
			<wfw:commentRss>http://www.ahdev.co.uk/tutorials/htmlcss/2010/03/02/css_sprites/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Category Menu Highlighting for Single Posts</title>
		<link>http://www.ahdev.co.uk/tutorials/wordpress/2010/02/18/category_menu_highlighting_for_single_posts/</link>
		<comments>http://www.ahdev.co.uk/tutorials/wordpress/2010/02/18/category_menu_highlighting_for_single_posts/#comments</comments>
		<pubDate>Thu, 18 Feb 2010 00:00:43 +0000</pubDate>
		<dc:creator>Alan Holmes</dc:creator>
				<category><![CDATA[WordPress]]></category>
		<category><![CDATA[Category]]></category>
		<category><![CDATA[current-cat]]></category>
		<category><![CDATA[Navigation]]></category>
		<category><![CDATA[Single Post]]></category>
		<category><![CDATA[wp_list_categories]]></category>

		<guid isPermaLink="false">http://ahdev.co.uk/?p=1</guid>
		<description><![CDATA[This tutorial will explain how to highlight WordPress categories, when viewing a single post page.]]></description>
			<content:encoded><![CDATA[<p>After a lot of searching, I found that a lot of people had come across the same problem as I had, which was that WordPress did not include either <strong><em>current-cat</em></strong> or <em><strong>current-cat-parent</strong></em> classes when calling <em><strong>wp_list_categories</strong></em> on a single post page.</p>
<p>I finally came across a partial solution to my problem on <a title="Studio Grass Hopper Article" href="http://www.studiograsshopper.ch/code-snippets/dynamic-category-menu-highlighting-for-single-posts/" target="_blank">Studio Grass Hopper</a> (SGH).  This solution provided a filter for adding <strong><em>current-cat</em></strong> class to that posts categories. However, this solution did not highlight Parent (empty) categories as well.</p>
<p>In this tutorial, I will expand on SGH&#8217;s solution, to also highlight Parent Categories.</p>
<h3>SGH Solution</h3>
<p>This solution offered by SGH, which works perfectly if you are only wanting to highlight assigned categories.</p>
<pre class="brush:php">function sgr_show_current_cat_on_single($output) {

	global $post;

	if( is_single() ) {

		$categories = wp_get_post_categories($post-&gt;ID);

		foreach( $categories as $catid ) {
			$cat = get_category($catid);
			// Find cat-item-ID in the string
			if(preg_match('#cat-item-' . $cat-&gt;cat_ID . '#', $output)) {
				$output = str_replace('cat-item-'.$cat-&gt;cat_ID, 'cat-item-'.$cat-&gt;cat_ID . ' current-cat', $output);
			}
		}

	}
	return $output;
}

add_filter('wp_list_categories', 'sgr_show_current_cat_on_single');</pre>
<h3>Changes</h3>
<p>Now I will go through the changes to the code that I made (skip to the end if you just want the code).</p>
<h4>Step One</h4>
<p>The first thing we need to do is get the category parents, which can be done by using WordPress&#8217; <strong><em>get_category_parents()</em></strong> function. This needs to be split into an array, so that we can loop through the values. To do this, add the following, after <strong><em>foreach( $categories as $catid ) {</em></strong>.</p>
<pre class="brush:php">$ancestors = preg_split("/[,]+/",get_category_parents($catid, false, ','));</pre>
<h4>Step Two</h4>
<p>We then need to loop through each category, and perform the <strong><em>str_replace</em></strong> function to add the class. The following is the code to do this:</p>
<pre class="brush:php">foreach ( $ancestors as $ancestor ){
	if ($ancestor !=""){
		$catID = get_cat_ID($ancestor);
		if(preg_match('#cat-item-' . $catID . '#', $output)) {
			$output = str_replace('cat-item-'.$catID, 'cat-item-'.$catID . ' current-cat', $output);
		}
	}
}</pre>
<h4>Step Three</h4>
<p>Finally, a small change to the <strong><em>preg_match</em></strong> and <strong><em>str_replace</em></strong> functions, as the changes thus far will case it to highlight more than the required categories.</p>
<pre class="brush:php">if(preg_match('#"cat-item cat-item-' . $catID . '"#', $output)) {
	$output = str_replace('"cat-item cat-item-'.$catID.'"', '"cat-item cat-item-'.$catID . ' current-cat"', $output);
}</pre>
<h3>Finished Code</h3>
<p>The final code is as follows, place this into your themes <em><strong>functions.php</strong></em> file, and its ready to go.</p>
<pre class="brush:php">function sgr_show_current_cat_on_single($output) {
 	global $post;
	if( is_single() ) {
		$categories = wp_get_post_categories($post-&gt;ID);

			foreach( $categories as $catid ) {

				$ancestors = preg_split("/[,]+/",get_category_parents($catid, false, ','));

				foreach ( $ancestors as $ancestor ){
					if ($ancestor !=""){
						$catID = get_cat_ID($ancestor);

						if(preg_match('#"cat-item cat-item-' . $catID . '"#', $output)) {
							$output = str_replace('"cat-item cat-item-'.$catID.'"', '"cat-item cat-item-'.$catID . ' current-cat"', $output);
						}
					}
				}
			}
	}
	return $output;
}

add_filter('wp_list_categories', 'sgr_show_current_cat_on_single');</pre>
<p>I would like to thank <a title="Studio Grass Hopper Article" href="http://www.studiograsshopper.ch/code-snippets/dynamic-category-menu-highlighting-for-single-posts/" target="_blank">Studio Grass Hopper</a> for the inspiration, and original code, any feedback or improvements are welcome.</p>
<h2>Update March 1, 2010</h2>
<p>In response to <a title="Read comment from Joan" href="http://www.ahdev.co.uk/tutorials/wordpress/2010/02/18/category_menu_highlighting_for_single_posts/#comment-5">Joan&#8217;s</a> comment, asking for adding the <strong><em>current-cat-parent</em></strong> class as well, I have made a a few alterations to the code, so that for the top level category, the <strong><em>current-cat-parent</em></strong> class will be added instead, and <strong><em>current-cat</em></strong> class will be added to any sub categories.</p>
<pre class="brush:php">function sgr_show_current_cat_on_single($output) {
 	global $post;
	if( is_single() ) {
		$categories = wp_get_post_categories($post-&gt;ID);

			foreach( $categories as $catid ) {

				$ancestors = preg_split("/[,]+/",get_category_parents($catid, false, ','));

				foreach ( $ancestors as $ancestor ){
					if ($ancestor !=""){
						$catID = get_cat_ID($ancestor);

						$category = get_category($catID);
						$catParentID = $category-&gt;category_parent;

						if(preg_match('#"cat-item cat-item-' . $catID . '"#', $output)) {
							if ($catParentID == 0){
								$output = str_replace('"cat-item cat-item-'.$catID.'"', '"cat-item cat-item-'.$catID . ' current-cat-parent"', $output);
							}else{
								$output = str_replace('"cat-item cat-item-'.$catID.'"', '"cat-item cat-item-'.$catID . ' current-cat"', $output);
							}
						}
					}
				}
			}
	}
	return $output;
}

add_filter('wp_list_categories', 'sgr_show_current_cat_on_single');</pre>
<p>Lines 14 -15 will get the Parent ID of the current category, and lines 18 &#8211; 22 will perform the check to determine which class to add.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ahdev.co.uk/tutorials/wordpress/2010/02/18/category_menu_highlighting_for_single_posts/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
	</channel>
</rss>
