Download source code
One can say that software development is not just a skill, but a myriad of interrelated, different skills. We use to say, "it´s all about code", when
in reality, the code itself is just a part of the problem. We often forget about the interpretation of the user requirements, for example. When specification
doesn´t make sense, we remember some bad experiences of failed projects in the past to reject it and ask for a clarification. And depending on how the
software packaging is done, sometimes we can foresee that some crucial piece of software will not be deployed correctly, then we report the issue to our
colleagues about the issue in time for a fix. In these examples, a technically good developer can prove itself to be even more valuable to the company by
applying common sense to non-code related aspects of software develpment.
Likewise, there are some areas where software developers are not supposed to know deeply about. This is the case of web design: that's not to say that all
developers are bad web designers, but most of them certainly are, even those who work daily on the back end of a website. This is why most companies have
full-time web developers, to create professional-looking web pages that also feature user-friendly functionality and coherent design throughout the user
navigation.
But there are times when brave developers dare to invade this web design territory... and usually they get into trouble. The problem is, the HTML is relatively
simple, and instinctively software developers would tend to apply HTML tables to design the web page. I mean, ALL the web page. This is so because software
developers usually solve problems by breaking them down into small parts, and if the web page itself is a big HTML table, then its parts would be divided into
HTML table rows and columns, and maybe inner HTML tables. Of course these days developers already know that applying CSS is the right way to do web design, but
there are many cases where CSS is so counterintuitive that even creating a simple web page could take hours for a non-web designer. This is why developers like
table-based web design: because it´s simple, comprehensive, and it works.
One of the recurrent challenges of web design is what is called the Holy Grail of Web Design. There
are some variations of this Holy Grail, but in a specific case, you have a page header, a page footer, a resizable main content area (the center column of the page)
and fixed left and right columns at the sides of the main content.
Now, what if we had a simple way to create the Holy Grail of CSS Design, so that even full time back end software developers could quickly create nice looking webpages,
with really little effort? This is what we are trying to accomplish in this article.
This article contains the code needed to run a website relying no programming languages other than JavaScript, and consequently without references to assemblies or C# code,
so it doesn't need to be compiled. Just download the code and open the HTML file in a web browser.
As we can see, the solution is quite simple. Only a handful of files are needed, and as we said before, no need to compiled code.
The joy of creating jQuery Plugin resides in the fact that you can wrap a big deal of jQuery code that otherwise could end up spread all over your codebase,
and by establishing a jQuery Plugin, you can confine a coherent set of functionalities in a self-contained component, and then work on this component in order
to make it useful for a very wide community of web developers.
In Holy Grail plogin code, we start by creating a immediately-invoked function expression (IIFE) in JavaScript code. The IIFE is a design pattern that provides the self-containment of
private functions variables and functions within the plugin scope, thus avoiding the pollution of JavaScript's Global Environment. JavaScript developers will easily recognize
the IIFE pattern by the following code:
(function(){
}());
In the above code, the outermost pair of parentheses wrap the function in an expression and immediately forces its evaluation. The pair of parentheses in the last line of code invokes the function immediately.
Notice that, within the jQuery plugin development, it's important to pass the jQuery reference as a parameter in our IIFE expression, so that the dollar sign ($) can be used safely within the scope of the plugin, without
the risk of external libraries overriding the dollar sign:
(function($){
}(jQuery));
Next, we create the function that will hold and execute the whole of our Holy Grail plugin functionality. Notice the options
parameter,
which will contain all the initialization settings needed to configure the bar chart according to the Holy Grail plugin requirements:
(function($){
$.fn.holygrail = function (options) {
}
}(jQuery));
Inside the plugin function, the context is given by the this
JavaScript keyword. Most often than not, developers will be tempted to
reference the context by enclosing it using the dollar sign (i.e. jQuery) function: "$(this)
", instead of just this
. This is a common mistake,
since the this keyword already refers to the jQuery object and not the DOM element inside which the bar chart is being created:
(function($){
$.fn.barChart = function (options) {
var self = this;
}
}(jQuery));
In the above JavaScript code, we are storing the value of the this
object in the self
reference. This is needed specifically inside functions,
where the this
keyword behaves as the context for the function itself, instead of the context for the outermost plugin function. Thus, the self
will
be used as the context for the bar chart plugin instead.
The plugin code starts by defining a series of settings that will become the default values for the most common configurations. This will provide our plugin users
with convenient standard values that can be either configured (allowing a flexible charting component) or ignored (so that the plugin user can provide the smallest set
of startup configuration).
As the plugin component gets more sophisticated, it's generally a good idea to provide a more complete and comprehensive set of default settings, in order to give
users a powerful, flexible and unobtrusive plugin.
$.fn.holygrail = function (options) {
var self = this;
var settings = $.extend({
headerContent: options.headerContent,
centerContent: options.centerContent,
leftContent: options.leftContent,
rightContent: options.rightContent,
footerContent: options.footerContent
}, options);
The above code snippet shows the plugin settings: there is a different plugin configuration for each of the page's sections:
headerContent, centerContent, leftContent, rightContent and footerContent:
=========================
| header |
=========================
| | | |
| left | center | right |
| | | |
=========================
| footer |
=========================
The plugin code itself is all about gathering the content elements and rearranging them in a way that
the resulting rendering complies with the above layout:
(function ($) {
var HolyGrail = {};
var raster;
$.fn.holygrail = function (options) {
var self = this;
var settings = $.extend({
headerContent: options.headerContent,
centerContent: options.centerContent,
leftContent: options.leftContent,
rightContent: options.rightContent,
footerContent: options.footerContent
}, options);
var body = $('body');
var hgHeader = $('<div>').attr({ id: 'hg-header' });
var hgContainer = $('<div>').attr({ id: 'hg-container' });
var hgCenter = $('<div>').attr({ id: 'hg-center', 'class': 'hg-column' });
var hgLeft = $('<div>').attr({ id: 'hg-left', 'class': 'hg-column' });
var hgRight = $('<div>').attr({ id: 'hg-right', 'class': 'hg-column' });
var hgFooter = $('<div>').attr({ id: 'hg-footer' });
$(hgContainer).append(hgCenter);
$(hgContainer).append(hgLeft);
$(hgContainer).append(hgRight);
$(body).append(hgHeader);
$(body).append(hgContainer);
$(body).append(hgFooter);
$(this.headerContent).attr({ 'class': 'hg-pad' });
$(this.centerContent).attr({ 'class': 'hg-pad' });
$(this.leftContent).attr({ 'class': 'hg-pad' });
$(this.rightContent).attr({ 'class': 'hg-pad' });
$(this.footerContent).attr({ 'class': 'hg-pad' });
$(hgHeader).append($(settings.headerContent));
$(hgCenter).append($(settings.centerContent));
$(hgLeft).append($(settings.leftContent));
$(hgRight).append($(settings.rightContent));
$(hgFooter).append($(settings.footerContent));
}
}(jQuery));
</div></div></div></div></div></div></reference>
Using Holy Grail Plugin is very simple. First, you have to reference the style sheet file...
<link href="../css/default.css" rel="stylesheet" />
...and then the JavaScript files (for both jQuery and jQuery Plugin):
<script src="../js/jquery-1.9.1.min.js"></script>
<script src="../js/jquery.holygrail.js"></script>
Next, you create the <class>div elements that will represent each of the page sections. Although I added explicit IDs to these
<class>div elements, the plugin is flexible enough so that you could use whatever IDs you want, or even use class attributes, or
any else means to identify those elements, as we are about to see.
<div id="headerContent">
<span><img src="../img/bob.gif" /></span>
<span class="title">The Holy Grail of 3-Column CSS Design</span>
</div>
<div id="centerContent">
<h1>This is the main content.</h1>
<img src="../img/grail.png" style="float: left;" />
<p>Lorem ipsum dolor sit amet, consectetuer...</p>
<p>Lorem ipsum dolor sit amet,...</p>
<img src="../img/monk.png" style="float: right;" />
<p>Lorem ipsum dolor sit amet,...</p>
<p>Lorem ipsum dolor sit amet,...</p>
</div>
<div id="leftContent">
<h2>This is the left sidebar.</h2>
<p>Lorem ipsum dolor sit amet,...</p>
</div>
<div id="rightContent">
<h2>This is the right sidebar.</h2>
<p>Lorem ipsum dolor sit amet, consectetuer...</p>
</div>
<div id="footerContent">
<hr />
<div>Holy Grail jQuery Plugin - ©2013 Marcelo Ricardo de Oliveira</div>
</div>
Now let's see how the page is rendered:
Notice that at this point, we are just piling up HTML elements, without any layout considerations. This is
great, because we can focus only on the content of our webpage, leaving the hard work for the plugin.
Setting up the Holy Grail jQuery plugin in our webpage is ridiculously easy. With just a few lines of JavaScript code we are done:
<script type="text/javascript">
$('body').holygrail({
headerContent: $('#headerContent'),
centerContent: $('#centerContent'),
leftContent: $('#leftContent'),
rightContent: $('#rightContent'),
footerContent: $('#footerContent')
});
</script>
Now the webpage shows the exactly same sections, but structured in the so desired layout we have been looking for:
Notice that the Holy Grail jQuery plugin automatically added paddings, to improve readability and respect the aesthetics of the layout.
Once the plugin code is applied, the whole structure of the page changes dramatically:
The idea behind this article is based on the fine research work of Matthew Levine, who provided
a very comprehensive way to achieve the Holy Grail via CSS, which Matthew summarized as having the following qualities:
- have a fluid center with fixed width sidebars,
- allow the center column to appear first in the source,
- allow any column to be the tallest,
- require only a single extra div of markup, and
- require very simple CSS, with minimal patches.
I hope you enjoy both the plugin and the article. It is quite short and simple, indeed, but anyway thanks for reading. I would be very glad
if in the end you had this in your Batman's utility belt. If you have any thoughts about the code or the article, please let me know.
- 2013-07-31: Initial version.
- 2013-08-01: Fixed "same height columns" problem.