Utilizing the Geolocation JavaScript API for Serving Alternate Style Sheets – Part 1

by in Tutorials on 20th Jul 2011 · Comments

First off, don’t panic! You might have already scanned the article and noticed no headings mentioning either geolocation or any APIs. Yes, it is true that there isn’t anything about geolocation in this part of the article, but that’s only because I wanted to ease you into it. Well, OK, that isn’t true. Here’s the truth: this article is envisioned as a continuation of my last post - Build a HTML5/CSS3 Website Layout Without Images – Part 1 on Onextrapixel where we discussed some of HTML5's new elements and some of the properties introduced with CSS3.

Starting with the demo from my previous article, I wanted to see what changes I could make to introduce more HTML5 elements and attributes and to also show off some more CSS3 goodness. There have also been some changes to the existing CSS to make sure we use the features now supported by Opera 11.10, Internet Explorer 9 and Firefox 4 (er, Firefox 5).

Utilizing the Geolocation JavaScript API for Serving Alternate Style Sheets - Part 1


Part 1

So, in part 1, we will discuss HTML and CSS and the idea for part 2 is to locate the visitors of our demo page using the geolocation API and then use PHP to calculate the sunrise and sunset times based on the users latitude and longitude. If the current time happens to be before sunrise or after sunset, we add a new style sheet which will darken the layout’s colors.

That’s probably too much for an intro, so here’s the dark layout that we will automatically switch to in case it’s nighttime at the visitor’s location:

Overview

The Content of Our Demo Folder

This time, we have a few extra files needed to make everything work. Alongside the usual index page and the style sheet, we have one more style sheet (I'll pretend that the style sheet for Internet Explorer isn't there) that changes the colors of the layout if we determine that it is after dark. There is also the calc.php file where we will determine if it is past sunset and before sunrise. Of the two folders, the scripts folder is new and it contains the JavaScript file which holds our small script.

Demo Folder

HTML – What Has Changed

Actually, this will be a rather short section as not much has changed in the markup – most of the changes were made to the CSS.

The Viewport Meta Tag

Starting from the top, we have one new meta tag which helps a lot when you need to control how your site/web app behaves in a mobile or a tablet browser. As our page now has a fluid layout which adapts to different resolutions, including the low ones on smartphones, pixel not being a pixel becomes a huge problem. This is where the viewport meta tag comes into play: it gives us a couple of properties which can “restrain” the scaling which mobile devices perform, e.g., when you change their orientation.

<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0" />

The first property, width, lets the browser know the width to which it should render the page. By setting it to device-width, we make sure that the width of our layout equals the width of the viewport.

The following three properties: initial-scale, minimum-scale and maximum-scale lock the scaling of our layout to the value of 1. In other words, we prevent the scaling of the layout on orientation changes (and if a visitor tries zooming by pinching). You can view it as making sure the layout adapts to the width of the device just like it does when we change the width of the browser window on desktop browsers as opposed to it scaling like we were zooming in or out of the page. By setting all these properties, our fluid layout can adapt to the width of the device, be it a smartphone or a tablet.

The Time Element

Another change from the original demo is reflected in the way the dates of the posts are coded in HTML (as well as the way they are presented). This time we make use of the HTML5 time element.

The time element represents either a time on a 24 hour clock, or a precise date in the proleptic Gregorian calendar, optionally with a time and a time-zone offset.

I didn't get to mark up the dates with the time element in the original demo because of all the nested elements which I used to style that section. This time, the date section has a simpler style and I was able to use the HTML5 element.

The time element is another asset in adding more semantic meaning to your pages. Here, we use it to specify the publishing dates of our posts.

<time datetime="2011-04-16" pubdate>16 apr</time>

Between the time tags, we place the date we want the visitors to see: "16 apr". Within the opening time tag, we have two attributes: the first one is datetime and it lets us specify the actual date in a standard format. Check out the HTML5 specification for a list of valid date & time formats. The second attribute, pubdate, is a Boolean attribute and it basically indicates that that's the publishing date of the content in its ancestor article element; if it isn't nested in an article element, then it signifies the publishing date of the entire document. Many of you are probably already rubbing your hands together knowing that you can use WordPress' template tags to echo out this information for your and your client's blogs.

Further (Minor) Markup Changes

Other than adding/removing some class and id attributes to certain elements, there aren’t many changes in the code since the original demo. One change worth noting is wrapping the post tags nested in the footer elements within the article elements in unordered lists. (I actually can’t figure out why I haven’t done this in the original demo). You’ll probably notice that one post has repeating post tags – those are there to test wrapping at different resolutions. There is also the new div element with the id of wrapper. I have used it to wrap the page's content and define the width of the site.

Another notable change is removing Remy Sharp's HTML5 shiv script which enabled older versions of Internet Explorer to apply styles to the new HTML5 elements. We are removing Remy's script because we will be using the Modernizr script to detect browser support for geolocation & localStorage and Modernizr can enable IE to style the new elements so it would be redundant to include Remy’s shiv as well.

The final addition to the HTML code is a div element with the id attribute of modalOverlay. This element holds the modal popup which will be presented to visitors if the script, about which we’ll talk in the second part of the article, calculates that it’s nighttime at the visitor’s location.

CSS – Making Our Layout Fluid & Responsive

Most of the changes in our CSS are reflected in the way we control our demo page’s layout. But, first, I have one new CSS transformation I wanted to show you.

Skew – A Distorted Perspective

Instead of the sliding animation from the original demo, we will rotate and skew the “Continue Reading” buttons when they are hovered.

Our button, rotated and skewed:

Skew

Here is our new :hover CSS rule:

.button:hover {
    border: none;
    -webkit-transform: rotate(-5deg) skew(-5deg,-5deg);
    -moz-transform: rotate(-5deg) skew(-5deg,-5deg);
    -ms-transform: rotate(-5deg) skew(-5deg,-5deg);
    -o-transform: rotate(-5deg) skew(-5deg,-5deg);
    transform: rotate(-5deg) skew(-5deg,-5deg);
}

As you can see from the code, we can combine the rotate and skew transformation to keep the left and right edges of the button vertical. The syntax is the same for all browsers; we just add the appropriate browser vendor prefix. Here, we included the -ms- prefix for Internet Explorer 9 which supports CSS transforms (but not the transition effects, those should come with IE10).

We first rotate the button by five degrees in the negative direction and that would look like this without skewing:

Hover

If we were only to apply the skew transform, distorting the button by five degrees in the negative direction on both axes, we would get the following look on hover:

Our button with just the skewing applied:

Skewing Applied

You can see how combining the two transformations make the side edges vertical. It’s a simple effect but you can come up with your own by combining different transitions.

Moving from Pixels to Percentages – Laying Out the Flexible Grid

Since the main topic of this article is the geolocation JavaScript API and since support for it on smartphones is fairly decent (iOS, Android, Maemo and Opera Mobile all support it) and very good on tablets, I wanted to make our layout look good on those smaller screens as well (or, rather, I wanted to remove the horizontal swiping). The best approach to accomplish this was Ethan Marcotte's Responsive Web Design. In his A List Apart article, Ethan suggests we should use a combination of flexible grids and CSS3 media queries to achieve a layout that is truly flexible and "device-agnostic".

Given how well Ethan explained this concept, I won’t talk too much about it. In a nutshell, the approach has two major 'phases': the first is converting our fixed width layout of not-as-standard-as-they-used-to-be 960 pixels to a fluid layout which will adapt to the changes of the browser window’s width. The second ‘phase’ consists of using media queries to pull the layout into shape at certain resolutions - you will see that our fluid layout will need some further adjustments at very low resolutions and that’s where you’ll see how awesome media queries are.

I’ll try to keep my explanations short enough not to bore you too much, but also clear enough so that you understand what and why I did things. (Of course, should I fail, don’t hesitate to ask me to elaborate on something in the comments.)

So, this is our task: make the layout adapt to the width of the browser window. We will move from:

#wrapper {
    margin: 0 auto;
    width: 960px;
}

to the following:

#wrapper {
    margin: 0 auto;
    width: 92%;
    min-width: 300px;
    max-width: 1180px;
}

The margin: 0 auto; rule should be very familiar to you – it has been used for quite some time to horizontally center our layouts. (Go ahead: inspect the #home element here on the Onextrapixel site. Told you!) Next, we set the width of our layout to 92% of the total width. The number ninety-two is the result of some experimentation but I’ve found that values around ninety percent generally work well to give the layout a decent amount of whitespace on either side.

I have mentioned that the second part in the process of making our layout responsive consists of making some further adjustments to ensure the layout doesn't break at lower resolutions (or at very high resolutions), we have made that process a bit easier by placing some constraints on the layout's width. By setting a minimum width of 300 pixels using the min-width property, we make sure that the layout doesn't fall below that value even if the browser window/viewport is narrower.

Exactly the opposite is achieved with the max-width property: by limiting the width to 1180 pixels, we don't have to worry about lines being too long to read comfortably and the sidebar getting ridiculously wide. Admittedly, this is taking the easy road as we could have spent a little more time later defining rules for the extremely low and high resolutions. On the other hand, the layout wasn't originally planned to be responsive so I am happy with how flexible it turned out to be – plus, media queries aren’t the main topic of this article.

Our old layout was 960 pixels wide with the main area split into two sections: a section containing the blog post snippets and an aside holding the social media links and the blogroll. This section which had the id attribute with the value mainContent was 630 pixels wide and had a 30 pixel right margin. Now, as we are using Ethan Marcotte’s responsive web design (or should that be capitalized?) approach, our goal is to convert those pixels to percentages which we will do by applying Ethan’s formula: target / context = result.

Here is a quick explanation of the method (for a better and more detailed explanation, check out Ethan’s article): the context in the above formula is the full width of our layout – 960 pixels, which we take to be 100 percent; the target is the desired width – 630 pixels; finally, the result is the same desired width but expressed in percentages.

Most of you have keyboards with a multimedia key dedicated to launching the operating system's calculator application so let's use them. If we divide 630 by 960, we get 0.65625. I am sure that doesn’t look like a proper percentage value to you (or it looks way too low) and with good reason: we need to multiply it by 100 and get: 65.625. The new width of the #mainContent section element is 65.625%.

We will get to the other widths in a second after I propose a formula that will get you to the percentage value immediately: (target / context) * 100[%] = result[%]. I just incorporated the additional step of multiplying the initial result value with 100 to get to the percentage value. I just think it might do away with some confusion if it’s placed in the formula from the start.

After that diversion and blasphemous formula alteration, we move onto calculating that right margin for the section element by placing the values into our new formula: (30 / 960) * 100, which gives us the value of 3.125. So, our #mainContent gets the following CSS rule:

#mainContent {
    width: 65.625%;
    margin-right: 3.125%;
    […]
}

We have the main section settled (the containing element, at least); now to calculate the width of the sidebar. The original aside element was 300 pixels wide, we plug that into the formula: (300 / 960) * 100. And the new width for the aside element is: 31.25%.

The next section that needs a responsive treatment is the header element nested in the article elements.

The article element with a slightly redesigned header:

Redesigned Header

A quick recap: we determine the width expressed in percentages by dividing our target width with that of the context. The key word here is context – it is very important to note that the context changes as the parent elements of our targets change. Originally we had the full width of our layout as the context but that changes when we start to look at the header element nested within the article elements. The article elements expand to the full width of their parent element – #mainContent – and that is 630px, but, having 20px margins on either side, the width its ancestor elements can occupy is 590px and that is our new context.

Now, since our layout wasn’t meant to be responsive and because I changed the date and the number of comments sections a little bit, the percentages resulting from our calculations won’t match the values in the style sheet of the demo. I got the actual values by tweaking the calculated values so they worked well with the content. The original value for the date section was 9.3220339 (= (55 / 590) * 100) but I tweaked that to 11%. The same goes for the div element holding the number of comments: it got tweaked from 10.16949153 to 11%. Finally the titles of the articles, the h1 tags, are 72% wide and have 3% margins on either side.

The same formula was applied for the website’s footer which has three sections, all 300px wide and spaced out by 30px margins. The new values for the element width and margins, respectably, are: 31.25% & 3.125%.

Before we move onto media queries, I wanted to give you an alternate way you can view this process: you can think of our old fixed layout as just one instance of the flexible layout where the full 100% width equals 960px, 65.625% equals 630px.

Media queries! – Bulletproofing the Layout

After applying a bunch of tweaks to our CSS, our layout now adapts to the changes in browser/device widths and it can go from 300px to 1180px. Pretty awesome, huh? It is, until you start playing around with the browser window and decrease its size to, say, about 700px.

Notice all the wrapping? Not as awesome:

Media Queries

Above is our layout when the browser window is about 700 pixels wide. Making the browser window narrow causes more wrapping and it makes the lines way too short to be read comfortably. What’s that? “What can we do?” you ask? Well, employ CSS3 media queries, of course.

You can view media queries as if statements for CSS: if the condition in the media query is satisfied, let the browser access the following CSS. The conditions we can check for are the orientation of the device (portrait, landscape), width, height, resolution and quite a few more. For the complete list, consult the W3C Media Queries Recommendation.

There are several ways we can use media queries:

Inline, in a media query block (the option we are going to use):

@media screen and (max-device-width: 840px) {
    #mainContent {
        width: 100%;
        margin-right: 0;
    }
}

When we use the @import rule in our CSS:

@import url(840px.css) screen and (max-device-width: 840px);

When we link a style sheet in the head section of our HTML documents:

<link rel="stylesheet" media="screen and (max-device-width: 840px)" href="840px.css" />

In each of the examples above, we are checking if our browser window or device isn’t wider than 840 pixels. If it isn’t, we let the browser see the CSS rules contained within (first example) or serve the style sheet to it (the other two examples). Media queries are equivalent to HTML conditional comments for Internet Explorer but they are work in modern browsers (IE9 included).

When working with media queries to specify different rules for various widths you’ll keep running into certain cut-off points and they will often match the common widths of many mobile & tablet devices (768px for the iPad in portrait orientation, 480px for the original iPhone in landscape orientation and 320px for the original iPhone in portrait orientation) and, on the other end, values around 1140-1180px for the widescreen desktop monitors and laptop screens. The media queries for the demo miss the 768px mark and yours might as well. I don’t consider this to be an issue but I do believe that I could have made the rules work with just the 768px rule (instead of specifying two: one for the 840px mark and one for 620px).

Let’s go over a few of the more important changes to the layout we make inside of the media query declarations.

Life, er: Layout width under 840 pixels

In our first media query, we make the biggest change to our page: we collapse it to a single column layout.

#mainContent {
    width: 100%;
    margin-right: 0;
}
aside {
    width: 100%;
    float: left;
    padding-bottom: 0;
}

Both the main section and the sidebar are set to be 100% wide and the margin between them is zeroed out. Next, we set the width of the sidebar and footer blocks to 48% and add a 4% margin between them.

aside nav, aside section {
    width: 48%;
    float: left;
}
aside section:first-child { margin-right: 4%; }
footer section {
    max-width: 48%;
    margin-left: 4%;
}

We have also hidden the latest tweet section from the sidebar and the recent comments from the footer:

#latestTweet, #recentComments { display: none; }

Please note that we don’t zero out the margin for the first section in the footer as that was already done when we originally wrote the rules for the footer elements earlier in our style sheet and, thanks to the cascade, that rule is inherited.

Layout Width Under 620 pixels

Before I say anything else, allow me to mention another benefit of the CSS cascade: since our layout widths under 620px also have a width under 840px, all of the rules written in the previous media query are inherited here. Neat!

Now is the time to make our logo and tagline a little smaller as they become too big for this layout width:

hgroup h1 { font-size: 56px; line-height: 56px; }
hgroup h2 { font-size: 13px; }

We also reduce horizontal padding for the main navigation to prevent wrapping:

#global ul li a { padding: 0 12px; }

And we let the date and the number of comments sections breathe a little more by making them slightly wider and the title a bit narrower:

article header h1 {
    width: 70%;
    margin: 0 2%;
}
time { width: 13%; }
.comments { width: 13%; }

Layout Width Under 480 Pixels

This is our final stop and, again, we reduce the logo and tagline as well as the navigation items’ font-size and padding properties:

hgroup h1 { font-size: 46px; line-height: 40px; }
hgroup h2 { font-size: 11px; }
nav#global ul li a {
    font-size: 12px;
    text-transform: none;
    padding: 0 10px;
}

We make the sidebar and footer single-column:

aside nav, aside section {
    width: 100%;
    float: left;
    margin: 0 0 20px;
}
footer section {
    width: 100%;
    max-width: 100%;
    margin-left: 0;
    float: none;
}

And do some more maintenance on the article headers:

article header { min-height: 38px; }
time { width: 20%; }
article header h1 {
    font-size: 18px;
    line-height: 22px;
    padding: 5px 0;
    width: 76%;
    margin: 0 2%;
}
.comments { display: none; }

We have hidden the comments section because the layout is quite narrow at this point and the post publishing dates are more important than the number of comments.

As I have already said, these aren’t all of the changes made to the CSS but that isn’t the main topic of this article.

Last Words

Well, we have reached the end of part 1. Stay tuned and Part 2 will be published tommorow with the promised geolocation API being used. Follow us on Twitter or Subscribe to our RSS Feed to stay up to date for part 2. In the meantime, please share any comments and questions below.

Marko is a freelance web designer & developer based in Serbia. He is always trying to improve his skills and create a better user experience for his clients. These days he is getting into writing and getting closer & closer to getting his degree in mechanical engineering.