Thursday 7 November 2013

Preprocessors

In time writing HTML and CSS may feel a bit taxing, requiring a lot of the same tasks to be completed over and over again. Tasks such as closing tags in HTML or repetitively having to looking up hexadecimal color values in CSS.
These different tasks, while commonly small, do add up to quite a bit of inefficiency. Fortunately these, and a handful of other inefficiencies, have been recognized and preprocessor solutions have risen to the challenge.
A preprocessor is a program that takes one type of data and converts it to another type of data. In the case of HTML and CSS, some of the more popular preprocessor languages include Haml and Sass. Haml is processed into HTML and Sass is processed into CSS.
Upon setting out to solve some of the more common problems, Haml and Sass found many additional ways to empower HTML and CSS, not only by removing the inefficiencies but also in creating ways to make building websites easier and more logical. The popularity of preprocessors have also brought along different frameworks to support them, one of the more popular being Compass.

Haml

Haml, known as HTML abstraction markup language, is a markup language with the single goal of providing the ability to write beautiful markup. Serving as its own markup language, code written in Haml is later processed to HTML. Haml promotes DRY and well structured markup, providing a pleasing experience for anyone having to write or read it.

Installation

Haml requires Ruby to be compiled to HTML, so the first step to using it is to ensure that Ruby is installed. Fortunately for those on Mac OS X Ruby comes preinstalled, and those on a Windows machine may visit Windows Installer for directions. Upon confirming Ruby is installed the gem install haml command needs to be run from the command line, using Terminal or the alike command line program, to install Haml.
  1. gem install haml
Files written in the Haml markup should be saved with the file extension of .haml. To then convert these files from Haml to HTML the haml command below needs to be run to compile each individual file.
  1. haml index.haml index.html
In the example above, the file index.haml is converted to HTML and saved as index.html within the same directory. This command has to be run within the same directory the files reside in. Should the command be run outside this directory the path where the files reside need to be included within the command. At any time the command haml --help may be run to see a list of different available options.

Watching a File or Directory

Unfortunately Haml doesn’t provide a way to watch a file, or directory, for changes without the use of another dependency.
Inside of a Rails application a Haml dependency may be added in the Gemfile, thus automatically compiling Haml files to HTML upon any changes. There are a few desktop applications available for those not using Rails, one of the more popular being CodeKit.
On top of Haml CodeKit also supports other preprocessors, which may also come in handy.

Doctype

The first part to writing a document in Haml is knowing what type of doctype is to be used. When working with HTML documents, the general document type is going to be the HTML5 doctype. In Haml document types are identified with three exclamation points, !!! followed by any specifics if necessary.
The default doctype in Haml is the HTML 1.0 Transitional document type so in order to make this the HTML5 doctypethe number five has to be passed in after the exclamation points, !!! 5.
HAML
  1. !!! 5
COMPILED HTML
  1. <!DOCTYPE html>

Declaring Elements

One of the defining features of Haml is its syntax, and how to declare and nest elements. HTML elements generally have opening and closing tags, however within Haml elements only have one tag, the opening. Elements are initialized with a percent sign, %, and then indented to identify nesting. Indentation with Haml can be accomplish with one or more spaces, however what is important is that the indentation remain consistent. Hard tabs or spaces cannot be mixes together, and the same number of tabs or spaces must be the same throughout an entire document.
Removing the need for both opening and closing tags, as well as mandating the structure with indentation creates an easy to follow outline. At any given time the markup can be scanned and changed without struggle.
HAML
  1. %body
  2. %header
  3. %h1 Hello World
  4. %section
  5. %p Lorem ipsum dolor sit amet.
COMPILED HTML
  1. <body>
  2. <header>
  3. <h1>Hello World</h1>
  4. </header>
  5. <section>
  6. <p>Lorem ipsum dolor sit amet.</p>
  7. </section>
  8. </body>

Handling Text

Text within Haml can be placed on the same line as the declared element, or indented below the element. Text cannot be both on the same line as the declared element and nested below it, it has to be either or. The example from above could be rewritten as the following:
  1. %body
  2. %header
  3. %h1
  4. Hello World
  5. %section
  6. %p
  7. Lorem ipsum dolor sit amet.

Attributes

Attributes, as with elements, are declared a bit differently in Haml. Attributes are declared directly after the element in either {} or (), all depending if you wish to use Ruby or HTML syntax. Ruby style attributes will use the standard hash syntax inside of {}, while HTML style attributes will use standard HTML syntax inside of ().
HAML
  1. %img{:src => "shay.jpg", :alt => "Shay Howe"}
  2. %img{src: "shay.jpg", alt: "Shay Howe"}
  3. %img(src="shay.jpg" alt="Shay Howe")
COMPILED HTML
  1. <img src="shay.jpg" alt="Shay Howe">

Classes & IDs

If you wish to, Class and ID attributes may be declared the same as all other attributes, however they may also be treated a bit differently. Rather than listing out the class or ID attribute name and value inside {} or () the value can be identified directly after the element. Using either a . for classes or a # for an ID the value can be added directly after the element.
Additionally, attributes may be mixed and matched, chaining them together in the appropriate format. Classes are to be separated with a . and other attributes may be added using one of the previously outlined formats.
HAML
  1. HAML CLASSES & IDS%section.feature
  2. %section.feature.special
  3. %section#hello
  4. %section#hello.feature(role="region")
COMPILED HTML
  1. HAML CLASSES & IDS<section class="feature"></section>
  2. <section class="feature special"></section>
  3. <section id="hello"></section>
  4. <section class="feature" id="hello" role="region"></section>

Saturday 2 November 2013

Mobile First Design

One popular technique with using media queries is called mobile first. The mobile first approach includes using styles targeted at smaller viewports as the default styles for a website, then use media queries to add styles as the viewport grows.
The operating belief behind mobile first design is that a user on a mobile device, commonly using a smaller viewport, should’t have to load the styles for a desktop computer only to have them over written with mobile styles later. Doing so is a waste of bandwidth. Bandwidth that is precious to any users looking for a snappy website.
The mobile first approach also advocates designing with the constraints of a mobile user in mind. Before too long, the majority of Internet consumption will be done on a mobile device. Plan for them accordingly and develop intrinsic mobile experiences.
A breakout of mobile first media queries might look at bit like the following.
  1. /* Default styles first then media queries */
  2. @media screen and (min-width: 400px) {...}
  3. @media screen and (min-width: 600px) {...}
  4. @media screen and (min-width: 1000px) {...}
  5. @media screen and (min-width: 1400px) {...}
Additionally, downloading unnecessary media assets can be stopped by using media queries. Generally speaking, avoiding CSS3 shadows, gradients, transforms, and animations within mobile styles isn’t a bad idea either. When used excessively, they cause heavy loading and can even reduce a device’s battery life.
  1. /* Default media */
  2. body {
  3. background: #ddd;
  4. }
  5. /* Media for larger devices */
  6. @media screen and (min-width: 800px) {
  7. body {
  8. background-image: url("bg.png") 50% 50% no-repeat;
  9. }
  10. }

Mobile First Demo

Adding media queries to our previous example, we overwrote a handful of styles in order to have a better layout on viewports under 420 pixels wide. Rewriting this code to use the mobile styles first by default then adding media queries to adjust for viewports over 420 pixels wide we build the following:
  1. section, aside {
  2. margin: 1.51515151%;
  3. }
  4. @media all and (min-width: 420px) {
  5. .container {
  6. max-width: 660px;
  7. }
  8. section {
  9. float: left;
  10. width: 63.63636363%;
  11. }
  12. aside {
  13. float: right;
  14. width: 30.30303030%;
  15. }
  16. }
Notice, this is the same amount of code as before. The only exception here is that mobile devices only have to render only one CSS declaration. All of the other styles are deferred, only loading on larger viewports and done so without overwriting any initial styles.

Viewport

Mobile devices generally do a pretty decent job of displaying websites these days. Sometimes they could use a little assistance though, particularly around identifying the viewport size, scale, and resolution of a website. To remedy this, Apple invented the viewport meta tag.
Website without Viewport Meta Tag
Fig. 4.04Although this demo has media queries, many mobile devices still do not know the initial width or scale of the website. Therefore, they may not interrupt media queries.

Viewport Height & Width

Using the viewport meta tag with either the height or width values will define the height or width of the viewport respectively. Each value accepts either a positive integer or keyword. For the height property the keyword device-height value is accepted, and for the width property the keyword device-width is accepted. Using these keywords will inherit the device’s default height and width value.
For the best results, and the best looking website, it is recommend that you use the device defaults by applying thedevice-height and device-width values.
  1. HEIGHT & WIDTH<meta name="viewport" content="width=device-width">
Website with Viewport Meta Tag
Fig. 4.05Letting devices know the intended width of the website,device-width in this case, allows the website to be sized properly and to pick up any qualifying media queries.

Viewport Scale

To control how a website is scaled on a mobile device, and how users can continue to scale a website, use theminimum-scalemaximum-scaleinitial-scale, and user-scalable properties.
The initial-scale of a website should be set to 1 as this defines the ratio between the device height, while in a portrait orientation, and the viewport size. Should a device be in landscape mode this would be the ratio between the device width and the viewport size. Values for initial-scale should always be a positive integer between 0 and 10.
  1. <meta name="viewport" content="initial-scale=2">
Viewport Scale Meta Tag
Fig. 4.06Using an integer above 1 will zoom the website to be larger than the default scale. Generally speaking, this value will most commonly be set to 1.
The minimum-scale and maximum-scale values determine how small and how large a viewport may be scaled. When using minimum-scale the value should be a positive integer lower than or equal to the initial-scale. Using the same reasoning, the maximum-scale value should be a positive integer greater than or equal to the initial-scale. Values for both of these must also be between 0 and 10.
  1. MINIMUM & MAXIMUM SCALE<meta name="viewport" content="minimum-scale=0">
Generally speaking, these values should not be set to the same value as the initial-scale. This would disable any zooming, which can be accomplished instead by using the user-scalable value. Setting the user-scalable value to no will disable any zooming. Alternatively, setting the user-scalable value to yes will turn on zooming.
Turning off the ability to scale a website is a bad idea. It harms accessibility and usability, preventing those with disabilities from viewing a website as desired.
  1. <meta name="viewport" content="user-scalable=yes">

Viewport Resolution

Letting the browser decide how to scale a website based off any viewport scale values usually does the trick. When more control is needed, specifically over the resolution of a device, the target-densitydpi value may be used. Thetarget-densitydpi viewport accepts a handful of values including device-dpihigh-dpimedium-dpilow-dpi, or an actual DPI number.
Using the target-densitydpi viewport value is rare, but extremely helpful when pixel by pixel control is needed.
  1. <meta name="viewport" content="target-densitydpi=device-dpi">

Combining Viewport Values

The viewport meta tag will accept individual values as well as multiple values, allowing multiple viewport properties to be set at once. Setting multiple values requires comma separating them within the content attribute value. One of the recommended viewport values is outlined below, using both the width and initial-scale properties.
  1. <meta name="viewport" content="width=device-width, initial-scale=1">
Website with Viewport Meta Tag
Fig. 4.07A combination of width=device-width and initial-scale=1 provide the initial size and zoom commonly required.

CSS Viewport Rule

Since the viewport meta tag revolves so heavily around setting the styles of how a website should be rendered it has been recommend to move the viewport from a meta tag with HTML to an @ rule within CSS. This helps keep the style separated from content, providing a more semantic approach.
Currently some browsers have already implemented the @viewport rule, however support isn’t great across the board. The previously recommended viewport meta tag would look like the following @viewport rule in CSS.
  1. @viewport {
  2. width: device-width;
  3. zoom: 1;
  4. }

Flexible Media

The final, equally important aspect to responsive web design involves flexible media. As viewports begin to change size media doesn’t always follow suit. Images, videos, and other media types need to be scalable, changing their size as the size of the viewport changes.
One quick way to make media scalable is by using the max-width property with a value of 100%. Doing so ensures that as the viewport gets smaller any media will scale down according to its containers width.
  1. img, video, canvas {
  2. max-width: 100%;
  3. }

Flexible Media Demo

100% WIDE CONTAINER
Chicago
75% WIDE CONTAINER
Chicago
50% WIDE CONTAINER
Chicago

Flexible Embedded Media

Unfortunately the max-width property doesn’t work well for all instances of media, specifically around iframes and embedded media. When it comes to third party websites, such as YouTube, who use iframes for embedded media this is a huge disappointment. Fortunately, there is a work around.
To get embedded media to be fully responsive, the embedded element needs to be absolutely positioned within a parent element. The parent element needs to have a width of 100% so that it may scale based on the width of the viewport. The parent element also needs to have a height of 0 to trigger the hasLayout mechanism within Internet Explorer.
Padding is then given to the bottom of the parent element, the value of which is set in the same aspect ratio of the video. This allows the height of the parent element to be proportionate to that of it’s width. Remember the responsive design formula from before? If a video has an aspect ratio of 16:9, 9 divided by 16 equals .5625, thus requiring a bottom padding of 56.25%. Padding on the bottom and not the top is specifically used to prevent Internet Explorer 5.5 from breaking, and treating the parent element as an absolutely positioned element.
HTML
  1. <figure>
  2. <iframe src="https://www.youtube.com/embed/4Fqg43ozz7A"></iframe>
  3. </figure>
CSS
  1. figure {
  2. height: 0;
  3. padding-bottom: 56.25%; /* 16:9 */
  4. position: relative;
  5. width: 100%;
  6. }
  7. iframe {
  8. height: 100%;
  9. left: 0;
  10. position: absolute;
  11. top: 0;
  12. width: 100%;
  13. }

Flexible Embedded Media Demo

100% WIDE CONTAINER
75% WIDE CONTAINER
50% WIDE CONTAINER