Chapter 15: CSS, JavaScript, and Ajax
+++++++++++++++++++++++++++++++++++++
.. index ::
single: Chap 15-CSS, JavaScript, and Ajax
One of the definitive technologies of Web 2.0 is Ajax, which means Asynchronous JavaScript and XML and allows the browser to communicate with a server without needing to refresh the page the user is viewing. Interestingly, Ajax doesn’t necessarily need to use JavaScript or XML, so it is only the *Asynchronous* part of the name that is the truly important aspect of the technology.
.. index ::
single: description of; JavaScript web frameworks
The world of JavaScript web frameworks is changing as fast now as the world of Python web frameworks was five years ago. Early versions of Pylons officially supported the Prototype and Script.aculo.us libraries used by Ruby on Rails, but despite this, Pylons users actually used a range of JavaScript frameworks. Two things quickly became apparent:
* Pylons users choose whichever framework best provides the tools they need, rather than going with the official library.
* JavaScript frameworks for the most part actually operate quite independently from the web framework that is using them. After all, one set of code runs on the server, and the other runs on the client.
The latest versions of Pylons (and in particular, WebHelpers) do not integrate any JavaScript framework, and as a result, you are free to choose whichever framework you prefer.
.. index ::
single: most popular; JavaScript web frameworks
At the time of writing, the following three JavaScript frameworks are the most popular with Pylons developers:
* JQuery
* YUI
* ExtJS
One of the main benefits of YUI is that it is more than just a JavaScript framework. It also has tools for managing CSS and for creating user interfaces.
Adding YUI to Your Project
==========================
.. index ::
single: adding to project; JavaScript web frameworks
You can use YUI in your project in two ways; the first is to copy the YUI library to your project’s ``public`` directory and have Pylons serve the files, and the second is to use the files that Yahoo serves directly from its content delivery network (CDN).
Because Yahoo has servers all over the world, it is more likely that it will have a server physically near the person using your application, which should mean that users a long way from the server serving your Pylons application might get a small performance improvement.
.. index ::
single: installing YUI into; public directory
I don’t know about you, but when I’m responsible for a web site, I like to be in control of as many of the dependencies as possible; therefore, despite the possible benefits, I recommend installing YUI into your ``public`` directory. That way, if someone should trip over a wire and disconnect a server at Yahoo, your application won’t be affected.
.. index ::
single: YUI; web sites
You can download the latest version of YUI from http://developer.yahoo.com/yui/download/. This book describes version 2.6.0.
To add YUI to a Pylons project, unzip the download into the project’s ``public`` directory:
::
$ cd public
$ unzip yui_2.6.0.zip
You need to serve files from the ``build`` directory only, although the other folders contain useful documentation and examples you might want to browse. Remove the files you don’t need with this:
::
$ cd yui
$ rm -r as-docs as-src assets docs examples tests index.html README
I usually also rename the ``build`` directory with the version number of the YUI library I’m using so that I can later use a different version alongside the current one:
::
$ mv build 2.6.0
.. index ::
single: adding to project; JavaScript web frameworks
The examples in this chapter will assume you have set up YUI in this way.
Resetting the Browser CSS
=========================
.. index ::
single: resetting browser; CSS
Anyone who has ever created a web site for one browser only to find that it looks completely different on another will understand this problem: different browsers interpret the same CSS in different ways. Fixing the broken style on one browser then makes it look different in the first, and before long you are tearing your hair out.
YUI has a fairly effective solution to this problem: reset browser styles across all browsers before you start coding your CSS; then, since the styles you add don’t rely on the styles the browser implementation has decided to add by default, your styles stand a much greater chance of being consistent across different browsers.
You can add the YUI ``reset.css`` style sheet by adding the following lines to the ``

`` section of your HTML page:
::
To add the style sheet to a Pylons application with the YUI files in the ``public`` directory as you added earlier, you would use this in the head of your HTML in your base template:
::
${h.stylesheet_link(h.url_for('/yui/2.6.0/reset/reset-min.css'))}
Always make sure the ``reset.css`` style sheet is defined before any others; otherwise, you might find that your carefully coded styles are reset when you didn’t expect them to be. You'll need to add this import to your ``lib/helpers.py`` file:
::
from webhelpers.html.tags import stylesheet_link
.. tip ::
It is much easier to use the YUI ``reset.css`` style at the beginning of a project before you define any styles rather than trying to apply it after other styles are already in place, so I strongly recommend you use it in all your projects from the beginning.
You can find more information about the ``reset.css`` style sheet at http://developer.yahoo.com/yui/reset/.
Once you have reset all the styles, there’s a good chance you’ll want some common ones back. For example, ``

`` tags usually have a margin, and the various headings should be different sizes. Once again, the YUI team has thought of this, and common styles are defined in the ``base.css`` file. You can add the ``base.css`` file by adding this line to the head of your HTML document:
::
${h.stylesheet_link(h.url_for('/yui/2.6.0/base/base-min.css'))}
.. index ::
single: resetting browser; CSS
Notice that for both the base and reset style sheets, I have included minimized versions (they have ``-min`` added just before the file extension). These have all the unnecessary whitespace removed so that they are faster for a browser to download and parse. If you ever want to take a look at the styles they contain, you can look at the nonminimized versions, which are identical except for the whitespace.
Fonts
=====
.. index ::
single: fonts; CSS
Another area developers sometimes struggle with is fonts. Typically you want the fonts to display at a particular size across all browsers, but you don’t want to specify those sizes explicitly using ``px`` units because that would prevent certain browsers from adjusting the font size based on the size a user has chosen from a browser menu.
Once again, YUI has a style sheet that comes to the rescue, this time named ``fonts.css``, which sets up font families and sizes so that they render consistently across browsers as 13-pixel Arial with 16-pixel line spaces. The ``

`` and ```` elements render in monospace.
.. index ::
single: pixels to percent translation for fonts
You can then specify any font sizes you want to use as a percentage of the default sizes, as shown in Table 15-1.
====================================== ==========================
If You Want This Size in Pixels (px) Declare This Percent (%)
====================================== ==========================
10 77
11 85
12 93
13 100
14 108
15 116
16 123.1
17 131
18 138.5
19 146.5
20 153.9
21 161.6
22 167
23 174
24 182
25 189
26 197
====================================== ==========================
Table 15-1. Pixels to Percent Translation
Be sure to always use percentages in your application, not the corresponding pixel size.
.. index ::
single: fonts; CSS
You can include fonts support in a Pylons application by adding the following after the reset CSS import in the ```` section of your HTML:
::
${h.stylesheet_link(h.url_for('/yui/2.6.0/fonts/fonts-min.css'))}
.. tip ::
The sharp-eyed amongst you might have spotted that you could achieve similar font standardization using ems, but the percentage technique described here results in more consistent rendering across browsers.
If you want to change the font family, you need to provide only the specific font you’re interested in and not any fallbacks. When your font is missing, YUI provides a fallback for you.
For example, you would write this:
::
font-family: "Times New Roman";
.. index ::
single: fonts; CSS
and not this:
::
font-family: "Times New Roman", serif;
Grids
=====
.. index ::
single: overview of; CSS
Another frequent problem in web development is the creation of grid layouts. Of course, you can always use tables to lay out your HTML content, but this is considered bad practice and is heavily frowned upon by CSS experts because table-based designs don’t degrade gracefully. For example, with a table layout, if your screen resolution is too small, your users will be forced to scroll. CSS layouts, on the other hand, can cause one column of information to appear below another when the browser width is too small, which is generally considered better.
Sites such as Amazon still use table-based layout for some aspects of their pages, so the importance of always using CSS layouts all the time is debatable. Of course, you could also detect the screen resolution with JavaScript and provide a different layout for small screens, but this requires extra work and will not work if the browser doesn’t support JavaScript or has it disabled.
Using a CSS grid framework makes setting up a CSS layout much easier. First you should declare your doctype as HTML 4 strict to force browsers into standards mode for rendering. You can do this by making sure the top of your HTML file looks like this:
::
You also need to include the YUI ``grids.css`` file, but using grids also requires the reset and fonts CSS files to be used. Rather than including three separate files, YUI also provides a combined and minified file called ``reset-fonts-grids.css`` that you can use instead like this:
::
Although the file doesn’t have ``-min`` as part of the file name, this is a fully minified CSS file.
.. index ::
single: overview of; CSS
You could also include this in a template with this line:
::
${h.stylesheet_link(h.rul_for('/yui/2.6.0/reset-fonts-grids/reset-fonts-grids.css))}
YUI assumes you will want a header, body, and footer in your HTML page, so to use the YUI grid, you need to set up your page’s HTML like this with a ``

`` tag containing three other ``

`` tags:
::

The ``id`` attribute of the inner ``

`` elements must be as shown earlier, but the ``id`` of the outer ``

`` element can be customized to determine the width of the page. You have the following options:
::

.. index ::
single: page widths, setting
It’s also possible to create your own page widths, but for the vast majority of cases, the YUI defaults are fine.
.. index ::
single: overview of; CSS
As an example, to create a content area with a 100 percent width, you would use an ``id`` of ``doc3`` on the outer ``

`` element, as shown here:
::

Once you’ve set up your template with the correct ID to specify the width of the content, you can think about how content within the header, body, and footer is arranged. YUI provides three types of grids you can use separately or combine to achieve a huge variety of different layouts:
* Template presets
* Nesting grids
* Special nesting grids
*Template presets* give you common configurations for two-column layouts with a column on the left or the right, and *nesting grids* and *special nesting grids* give you more control to produce more complex layouts, as you’ll see in the following sections.
Template Preset Grids
---------------------
.. index ::
single: template preset grids; CSS
Template preset grids are used after you have chosen the overall width of the content to subdivide either the header, body, or footer into two columns, one of which has a fixed width. To achieve, this you need to add some extra markup to either the header, body, or footer ``

``. In this example we are splitting the body into two columns. The extra markup is shown in lines 3-6:
.. highlight:: html
:linenothreshold: 5
::

.. highlight:: python
:linenothreshold: 5000
You then choose which template preset to use by adding a class to the same outer ``

`` element that was used earlier to specify the width. Table 15-2 lists the options.
================ ====================
Template Class Preset Description
================ ====================
``.yui-t1`` 160px on left
``.yui-t2`` 180px on left
``.yui-t3`` 300px on left
``.yui-t4`` 180px on right
``.yui-t5`` 240px on right
``.yui-t6`` 300px on right
================ ====================
Table 15-2. Template Class Presets
As an example, to have a 240-pixel column on the right of the same layout that you saw in the previous example with a 100 percent width, you would use an outer ``

`` element with a ``class="yui-t5"`` attribute:
::

.. index ::
single: template preset grids; CSS
This will produce the desired layout. What is more, you can also use a similar structure in the header and footer divs, but because it is the class of the outer div that defines the layout, the header, footer, and body all use the same layout with the template preset approach.
Sometimes you might want the content in the second ``

`` element to appear in the HTML before the first, perhaps for search engine optimization reasons or perhaps to put your navigation before your content for accessibility reasons. If you are using a YUI template preset, you can change the order of the two columns in the HTML without changing how they are displayed. For example, the altered markup in lines 5-8 will produce the same results:
.. highlight:: html
:linenothreshold: 5
::

``.
Nested Grids
------------
.. index ::
single: nested grids; CSS
Within the basic templates you can nest further grids so that each grid you nest divides the content area in two, with each area taking up 50 percent of the available space. Here’s an example of how to do this:
::

The important point to notice is that the first child of the grid has to be marked with the class ``first`` to ensure the grids work in all the main browsers. You can also nest nested grids within other nested grids to create more complex layouts.
Special Nested Grids
--------------------
.. index ::
single: special nested grids; CSS
It isn’t always particularly useful to subdivide areas in half, so YUI provides five *special nested grids* that subdivide grids in the ratios given in Table 15-3.
==================== ===============
Special Grid Class Ratios
==================== ===============
``.yui-gb`` 1/3, 1/3, 1/3
``.yui-gc`` 2/3, 1/3
``.yui-gd`` 1/3, 2/3
``.yui-ge`` 3/4, 1/4
``.yui-gf`` 1/4, 3/4
==================== ===============
Table 15-3. Grid Class Ratios
.. index ::
single: yui-gf class
Let’s extend the example from the “Template Presets” section to use the ``yui-gf`` class in the header so that you can have a logo on the left taking up 1/4 of the page and the main navigation tabs on the right taking the remaining 3/4 of the space, while the body remains split in two with a 240-pixel column on the right.
Here’s what the updated HTML looks like:
::

.. index ::
single: special nested grids; CSS
Notice that although in this example you are using a special nested grid directly in the header, you can also put them within template preset regions and nested grids too.
Updating SimpleSite to Use CSS Grids
====================================
.. index ::
single: updating SimpleSite to use; CSS
Now that you’ve seen the theory of how to use YUI’s CSS reset style sheet, fonts, and grids, you can update the SimpleSite project to use them too.
Start by preparing the YUI source code as described at the beginning of the chapter:
::
$ cd public
$ unzip yui_2.6.0.zip
$ cd yui
$ rm -r as-docs as-src assets docs examples tests index.html README
$ mv build 2.6.0
Make sure the first HTML in the ``templates/base/index.html`` file looks like this:
::
Then edit the ``head()`` def to add the YUI combined ``reset-fonts-grids.css`` file, which includes the grid styles:
::
${h.stylesheet_link(h.url_for('/yui/2.6.0/reset-fonts-grids/reset-fonts-grids.css'))}
${h.stylesheet_link(h.url_for('/css/main.css'))}
%def>
For this example, you’re going to have a two-column layout with a header and footer. You’d like the right column to be 240-pixels wide and contain the menu navigation and the list of tags that can be used on the page. You’ll put the main navigation tabs in the header and style the footer to match it.
.. index ::
single: %(body%) part of; base/index.html file
Replace the ```` part of the ``base/index.html`` file that currently looks like this:
::
${self.header()}
${self.tabs()}
${self.menu()}
${self.heading()}
${self.breadcrumbs()}
${self.flash()}
${next.body()}
${self.footer()}
.. index ::
single: updating SimpleSite to use; CSS
with the YUI grids version that looks like the following. Notice the ``id=doc3`` attribute on the outer ``

`` element to make the content use 100 percent of the width. The ``self.heading()`` def is now also called in the header, not the body:
::

${self.heading()}
${self.header()}
${self.tabs()}

${self.breadcrumbs()}
${self.flash()}
${self.menu()}
${next.body()}

${self.footer()}

Next, add the markup to use a template preset for a 240-pixel column on the right. Notice the ``class="yui-t5"`` attribute and the two extra ``

`` elements with the content for the two columns:
::

${self.heading()}
${self.header()}
${self.tabs()}

${self.breadcrumbs()}
${self.flash()}
${next.body()}

${self.menu()}

${self.footer()}

.. index ::
single: updating SimpleSite to use; CSS
Finally, modify the header to contain a logo or title on the left and space for some additional links on the right using a special nested grid:
::