Image Optimization for the web

When creating images for online use your adventure probably begins in Photoshop. Choosing File -> Save for Web… allows precise optimization of your images to achieve just the right balance between quality and file size. But you shouldn’t stop there! There are tons of image optimization programs and websites out there and these can usually help you to compress your image files even more, resulting in faster page load times.

Since there are so many solutions out there, I couldn’t possibly review them all. Furthermore every image is different so your results many vary. What you will find here is just my recommendation for the best PNG, GIF, and JPG optimizers, based on my results after trying some of the more popular solutions.

PNG

TinyPNG was the winner for me! Images were reduced in file size anywhere from 9% – 91%. That’s a big margin, but it was also 29 images that I tested. The amount of reduction didn’t seem to have anything to do with the initial file sizes.

GIF

I tested only four images with RIOT. In the end I was able to reduce file sizes anywhere from 62% – 96%. Again, the original file sizes didn’t seem to have anything to do with how much RIOT was able to compress them.

JPG

I thought I had found my optimal optimizer in the form of Imagemin (the official Grunt image optimzation task) but I quickly noticed that it was somehow very unpredictable.  While some JPGs were optimized beautifully, others became horribly pixelated. What’s more, this behavior seemed completely random: every time I ran the script I got different results for different images. In the end I decided to forego optimizing past Photoshop’s Save for Web… dialog box since I find badly optimized JPGs very ugly to look at. If anyone knows of a good JPG optimizer please leave a comment and tell me about it!

Avoid CSS @import

From Google Developers:

CSS @import allows stylesheets to import other stylesheets. When CSS @import is used from an external stylesheet, the browser is unable to download the stylesheets in parallel, which adds additional round-trip times to the overall page load.

Instead of @import, use a tag for each stylesheet. This allows the browser to download stylesheets in parallel, which results in faster page load times.

Grunt: the ultimate task runner for web developers.

Grunt Simplifying your workflow is an invaluable undertaking that can be applied to any type of work. Web development is no exception, and the Javascript task runner Grunt is probably the most popular tool for automating monotonous tasks and speeding up your workflow. Like many people I was scared of the command line at first so I opted for a task runner with a GUI, namely Prepros. Eventually I realized I needed more power, which even the paid version of Prepros couldn’t provide. So I decided to give Grunt a go and I followed Chris Coyier’s guide “Grunt for People Who Think Things Like Grunt are Weird and Hard.” As the name suggests it was very beginner-friendly, which is why I don’t feel I need to write my own guide. What you will find here is a supplement to Chris’s guide with a few more in-depth explanations of the few things I had trouble with, as well as some of my own modifications. Before we jump into it, here is a list of some of the things Grunt can do for you:

  • Compile LESS, SASS, SCSS, Compass, and loads of other languages
  • Autoprefix CSS files
  • Code-hinting
  • Concatenate and minify various file types
  • Optimize images
  • Build image sprites and SVG icons automatically (!)
  • Start a server

And a hell of a lot more! After installing Grunt and its dependencies, it’s up to you to configure the tasks you want it to carry out for each project and when. From there, it’s a breeze: simply type grunt into the command line and it all happens automagically. Alternatively, specify a single task by typing grunt [task name]. For example, grunt concat concatenates everything you’ve configured Grunt to concatenate in your project. Alternatively, grunt:css would concatenate only CSS files. If this all sounds confusing, I recommend just jumping into it and things will start making sense.

Installing Compass

One of the things Chris Coyier doesn’t mention in his article is how to incorporate Compass into a Grunt workflow. As Christian Krammer mentioned in the article’s comments section, “if you use Compass (e.g. you use mixins like border-radius, which you really should), install grunt-contrib-compass instead of the mentioned grunt-contrib-sass. It’s basically the same with the same configuration variables.” The thing is that Compass has some dependencies so incorporating it into Grunt is not as straightforward as most other plugins. Compass The first thing you need to do is check if you have Ruby installed on your system and if not, install it. To do all that I recommend following the short Ruby on Rails Installation tutorial at tutorialspoint. Basically if you’re on OS X or Linus you probably already have Ruby installed, and if you’re on Windows, you can download and install it from RubyInstaller. The next step is setting up the Ruby environment. RubyInstaller should have created a shortcut called “Start Command Prompt with Ruby” inside the Start menu. Click on it and then type gem update –system && gem install compass into the command prompt. You don’t have to be in your project’s directory to do this. After installing the Ruby environment, it should be available to all your projects and you can install grunt-contrib-compass like any other plugin.

Installing LiveReload

LiveReload The last thing Chris Coyier shows us in his article is how to incorporate LiveReload into our Grunt installation. Unfortunately it didn’t go so smoothly for me. I suspect it’s because I’m running my site from a DesktopServer server, but I haven’t tested on different servers to confirm this. What happened was I got a pop-up message from the LiveReload plug-in when I tried to activate it: “Could not connect to LiveReload server. Please make sure that a compatible LiveReload server is running. (We recommend guard-livereload, until LiveReload 2 comes to your platform.)” If you run into the same problem you can solve the issue by actually installing the LiveReload app in addition to the browser plug-in. That also means you can forego the extra code (options: {livereload: true,}) in gruntfile.js. Add your project folder to the LiveReload app and remember: you need to have both the app running and the browser plug-in activated in order for live changes to show in the browser.

Subtasks

You can get pretty specific about what you want Grunt to do and when. Suppose you wanted to concatenate both Javascript and CSS files, so that you would end up with production.js and production.css. The plugin grunt-contrib-concat Chris Coyier recommends works on a variety of file types, so all you need to do is define the Javascript and CSS subtasks separately and then call them by their name. An example will make it easier to understand:

concat: { // Javascript js: { src: [ ‘js/*.js’,], dest: ‘js/build/production.js’, }, // CSS css: { src: [ ‘css/style1.css’, ‘css/style2.css’, ], dest: ‘css/build/production.css’, }, },

Now anytime you want to concatenate only Javascript, you can call concat:js. When you want to concatenate only CSS, you can call concat:css.1 And if you want to concatenate everything, just call concat. 1 You don’t have to name these subtasks js and css; call them whatever you want. 

Final thoughts

Grunt is an extremely powerful task manager guaranteed to speed up your workflow. Installing things like Node.js and Ruby is a one-time thing. After that, you’ll be ready to install different plugins for different projects with just a single line of code. Configure Gruntfile.js (why not use a previous project as a template?) and you’re done! It’s actually simpler than it seems and will make your life easier in the long run.

FREEBIE FRIDAY! Manipulate divs dynamically and proportionally with Javascript.

What is it?

This is a script I’ve written to dynamically manipulate divs according to viewport height. Any property that can be set with a pixel value can be manipulated, e.g. height, margin, line-height or background-position, just to name a few. It has been tested in Internet Explorer 10, Firefox 24.0, Chrome 30, Opera 12.16 and Safari 5.1.7. It works great with my imgResize script and is available for free use, private or otherwise.

How to implement it

HTML markup and CSS styling

The first thing you need to do to make the script communicate with the divs on your webpage is to name those divs. In your HTML markup add an id to each div that will be manipulated. It should look something like this:

<div id=”div1“>

So far so good. The next step is to declare what properties of the div will be manipulated and by how much. This will actually be done in your CSS styling. For example:

#div1:before {
    content: ‘height .04900‘;
    display: none;
}

The parts in bold can be edited; everything else should be left alone. #div1 could well have a different name, for example. The important thing is that it references the div to be resized; this example correctly references the HTML markup example above it. In this example height is the property to be manipulated and .04900 the percentage value, i.e. 4.9%. The value must contain 5 digits. If the property name contains a dash, it should be written in camel case instead. For example, the CSS property “background-position” should be written as “backgroundPosition.”

In summary the combination of this HTML markup and this CSS styling, when correctly coupled with divManipulate.js would result in #div1 always taking up 4.9% of the viewport’s vertical space.

It is possible to manipulate up to two different properties for each div. For example, if we wanted #div1 to not only take up 4.9% of the viewport’s height, but also maintain a top margin of 1% of the viewport’s height, the complete code would look like this:

#div1:before {
    content: ‘height .04900‘;
    display: none;
}

#div1:after {
    content: ‘margin-top .01000‘;
    display: none;
}

Notice the keyword “after” following #div1: – when a div has two properties to be changed, the second should always use the keyword “after.”

Customizing the script

Upon opening divManipulate.js take a look at line 5. This is where you can enter the names of the divs to be resized. The names refer to the ids assigned to each div.

Inserting the script on your webpage

We want the script to execute automatically on page load so the user is immediately presented with a page tailor-made for the current size of his or her browser. We also want it to execute on page resize for real-time adaptation upon browser resize. To achieve these objectives we will be calling the script using the following code:

window.onload = function() {
    divManipulate();
};

window.onresize = function() {
    divManipulate();
};

We can place the above in the file containing the HTML (enclosed by <script> tags) or in its own .js file. Just make sure this code comes after the divManipulate.js script itself — we can only instruct it to call something it already knows about! It’s also important to note that divManipulate.js should come after any CSS styling.

Implementing it, summarized

  • In the HTML markup add an id to every div that will be manipulated.
  • For each div, declare the properties to be manipulated and by how much. If manipulating more than one property per div remember to use the keyword “before” for the first and “after” for the second. Remember also that the value should contain 5 digits.
  • Edit line 5 of divManipulate.js – div id names.
  • Use the following order inside the HEAD tags in your HTML markup:
    1. CSS styling
    2. divManipulate.js
    3. window.onload = function() {
          divManipulate();
      };
      window.onresize = function() {
           divManipulate();
      };

Download

https://www.dropbox.com/s/snc32twm2lcql2p/divManipulate.zip

Color Spaces

If you’re like many people who work with photos and other images for print or the web, there’s a good chance you’re confused about color spaces. In fact, you might just ignore them altogether. I hope this article will help you get your head around the topic. Since I deal mostly with Photoshop and Lightroom, I will focus on these two programs and how color spaces relate to my own workflow. But no matter how you work with your images, I believe there is a lot of useful information here and I think you will get something out of it. Let’s jump right into it…

Photoshop

Photoshop

  • When an image is opened in Photoshop, the program assigns your current RGB Working Space to it if it doesn’t have an embedded profile. This behavior can be changed in Color Management Policies under Edit > Color Settings…
  • To change an existing image’s color profile, go to Edit > Convert to Profile (not Assign to Profile).
  • If your image is embedded with a color profile other than sRGB, Photoshop will automatically convert it to sRGB when you choose Save for Web. This is because most browsers have that as their default color space. However the conversion will change the colors of the image so it is better to change the image’s profile using Edit > Convert to Profile before using Save for Web.

Lightroom

Lightroom

  • Lightroom works in its own color space, which has a wide gamut. You don’t need to choose color settings or color profiles until you are ready to output your photos, i.e. exporting them or choosing to edit them externally. Color spaces for exported files can be chosen in the Export dialog box, while External Editing color spaces can be chosen in the External Editing tab of Lightroom’s Preferences.
  • When you are finished editing a photo outside of Lightroom, just choose Save to import it back into Lightroom. The color space will be retained. From Lightroom you can export it for different purposes and the program will automatically convert color spaces accurately. If you want to use Save for Web from within Photoshop, remember to choose Edit > Convert to Profile and choose sRGB first, otherwise the colors will be changed.
  • If you get a pop-up that says “This version of Lightroom may require the Photoshop Camera Raw plug-in version x for full compatibility” upon choosing Edit In > Photoshop from within Lightroom, here’s what it means and what you can do (thanks to Jim Wilde at the Lightroom Forums):

That message will always be issued whenever there’s an “ACR (Adobe Camera Raw) Mismatch” between Lightroom and Photoshop. In other words, this happens when the two programs are using different versions of the Camera Raw plug-in. When the ACR levels are in sync, what happens when you use “Edit in….” is that LR passes all the relevant information to PS which then uses its ACR plug-in to render the file into PS’s working space. This means that a new file (Tiff or PSD) isn’t actually created on disk and imported into Lightroom until you select “Save” in the PS file menu… in other words if you change your mind and close the file in PS without saving, no new file will exist.

However, you don’t have to upgrade PS or its ACR plug-in just to get the ACR levels in sync…..when you receive the mismatch warning in Lightroom, simply use the “Render using Lightroom” option. This uses Lightroom’s ACR engine to render the file, then passes that to PS for editing…..the only real consequence of doing this is that the rendered file (Tiff or PSD) is created by Lightroom (and appears in Lightroom) before it’s passed to PS for editing. If you edit and save in PS, no difference to a workflow that is in sync, but if you cancel out of the editing in PS you are now left with a Tiff/PSD in LR which you probably don’t want and so have to delete. Other than that, the workflow works fine.

Using “Open Anyway” means that Lightroom passes all the edit information to PS which then uses its ACR plug-in to render the file….however because the ACR plug-in is at a lower level than LR the consequence is that any LR edits done using tools that were introduced AFTER the ACR plug-in for your version of PS will not be understood by PS/ACR and so will be ignored.

Other useful stuff

gamuts

  • Hex colors are just RGB colors written in a different format (example: pure red is written as “255, 0, 0” in RGB and “FF0000” in Hex).
  • Many cameras allow you to change the color space that photos are captured in. If you’re shooting RAW, you don’t need to worry about this; otherwise it’s a good idea to choose Adobe RGB (1998). That way your images will have a wider gamut of colors and you can always convert them to another color space from within Photoshop (recommended for displaying them on the web or printing in printers that don’t support or are not calibrated for Adobe RGB (1998)).
  • Range of colors (gamut) from smallest to largest: sRGB -> Adobe RGB (1998) -> ProPhoto RGB
  • A color space with a smaller gamut has the advantage that average monitors can display all its colors (what you see is pretty much what you get). Web browsers use sRGB so anything else doesn’t make sense if your images will be displayed on the web.
  • Color spaces with a large gamut have the advantage of… more colors. They are good for working on photos (especially with high-end monitors that can display all the colors) and for printing with high-end printers that support and are configured to take advantage of the large gamut.

More information

Check out these resources for other useful articles on color spaces:

Sublime Text and SublimeLinter

Sublime TextThis is a quick update about a text editor called Sublime Text and a plugin called SublimeLinter that lets you turn on linting and highlighting for over 15 different languages.

I had been going back and forth between Notepad (really), Notepad++ and Adobe Dreamweaver for coding and website development. I couldn’t stick with one editor because I wasn’t satisfied with ANY of them. Notepad is way too basic. Notepad++ is not bad but there is something about it that rubs me the wrong way. I think it’s actually more complex than I need it to be and I’ll probably never use half the functions it has. It’s pretty much the same thing with Dreamweaver, but lately I had been using it as my main editor just because I really like how it lets me organize projects instead of dealing with files individually.

Then I heard about Sublime Text and decided to try it out. First, let me just say that it is not free, but what you get from it is priceless in my opinion. My first impression was that it looked very nice, seemed user-friendly and made me feel like it did everything I needed it to do without overwhelming me with extra crap. When I found out that it had a sidebar where I could organize different projects I was sold. I started gradually finding out about other very useful features that none of the other editors I mentioned have. For example, split editing lets you edit multiple files side by side. I like to have my HTML file on the left column and my CSS file on the right column. I don’t know how I ever lived without that. Of course it has tabs as well; this is 2013 after all. It also lets you make multiple selections and edits simultaneously. And a bunch of other stuff guaranteed to increase productivity. Hey I’m not getting paid to write this so I’ll stop here! If you want to find out about all the features it has to offer, just check out their website: www.sublimetext.com

SublimeLinter

One thing that I noticed after installing Sublime Text was that the text in my SASS/SCSS files were not being color-coded. I had experienced the same thing with Notepad++ and DreamWeaver. Actually most text editors don’t support color-coding these file types out of the box. It’s usually necessary to download and install some kind of plugin to get this functionality, so I set out trying to find one for Sublime Text. It was then that I came across SublimeLinter. Coupled with node.js (more on that later) it turned out to provide yet another functionality  that I don’t know how I ever lived without: examining Javascript for syntactic discrepancies. It basically checks if the code you’ve written is valid and suggests fixes if it’s not. As I understand it, this is the main functionality of linters. In fact, although a vanilla install of SublimeLinter will provide a lot of capabilities that Sublime Text doesn’t provide out of the box, node.js is also required for color-coding SASS/SCSS files!

Sublime Text

Features of Sublime Text

This is the description of SublimeLinter found on their GitHub page:

SublimeLinter is a plugin that supports “lint” programs (known as “linters”). SublimeLinter highlights lines of code the linter deems to contain (potential) errors. It also supports highlighting special annotations (for example: TODO) so that they can be quickly located.

SublimeLinter has built in linters for the following languages:

  • C/C++ – lint via cppcheck
  • CoffeeScript – lint via coffee -s -l
  • CSS – lint via built-in csslint
  • Git Commit Messages – lint via built-in module based on A Note About Git Commit Messages.
  • Haml – syntax check via haml -c
  • HTML – lint via tidy (actually tidy for HTML5)
  • Java – lint via javac -Xlint
  • JavaScript – lint via built in jshintjslint, or the closure linter (gjslint) (if installed)
  • Lua – syntax check via luac
  • Objective-J – lint via built-in capp_lint
  • Perl – lint via Perl::Critic or syntax+deprecation check via perl -c
  • PHP – syntax check via php -l
  • Puppet – syntax check via puppet parser validate
  • Python – native, moderately-complete lint
  • Ruby – syntax check via ruby -wc
  • XML – lint via xmllint

Installation

The easiest way to install SublimeLinter is through Package Control:

  • Follow the instructions on this page and then restart Sublime Text.
  • From the menu bar choose Preferences -> Package Control.
  • Choose “Install Package” from the list that pops up.
  • Type SublimeLinter into the text box and it will install automatically.

SublimeLinter should technically be up and running now, but we’re not done yet. SublimeLinter is still not checking our Javascript for syntactic discrepancies and even our SASS/SCSS is not being color-coded. I recommend checking out the README from within Preferences -> Packages Settings -> SublimeLinter. The following section on Javascript-based linters is of special importance:

If you plan to edit files that use a JavaScript-based linter (JavaScript, CSS), your system
must have a JavaScript engine installed. Mac OS X comes with a preinstalled JavaScript engine called
JavaScriptCore, which is used if Node.js is not installed. On Windows, you **must** install the
JavaScript engine Node.js, which can be downloaded from [the Node.js site](http://nodejs.org/#download).

On Mac OS X, you **must** install Node.js if you plan to edit JavaScript or CSS files that
use non-ASCII characters in strings or comments, because JavaScriptCore is not Unicode-aware.

After installing Node.js, if the Node.js executable (“node” on Mac OS X, “node.exe” on Windows)
cannot be found by SublimeLinter, you may have to set the path to the executable in the
“sublimelinter_executable_map” setting. See the “Configuring” section below for info on
SublimeLinter settings.

node.js

After following these final instructions you should now be getting the full functionality out of Sublime Text and SublimeLinter. Nowadays I personally experience not only increased productivity and less frustration, but also more joy in working on my projects. It’s almost sublime!

FREEBIE FRIDAY! Resize images dynamically and proportionally with Javascript.

What is it and how does it work?

Here is a script I’ve created to resize images according to viewport height. It has been tested in Internet Explorer 10, Firefox 24.0, Chrome 30, Opera 12.16 and Safari 5.1.7. I’m making it available for free use, private or otherwise. Just download it from the link at the bottom of this post.

I originally created this to ensure that my layout would adapt itself to different screen resolutions. For example, I wanted an image that takes up 50% of the screen’s height on a 2560×1440 resolution to still take up 50% of the screen’s height on a 1280×720 resolution. Without this script the image would take up 100% of the screen’s height when the page is viewed on a display with 1280×720 resolution.

Eventually I realized that the script would be more effective if it resized images based not on screen resolution, but on viewport height. So I re-designed it to take into account OS and browser bars at the top and bottom of the screen — e.g. Windows taskbar, Mac dock/menu bars, browser toolbars and status bars. The result is that images will be shrunken accordingly when those are present. Bars at the left and right edges of the screen/browser are not taken into account, just as resizing the browser window horizontally does not affect image size: this script is only designed to resize images according to the viewport height.

Having the script do its thing based on viewport size rather than resolution also opened up another possibility: real-time adaptation upon browser resize. This is true fluid design. A script based solely on screen resolution will run on page load and stop there, but one based on browser window/viewport can be fluid since the window/viewport can always be resized, at least on a regular desktop or laptop computer.

How to implement it

Creating the images

Images should be designed on a canvas with the same dimensions as your chosen maximum resolution. This will ensure that they will scale down proportionally to take up the same percentage of a browser’s viewport as it does on the canvas. For example, if we wanted to design a webpage for a maximum resolution of 2560×1440 we should create our images on a canvas of those exact dimensions (e.g. create a new Photoshop file that is 2560×1440). And if we wanted a particular image to always take up 20% of the viewport’s height we should make it take up 20% of the canvas’s height (288px in this case).

Customizing the script

After deciding on a maximum resolution for your layout, the script is ready to be customized. Upon opening imgResize.js take a look at lines 4 and 5. It’s pretty self-explanatory: on line 4 the names of the image files to be resized can be entered and on line 5 the maximum resolution for which they were designed. It may sound counter-intuitive but you can actually increase these values down the line if you change your mind and decide that the images are too large. However, don’t decrease the values or the image will be displayed larger than their native sizes at the original maximum resolution — in other words, there will be a loss of quality.

Last steps

In your HTML markup add an id to each image that will be resized. It should look something like this:

<img src=”image1.jpg” id=”image1“>

Notice that the id name is the same as the image name, minus the extension. This is very important, otherwise the code will not work.

Finally add the following lines in your CSS styling:

#image1, #image2, #image3 {
    display: none;
}

Of course this is just an example; #image1, #image2, and #image3 could well have different names. The important thing is that they reference the images to be resized. What this step does is hide the images until the resizing script has run. This prevents them from “flashing” in their native dimensions before being resized. It’s not crucial to the functionality of the script but it adds a professional touch to the whole thing.

Inserting the script on your webpage

We want the script to execute automatically on page load so the user is immediately presented with a page tailor-made for the current size of his or her browser. We also want it to execute on page resize for real-time adaptation upon browser resize. To achieve these objectives we will be calling the script using the following code:

window.onload = function() {
    imgResize();
};

window.onresize = function() {
    imgResize();
};

We can place the above in the file containing the HTML (enclosed by <script> tags) or in its own .js file. Just make sure this code comes after the imgResize.js script itself — we can only instruct it to call something it already knows about! It’s also important to note that imgResize.js should come after any CSS styling.

Implementing it, summarized

  • Create images in a canvas of the same size as the maximum resolution for which the webpage will be optimized.
  • Edit lines 4 and 5 of imgResize.js – image file names and maximum resolution.
  • In the HTML markup add an id to every image that will be resized. Each id should have the same name as the image file it represents.
  • Style each id with display: none; in your CSS styling.
  • Use the following order inside the HEAD tags in your HTML markup:
    1. CSS styling
    2. imgResize.js
    3. window.onload = function() {    
          imgResize();
      };
      window.onresize = function() {    
          imgResize();
      };

Download

https://www.dropbox.com/s/h08851b0yb586ou/imgResize.zip

Internet Explorer Conditional Comments

Internet Explorer: the bane of any web developer trying to make their pages cross-browser compatible. Sure it has improved a lot with the last couple of versions, but because it has always been such a popular browser its older versions are still in use by an arguably large percentage of the public. Not long ago I was at the library only to find that their computers are still equipped with IE6! The problem of course is that these old versions don’t seem to follow any logic other than their own in interpreting HTML and CSS. How many times have you worked hard on a webpage when, after hours of toiling away at it, you decide to check it on an old version of IE only to find that it doesn’t know how to interpret what you’ve created at all and your masterpiece is displayed as something else entirely — something that probably doesn’t make any sense!? Worse yet, each version of IE will display a unique kind of mess.

The importance of cross-browser compatibility

Trying to write HTML and CSS in such a way that every browser will interpret it in the same way can be very difficult, possibly impossible and most likely very time consuming. This is the reason a lot of web developers throw in the towel and decide to ignore outdated browsers. I do agree that the web needs to move on and the less lip service we pay to outdated browsers the faster we will achieve that goal — but we don’t always have that choice. Sometimes clients demand that their websites be compatible with old browsers. Other times we can check statistics and see that the percentage of users accessing a website with outdated browsers really is significant — of course that percentage varies with each website and the type of audience that has an interest in it.

How IE conditional comments work

So it seems the problem is writing one absolute piece of code that is interpreted equally by every web browser, or at least every modern browser and Internet Explorer versions going back to 6 (everything else is probably negligible despite the site’s audience and this might need to be explained to certain clients). Then let’s eliminate the problem: we will not write an absolute piece of code for every browser; we will write code that is conditional. Since we are not worried about the outdated versions of any browsers besides IE6 these “conditional comments” will specifically target IE and will be ignored by any other browsers. It sounds almost like we will be programming using if-else statements. In principle that’s how conditional comments work, but in practice it just involves writing a couple extra lines of HTML, no programming knowledge required. These comments are only read by IE browsers. It’s as if its developers unleashed an unspeakable evil upon us and then felt guilty and decided to throw us a bone.

Writing conditional comments

Conditional comments can be used either within the head of your page (to present different stylesheets depending on the browser, for example) or directly in the body. They look like this:

<!--[if IE]>
According to the conditional comment this is IE.
<![endif]-->

Simple, isn’t it?  If the website is being accessed through IE (any version in this case) the text between the opening and closing comments will be displayed; otherwise it will be completely ignored.

If we wanted to target a specific version of IE, this is how it would look:

<!--[if IE 6]>
According to the conditional comment this is IE6.
<![endif]-->

<!--[if IE 7]>
According to the conditional comment this is IE7.
<![endif]-->

<!--[if IE 8]>
According to the conditional comment this is IE8.
<![endif]-->

<!--[if IE 9]>
According to the conditional comment this is IE9.
<![endif]-->

As of this writing we have conditional comments up to IE9 available to us. It’s just as well since IE10 seems to have finally caught up with the times.

“What if I want to target all IE versions under or above a specific one?” I’m glad you asked. In this case we would use lt (lower than), lte (lower than or equal), gt (greater than) or gte (greater than or equal) in our syntax. Like so:

<!--[if lte IE 9]>
According to the conditional comment this is all versions of IE up to and including version 9.
<![endif]-->

Finally it is also possible to target every browser except IE. There are two ways to do achieve this:

<![if !IE]>
According to the conditional comment this is not IE.
<![endif]>

<!--[if !IE]><!-->
According to the conditional comment this is not IE.
<!--<![endif]-->

Note that the first way required that we remove the dashes from the conditional comments! The second way looks more complicated but if you write your code in a program with color coding, or which in some way modifies your text to make it easier to visualize its different parts (comments in this case) the second method might be preferrable. Try it out and see which works better for you. The output to the browser will be exactly the same.

Similarly we have the option of target every browser except a certain version of IE. Once more, we have two ways of doing this, as shown below:

<![if !IE 6]>
According to the conditional comment this is not IE6.
<![endif]>

<!--[if !IE 6]><!-->
According to the conditional comment this is not IE6.
<!--<![endif]-->

Again, notice the missing dashes in the first method!

Finally, there might be times when we need to target more than one browser without using greater/less than [or equal]. For this we can use operators! Available in our arsenal are the subexpression operator (), the OR operator (|) and the AND operator (&). Here’s an example using OR:

<!--[if (IE 6)|(IE 7)]>
According to the conditional comment this is IE6 or IE7.
<![endif]-->

As with the other “not IE” conditional comments we have a choice of two different syntaxes when using “not IE” with operators. This is how they look:

<![if (!IE)|(gt IE 7)]>
According to the conditional comment this is either not IE or it is IE8+.
<![endif]>

<!--[if (!IE)|(gt IE 7)]><!-->
According to the conditional comment this is either not IE or it is IE8+.
<!--<![endif]-->

More tools that help development for different browsers/versions of IE

IE7.js is “a JavaScript library to make Microsoft Internet Explorer behave like a standards-compliant browser. It fixes many HTML and CSS issues and makes transparent PNG work correctly under IE5 and IE6.”

Also check out my article about testing on different browsers and browser versions using VirtualBox and go make your pages cross-browser compatible!

Test on different browser versions with VirtualBox

As web developers it is imperative to be constantly checking the websites we are working on in different browsers since they each have their specific ways of interpreting the code we write. The point is to make sure that our sites are presentable for as many different users as possible. There are other factors to consider like operating system and screen resolution, but in this article I want to concentrate on browsers, specifically their different versions and how we can get them to co-exist in the same machine — something that a browser like Internet Explorer doesn’t normally allow.  One way of doing this is by setting up virtual machines. In this article you will learn how to do that using VirtualBox, an incredibly powerful program that is free and will, for our purposes, grant us separate environments in which to install several versions of each browser.

A consistently usable and attractive browsing experience

Although it is a good start to check our websites in different browsers as we are coding them it is perhaps even more important to check them on different versions of those browsers: we can usually count on all of the latest versions supporting — to varying degrees — new technologies like HTML5 and CSS3, but at the same time we can always count on a significant number of users not having the latest versions of those browsers installed. That means they may miss out on those features specific to HTML5 and CSS3. It is generally agreed upon that it is bad practice to tell users to upgrade their browsers. Much better and more effective is to make sure that our code smoothly “downgrades” in those situations, presenting those users with an experience that is still relatively attractive and completely usable.

browsers

As I’ve mentioned the dilemma is that certain developers do not actually allow us to install several versions of their browsers. This is notoriously true for Internet Explorer. I also experienced it with Firefox, but apparently there is a very simple way around this. I have not tried it with other browsers, but considering that Internet Explorer is one of the most used browsers out there, it is critical to test on its older versions as well. This is particularly true since this specific browser comes pre-installed with Windows and less tech-savvy people may never upgrade it.

How does VirtualBox work?

vbox_logoHaving access to several computers in which to install the different versions of our browsers might technically seem like the perfect solution — if it weren’t severely impractical assuming that we even had access to several physical machines and were allowed to overwrite their browser installations.

Enter VirtualBox: a “virtualizer” that allows us to install several virtual machines (in essence operating systems) in just one physical machine. VirtualBox is free, user-friendly, chock-full of features and in contrast to some other virtualizers/emulators it is FAST! Plus it supports shared folders and virtual USB controllers in addition to the usual floppy and CDROM drive support.

The list of operating systems to choose from is huge; in fact I can’t think of any OS that is missing. But it is not a completely free ride for pirates: you do need to have the installation disk for your desired OS. The installation will be done as if on a physical machine.

Installing and using VirtualBox

To begin, grab a copy of VirtualBox here. After you’ve installed it, setting up different virtual machines is pretty straight-forward: just click on “New” and follow the wizard. Once you’re up and running with an OS installed in your virtual machine, there are several things you can do to make your VirtualBox experience even easier:

  • Clone your virtual machines. This is the first thing you should do after installing an OS in your virtual machine. It means that you will have a fresh copy of the installation ready for your next project or in case you mess something up. Always have a fresh copy available to avoid having to install the OS again. You can clone a virtual machine simply by right-clicking it in the VirtualBox Manager and choosing “Clone…”
  • Set up shared folders. This is very important if you’re planning to use your virtual machines to check your websites on different browsers.1 Failing to set up virtual folders means that you will have to constantly be copying updated files of your website to each individual virtual machine — killing your time, creativity, and sanity! It couldn’t be much easier to share folders between your host and your virtual “guest” OS:
    1. First you will need to install “Guest Additions.” From your virtual machine’s window, go to “Devices -> Install Guest Additions…” and follow the wizard. You only need to do this once in VirtualBox; shared folders will then work for all of your virtual machines.
    2. Now you are ready to set up shared folders. Go to “Devices -> Shared Folders…” and add the folders you would like access to by clicking on the little folder with a plus sign. Make sure to check “Make Permanent” for each folder you add, otherwise they will not be available when you restart the virtual machine.
    3. The folders you’ve shared from your host machine should now be available in your virtual machine. If it is running Windows you can access them by going to Start -> Run…, typing “explorer” and hitting enter.  On the window that pops up click the + arrow next to “My Network Places,” then the + arrow next to “Entire Network.” Finally click the + arrow next to “VirtualBox Shared Folders” and select the folder that is revealed. Note the address of that folder. An alternative to these steps is to simply type in that address. It may vary in different versions of VirtualBox, but for me the address is “\Vboxsvr”
  • Shutting down your virtual machine. Actually don’t do it. There isn’t actually anything wrong with shutting down your virtual machine, but there is seldom a point. Saving the machine state instead, will make it much faster to start up again the next time you want to use that particular virtual machine. You can do this by going to Machine -> Close… and choosing “Save the machine state.” Also be aware that it’s not necessary to exit a virtual machine in order to use another: you can run as many of them as you want, simultaneously.

1 If your website is running off a server (e.g. Apache HTTP server) on your host machine it is not necessary to set up shared folders since you should be accessing the website through the server and not directly from its folder. To see a website that is on a server, simply go to its IP address.

I personally use DesktopServer for my server needs. It is aimed at developing WordPress websites, but works just as well for regular sites. Websites hosted on DesktopServer are usually accessed from fictional “.dev” domain names, but from the program’s window it is possible to assign an IP address to a site. Following are the directions, originally written by Stephen Carroll at the ServerPress forums:

  1. From DesktopServer’s main list of options, select “Import, export or share…”
  2. Select “Share…”, followed by clicking the next button. You’ll then be presented with a list of sites.
  3. Select the website you wish to share and select the “LAN” option (please make a note of the IP Address).
  4. Be sure to click next to save your options and automatically restart the server. You will now be able to access your site via the IP address on both your local and remote computers and mobile devices on you LAN. 

A few more things…

Optimizing webpages for mobile devices, part 2: CSS media queries, Javascript and mobile-specific websites

In part 1 of this article we went over the viewport meta tag. Although it can be useful in certain circumstances I feel that it is often unecessary. What’s worse, it’s hard to predict how it will behave on different browsers and it can in fact ruin some users’ experiences if not used very carefully.

If you really want your webpage to be able to transform itself to suit mobiles, as well as various other types of devices and specific features, you can  add special CSS rules that will automatically be applied to suit the situation. This can be done either with media queries or Javascript.

Lastly, if you prefer to create a completely separate webpage for mobile devices, you’re covered there too.  Mobile-specific websites are very popular and definitely worth considering as part of your strategy.

Media Queries

Media queries have become a very popular way of optimizing webpages for mobile devices since their introduction with the advent of CSS3. They work by telling a browser to apply special CSS rules depending on the type of device a webpage is accessed from and what media features it has. As you might have inferred from the previous sentence media queries, unlike the viewport meta tag, influence not only mobile devices, but also “regular” computers (heron referred to as “desktops”), printers, and anything else that can display the webpage.

Media queries can, for example, tell a browser to use a specific stylesheet for a webpage when it detects that it is being accessed from the “printer” media type (this happens when the browser is told to print the page). That stylesheet could remove ads and background images, for instance.

Below is an example of a media query that displays a webpage’s background in different colors depending on the “width” feature. This feature corresponds to the width of the browser window.

Media queries

As with “normal” CSS, media queries can be defined in several ways. However unlike regular CSS selectors, media queries cannot be defined inline in an HTML tag. The ways in which we can refer to media queries are:

  • From inside the document in which they will be used. As shown below, the code should be enclosed by the <style> tags, which in turn are enclosed by the <head> tags.

<head>
     <style type=”text/css”>
@media screen and (max-width: 480px) {
selector { property: value; }
}
     </style>
</head>

While the page has a maximum width of 480 pixels it will follow the rules inside the bracketes (selector { property: value; })

  • From an external stylesheet by importing said stylesheet into the document in which it will be used using the <style> tags. Again, the code should be enclosed by the <style> tags, which in turn are enclosed by the <head> tags. 
    • @import rules must always be placed before any other CSS content, including comments. They are not supported by really, really old browsers.

<head>
<style type=”text/css”>
          @import “480pxRules.css” screen and (max-width:        480px);
</style>
</head>

While the page has a maximum width of 480 pixels it will follow the rules defined in “480pxRules.css.”

  • From an external stylesheet by importing a stylesheet into the document in the “regular” manner using the <link> tag enclosed by the <head> tags. With this method media queries will be handled by the imported stylesheet instead of the document. The imported stylesheet can contain any combination of the two methods above (the parts which are in bold), and of course regular CSS.  Two things to note:
    • Remember that @import rules must be placed before any other CSS content and are not supported by very old browsers.
    • Rules of selectors that appear more than once are always overriden by the last definition. This means that media queries should always appear after all other CSS.
    • As a result of the above two rules any CSS imported into a document must not contain selectors that are repeated in said document or later import.

<head>
<link rel=”stylesheet” type=”text/css” media=”screen” href=”style.css” />
</head>

This is a usual stylesheet import. Testing for page width and applying the corresponding CSS rules is done either in “style.css” or in other stylesheets imported into “style.css.”

  • From an external stylesheet by importing said stylesheet into the document in which it will be used using the <link> tag. The code should be enclosed by the <head> tags.

<head>
     <link rel=”stylesheet” type=”text/css”      href=”480pxRules.css” media=”screen and (max-width: 480px)” />
</head>

While the page has a maximum width of 480 pixels it will follow the rules defined in “480pxRules.css.”

Although the different ways of referring to media queries might cause some confusion due to their different syntaxes, the overall “template” should make sense to anyone well versed in CSS. In any case, it’s just a matter of deciding which method to call the queries with and sticking to that general template while modifying media types and detectable media features to suit the situation. These variables are defined as such:

  • Media types: used to specify which type(s) of media the CSS rules will apply to. For example, in the examples above I have used the “screen” media type, which was primarily meant for color computer screens. However this media type also targets most smartphones nowadays, despite the fact that there also exists a “handheld” media type. If you don’t care about old “handheld” devices it’s enough to set your media type to “screen.” If you want to be safe, set it to “screen, handheld.” By leaving out media types entirely the CSS rules you define will apply to all media types. Here is W3C’s guide to media types and an article on the doomed “handheld” media typePro tip: instead of driving yourself crazy with 10 different stylesheets for each media type, focus on “screen” and possibly “print,” which are the two most used and useful media types.
  • Detectable media features: the most important part of media queries, these are the conditions we can screen for. “Max-width” and “min-width” are the most useful for our purposes; possibly also “orientation.” As with the viewport meta tag, each “width” variant has different uses when optimizing for mobile devices, but since media queries also apply to desktops, you will probably want to avoid the ones which refer to device-width, which always returns the resolution of the device. That’s fine for mobile devices since the browser usually takes up the entire screen space but if the user is on a desktop  it will return that device’s resolution regardless of the current window size. On the other hand “width,” “min-width” and “max-width” always return the width of the browser window.1

There is actually one last component that is very important. Don’t worry, it’s an easy one:

  • Logical operators: allows screening for both media type and multiple media features using the notand, and only operators. For example, “min-width” and “max-width” can be used together to specify that the CSS rules are only to be used when the window is between two different widths:

<head>
<link rel=”stylesheet” type=”text/css” href=”480to900pxRules.css” media=”screen and (min-width: 480px) and (max-width: 900px)” />
</head>

1 Media queries that refer to device-width are relevant if you actually want mobile devices to use different CSS rules than desktops. My HTC Desire has a resolution of 480px, which is the most common resolution for smartphones. CSS rules set for “max-device-width: 480px” will affect my Desire and most other smartphones. Desktop browsers would not be affected by these rules unless the actual screen monitor was 480 pixels wide, an uncommon sight to say the least. 

Javascript

Media queries are not the only way of specifying CSS rules based on different media types or features. Basically by using Javascript to get a desired value (width, for example) and then feeding them it into a specific function we can assign different CSS rules to differently sized windows and devices. That’s beyond the scope of this article, but Particletree wrote a very good article about it over 7 years ago! It is definitely worthy of consideration. With that thought, following are the pros and cons of both media queries and Javascript. I can’t recommend one or the other; read about both and pick what’s right for you!

Advantages of CSS media queries

  • Do not require Javascript to be enabled in the user’s browser.
  • Browsers that support CSS2 and CSS3 all interpret detection of media features and media types in the same way.

Disadvantages of CSS media queries

  • Detectable media features are CSS3, which means older browsers may not support them (media types were introduced in CSS2 so they have wider browser support).
  • As Rob Glazebrook pointed out in his article Using the CSS @import Rule Internet Explorer versions 4-7 cannot handle media types correctly. Still no confirmation if they work on IE8. Leave a comment if you’ve got the answer!
  • All CSS is loaded upon page load even if the conditions on which it depends are never met.

Advantages of Javascript

  • Older browsers that do not support CSS2 media types or CSS3 detectable media features can handle all of that through Javascript.
  • Allows checking for media types and features before loading the corresponding CSS files (assuming that CSS is not defined in the same document). This keeps unecessary CSS files from loading, but the Javascript itself slows down page loading. The conclusion is that this point is only relevant when every second counts, and then only if the amount of CSS to load for different situations is large enough that it pays off having the extra Javascript.

Disadvantages of Javascript

  • Users must have Javascript enabled in their browser.
  • Different browsers detect media features using different object/property combinations. According to Craig Buckler at Sitepoint “all the main browsers support document.documentElement.clientWidth anddocument.documentElement.clientHeight but it’s inconsistent. Either the window or document dimensions will be returned depending on the browser and mode.”
  • When the amount of special CSS rules is small, the extra Javascript doesn’t pay off with regards to page load times.

Mobile-specific websites

Because of the huge potential media queries and Javascript have in allowing you to control how your webpages are displayed under different circumstances, I would recommend getting familiar with and making use of them. At the same time it can be easy to get overwhelmed by the amount of possibilities. That’s never good, so if your aim is simply to create a good mobile experience to match what you’ve created for desktop users, a mobile-specific website just might be the answer.

As you might have guessed a mobile-specific website is completely separate from the main website, although it is usually a sub-domain of that site (for example, m.yourdomain.com). Everytime someone visits the main domain name (yourdomain.com), a function runs and checks what kind of device it’s being accessed from and then re-directs them to the appropriate site.

The code which checks the device type can be written in a variety of languages. Javascript is popular for this application but if your server supports a server-side language I would recommend that to ensure that it will work for all users. If you don’t want to write your own code I’ve come across a very nice solution called WURFL. What’s awesome about it is that it uses a “repository” (wurfl.xml), which contains the definitions of thousands of devices, and is constantly being updated. On their website it is stated that “WURFL is deployed by key Internet companies such as Facebook and Google” so I can’t imagine that there is a more effective way to do device detection, but I haven’t actually tried it myself. There are APIs available in several programming languages or you could write your own and just use their wurfl.xml file.

Conclusion

The viewport meta tag, media queries, Javascript, and mobile-specific websites — and that’s not to mention good design sense! With so many options and a growing number of users accessing webpages through iPhones, Android phones, tablets and other mobile devices there is no excuse not to give your visitors a great experience everytime.