Tuesday 17 June 2014

Feature Support & Polyfills

Building a website can be both extremely rewarding and frustrating. Common frustrations arise from trying to get a website to look and perform the same in every browser. All front end developers have shared this frustration at one point or another.
Truth be told, websites do not need to look or perform the same in every browser. Exactly how close a website works in each browser is up to you and your level of comfort for a given website. If a website receives under half a percent of traffic from Internet Explorer 6 it might make sense to drop support for it. If that half a percent is still contributing to thousands of dollars in sales, support may be mandatory. Determine what is acceptable for a given website and work from there.
There are a handful of common practices to get websites to perform adequately in all browsers, some of which have already been covered within this guide. When incorporating CSS3 properties, fallbacks are recommend to support older browsers. Other techniques include shivs and polyfills. Generally speaking, shivs and polyfills are small JavaScript plugins that add support for a requested set of features not natively supported by a specific browser.

HTML5 Shiv

Perhaps the most popular shiv, and one you may have likely used already, is the HTML5 Shiv. The HTML5 Shiv was created by Remy Sharp to provide the ability to use HTML5 elements within versions of Internet Explorer 8 and below. The HTML5 Shiv not only creates support for HTML5 elements but also allows them to be properly styled with CSS.
The shiv should be downloaded from Google, where Remy maintains the latest version, then hosted on your server. For the best performance, reference the shiv JavaScript file within the head of the document, after any stylesheet references. Additionally, you want to reference the shiv inside of a conditional comment, making sure that the file is only loaded within versions of Internet Explorer 8 and below.
In this case the conditional comment looks like <!--[if lt IE 9]>...<![endif]-->.
1
2
3
<!--[if lt IE 9]>
  <script src="html5shiv.js"></script>
<![endif]-->

The Difference Between a Shiv & a Shim

Chances are you may have heard of both the HTML5 Shiv and HTML5 Shim, and wondered what the difference, if any, may be. Oddly enough, there is nodifference between the HTML5 Shiv and HTML5 Shim. The two words are often used interchangeably and are commonly transposed.
Additionally, once the new HTML5 elements are created using the shiv, any block level elements need to be identified and updated using the display: block; declaration.
1
2
3
4
5
6
7
8
9
10
11
12
13
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
nav,
section,
summary {
  display: block;
}
Lastly, Internet Explorer 8 and 9 do not correctly define styles for a few HTML5inline-block level elements. As before, these styles will need to be explicitly stated. After which, all versions of Internet Explorer should be good to go using any new HTML5 elements.
1
2
3
4
5
audio,
canvas,
video {
  display: inline-block;
}

Detecting Browser Features

Referencing the HTML5 Shiv works well with a conditional comment because the intention is to specifically target browsers that don’t support new HTML5 features and elements. Additionally, there is a way to to provide support for specific HTML5 and CSS3 features, regardless of which browser is being used.
Feature detection, as provided by Modernizr, provides a way to write conditional CSS and JavaScript based on whether or not a browser supports a specific feature. For example, if a browser supports rounded corners Modernizr will add the class ofborderradius to the html element. If the browser doesn’t support rounded corners, Modernizr will add the class of no-borderradius to the html element.

Loading Modernizr

To get feature detection with Modernizr up and running, simply visit their downloadpage and customize what features you are looking to detect, or use the out of the box development version. Most commonly the development version is the way to go, however, if you are only looking for support for one feature, a custom build would be more appropriate. Once downloaded, upload the JavaScript file on your server and reference it within the head of your HTML document, below any referenced style sheets.
It is worth noting that Modernizr may be configured to include the HTML5 Shiv, in which case the shiv doesn’t need to be referenced on top of Modernizr.
1
<script src="modernizr.js"></script>

Conditionally Applying CSS Styles

Once Modernizr is up and running CSS styles may be conditionally applied based on the features a given browser supports. Modernizr has detection for the majority of the CSS3 properties and values, all of which can be found in the Modernizrdocumentation.
One item to weigh out is if feature detection is necessary for certain styles. For example, using an RGBa color value may easily be supported with a fallback hexadecimal value without the use of feature detection. When deciding to use feature detection, it is important to keep styles organized and performance in mind. Avoid duplicating any code or making additional HTTP requests when possible.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
button {
  border: 0;
  color: #fff;
  cursor: pointer;
  font-size: 14px;
  font-weight: 600;
  margin: 0;
  outline: 0;
}

/* With CSS Gradient Styles */

.cssgradients button {
  border: 1px solid #0080c2;
  background: linear-gradient(#00a2f5, #0087cc);
  border-radius: 6px;
  padding: 15px 30px;
}
.cssgradients button:hover {
  background: linear-gradient(#1ab1ff, #009beb);
}
.cssgradients button:active {
  box-shadow: inset 0 1px 10px rgba(255, 255, 255, .5);
}

/* Without CSS Gradient Styles */

.no-cssgradients button {
  background: transparent url("button.png") 0 0 no-repeat;
  padding: 16px 31px;
}
.no-cssgradients button:hover {
  background-position: 0 -49px;
}
.no-cssgradients button:active {
  background-position: 0 -98px;
}

Feature Detection Demo

In the demonstration above, the button inherits some default styles. However, specific styles are only applied based on whether or not CSS3 gradient background are supported. In this case, rounded corners and box shadows are also included within the conditional styles. Those browsers that support gradients get a gradient background, rounded corners, and a box shadow. Those browsers that do not receive an image with all of these styles included within the image. With this code none of the styles are being over written and an HTTP request is only made when necessary.
When working with CSS3 feature detection it is hard to know what the styles look like in browsers that do not support specific CSS3 features. Fortunately, there is a bookmarklet called deCSS3 which disables any CSS3 features. Doing so allows you to see what a website would look like without CSS3, and if your conditional styles are working. To get a quick idea of what an individual browser supports, visit haz.io within that specific browser.

Sunday 30 March 2014

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>

Division Classes & IDs

In the event a class or ID is used on a div the %div may be omitted, and the class or ID value can be used outright. Again, classes are to be identified with a . and IDs are to be identified with a #.
HAML
  1. HAML CLASSES & IDS.awesome
  2. .awesome.lesson
  3. #getting-started.lesson
COMPILED HTML
  1. HAML CLASSES & IDS<div class="awesome"></div>
  2. <div class="awesome lesson"></div>
  3. <div class="lesson" id="getting-started"></div>

Boolean Attributes

Boolean attributes are handled just as they would be within Ruby or HTML, all depending on the syntax being used.
HAML
  1. %input{:type => "checkbox", :checked => true}
  2. %input(type="checkbox" checked=true)
  3. %input(type="checkbox" checked)
COMPILED HTML
  1. <input type="checkbox" checked>

Escaping Text

One of the benefits of Haml is the ability to evaluate and run Ruby, however this isn’t always the desired action. Text, and lines of code, can be escaped by using a backslash, \, allowing the text to be rendered explicitly without being executed.
In the example below, the first instance of = @author is executed Ruby, pulling the authors name from the application. The second instance, starting with the backslash, is escaped text, printing it as is, without execution.
HAML
  1. .author
  2. = @author
  3. \= @author
COMPILED HTML
  1. <div class="author">
  2. Shay Howe
  3. = @author
  4. </div>

Text Escaping Alternatives

Occasionally escaping text doesn’t quite do the job and Ruby is needed to generate the desired output. One popular instance of this is when trying to include a period directly after a link, but not as part of the anchor text. Putting the period on a new line isn’t acceptable as it will be treated as an empty class value, causing a compiling error. Adding a backslash before the period will escape the character however it places a blank space between the last word and the period. Again, not producing the desired output.
In these cases a Ruby helper comes in handy. In the example below, the helper is used to place a period directly after the last word but still outside of the anchor text.
HAML
  1. %p
  2. Shay is
  3. = succeed "." do
  4. %a{:href => "#"} awesome
COMPILED HTML
  1. <p>Shay is <a href="#">awesome</a>.</p>

Comments

As with elements and attributes, comments are handled a bit differently in Haml as well. Simply enough, code can be commented out with the use of a single forward slash, /. Individual lines may be commented out with the use of a forward slash at the beginning of the line, and blocks of code can be commented out by being nested underneath a forward slash.
HAML
  1. %div
  2. / Commented line
  3. Actual line
  4. /
  5. %div
  6. Commented block
COMPILED HTML
  1. <div>
  2. <!-- Commented line -->
  3. Actual line
  4. </div>
  5. <!--
  6. <div>
  7. Commented block
  8. </div>
  9. -->

Conditional Comments

Conditional comments are also handled differently in Haml. To create a conditional comment use square brackets, [], around the condition. These square brackets need to be placed directly after the forward slash.
HAML
  1. /[if lt IE 9]
  2. %script{:src => "html5shiv.js"}
COMPILED HTML
  1. <!--[if lt IE 9]>
  2. <script src="html5shiv.js"></script>
  3. <![endif]-->

Silent Comments

Haml also provides the ability to create Haml specific comments, or silent comments. Silent comments differ from general HTML comments in that upon being complied any content within a silent comment is completely removed from the page, and is not displayed in the output. Silent comments are initialized with a dash then the number sign, -#. As with other comments, silent comments may be used to remove one line or multiple lines with the use of nesting.
HAML
  1. %div
  2. -# Removed line
  3. Actual line
COMPILED HTML
  1. <div>
  2. Actual line
  3. </div>

Filters

Haml provides a handful of filters, allowing different types of input to be used inside of Haml. Filters are identified with a colon followed by the name of the filter, :markdown for example, with all of the content to be filtered nested underneath.

Common Filters

Below are some of the more common filters, with the more popular ones of the group being :css and :javascript.
  • :cdata
  • :coffee
  • :css
  • :erb
  • :escaped
  • :javascript
  • :less
  • :markdown
  • :maruku
  • :plain
  • :preserve
  • :ruby
  • :sass
  • :scss
  • :textile

Javascript Filter

HAML
  1. :javascript
  2. $('button').on('click', function(event) {
  3. $('p').hide('slow');
  4. });
COMPILED HTML
  1. <script>
  2. $('button').on('click', function(event) {
  3. $('p').hide('slow');
  4. });
  5. </script>

CSS & Sass Filters

HAML
  1. CSS & SASS FILTERS:css
  2. .container {
  3. margin: 0 auto;
  4. width: 960px;
  5. }
  6. :sass
  7. .container
  8. margin: 0 auto
  9. width: 960px
COMPILED HTML
  1. CSS & SASS FILTERS<style>
  2. .container {
  3. margin: 0 auto;
  4. width: 960px;
  5. }
  6. </style>

Ruby Interpolation

As previously mentioned Haml can evaluate Ruby, and there may occasionally be times where Ruby needs to be evaluated inside of plain text. In this event Ruby needs to be interpolated, accomplished by wrapping the necessary Ruby code inside #{}.
Below is an example of Ruby being interpolated as part of a class name.
HAML
  1. %div{:class => "student-#{@student.name}"}
COMPILED HTML
  1. <div class="student-shay">