Introduce Yourself to SASS and Compass

So you’re a front-end web developer? If so, you probably spend a good portion of your day writing a lot of CSS. I remember those days of copying and pasting over and over again, racking your brain remembering the various vender prefixes, trying to ensure your website is cross-browser compatible, all while doing your best to write solid and clean CSS code.

Ever heard of SASS and Compass? I’ll walk you through how these two powerful tools will be able to speed up development time by doing the heavy lifting for you.

Sass could be defined as a meta-language on top of CSS that helps developers code more elegant syntax for CSS and implements various features that makes building stylesheets more manageable.

SASS & Compass

If code could have relationships, SASS and Compass are soul mates. When I first learned of SASS and then it’s pimp cousin Compass, I was intrigued. In the first couple of projects I worked on where I used these valuable tools, so many of my frustrations were solved. Like magic, I could set some standard site colors and then easily reuse them throughout my stylesheets all while managing that color from a single variable.

Then I came across something called “mixins“. These are analogous to the way many programming languages like PHP work. They let you write CSS in a DRY (Don’t Repeat Yourself) fashion while creating optimized stylesheets that are easier to read, write and edit than the old-school way. Plus with Compass, you’ll have access to several useful mixins which you can quickly incorporate into pre-built CSS frameworks like Blueprint, HTML5 Boilerplate, Susy and more. Even more, you can use them semantically, rather than litter your markup with presentational class names. This is great when working with Drupal theming where it’s not always quick and easy to change classes on elements.

SASS: Syntactically Awesome Stylesheets

SASSOne of the first things that caught my eye when visiting their site was the quote, SASS makes CSS fun again.

Basically, writing SASS is exactly the same as writing CSS… if you so choose. Using the SCSS syntax makes all of your CSS files SASS-ready. The only thing missing is all the exciting features SASS provides. Alternately you can write using the more terse syntax that can save you keystrokes.

Here’s both syntaxes below:

SCSS

Check out how similar SCSS is to CSS. The only thing different here is some variables. This is the method I prefer.

SASS

Tired of those repetitive curly braces and semicolons? They’ve been replaced with a more strict indentation-aware syntax. This method may allow you to type faster and visually scan easier. Both syntaxes are equally functional, so your choice should be based on preference.

Compiled to CSS

Here’s what the compiled CSS from either of the SASS code blocks above:

Install and Setup SASS & Compass

There’s a ton of great resources out there on the web on how to install and setup SASS and Compass. Their own documentation is a great start and should provide you all the information you’ll need to get up and running.

Compass

CompassCompass is SASS built pimp. Without SASS, Compass would be homeless. At the very least, Compass can run in the background and watch when changes get made to your sassy files so it can then re-compile and save it as a production-ready CSS file. That’s awesome and all, but that’s not even close to what this pimp has to offer. Compass allows you to setup your project structure so you can incorporate various frameworks, including your own if you’re a rebel. Out of the box, figuratively, Compass comes with a large number of utility mixins and the popular Blueprint CSS framework. That’s a lot of bling already, but mosey on over to GitHub and check out the other awesome goodies that people are working on. 960.gs, Susy, HTML5 Boilerplate and a whole lot more are already waiting for you to play around with. In addition, there’s a number of plugins you can incorporate that were created to perform certain specific tasks in CSS. Fancy Buttons is just one of the many plugins that provides a easy way to add progressively enhanced CSS buttons. Another is Lemonade which allows you to compile all of your .png background images into a nice, tidy sprite file.

Variables

One of my favorite features of SASS is the ability to use variables. Variables you say? Yup. It’s incredible that this isn’t already available is plain ‘ole CSS, because it’s so simple and yet powerful. I did a presentation at my job on using SASS and Compass in a new project we were starting. The first thing I heard about SASS was, “Whoa, now I don’t have to remember hex numbers for all my colors!” Or something similar to that. Here’s an example below using variables and functions to do things like change colors.

$my-red: #b80000;
$my-dark-red: darken($my-red, 10%); // renders as #410101
$my-muted-red: desaturate($my-red, 40%); // renders as $5c1919
$my-transparent-red: transparentize($my-red, 0.5); // renders as rgba(115, 2, 2, 0.5)

It doesn’t stop at colors either. SASS variables can be used to store pretty much any value you’ll need to reuse.

$vertical-margin: 24px;
$horizontal-margin: $vertical-margin * 0.5;
div.container {
  margin: $vertical-margin $horizontal-margin;
}

// Renders as:
div.container P
  margin: 24px 12px;
}

Mixins

Mixins are one of the most powerful features of SASS. Mixins allows coder’s to reuse entire snippets of code and even interject logic while doing it. This gives you reusable and flexible ways to style your markup. You’ll be using mixins everywhere, but let’s start by looking at humble html lists. We use lists in html almost as often as we use div’s. They’re versatile, and therefore are often the best semantic element for a given piece of content, be it a menu, a tag cloud, or upcoming concerts.

Let’s look at the mixin for removing bullets from lists that is included with Compass.

Defining the Mixin

This is where we write the code we want to apply to multiple places. This example happens to be included with Compass but you can easily write your own.

// REMOVE BULLETS FROM A LIST
// Turn off the bullet for an element of a list
@mixin no-bullet {
  list-style-image: none;
  list-style-type: none;
  margin-left: 0px;
}
// turns off the bullets for an entire list
// NOTE THAT THIS MIXIN NESTS THE PREVIOUS ONE ON ELEMENTS
@mixin no-bullets {
  list-style: none;
  li {
    @include no-bullet;
  }
}

Including the Mixin

This is how you apply the mixin as you work.

ul.my-list {
  @include no-bullets;
}

Or you can use the shorthand syntax:

ul.my-list
  +no-bullets

Rendered CSS

ul.my-list {
  list-style: none;
}
ul.my-list li {
  list-style-image: none;
  list-style-type: none;
  margin-left: 0px;
}

Mixins are also used when implementing a CSS framework in Compass. My main problem with implementing the increasingly numerous CSS frameworks is that in order to apply the predefined styles you need to use presentational class names in your markup like, span-6. I used to use them anyway in order to gain the other benefits, but it always tasted funny. Mixins are a huge part of overcoming that hurdle. Since mixins can accept arguments we can use them to calculate an element’s width and other properties, and apply those properties to semantic classes. So if your CSS framework has a set of styles that make an element 6 columns wide, set a margin, and float it to the left we can now write a mixin that can be applied to any class. What’s more, we can make that mixin dynamic so that it can calculate that width and margin instead of just dumbly spitting out static declarations. Mixins are part of the reason SASS and Compass make the perfect pair.

Extend

@extend is the new kid on the block, having recently been developed for SASS version 3, and honestly I’ve only recently started to understand it well enough to know when it’s the right tool to reach for. It’s pretty simple to grasp the concept. Sometimes you write a style for an element, and then you want to apply that style to something else, but add a little more to it. For example you might have a call out, and then want to position it on the left or right of the content.

SASS

$horizontal-margin: 18px;
$padding: 6px;
.callout {
  border: 1px solid black;
  padding: $padding;
}

.left-callout {
  @extend .callout;
  float: left;
  margin-right: $horizontal-margin;
}

.right-callout {
  @extend .callout;
  float: right;
  margin-left: $horizontal-margin;
}

Rendered CSS

.callout, .left-callout, .right-callout {
  border: 1px solid black;
  padding: 6px;
}

.left-callout {
  float: left;
  margin-right: 18px;
}

.right-callout {
  float: right;
  margin-left: 18px;
}

Stay Sassy, Austin

SASS and Compass has been added to my arsenal of web development weapons and should be in yours too! Since I’ve started using these two powerful tools, I’ve become spoiled. Give it a try on your next project and you will be too. Here’s to SASS and Compass, the perfect relationship.

CSS4! But, I Just Learned CSS3! A Sneak Peek Into CSS Level 4

[dropcap type=”v2″]H[/dropcap]ave you heard? No, bird is not the word, it’s CSS4. It’s starting to become a hot topic around the web development water cooler. Some of you may be thinking, Great, just when I started to get the hang of CSS3! Well, if it helps any, technically there is no such thing as CSS4. It’s little comfort I know, but you really should be excited. As a front-ender, we should all rejoice when progress is made even if it’s smelly IE crawling past simple milestones like rounded corners (thanks IE 9, about time!). When progress is made, it brings us new exciting tools to add to our development kit, making our life easier and bringing the quality of websites to that next level. CSS is going to that next level with 4, shouldn’t your site?

Continue reading “CSS4! But, I Just Learned CSS3! A Sneak Peek Into CSS Level 4”

Object-Oriented CSS for High Performance & Cleaner Code

There’s a common phrase that get’s tossed around all the time in the web development world, object-oriented programming. Usually when brought up, it’s in context of some back-end language like PHP, but what about for us front-end guys? Can we take this concept and apply it to the ever-changing landscape of CSS? The answer is yes, we can! And doing so will turn your CSS markup into a lean, mean and clean high performance styling machine. Let’s dive into object-oriented CSS!

There’s a common phrase that get’s tossed around all the time in the web development world, object-oriented programming. Usually when brought up, it’s in context of some back-end language like PHP, but what about for us front-end guys? Can we take this concept and apply it to the ever-changing landscape of CSS? The answer is yes, we can! And doing so will turn your CSS markup into a lean, mean and clean high performance styling machine. Let’s dive into object-oriented CSS!

Why should I care about Object-Oriented CSS?

Great, just what I needed, another new best practice concept to learn. Everyday it seems like there’s a new “best practice” idea you should be implementing in your project. So why should you use OOCSS and is it going to stick around?

There’s a couple of good reasons why as a developer you will want to write your CSS in an object-oriented way. Another common phrase thrown around in the web development world is “reusable” and the first reason why you should write OOCSS. In addition, making your CSS reusable will inevitably make your stylesheets become much smaller and easier to manage. OOCSS should make changing the design of your site easier.

You’ll also gain peace of mind when writing your styles this way. How so you ask? It will be mush easier to change parts of your site without breaking it. Keeping your CSS object-oriented enables you to change your site consistently.

Object-Oriented Programming, an easy concept to grasp

Object-oriented programming isn’t a new idea, it’s been put into practive since the late 1950s starting at MIT in the environment of the artificial intelligence group. According to Wikipedia,

Object-oriented programming (OOP) is a programming paradigm that represents concepts as “objects” that have data fields (attributes that describe the object) and associated procedures known as methods. Objects, which are instances of classes, are used to interact with one another to design applications and computer programs.

In layman’s terms, OOP is the practice of making your code reusable, efficient and fast. So how do we apply that idea to CSS?

Make Way for OOCSS!

Object-Oriented Cascading Stylesheets or OOCSS for short introduces object-oriented programming to the wonderful world of CSS. OOCSS, at its core, is simply writing less and cleaner CSS. It’s not a different language: still the same old CSS we all know and love. It’s just a paradigm shift. Really, object-oriented CSS is a few simple patterns and best practices.

I first learned of OOCSS from Nicole Sullivan (worked on the high performance team at Yahoo!) when I watched her presentation, Object Oriented CSS: for high performance we applications and sites. If you have about an hour, I’d highly suggest watching her presentation because she does a great job in explaining OOCSS and how to implement it. To understand OOCSS, you need to understand it’s two main principles: Separation of Structure from Skin, Separation of Containers and Content.

OOCSS: Separation of Structure from Skin

I never went to college for web development or programming so I’ve never liked those long, big-worded explanations about what certain terms or concepts meant. So I’m going to try my best to break it down for the layman’s like me out there. Separation of structure from skin basically means you put the layout classes or the classes you create to position regions on your webpage like grids from the visual features of your site or your site’s skin. Think of the structure like the foundation and wood framing of a home and the skin as the paint, wallpaper and other ascents. I’m more of a hands-on learned so here’s an example:

CSS before Implementing OOCSS

Here’s a block of CSS before any OOCSS concepts are applied to it.

Take a look at the CSS above. It’s valid CSS, however it could be optimized and made reusable using the OOCSS concept. Currently it uses non-reusable ID selectors to define styles. If you take a closer look, you’ll also notice they have a number of styles in common. Those common styles may be required to be consistent with the product or company the website represents.

CSS after Implementing OOCSS

With a little bit of planning and forethought, we can abstract the common styles so the CSS would end up looking something like this:

Now all the elements are using classes, the common styles are combined into a reusable “skin” and nothing is unnecessarily repeated. We just need to apply the “skin” class to all the elements and the result will be the same as what the first example would produce, except with less code and a possibility for further reuse.

Something to keep in mind…

When coding OOCSS, it’s important to make all styles you create as generic and adaptive as possible. A general rule of thumb is to try and never use defined widths and heights. The content should be able adapt accordingly while keeping the same look. This is true for most all styles in OOCSS.

For instance, let’s say you have a widget container inside a right column container. The right column container’s width could depend on a number of factors from the user’s screen size to the page type. You’ll need the widget container’s width to adjust accordingly so it fills all the horizontal space in the right column. In the example above, we’re defining the widget container’s width which wouldn’t allow it to adjust accordingly. Instead, if we left out the width definition in the widget class, it could dynamically fill all the horizontal space in the right column container. Make sense?

OOCSS: Separation of Containers and Content

The second principle of OOCSS is the separation of containers and content. We should rarely use location dependent styles, because those styles then become locked into specific selectors. The “skin” of an object should look the same no matter where it’s located. Take a look at the example below:

The style above locks all h3’s that appear in the sidebar container to a certain look. Also, this approach doesn’t allow the use of this style in other sections of the site like the footer. But what if we want to apply those exact same styles to h3’s that appear in the site’s footer with the exception of a different font size and a modified text shadow. To accomplish that there will be some duplication of code, see below.

I’m sure the above looks familiar. I’ve written css like this and I’m sure you have to. The code above now unnecessarily duplicates styles, BAD! But now with OOCSS, more forethought is required to figure out what is common among different elements. Then you must separate those common features into modules or objects that can be reused anywhere on the site. Doing this avoids the problem of needing to overwrite styles over an over again to achieve the desired result and avoids creating specificity issues.

Here’s a real world example. On the project I’m currently working on, we have default list stylings, another set of styles for our global navigation list and yet another for secondary navigational lists. Later on, we may want to add even more random lists that could appear in a sidebar or footer. The old way of doing CSS is to write what your default styles will be and then override those styles for the various different lists. This can get overwhelming, hard to manage, and cause code duplication.

To combat that, we spent a little bit more time upfront thinking about the common elements that will appear on the site and then abstracted those commonalities out into reusable modules. We didn’t attach our modularized classes to specific elements so it will allow us to add the box styles to any container.

The Bottom Line on Object-Oriented Cascading Stylesheets

I’m famous for saying, just give me the bottom line. Well here it is for object-oriented CSS, some simple guidelines to follow when implementing the OOCSS concept in your next project:

Object-Oriented CSS Guidelines to Follow

  • Avoid the descendent selector (i.e. don’t use .sidebar h3)
  • Avoid IDs as styling hooks
  • Avoid attaching classes to elements in your stylesheet (i.e. don’t do div.header or h1.title)
  • Except in some rare cases, avoid using !important
  • Use CSS Lint to check your CSS (and know that it has options and method to its madness)
  • Use CSS grids

For the Overachievers

Being in the IT industry, I know there’s many of you that eat this stuff up like it was candy. For the dedicated out there, here’s some additional resources you can use to learn more about object-oriented CSS. I would also highly suggest following Nicole Sullivan if you want to continue learning about OOCSS. In addition to posting articles regularly on object-orientated CSS, Nicole has done a number of presentations with accompanying slideshows. Here’s some that I would suggest checkout out:

A Little Extra on Object-Orientated CSS

Nicole Sullivan gave a talk at An Event Apart in Boston, MA on Object-Oriented CSS. She shared ways to optimize CSS code and why performance matters for websites. Here’s some of the important points worth mentioning:

Performance Matters

  • Yahoo! 5-9% drop in full page traffic from an added 400ms
  • Google lost 20% of searches from an added 500ms
  • Shopzilla improved Website performance by 3.5 seconds and conversion rate went up 7-12% and page views went up 25%
  • Bing and Google added added 200ms to a page it took people 500ms to make a first click. People get out of their flow when performance degrades
  • Over time, as you slow down user experience, people’s interactions get worse and worse. Even when people’s performance gets improved, if you lost them before, they may not come back. Build performance into your process.
  • Active users are the ones most impacted by performance. Time to click is two times worse than the delay was. Your users care about performance.
  • The biggest thing you can do to improve performance is reduce file size and number of http requests. CSS is a factor in both of these. We have to do CSS right.

Issues with CSS

  • CSS code is too fragile -even the cleanest code can get ruined by the first non-expert to work on it. CSS requires expert ability to just get started.
  • Code re-use is almost non-existent. Most people start over when writing CSS.
  • Because of these issues, file size just keeps getting.

Cascading CSS

  • Browsers all have default styles. All these internal style sheets are different. A CSS reset sheet can make things equal across browsers.
  • Browsers ignore code they don’t understand. Invalid property values are skipped.
  • The order of classes does not guarantee which one will be applied first.
  • The last property value pair in a CSS declaration is the one that applies.
  • The order of style sheets also matters. The last style sheet wins.
  • CSS inheritance: properties are inherited by child elements. For example, paragraphs inherit the font-size of the body.
  • IDs win over classes. Inline styles win over external style sheets. !important wins even over inline styles.
  • Avoid ID, inline and !important when styling elements. This allows cascade order to determine the winner.
  • You can use the cascade ordering of styles to save code and improve performance.
  • Avoid applying styles in a “.message.error” manner. This causes issues in some browsers.

How to Optimize CSS

To optimize CSS: reduce duplication and improve predictability (don’t change expectations based on where the component is).

  • Analyze how much duplication there is.
  • Find simple solutions. Problems may seem complicated but that does not mean they necessarily are. Determine what you can know about each object and determine what you can’t know.
  • Simplify specificity: use hacks very sparingly and in way that does not impact specificity.
  • Avoid styling IDs: they impact specificity and can’t be re-used
  • Avoid styling elements: style classes instead
  • Avoid !important :except on leaf nodes
  • Give all rules the same strength: use cascade order to overwrite previous rules.
  • Reuse elements: this makes them performance “freebies”

Wrapping Up

I know there’s probably a lot of you out there that fear the OOCSS ideology because it appears to go against a lot of the so-called “best practices“. Never fear! Once you understand the benefits of using OOCSS, I have no doubt that you will convert.

Even though there are new frameworks, best practices, concepts and technology coming out daily, I think overall object-oriented CSS will stick around in the future of CSS development. I strongly believe it’s a concept that all developers from back-end to front-end should incorporate into their projects.

Bet I can guess your address! Reverse Geocoding with HTML5 & Google

No, this isn’t one of those bet I can guess your weight or age games you find at places like carnivals and Six Flags. I bet you I can guess your approximate address with HTML and reverse geocoding.

No, this isn’t one of those bet I can guess your weight or age games you find at places like carnivals and Six Flags. I bet you I can guess your approximate address with HTML and reverse geocoding.

Last month I wrote an article on the HTML5 Geolocation API. I’m going to take what I showed you there, expand on it and show you how to take advantage that powerful API and the Google Maps JavaScript API to perform reverse geocoding to find an approximate address.

See it in action!

Turning geographic data like a street address and zip code into geographic coordinates such as latitude and longitude is called geocoding

The process of turning geographic data like a street address and zip code into geographic coordinates such as latitude and longitude is called geocoding. When you do the opposite, turning coordinates into an address, it’s called reverse geocoding. See a live demo below:

I know, I know, it’s not perfect, but it’s a lot closer than we had which at most times was somewhere in the city, state and sometimes just country. And granted, if the user doesn’t allow us to grab their location we’re back to using the IP, but it’s still a pretty good guess. Now only if we could have got Osama Bin Laden to visit one of our webpages while logged on as himself… long shot, but wouldn’t that be awesome if that’s how it went down.


In order to guess your user’s approximate address, just take what we learned in the HTML5 Geolocation Guide to get the user’s latitude and longitude using the HTML5 Geolocation API. Add a little pitch of the Google Maps JavaScript API and BAM! We’ll have a pretty good guess at where their located.

Download Demo Files

The HTML

index.html

All basic stuff, nothing too exciting. Just ensure you load the jQuery library, MaxMind GeoIP API for our fallback and the Google Maps JavaScript API. And of course, the script we’ll write below.

The JavaScript

script.js

A Deeper Look

If you’ve already, I suggest you read my other post on HTML Geolocation to familiarize yourself with 90% of the code above. The rest is fairly simple to understand. You get the coordinates from getCurrentPosition() , then pass them to a printAddress() function, which uses the Google Maps API to perform the reverse geocoding.

The printAddress() function begins by creating a new Google Geocoder object. The Geocoder object gives us access to the geocode() method, which can take in a variety of options and return information based on them.

In this case, we’re using the google.maps.LatLng() method to create a new Google LatLng object that is passed into geocode() in order to get the address. The geocode() method is asynchronous, just like getCurrentPosition(), so we define an inline JavaScript function to handle the callback.

The callback’s response contains two parameters, one for the results and the other for the status code. If the status is OK, then it’s safe to parse the array of GeocoderResults objects stored in the results variable. The results variable is an array since Geocoder may return more than one entry.

Next, check for a GeocoderResults object in the first position of the array and, if it exists, append the formatted_address property to the defined results element.

For more information about reverse geocoding, check out Google’s documentation.

Wrapping Up

screenshot_meetwaysThe possibilities are limitless with what you can do with this functionality. Internet marketers are biting at the bit to start using this technology to drive even better user-specific ads to the eyes of millions. Online game developers like Parallel Kingdom are building ground-breaking web-based massive multiplayer online (MMO) games. With a little extra code, we can turn our code into a mobile app that gives user’s the ability to send their location to a friend or family member with a click of a button. Our imagination has now become the limit with what we can build. The next fives years is sure to be an exciting time in the web development arena bringing the whole world a better internet. Are there any projects you’ve done you can share that use the HTML5 Geolocation API?

Cross-Browser CSS Styled Select Lists Using jQuery

Front-enders won’t be the only ones to rejoice after reading this. I’m going to walk you through how to build a prettyfied cross-browser CSS-styled select lists.

Front-enders won’t be the only ones to rejoice after reading this. I’m going to walk you through how to build a prettyfied cross-browser CSS-styled select lists.

I know for many years web designers have yelled at us front-enders about why we can’t style our site’s select box like the one’s in the mockups they create. With the added rounded corners, customized drop down arrows, gradients, images and more; styling drop down select boxes can become a nightmare for us. Not only is styling them a pain, but different browsers render them differently.

If you’re a pixel perfect coder like I am, I’m sure you share in my frustration trying to make those stupid drop downs look good and the same if the various browsers. Well, hopefully after reading this article you’ll be getting some better sleep at night because I’m going to make styling cross-browser CSS styled select lists using as easy as pie! Ready for some delicious code?

UPDATE (Mar. 18, 2014): Fixed issue where selects would break when more than one appears on the page.

Download Demo Files


Enough with the small talk, let’s get into the code. First we’re going to start off by coding the structure and content of the page.

Step 1: Start with the basics

index.html

Take a look at the markup above. Most of it should be pretty straight forward for the majority of you. There’s one thing that may stick out a little and that’s the use of the data attribute:

  • data-icon, the location of the icon for the specified list element
  • data-html-text, the content that will appear for the list element

Step 2: Build the functionality

script.js

This is where the magic happens. If you’re familiar with jQuery, you should be able to read and understand the markup above. It’s pretty simple and straightforward, nothing too complex.

Basically, we hid the select box and looped through all of the items to generate the rendered HTML content. That content will turn into our styled select box. When someone clicks on the rendered box, the list will slide down with all of the available list items from the hidden select box. Once the user select an item, we update the visible text. Simple stuff!

Now that we’ve got the structure, content and functionality built, we need to make it prettyfied. This is where the power of CSS3 comes in.

Step 3: Make it prettyfied

styles.css

That’s all the styling you’ll need to build this cross-browser CSS styled select list. Of course, you can always embellish it with your own little flair. Just remember to be vigilant about the capabilities of outdated browsers.

The Final Product

CSS3 Styled Select

Browser Support

I made a point to ensure that this method of doing styled select dropdowns would be cross-browser compatible and work with older versions. I’ve testing the code in the following browsers:

  • Google Chrome
  • Firebox
  • Internet Explorer (version 7 and up!)
  • Opera
  • Safari

Let me know if you run into a different browser or a specific version of a browser that this doesn’t work on or comes out a little messed up.


In Conclusion

I’ve demonstrated just one of the many ways to build a cross-browser CSS styled select list using jQuery. I prefer this method because of it’s simplicity and ability to style it however needed. A major bonus is that it’s cross-browser compatible, which many of the styled select box scripts aren’t.

I’d love to see how you’ve incorporated it into your site and any feedback other developers might have.

HTML5 Geolocation

Learn how to use the HTML5 Geolocation API to make one-shot location requests, or repeated position updates to get and keep track of the user’s position.

What is the HTML5 Geolocation API?

HTML5 GeolocationAbout four years ago, the big smartphone “boom” was still an uncertain possibility. Today, it’s no longer a possibility, it’s reality. We’re surrounded by people that are addicted to their phones. Because of that addiction, in the past four years wireless companies have made some major improvements, geolocation being one of the most used. I know that I’m constantly on my GPS-fitted Android phone looking up directions on how to get somewhere. Google Maps and Waze being to of my favorite geolocation based phone apps. Here, we’re going to discuss the geolocation capabilities of HTML5 using the browser’s native HTML5 Geolocation API and provide some fallbacks incase it doesn’t work.

Download Demo Files

Browser Geolocation and How It Works

The HTML5 Geolocation API is used to get the geographical position of a user. Unfortunately, since this can compromise user privacy, the position is not available unless the user approves it. W3C has developed a set of APIs to effectively allow the user or client-side device to retrieve geographic positioning information with JavaScript.

HTML5 geolocation is slowly finding its way to the mainstream applications. In the past two years, there’s been an explosion in geolocation based tools. Google Maps is a great example of this. They fully support geolocation in all major browsers. See a current list of supported browsers and devices below.

HTML5 Geolocation Supported Devices

  • Firefox 3.5+
  • Chrome 5+
  • iPhone Safari
  • Opera 10.6+
  • Opera Mobile 10.1+
  • Safari 5+
  • iPhone 3.0+
  • Android 2.0+
  • Internet Explorer 9+
  • Symbian (S60 3rd & 5th generation)
  • Palm WebOS 2.0+
  • Blackberry OS 6
  • Maemo

I've seen the future, it's in my browser.If you’re interested in the HTML5 Geolocation API specs, you can read W3C’s Geolocation API Specification. If you just skim through it, an important section to pay attention to is section 6.2.8 titled: “The geolocation API must be agnostic to the underlying sources of location information“. Basically, it’s saying that the underlying technology on the device may achieve geolocation via either GPS, cell tower triangulation or possibly other techniques. The down side here is the geolocation API won’t identify how that location was determined. That’s usually not going to be a problem, but you’ll notice the accuracy of the location may vary greatly depending on which technique was used.

Geolocation Sources

Desktop browsers are most likely to use WiFi which is accurate up to 20m or IP-based geolocation which is what most people are used to (though this method can provide false positives). Mobile devices tend to use triangulation techniques such as GPS which is accurate up to 10m. WiFi and GSM/CDMA cell IDs are accurate up to 1000m.

Protecting Your Data

Is big brother really watching? In W3C’s specification, it says that since the API exposes the user’s location it therefore could compromise their privacy. To combat this, W3C says the user’s permission must be obtained first before any geolocation information is given. I know that doesn’t give the conspiracy theorist out there peace of mind—but then again, will anything really? The browser will take care of this by displaying a message as either a pop-up box or at the top of the browser (implementation is browser specific) requesting the user’s permission.

How the HTML5 Geolocation API Works

Luckily, once you understand how to geolocation API works, it’s a cinch to implement it. With the HTML5 Geolocation API, you must use asynchronous functions. Big word, I know and if you don’t know what it means, I’ll try to explain it to you below. But before that, you’ll first need to know if user’s browser supports the API.

Checking for Browser Support

It’s always a good idea to check if a user’s environment supports features like the geolocation API. Luckily the API provides a function for this which can be called doing the following:

if ( navigator.geolocation ) {
  // do fancy stuff
}

If it returns false, you should probably tell the user that they’re browsers blows and they shouldn’t be allowed near a computer… not (But if you do, I’d love to see it). If you’re already using Modernizr, you can also use it to check for geolocation device support:

if ( Modernizr.geolocation ) {
  // do fancy stuff
}

How Asynchronous Functions Work

So what’s an asynchronous function? It’s a function that is executed outside of the main program flow. In the context of JavaScript, it means our code will call a function and then continue to execute statements before the function returns. So basically it allows you to run other functions before your function is completed.

An Asynchronous function is one that is executed outside of the main program flow.

When we follow this model, our code should look something similar to this:

// The function we want to call.
do_something( handle_response_to_do_something );

// The function that will handle the response of the above function call.
function handle_response_to_do_something( response ) {
  alert( response );
}

Since the response to do_something() function is given to us asynchronously, we must choose a function that will receive a response and use it. In this case, we must define another function, handle_response_to_do_something(), that will display the result in a dialog box.

So why do we need to use asynchronous functions when using the HTML5 Geolocation API? Well, when our application tries to query its location, the user of the device must first agree to share their location with our application. If we didn’t make this action a asynchronous one, then everything inside the browser would freeze until the user responds; not exactly user-friendly.

How to Use the getCurrentPosition API

Now let’s dig into the geolocation API. The first API we’re going to work with is the getCurrentPosition() API. When that function is called, it must immediately return and then asynchronously acquire a new Position object. If it worked, this method must call it’s associated successCallback argument with a Position object as an argument. If it fails and the method was invoked with a non-null errorCallback argument, this method must invoke the errorCallback with a PositionError object as an argument.

I’m going to assume that you already know how to create an HTML document so I’m not going to walk you through the process as if you were in kindergarten. In our example, we have a basic HTML document with the HTML5 doctype defined using the latest version of jQuery. On the page we’ll put a button the user can click on to grab their location information using the HTML5 Geolocation API.

Step 1: Create the action button
<input id="find-me" type="button" value="Find my location" />

Simple.

Step 2: Build the JS functions to get the user’s information

Now we’re going to build the functions the button we created will call when it get’s clicked on.

$( function() {
  $( "#find-me" ).live( "click", function( e ) {
    e.preventDefault();
    find_me();
  });
});

function find_me() {
  if ( navigator &amp;&amp; navigator.geolocation ) {
    navigator.geolocation.getCurrentPosition( geo_success, geo_error );
  } else {
    alert( "Your browser sucks balls and so do you!" ");
  }
}

function geo_success( position ) {
  printLatLong( position.coords.latitude, position.coords.longitude );
}

// The PositionError object returned contains the following attributes:
// code: a numeric response code
// PERMISSION_DENIED = 1
// POSITION_UNAVAILABLE = 2
// TIMEOUT = 3
// message: Primarily for debugging. It's recommended not to show this error
// to users.
function geo_error( err ) {
  if ( err.code == 1 ) {
    error( "The user denied the request for location information." )
  } else if ( err.code == 2 ) {
    error( "Your location information is unavailable." )
  } else if ( err.code == 3 ) {
    error( "The request to get your location timed out." )
  } else {
    error( "An unknown error occurred while requesting your location." )
  }
}

// Output lat and long.
function printLatLong( lat, long ) {
  $( "body" ).append( "Lat: "" + lat );
  $( "body" ).append( "Long: "" + long );
}

function error( msg ) {
  alert( msg );
}

The markup above listens to when the button is clicked and then calls the find_me() function. Next, it determines if the user’s browser supports the HTML5 Geolocation API feature natively. If it does, we can call the getCurrentPosition() method. Since this method executes asynchronously, pass it two callback functions: geo_success and geo_error.The error callback is passed a position error object that contains a code and a message property. Here’s a list of the possible messages:

  • Unknown
  • Permission Denied
  • Position Unavailable
  • Timeout

The success callback is passed a position object that contains a coordinates object and a timestamp. The coordinates object contains the following:

  • latitude, which is specified in decimal degrees
  • longitude, which is specified in decimal degrees
  • altitude, which is specified in meters above the ellipsoid
  • accuracy, which is specified in meters
  • altitudeAccuracy, which is specified in meters
  • heading, which is the direction of travel specified in degrees
  • speed, which is specified in meters per second

Of those seven, only three are guaranteed to be there: latitude, longitude, and accuracy.

Step 3: Run the Code!

Once you run the code above, assuming it’s in a browser that supports geolocation, you should see your latitude and longitude coordinates displayed to you. This all goes to plan if the user has agreed to share their location information, but what if they don’t want to share that information? Or what if something went wrong trying to get that information? Wouldn’t it be nice to be notified of the problem? You can.

Our code can detect HTML5 geolocation issues by calling the geo_error() function. In the code above, geo_error() takes the error argument. With this information we can check for the kind of error that’s occurred. Usually, the browser will identify one of the following three errors as the cause:

  • User chose to not share location data
  • Device was unable to obtain position data
  • Device timed out while waiting to retrieve position data

How to Use the watchPosition and clearWatch APIs

We’ve learned how to use the getCurrentPosition API, now let’s quickly look at the watchPosition API. When this function is called, it must immediately return and then asynchronously start a watch process defined by the following steps:

  1. Acquire a new Position object. If successful, invoke the associated successCallback with a Position object as an argument. If the attempt fails, and the method was invoked with a non-null errorCallback argument, this method must invoke the errorCallback with a PositionError object as an argument.
  2. Invoke the appropriate callback with a new Position object every time the implementation determines that the position of the hosting device has changed.

This method will return an integer value that uniquely identifies the watch process. When the clearWatch() function is called with this identifier, the watch process will stop acquiring any new position fixes and will cease invoking any callbacks. So in other words this API enables our code to repeatedly receive location information as the device location changes.

Step 1: Create the scaffolding

[code_highlight]<script type="text/javascript" src="js/jquery-1.4.2.min.js"></script><script type="text/javascript">// <![CDATA[
jQuery(window).ready(function(){
jQuery("#btnInit").click(initiate_watchlocation);
jQuery("#btnStop").click(stop_watchlocation);
});
var watchProcess = null;
function initiate_watchlocation() {

}
function stop_watchlocation() {

}
function handle_errors(error) {
switch(error.code) {
case error.PERMISSION_DENIED: alert("user did not share geolocation data");
break;
case error.POSITION_UNAVAILABLE: alert("could not detect current position");
break;
case error.TIMEOUT: alert("retrieving position timedout");
break;
default: alert("unknown error");
break;
}
}
function handle_geolocation_query(position) {

}
// ]]></script>
<button id="btnInit">Monitor my location</button>
<button id="btnStop">Stop monitoring</button>
<div id="”info”"></div>[/code_highlight]

So what’s new in the code above? Well, first we have added a new button to allow us to stop the watch process with the stop_watchlocation() function to handle its click. We also have a watchProcess variable to keep track of the watch process.

Step 2: Add code to call the watchPosition() API

To start the process we need to add the code that calls the watchPosition() API like the code below:

function initiate_watchlocation() {
  if ( watchProcess == null ) {
    watchProcess = navigator.geolocation.watchPosition( handle_geolocation_query, handle_errors );
  }
}
Step 3: Add code to call the clearWatch() API

To stop the process we need to add the code that calls the clearWatch() API like the code below:

function stop_watchlocation() {
  if ( watchProcess != null ) {
    navigator.geolocation.clearWatch( watchProcess );
    watchProcess = null;
  }
}
Step 4: Display the geolocation data

Finally, we handle displaying the geoposition data like this:

function handle_geolocation_query( position ) {
  var text = "Latitude: " + position.coords.latitude + "<br>";
  text += "Longitude: " + position.coords.longitude + "<br>";
  text += "Accuracy: " + position.coords.accuracy + "m<br>";
  text += "Time: " + new Date( position.timestamp );

  jQuery( "#info" ).html( text );
}

What’s in Geolocation Data

Inspecting what we receive from the geolocation API will give us the coords and timestamp fields. The timestamp field simply denotes the time at which the instance of geolocation data was created. The coords attribute contains a set of geographic coordinates together with their associated accuracy as well as a set of other optional attributes such as altitude and speed. Per W3C specs:

  • The latitude and longitude attributes are geographic coordinates specified in decimal degrees.
  • The accuracy attribute denotes the accuracy level of the latitude and longitude coordinates. It is specified in meters and must be supported by all implementations.
  • The altitude attribute denotes the height of the position, specified in meters above the WGS84 ellipsoid. If the implementation cannot provide altitude information, the value of this attribute must be null.
  • The altitudeAccuracy attribute is specified in meters. If the implementation cannot provide altitude information, the value of this attribute must be null.
  • The heading attribute denotes the direction of travel of the hosting device and is specified in degrees counting clockwise relative to the true north. If the implementation cannot provide heading information, the value of this attribute must be null.
  • The speed attribute denotes the current ground speed of the hosting device and is specified in meters per second. If the implementation cannot provide speed information, the value of this attribute must be null.

Data for some of these fields may not be available depending on the target device.

Getting Geolocation Data with a Fallback

What happens if something goes wrong when attempting to get your user’s geolocation data? Don’t worry, there’s fallback options available. You can still get your user’s geolocation, it just won’t be as accurate. You can perform an IP-to-location lookup as a fallback using an external geolocation service. It’s certainly not as accurate as latitude and longitude coordinates, but it’s far better than not having any location data at all. These services are better than you just using PHP to get the user’s IP address because they do their best to map the IP of a device to the geographic location using large geolocation databases. There’s still some downsides though:

  • IP addresses may be associated with the wrong location (e.g., the wrong postal code, city or suburb within a metropolitan area).
  • Addresses may be associated only with a very broad geographic area (e.g., a large city, or a state). Many addresses are associated only with a city, not with a street address or latitude/longitude location.
  • Some addresses will not appear in the database and therefore cannot be mapped (often true for IP numbers not commonly used on the Internet).
  • The important thing to remember is that when an external geolocation service is used, the accuracy is not as good as geolocation native to the device, and in some scenarios it may be completely off. Additionally, such services do not provide any information regarding the altitude, speed or heading of the device. Regardless, when GPS or triangulation are not available, they are a good fallback.

3rd Party Geolocation Services

  • Google offers the google.loader.ClientLocation object in it’s Google Maps API, but at last check, doesn’t work for many US IP addresses.
  • The MaxMind GeoIP JavaScript Web Service seems more accurate and up-to-date. Also, it’s free as long as you link back to their website. Alternatively, MaxMind offers a JavaScript attribution-free license that can be purchased for $250/year.
  • geoPositon.js is an open source, MIT-licensed JavaScript library that smooths over the differences between the W3C geolocation API, IP geolocation services, and the APIs provided by mobile platforms.

Coding the Fallback Solution

Now let’s get into actually coding a fallback solution. I’m going to show you how to do it using Yahoo’s library and MaxMind. I’m not going to include Google’s since currently it doesn’t work for many US IP addresses or geoPositon.js because it’s not really a fallback, more of an alternative.

MaxMind’s Geolocation Fallback Solution

MaxMindWhoops, couldn’t get your location, never fear MaxMind is here. Let’s start by modifying our previous code to use MaxMind as a fallback. First, you’ll need to add the JavaScript library to the page.

<script src="http://j.maxmind.com/app/geoip.js"></script>
Next, add the MaxMind fallback:
$(document).ready(function () {
  // wire up button click
  $('#go').click(function () {
    // test for presence of geolocation
    if (navigator &amp;&amp; navigator.geolocation) {
      // make the request for the user's position
      navigator.geolocation.getCurrentPosition(geo_success, geo_error);
    } else {
      // use MaxMind IP to location API fallback
      printLatLong(geoip_latitude(), geoip_longitude(), true);
    }
  });
});

// output lat and long
function printLatLong(latitude, longitude, isMaxMind) {
  $('body').append(' Lat: ' + latitude + ' ');
  $('body').append(' Long: ' + longitude + ' ');
  // if we used MaxMind for location, add attribution link
  if (isMaxMind) {
    $('body').append('<a href="http://www.maxmind.com" target="_blank">IP to Location Service Provided by MaxMind</a>');
  }
}

function geo_error(err) {
  // instead of displaying an error, fall back to MaxMind IP to location library
  printLatLong(geoip_latitude(), geoip_longitude(), true);
}
When calling printLatLong() using MaxMind, pass in an extra true parameter.
A Closer Look

When navigator errors and you’re unable to get the user’s location, instead of showing an error, use the geoip_latitude() and geoip_longitude() functions that MaxMind’s JS library provides. Looking at the source of the MaxMind geoip.js file, you’ll notice that it’s already translated your IP address into location data. MaxMind create a dynamic JS file by reading the IP address that made the HTTP request, doing the IP-to-location translation on the server side and then outputting the results. In addition to latitude and longitude, the location data shown below is also available:

  • geoip_country_code(), Country Code
  • geoip_country_name(), Country Name
  • geoip_city(), City
  • geoip_region_name(), Region
  • geoip_postal_code(), Postal Code
  • geoip_area_code(), Telephone Area Code
  • geoip_metro_code(), Metro Code

An advantage to using MaxMind to a fallback is it’s free as long as you give them attribution in the form of a back link to their website. Depending on your project, if the browser fails to get the user’s location and you end up using MaxMind, you could comply with their usage terms by doing the following using the example above:

function printLatLong( latitude, longitude, isMaxMind ) {
  $( "body" ).append( "Lat: " + latitude );
  $( "body" ).append( "Long: ' + longitude );

  // If we used MaxMind for location, add attribution link.
  if ( isMaxMind ) {
    $( "body" ).append( '<a href="http://www.maxmind.com" target="_blank">IP to Location Service Provided by MaxMind</a>' );
  }
}
See also

MaxMind provides free/open source geolocation solutions for city, country, and IP lookups at www.maxmind.com/app/ip-location.

YQL Geo Library Fallback Solution

Another fallback option you have when the browser fails to get the user’s geolocation data is YQL Geo Library. This library can do other things which I’ll leave to you to discover, but for now let’s look at how we should modify our code to successfully detect the location on both supporting and non-supporting browsers. First, we need to add the JS:

<script src="//code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="js/yqlgeo.js"></script>

Then code the geolocation methods:

;( function( $ ) {
  "use strict";

  $( function() {

    function initiate_geolocation() {
      if ( navigator.geolocation ) {
        navigator.geolocation.getCurrentPosition( handle_geolocation_query, handle_errors );
      } else {
        yqlgeo.get( "visitor", normalize_yql_response );
      }
    }

    function handle_errors( error ) {
      switch( error.code ) {
        case error.PERMISSION_DENIED:
          alert( "User did not share geolocation data." );
        break;
        case error.POSITION_UNAVAILABLE:
          alert( "Could not detect current position." );
        break;
        case error.TIMEOUT:
          alert( "Retrieving position timed out." );
        break;
        default:
          alert( "Unknown error." );
        break;
      }
    }

    function normalize_yql_response( response ) {
      if ( response.error ) {
        var error = { code : 0 };
        handle_error( error );
        return;
      }

      var position = {
        coords: {
          latitude  : response.place.centroid.latitude,
          longitude : response.place.centroid.longitude
        },
        address: {
          city    : response.place.locality2.content,
          region  : response.place.admin1.content,
          country : response.place.country.content
        }
      };

      handle_geolocation_query( position );
    }

    function handle_geolocation_query( position ) {
      alert( "Lat: "" + position.coords.latitude + " " + "Lon: " + position.coords.longitude );
    }

    // Click handler for the button.
    $( "#btnInit" ).click( initiate_geolocation );
  });
})( jQuery );

So what’s going on in the markup above?

  1. We are importing the YQL Geolocation Library into the page
  2. Inside the initiate_geolocation() function, the code checks to make sure geolocation is natively supported. If not it makes use of the YQL Geolocation Library.
  3. Finally we’ve defined the normalize_yql_response(response) function to turn the result of the YQL Geolocation Library into an output format similar to the W3C geolocation API specs.

In Conclusion

After reading though this guide, hopefully you now understand the HTML5 Geolocation API, how to use it and implement it in your next project. Your imagination truely is the limit with what you can build. For example, imagine how useful your site could be if it provided online timetables for all public transportation in a particular city. Using geolocation, the site could recommend optimal travel routes to get people where they’re going as quickly as possible. Desktop users could get their start location sorted by proximity to their computer. Mobile users trying to get home after a night out could quickly find the closest bus stop within walking distance. These possibilities are limitless.

HTML5 Geolocation Real-World Scenarios

Here’s just a few example that show how a website might implement the HTML5 Geolocation API. Keep in mind, it’s the small things on a site that make a huge difference. Some of these may seem obvious, but can make a huge difference in the user’s experience.

  • Public transportation sites can list nearby bus stops and metro locations.
  • Late night out? Taxi or car service Web sites can find where you are, even if you don’t know.
  • Shopping sites can immediately provide estimates for shipping costs.
  • Travel agencies can provide better vacation tips for current location and season.
  • Content sites can more accurately determine the language and dialect of search queries.
  • Real estate sites can present average house prices in a particular area, a handy tool when you’re driving around to check out a neighborhood or visit open houses.
  • Movie theater sites can promote films playing nearby.
  • Online games can blend reality into the game play by giving users missions to accomplish in the real world.
  • News sites can include customized local headlines and weather on their front page.
  • Online stores can inform whether products are in stock at local retailers.
  • Sports and entertainment ticket sales sites can promote upcoming games and shows nearby.
  • Job postings can automatically include potential commute times.

HTML5 Geolocation Application Tutorials & Demos


Frequently Asked Questions

I don’t want people knowing my location! Can I turn it off?

Privacy is an obvious concern when you’re talking about sharing your physical location with a remote web server. The geolocation API explicitly states: User Agents must not send location information to Web sites without the express permission of the user. In other words, sharing your location is always opt-in. If you don’t want to, you don’t have to.

Does the geolocation API work on the International Space Station, on the moon, or on other planets?

The geolocation specification states, The geographic coordinate reference system used by the attributes in this interface is the World Geodetic System (2d) [WGS84]. No other reference system is supported. The International Space Station is orbiting Earth, so astronauts on the station can describe their location by latitude, longitude, and altitude. However, the World Geodetic System is Earth-centric, so it can’t be used to describe locations on the moon or on other planets.

What about Internet Explorer?

Prior to version 9 (technically 9.0RC1), Internet Explorer did not support the W3C geolocation API. But no worries! Like I described above, there’s JS fallback options you can use. It’s not quite the same as the W3C geolocation API, but it serves the same purpose.

While we’re on the subject of legacy platforms, I should point out that many older mobile phone platforms had their own device-specific geolocation APIs. BlackBerry, Nokia, Palm, and OMTP BONDI all provide their own geolocation APIs. Of course, they all work differently which in turn works differently from the W3C geolocation API.


Additional Resources