Web Design: A Fluid Layout Exercise

fluidlayout

Using CSS media queries is one part of making your web site responsive but you are limited to specific viewports.  Having a fluid layout on top of that will greatly improve the responsiveness and makes it more future proof.  In CSS, you can implement a fluid layout by sizing your elements’ horizontal dimensions in proportion using percentage % rather than pixel px and your fonts’ sizes using relative measurement em.

When sizing using proportion, you need to know the context to which this measure is related to.  Say you set an element’s font size to 90%.  90% of what?  That what will be the context.  If you have defined a font-size in the closest containing element as 20px, then it will be 90% of 20px.

If you are converting a fixed width layout to a fluid layout, the general formula used is target divided by context. Say you have an element’s width set to 10px and the containing element’s width is 100px.  To convert, you divide 10px by 100px which gives us 10% and that will be the resulting element’s proportional width.

Images can be fluid too by taking the same logic as with the elements.  Also worth knowing is that you can set a maximum width that these images (and even elements) can go up to in case you don’t want them to get very, very big.

Another way of making images fluid is by resizing these images on the server before it is rendered to the browser.  This also saves bandwidth spaces for bandwidth challenged devices.  This I will not cover here.

Also, there is a rapid or quick way of making a web site fluid by using a grid system.  One example of a grid system is Bootstrap.  This I will not cover too.

For this exercise, I have 2 sites, one with non-fluid layout and another with a fluid layout.  Both of these use CSS media queries.  I only have listed below the fully commented CSS for the fluid layout web site.  The HTML source you can view from the browser and the non-fluid CSS should be the same name except for the CSS extension (*.css instead of *.html).

/*
	When converting from fixed width to fluid, 
	the general formula used is: divide target by context.
*/
body {
	font-family: Calibri;
	font-size: 100%;
	/*  16px is the default font-size for most browsers.
		It's equal to 1em and equal to 100%.
		16px will be the context for our proportional fonts.
	*/
}
div {
	padding-top: 3px;
	padding-bottom: 3px;
	padding-left: 0.50%; /* divide 5px by 960px */
	padding-right: 0.50%;
}
ul, p {
	margin-top: 0px;
	margin-bottom: 0px;
}
a {
	text-decoration: none;
}
h1 {
	font-size: 2.125em; /* divide 34px by 16px */
}
h2 {
	font-size: 1.1875em;
}
h2 span {
	color: Red;
	/*  The context for span is h2.
		span's pixel font size is 22px and h2's is 19px.
		So to get the proportional font-size of span, 
		we divide 22px by 19px, not 16px.
	*/
	font-size: 1.157em;
}
h3 {
	font-size: 0.75em;
}
/*  #wrapper width's pixel size is 960px.
	This will be the context for our proportional elements.
	Note that I did not exactly follow the formula's result
	to the decimal point.
	As long as it's approximate and everything tallies exactly to 100%
	of their containing element, it should be fine.
*/
#wrapper {
	margin-top: 10px;
	margin-right: auto;
	margin-left: auto;
	padding-left: 0px;
	padding-right: 0px;
	width: 100%;
	/*max-width: 960px;*/ 
	/* if you don't want to scale out beyond some point
	then set max-width */
}
#header {
	margin-right: 1%;
	margin-left: 1%;
	/*  For the width, divide 930px by 960px.
		But I rounded it to whole number for easy maintenance.
		Just need to make sure everything tallies to 100%.
		97% for the header content's width, 
		2% total for it's left and right margins.
		And don't forget we have padding of 1% total
		for both sides of a div.
		So that makes a 100%.
	*/
	width: 97%;
	background-color: #6FD7FF;
}
#navigation ul li {
	display: inline-block;
	margin-right: 2.5%;
}
/*  Note that the anchor tag does not have explicit context.
	So the right margin is moved to the containing li tag (above).
*/
/*#navigation ul li a {
	margin-right: 25px;
}*/
#sidebar {
	margin-left: 1%;
	float: left;
	background-color: #9FADE6;
	width: 20%;
}
#sidebar ul {
	margin-top: 10px;
}
#sidebar ul li ul li a {
	font-size: 0.875em;
}
#content {
	margin-right: 1%;
	float: right;
	width: 76%;
	background-color: #FFCDAF;
}
#footer {
	margin-right: 1%;
	margin-left: 1%;
	clear: both;
	background-color: #CC6444;
	width: 97%;
}
#footer p {
	font-size: 0.75em;
}
.art {
	width: 32.5%;
}

/*  Below are the breakpoints, 604px and 320px. */

/* I put addtl breakpoint here and set the page to fixed width
	so sidebar text won't wrap */
@media screen and (max-width: 665px) {
	#wrapper {
		width: 665px;
	}
}

@media screen and (max-width: 604px) {
	#wrapper {
		width: 99%;
	}
	#sidebar {
		width: 33%;
	}
	#content {
		width: 63%;
	}
	.art {
		width: 49%;
	}
}

/* I put addtl breakpoint here and set the page to fixed width 
	so sidebar text won't wrap */
@media screen and (max-width: 412px) {
	#wrapper {
		width: 412px;
	}
}

@media screen and (max-width: 320px) {
	#wrapper {
		width: 99%;
	}
	#sidebar {
		display:none;
	}
	#content {
		float: none;
		margin-left: 1%;
		width: 97%;
	}
	.art {
		width: 100%;
	}
}

C#: Does the code below look familiar?

extmethod

If not or you are struggling to understand it, then no worries.  I too didn’t understand it fully well when I coded this, but it worked wonderfully.  I am going to break down this code into digestible parts because there is just too much.  I would suggest going through the provided links as well to fully understand each part before going to the next.

In the code, I am declaring a new extension method, named OrderByWithDirection, to be used as a LINQ query operation to sort elements in either ascending or descending order.  See Standard Query Operators Overview.  In LINQ query, you have separate methods for sorting in ascending order, the OrderBy , and sorting in descending order, the OrderByDescending.  OrderByWithDirection can do both ways, so I am passing a sort direction in the third parameter:

    public static IOrderedQueryable<TSource> 
		OrderByWithDirection<TSource, TKey>(
			this IQueryable<TSource> query, 
			Expression<Func<TSource, TKey>> keySelector, 
			string sortDir)

 

So what’s an extension method?  An extension method is like a static function that you can add to an existing type so you can call it from any instance of that (extended) type.  See Extension Methods and How to: Implement and Call a Custom Extension Method.  In the code, I am making OrderByWithDirection available to any data structures that implement IQueryable<TSource>, which is why the first parameter to this method is of that type:

    public static IOrderedQueryable<TSource> 
		OrderByWithDirection<TSource, TKey>(
			this IQueryable<TSource> query, 
			Expression<Func<TSource, TKey>> keySelector, 
			string sortDir)

 

Depending on the sort direction, OrderByWithDirection calls either OrderBy or OrderByDescending, both of which are actually extension methods themselves extending IQueryable<TSource>.  So it’s only logical that OrderByWithDirection extends the same type as well.  OrderBy and OrderByDescending are part of the Queryable class, much like OrderByWithDirection is part of ExtensionMethods class in the code.  See Queryable Class, Queryable.OrderBy Method, and Queryable.OrderByDescending Method.

OrderBy and OrderByDescending requires an Expression<Func<TSource, TKey>>, basically a function to extract a key from an element.  So in OrderByWithDirection, I am passing this function on the second parameter:

    public static IOrderedQueryable<TSource> 
		OrderByWithDirection<TSource, TKey>(
			this IQueryable<TSource> query, 
			Expression<Func<TSource, TKey>> keySelector, 
			string sortDir)

 

To call OrderByWithDirection you would code something like this:

// products variable is of type IQueryable<Product>
products = products.OrderByWithDirection(p => p.ProductName, "desc");

 

Here we are passing a lambda expression.  At first, it might look like this lambda expression is returning the product name value and not the product name key, ProductName.  But because we are passing this as an Expression<Func<TSource, TKey>>, the lambda expression is being represented as an expression tree which makes this possible.  See Expression<TDelegate> Class, Func<T, TResult> Delegate, Expression Trees, and How to: Use Expression Trees to Build Dynamic Queries.

Last but not the least, the return type.  Since OrderByWithDirection returns whatever the OrderBy or OrderByDescending returns, it’s only logical to return the same type as well, which is IOrderedQueryable<TSource>. See IOrderedQueryable Interface.

Below is the complete code in text:

using System;
using System.Linq;
using System.Linq.Expressions;

public static class ExtensionMethods
{
    public static IOrderedQueryable<TSource> 
		OrderByWithDirection<TSource, TKey>(
			this IQueryable<TSource> query, 
			Expression<Func<TSource, TKey>> keySelector, 
			string sortDir)
    {
        if (sortDir.ToUpper().Equals("DESC"))
        {
            return query.OrderByDescending(keySelector);
        }
        else
        {
            return query.OrderBy(keySelector);
        }
    }
}

SQL Server: My Quick and Dirty Way of Debugging Stored Procedure

I use the below SQL script to debug a stored procedure in chunks, replacing or adding into it the rest of the stored procedure code until every code checks out fine.  Since I use transactions, changes are temporary and it rolls back the transaction at the end.  I also used the error handling in SQL Server to catch and print the error line, error number and error message.

BEGIN TRANSACTION
BEGIN TRY
	--
	-- your SQL code here
	--
END TRY
BEGIN CATCH
	PRINT 'Error at line # ' + CAST(ERROR_LINE() AS VARCHAR(MAX)) 
		+ ': ' + CAST(ERROR_NUMBER() AS VARCHAR(MAX)) 
		+ ' - ' + ERROR_MESSAGE()
END CATCH
IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION

ASP.NET Web Services – Blast From The Past (Part 2)

Here is part 2 of this topic as promised.  It will cover consuming web service using HTTP POST and using jQuery AJAX.  If you missed part 1 of this topic, click here.

But before I start, I forgot to mention in part 1 that when you set up your web service as part of a web site, like when you deploy your web service in a virtual directory of a web site, you need to make sure the <compilation> setting in the web site’s web.config file does not have the targetFramework attribute which is usually present when targeting .NET Framework 4.0 and up.  Otherwise, your web service will not work.  Ok, so on to part 2.

 

Consuming a Web Service Using HTTP POST

Another article that covers the basics of a web service including consuming it using HTTP POST is Understanding the Basics of Web Service in ASP.NET.  I have a demo web page that uses HTTP POST to consume the simple web service I created.

Some important points:

  • When you use this method, you need to add the below config to the web service’s web.config file, otherwise you will get this error.
<configuration>
    <system.web>
		<!-- enable HttpGet and HttpPost on the web service -->
		<webservices>
			<protocols>
				<add name="HttpGet" />
				<add name="HttpPost" />
			</protocols>
		</webservices>
    </system.web>
</configuration>

 

  • The response you get will be displayed in the browser in XML format (see my demo web page).  If you want to handle the response, you need to code to send a POST request and handle the response, as in below:
protected void Translatev2Button_Click(object sender, EventArgs e)
{
	if (EnglishTextBox.Text != string.Empty)
	{
		try
		
{
	// this is the content of the request
	byte[] content = System.Text.Encoding.ASCII.GetBytes(
		"english=" + EnglishTextBox.Text);

	// create the request
	System.Net.WebRequest request = System.Net.HttpWebRequest.Create(
		"http://rodansotto.com/asmx/" +
		"TranslateToFrenchService.asmx/TranslateToFrench");
	request.Method = "POST";
	request.ContentType = "application/x-www-form-urlencoded";
	request.ContentLength = content.Length;

	// write the content to the request stream
	System.IO.Stream requestStream = request.GetRequestStream();
	requestStream.Write(content, 0, content.Length);
	requestStream.Flush(); 

	// get the response
	System.Net.WebResponse response = request.GetResponse();
	// get the stream associated with the response
	System.IO.Stream responseStream = response.GetResponseStream();
	// pipes the stream to a higher level stream reader with the 
	//  required encoding format
	System.IO.StreamReader streamReader = 
		new System.IO.StreamReader(
			responseStream, System.Text.Encoding.UTF8);

	// the response is in XML format and normally needs to be handled
	// but since the XML response is simple enough that when displayed
	//  by the browser, it only displays what we need to display,
	//  the french text
	FrenchLabel.Text = streamReader.ReadToEnd();
}
		
		catch (Exception)
		{
			throw;
		}
	}
}

 

Consuming a Web Service Using jQuery AJAX

Another way to call a web service is by using jQuery.ajax() function.  This is the preferred way by many.  Understand jQuery Ajax Function: Call Web Service Using jQuery Ajax Method shows you how.  Below is the client-side code for my demo web page that uses jQuery AJAX to consume the simple web service I created.

<head runat="server">
    
    <script src="http://ajax.googleapis.com/.../1.11.2/jquery.min.js">
    </script>
    <script>
        $(document).ready(function () {
            $("#TranslateButton").click(function () {
			
// have to add following statement to enable cross-domain request
$.support.cors = true;

$.ajax({
	type: "POST",

	url: "http://rodansotto.com/...Service.asmx/TranslateToFrench",

	//contentType: "application/x-www-form-urlencoded; charset=UTF-8",
	// no need to specify contentType above as that is the default

	data: "english=" + $("#EnglishTextBox").val(),

	dataType: "text",

	success: function (response) {
		$("#FrenchLabel").html(response);
	},

	error: function (jqXHR, textStatus, errorThrown) {
		var errorMsg = "jQuery AJAX ERROR!!!\njqXHR.statusText = " + 
			jqXHR.statusText + "\ntextStatus = " + 
			textStatus + "\nerrorThrown = " + errorThrown;
		alert(errorMsg);
	}
});
				
            });
        });
    </script>

 

Some important points:

  • If your web app will be making a cross-domain request to call the web service, you need to set $.support.cors = true, otherwise you will receive the ‘No Transport’ error.
  • And don’t forget to enable the following attribute in your web service class: [System.Web.Script.Services.ScriptService].
namespace MyWebService
{
    /// <summary>
    /// Summary description for TranslateToFrenchService
    /// </summary>
    [WebService(Namespace = "http://rodansotto.com/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    // To allow this Web Service to be called from script,
    //  using ASP.NET AJAX, uncomment the following line. 
    [System.Web.Script.Services.ScriptService]
    public class TranslateToFrenchService : 
        System.Web.Services.WebService
    {

 

And that concludes this topic ASP.NET Web Services – Blast From The Past.