Even as browsers progress and add more support for CSS-based animation, we still find ourselves relying on JavaScript to get the job done. But that doesn’t mean we need to define our styles in our scripts.

Nikita Vasilyev has described a simple yet useful JavaScript technique for transitioning to and from ‘auto’ for CSS height and width values. While this is arguably something CSS should handle natively, it’s not in the spec and it’s unclear if any browser vendors will implement it independently.

As nicely as this solution works, I still prefer to keep the presentation defined by CSS as much as possible. In particular, I wasn’t happy leaving this particular line from Nikita’s script as-is:

element.style.transition = 'width .5s ease-in-out';

We regularly get caught in this scenario — wanting to style with CSS, but needing JavaScript to make it happen. All too often, we end up with styles that are hardcoded into JavaScript.

If we’re smart we make these styles configurable, but then we’re adding complexity to our code and making it harder for other developers to use our code (do I pass my custom CSS as the third argument or fourth?). We can do better.

Referencing Style Sheets

In this particular case, the three transition values — property, duration, and timing function — are all hardcoded. It may make sense to leave the height or width property declared in the JavaScript if the script will be called upon for a specific property (e.g. an expandWidth() function customized for a particular module). But there’s no reason the duration and timing function can’t be defined in CSS.

Let’s make that line a little more adaptive:

element.style.transitionProperty = 'width';
element.style.transitionDuration = getComputedStyle(element).transitionDuration;
element.style.transitionTimingFunction = getComputedStyle(element).transitionTimingFunction;

And in the CSS:

.expandable {
    transition-property: none; /* More on this in a moment */
    transition-duration: .5s;
    transition-timing-function: ease-in-out;
}

View a Gist of the entire code

Separation of Concerns

Now the transition can be changed by another JavaScript module or style sheet without disrupting the expandWidth() function:

.expandable.molasses {
    transition-duration: 3s;
}

.expandable.robotic {
    transition-timing-function: linear;
}

Extendability

This pattern is handy if you’re working on a customizable framework:

app.scss

$expand-transition-duration: 1s;

@import "_framework"

_framework.scss

$expand-transition-duration: 500ms !default;
$expand-transition-timing-function: ease-in !default;

.expandable {
    transition: none $expand-transition-duration $expand-transition-timing-function;
}

Which compiles to:

app.css

.expandable {
    transition: none 1s ease-in;
}

Note

You’ll notice that the CSS includes transition-property: none. This prevents the CSS from having an effect on the element — that is, if you were to set transition-property: width you would see a wonky ‘double’ animation as both the JavaScript and CSS adjust the element’s width simultaneously. If you try to leave the property out, the browser will default to transition-property: all which isn’t what we want either.

And of course you will need to add vendor prefixes to keep things working across most browsers.


This is an update to the console.log wrapper; see this blog post for background and a more detailed discussion of the problems with console logging.

While logging the console can be useful during development, some browser consoles do not display logged data in a readable, useful format. These primitive consoles do not expand arrays, do not link DOM elements to the source code, print objects as [object Object] rather than listing their properties, etc.

For example, try logging the following in Internet Explorer 8 through 10:

console.log( "Here's a string",
             3.14,
             {"alpha": 5, "bravo": false},
             document.getElementById('charlie'),
             new Date()
            );

It will result in:

IE8 without detailed print

On the other hand, Firebug, WebKit’s Developer Tools, and Opera’s Dragonfly print useful, interactive items to the console. Here’s the same code as above, but this time in Firebug:

Firebug running in Firefox

Expanded details

But it is possible to eke a bit more information out of the data in primitive consoles. I’ve added a detailed print plugin to my console.log wrapper.

By including the plugin and sending the data to log(), the same call as above now looks like this:

IE8 with detailed print

It’s still not pretty, nor is it linkable like modern consoles. But now instead of [object Object] you can see that it was an array (along with its length), or a DOM element (along with its selector), and so on. This can be useful in IE 7/8/9/10, iOS 5 and older, and Opera 11 and older, among others.

Alternatives

For iOS 5 and older, if you are so inclined you may instead try installing Firebug or using a remote debugging tool like Adobe Edge Inspect or Weinre.

If you’re sticking to modern browsers, you can simply ignore the new consolelog.detailprint.js plugin and continue to use log() as usual.

Thanks to Jörn Berkefeld for pointing out that this was needed on iOS 5 and for testing.

Live Demo Github Repo

The viewport is a direct window into what the user sees, and a lot can be learned by watching it. In my previous post I introduced Within Viewport and I want to discuss how, particularly through my Twitter app signal:noise, I’ve found it useful in making interfaces respond sensibly to user behavior.

Dynamic content loading

A common solution for developers looking to increase their site’s performance is to load data on demand, for example using Infinite Scroll. But sometimes the scroll position isn’t enough — you need to know about the content on screen.

In signal:noise I want to control how heavier content is loaded. Since a tweet is a paltry 140 characters, and dynamically adding more of them to the top of a page causes it to scroll, it’s reasonable to start out by loading fifty or so at the initial page load. But when you factor in images and video previews linked within those tweets (which signal:noise presents inline) the page can take longer to load. I use Within Viewport to make sure I’m only loading media for tweets that are on screen or just about to be shown.

Responding to user behavior

The obvious thing to do when a user reaches the boundary of their timeline is to load more tweets. But it takes time to call the Twitter API (possibly more than once), process that response, and send the new content back to the client. By comparing the number of tweets in the user’s field of view to the number that are out of sight, and tracking the speed with which those tweets move in and out view, the app can get a sense of the user’s momentum. With this knowledge the app can avoid calling the API too late (not having tweets ready to go) or too soon (unnecessarily hitting the API rate limit).

Making appropriate measurements

The app also tracks each user’s reading position so the can resume reading at the same place in future sessions. When determining which tweets have been read, it only makes sense to consider ones that are fully in view. The app has a fixed header that shrinks the viewport by about 60 pixels, so I need to make sure a tweet is not covered by that.


Diagram showing elements of a Twitter feed being in and out of view

Larger version

Live updates

My app also allows keyboard navigation from tweet to tweet, similar to Google Reader. When the user jumps to a tweet that is not completely visible, the app needs to know so it can scroll the page.

Tracking usage

While not directly applicable to a Twitter app, you may want to find out what areas of your site a visitor actually sees. By firing events when sections move into and out of the viewport, you can use Google Analytics’ Event Tracking to find out how often users actually see parts of your page. Wondering why a particular widget doesn’t result in many click throughs? Perhaps the answer is as simple as not many people even get to see it.

And more?

All that from just a viewport? I initially wrote Within Viewport to solve only one of the problems above, but I soon found many other uses for it. It wasn’t until I began using it that I realized, as obvious as this may seem, how pertinent the viewport is as an insight to the user’s experience.

If you have any other ideas, or suggested additions to the script, I’d love to hear them in the comments.

Within Viewport indicates whether an element is entirely within the viewport. It also allows you to specify your site’s effective viewport (eg, to account for fixed header and navigation bars) and provides a few handy shortcut notations.

It’s quite simply to use:

var elem = document.getElementById("myElem");

// Returns true if it's completely visible
withinViewport(elem);

// Same as above, but using the jQuery plugin
$(elem).is(":within-viewport");

// Run some function on all visible divs
$("div").withinViewport().myFunction();

Live Demo Source Code at Github

There are a few “in view” scripts out there — namely, Mika Tuupola’s Viewport Selectors for jQuery provides some convenient selectors that can be tested against elements, and Remy Sharp’s Element ‘in view’ Event Plugin fires events when elements pass in and out of the viewport.

While useful, these utilities only detect whether elements are partially in view. The aim of Within Viewport is to determine what content the user can see and interact with.

Use Cases

A lot can be learned from monitoring the viewport, especially on a site with content that spans well outside of the user’s view. I will discuss how I use Within Viewport in much more detail in my next post. But here’s a quick overview of what you can do.

  • Dynamic content loading

    A site’s performance can be increased effectively by loading data on demand, for example when the user scrolls near the bottom of the page. But perhaps the content on screen is more pertinent than the scroll position. For example, you may want to load the entire structure of your site during the initial page load, but then populate that structure with heavier media as it nears the user’s field of view.

  • Responding to user behavior

    You may also want to tailor when that content is loaded based on how rapidly the user moves about the page. If you are relying on a third party API for content, you may want to start the process sooner than you would begin requested content from your own server.

    For example, the script below would find and load items with local content that is merely just beyond the viewport, but also load third-party content that appears much further down the page.

    // Image placeholders at most 100px below the fold
    $('img:not([data-src^="http://"]')
        .withinViewport({bottom:-100})
            .loadTheseImages();
    
    // Image placeholders as far as 500px below the fold
    $('img[data-src^="http://"]')
        .withinViewport({bottom:-500})
            .loadTheseImages();
    
  • Making appropriate measurements

    If you want to know what your user has seen, for example to remember their reading position in a feed, you can only consider ones that are fully in view. You also need to take into account the actual viewport, avoiding things like fixed header bars that cover parts of the page.


    Diagram showing elements of a Twitter feed being in and out of view

    Larger version
  • Live updates

    If you implement keyboard navigation between items, similar to Google Reader, you need to make sure a newly-selected item is actually visible.

  • Tracking how your app is used

    You can tap into Google Analytics’ Event Tracking to find out how often items enter your visitor’s field of view.

I built Within Viewport to accomodate those needs, but I made it generic enough that any site or web app could benefit from it. There are configurable defaults and several shorthand notations described with examples in the documentation.

No jQuery? No problem

I wanted to write a tool that was independent of jQuery so it could be dropped into any project. Of course jQuery does offer some useful mechanisms such as filtering and custom selectors, so I added an optional plugin to provide that functionality.

Live Demo Source Code at Github

Update

I’ve made a significant update to this project which is targeted at primitive consoles (IE, Opera 11 and older, iOS 5 and older, and more). A separate blog post has more details or you can jump right ot the updated Github repo. The original post below still applies.

Many front-end web developers make use of the wonderful browser consoles that have matured in the past few years. While the tried-and-true console.log() often does the trick, its lack of support (particularly in IE) has led to the use of proxy functions, such as Paul Irish’s console.log wrapper and Ben Alman’s Debug() which prevent unsupportive browsers from throwing errors.

I had a need for logging data in every browser, not just ones that natively support console.log(). So I forked Paul’s function and expanded it to work with every browser I could test — IE6-9, Firefox 3.6 & 4+, Chrome 10+, Safari 5+, and Opera 11+.

This will be exhaustive, so you may want to jump directly to:

Live Demo Github Repo Source Code Minified Source Code

Current state of the console

Like Paul’s implementation, we’re simply going to create a function called log() and pass along any arguments it receives to console.log(). But before that we need to do a little setup to ensure that, when possible, console.log() is properly defined as a function in every browser.

First, let’s review console support in today’s browsers:

  • Chrome, Safari, Opera: native console.log()
  • Firefox: native console.log() with Firebug
  • IE9: native console.log(), but it needs a little nudge to turn on
  • IE8: While console.log() exists, it’s an object rather than a function — But we can still write to the console with a clever trick.
  • Others: We can inject Firebug Lite which will define console.log() as a function

Note that when I talk about IE I’m referring to the native versions — “IE8″ means IE8, not IE9 switched to IE8 mode with the Developer Tools.

IE's developer toolbar tricking you into thinking that it's running as a different version

IE9

Before we build log() we need to tell IE9 to use its own console and to consider console.log() to be a function. Many thanks to Andy E for this piece.

if (typeof console.log == "object" && Function.prototype.bind && console) {
	["log","info","warn","error","assert","dir","clear","profile","profileEnd"]
		.forEach(function (method) {
			console[method] = this.call(console[method], console);
		}, Function.prototype.bind);
}

For this particular case we really only need to define the log method, but it can’t hurt to flip the switch on the others as well.

Modern browsers

Now we can define log(). There’s no sense in re-inventing a very round wheel, so I’m just going to fork Paul Irish’s original console.log wrapper.

if (!window.log) {
	window.log = function () {
    log.history = log.history || [];  // store logs to an array for reference
    log.history.push(arguments);
	if (typeof console.log == 'function') {
		// Modern browsers
		if ((Array.prototype.slice.call(arguments)).length == 1 && typeof Array.prototype.slice.call(arguments)[0] == 'string') {
			console.log( (Array.prototype.slice.call(arguments)).toString() );
		}
		else {
			console.log( Array.prototype.slice.call(arguments) );
		}
	}
	// to be continued...

Notice that if() condition on line 7. Paul’s use of Array.prototype.slice.call() is great because you can pass along any amount and variety of objects, strings, functions, etc directly to the console. However, there’s one unfortunate side effect: in Firebug and Chrome (and possibly others), if the argument array’s sole content is a single string greater than 50 characters, it will be truncated faster than you can say Llanfairpwllgwyngyllgoger…wllllantysiliogogogoch.

So we’ll check the array length, and if it’s 1, and that 1 thing is a string, then we’ll convert the entire argument array to a string before passing it along. You could use console.error() to avoid truncation, but then it will look like an error when it’s not.

Opera

Update: Since I first wrote this post, Opera has updated Dragonfly such that the console now properly displays basic types — arrays are enumerated, objects are presented in a tree-like structure, etc. I have removed the if (window.opera) { section from the code. You can ignore this section and skip down to IE8. I’ll leave this section in place in case anyone has a need to test on Opera 11.

So that takes care of the modern browsers… except Opera. Opera seems to display the arguments as a whole Array() rather than splitting them apart. So if you passed several arguments you’d just see this:

Opera console showing "Array()" rather than the actual arguments

And that’s not too helpful. We can get around this with a rather boring while() loop to log each argument one by one.

var log = function () {
			// Modern browsers
			if (typeof console != 'undefined' && typeof console.log == 'function') {
				// Opera 11
				if (window.opera) {
					var i = 0;
					while (i < arguments.length) {
						console.log("Item " + (i+1) + ": " + arguments[i]);
						i++;
					}
				}
				// All other modern browsers
				else if ((Array.prototype.slice.call(arguments)).length == 1 && typeof Array.prototype.slice.call(arguments)[0] == 'string') {
					console.log( (Array.prototype.slice.call(arguments)).toString() );
				}
				else {
					console.log( Array.prototype.slice.call(arguments) );
				}
			}
			// to be continued...

Which results in:

Opera's console listing each argument on a separate line

It’s a little messy and if you use log() a lot you’ll find that your console will fill up fast, so you’ll have to decide how important Opera support is to you.

IE8

As we discussed earlier, IE8 has a console but your scripts can’t call console.log() directly, so we’re going to add a special condition for it. Andy’s aforementioned post included a similar bit of code for writing to IE8′s console, however in actual IE8 (as opposed to IE9 switched to IE8 mode) Function.prototype.bind is not defined. Instead, I’m using @kangax‘s alternative, Function.prototype.call.call().

			else if (!Function.prototype.bind && typeof console != 'undefined' && typeof console.log == 'object') {
				Function.prototype.call.call(console.log, console, Array.prototype.slice.call(arguments));
			}

One slight alteration: I changed the second part of the condition from console to typeof console != 'undefined'). It seems a little silly, but IE7 actually throws an error without the typeof check.

Older browsers

Now we’re going to inject Firebug Lite (“FBL”) for all the other browsers — namely, IE7 and older — by adding a <script> tag to the DOM. (Personally, I like FBL better than IE’s and Opera’s consoles anyway, so you may want to use this for any browser where (typeof console.log != 'function' || window.opera) is true.) Doing this will expose console.log() as a function, which means your calls to log() will end up being handled by the “Modern browsers” section in the beginning of the function.

You can pull it directly from getfirebug.com, or use a local copy (point to the /path/to/firebug-lite/build/firebug-lite.js file).

In my experience FBL takes a few moments to load and begin accepting console logs, even locally. To compensate for this delay, this piece of code is split into two conditions. The first one loads FBL and will only run the first time you call log():

		else {
			// Inject Firebug lite
			if (!document.getElementById('firebug-lite')) {
				// Include the script
				var script = document.createElement('script');
				script.type = "text/javascript";
				script.id = 'firebug-lite';
				script.src = '/lib/js/firebug-lite/build/firebug-lite.js';
				// If you want to expand the console by default, uncomment this line
				//document.getElementsByTagName('HTML')[0].setAttribute('debug','true');
				document.getElementsByTagName('HEAD')[0].appendChild(script);
				setTimeout(function(){log(Array.prototype.slice.call(arguments));}, 1500);
			}
			else {
				// Script was included but hasn't finished loading yet
				setTimeout(function(){log(Array.prototype.slice.call(arguments));}, 500);
			}
		}
	} // <= that's the end of log(), btw
}

The second condition is caught when your script calls log() before FBL has finished loading. Notice the id that I added to the <script> tag in the first condition — that tells us that FBL has begun loading. But since console.log is still not defined (otherwise we wouldn’t have gotten to this point in the code) we know that the script hasn’t fully loaded yet. Therefore we can simply use a setTimeout to try our call again every half second until it succeeds.

“It is so big”

Yeah, it is. Compared to Paul’s 6 lines, this version is a beast. But consider this: you log to the console during development. You’re not going to leave this in your production code (I hope!). So this function — and let’s face it, it’s not that long, especially when minified — is likely to be used only via localhost or over a LAN connection. I think the ability to log data in every browser is well worth a couple dozen lines of code tucked out of sight down at the bottom of dev.js.

I look forward to any suggestions or improvements you may have.

Live Demo Github Repo Source Code Minified Source Code

The idea behind using a common CDN such as Google’s, as opposed to your own CDN (or none at all), is that by the time a person reaches your site there’s a chance they already have your JavaScript libraries cached. While it’s likely that an übergeek with fifty opened tabs will have jQuery cached before hitting one of your pages, the same isn’t so true for every Joe Facebook.

But what if a very popular site, one that nearly everyone would hit before reaching your site, loaded those libraries? I imagine the number of users running cached libraries would increase dramatically.

So which site? How about the most popular default home page — Google Search. (Sure, Facebook is popular, but we all know that even Facebook user’s hit up Google first.)

Think about it: a typical user begins their browsing session by loading Google’s search page, searches for something or other, and moves on with their task. But in the mean time, Google has silently loaded — not used, just loaded — jQuery, some popular web fonts, etc in the background. Perhaps the libraries are even chosen as the most likely ones the user will encounter based on his or her search terms. Those libraries are now cached in the user’s browser and your page will load that much faster with zero effort.

Of course there are some glaring drawbacks that would need to be addressed, but the solutions are pretty straightforward:

  • Page load speed. Among other things, one could use a setTimeout() to lazy-load the library after, say, 8 seconds. (If you’ve been on the page for 8 seconds, chances are you’re hanging around for another 0.5 seconds to allow the download to finish.)
  • Bandwidth. Obviously mobile devices are out, at least until there’s some way to detect whether the user is on wifi and running a buff enough browser not to blink at the <script> parsing. Even so, there are ISP bandwidth caps to consider, but is a one-time 20KB download going to push anyone over their limit?
  • Privacy. People will kick and scream at the thought of something loading without their explicit request. Surely there should be an option to turn this off; but really, if you’re paranoid enough not to want MooTools in your cache than you’ve surely installed NoScript anyway.

Naturally this is all just a wish. It’s something I think Google could certainly pull off smartly, but I’d love to see it in practice even in a limited test (Chrome beta channel users, perhaps?) to see what effect it has on a typical person’s web experience.

If you’re preparing to travel overseas and you’ve had an iPhone for any amount of time you’re probably excited about its usefulness as a travel aid. In particular, you’ll be keen to make use of its always-on Internet connection.

But you’ve probably heard the horror stories of arriving home to a thousand-dollar cell phone bill littered with roaming charges. Fortunately, you have some options to make use of your iPhone’s capabilities outside of the United States.

While this topic has been covered before, most approaches are far too conservative. You don’t want to spend your entire vacation with your iPhone locked down in airplane mode, or constantly toggling Data Roaming on and off — nor do you need to. That defeats the entire purpose of a smartphone and prevents you from enhancing your trip with the iPhone’s many tools.

Note that this post is specific to American AT&T users, but the fundamental principles still apply to other smartphones on other carriers. It is also a bit Europe-centric — I’m just sticking to what I have experience with.

I also assume that you’re familiar with what a SIM card is, as well as the difference between voice and data where cellular networks are concerned.

An Offline Frame of Mind

When your iPhone is in its most helpful state, it’s probably consuming a lot of data, which unfortunately is your primary concern when it comes to roaming charges. So the first order of business is to concentrate on orienting yourself to being less network-reliant. This isn’t as daunting as it may seem.Google provides Mobilized links for web pages in its search  results

An important note to consider is that native apps tend to consume far less data than web browsing. For example, it uses a trivial amount of data (tens of kilobytes) to complete a simple FourSquare check in, so have a ball boasting about all the exotic locations you’re visiting. (Just be safe and don’t overshare.) And while Google Translate‘s mobile interface is slim, consider an app such as iTranslate which will only transfer the actual text you’re translating.

If you must perform a simple Google search away from wifi, hit the mobile link for a stripped down (read: image-lite and less data gobbling) version of the site.

A Few ‘Offline’ Tips

  • Wifi
    This seems a bit obvious, but try to book hotels with free wifi. Assuming your travel is for leisure, you’ll probably want to enjoy your day and save the web browsing, RSS feeds, and Facebook for when you’re unwinding in your room at the end of a long day.

    Save your cellular data for the situations that are truly helpful while on foot — finding out where you are, checking for nearby points of interest, and verifying other time sensitive information.You can also use a service such as JiWire and their Wi-Fi Finder app to find and download a map of wifi locations in your city.

  • Maps
    Perhaps the killer app of the iPhone when it comes to travel is its mapping capabilities and location awareness. Maps, however, are extremely data-intensive, so you’ll want to have them preloaded on your device.

    • OffMaps (99 cents) is an excellent app which allows you to freely download maps. On the ground, it will utilize the phone’s (free, non-data-consuming) GPS abilities to display your position on the map. (It can, of course, stream maps on-the-fly if you have a generous data plan.) It typically locates you within a second or two; it’s much faster than the GPS devices of the past.Before you leave home, use the maps to download the maps at several zoom levels for the destinations you will be at. A typical city may take a couple hundred megabytes at the most detailed zoom level, so be sure to use Wifi. You might also consider their useful but less-than-polished city guides which highlight sights, hotels, restaurants, and other travel-related points of interest collated from WikiTravel.org and other free sources (in-app purchase; first one’s free, then 99 cents for three or $9 for unlimited).
    • Navigation apps (various products and prices, usually $40-$100) are available for many worldwide locations if you intend to do some driving. Just make sure you choose the right region, and that the maps are included in the download for offline access.
  • Guides
    Search the App Store for the name of your destination city or country and you’ll find a range of guides, from basic “WikiTravel in a nice package” apps to sleek but more costly Lonely Planet guides. Also consider using a service like Instapaper to collect articles and download them to your phone using the Instapaper app. As a last resort, paste the text into an email or the Notes app.Or you could just lug around a dead-tree guidebook, which has its benefits.
  • Toggle Cellular DataCellular Data switched to "Off" in Settings

    An easy way to ensure no data will be sent over your cellular connection, while still maintaining the ability to make and receive phone calls and use the phone’s location awareness, is to turn off cellular data in Settings.

    That’s it. There is no need to turn on airplane mode to avoid data usage. Note that you do not need to explicitly turn off data roaming when toggling this setting.

    If you’re confident that you’ve turned off all background processes (fetching mail, etc) then you can just leave cellular data flipped on to avoid the hassle of constantly toggling it. I recommend testing this at least once: make note of your current data usage (e.g., dial #3282* if you’re on AT&T’s plan described below), leave the phone idle for an hour or two, then check your data usage again and make sure it hasn’t gone up. If it has, you’ve still got something running in the background.

Getting Connected

You have three basic choices when it comes to connecting to a cellular network abroad. The first is the cheapest but requires a bit of research and a little leg work at your destination, while the other two are more expensive but just plain work with no hassle.

  1. Foreign SIM Card
    This is the cheapest option which gives you the most flexibility, and depending on the country, even the possibility of having so much data at your disposal you won’t even need to monitor your usage. Unfortunately, it requires jailbreaking and unlocking your device. This has its own implications; I’ll leave it up to the reader to decide whether this is a path worth taking, and to figure out how to do it (the process and ability depends on your device and OS version, not to mention your tech savviness).If you do unlock your phone, you will be free to use any SIM you can find. You will quite likely want to use a contract-free prepaid SIM which will allow you to just pay for what you use and can usually be found all over, from airports to convenience stores to specialty phone shops. These options are country-specific, so if you’re traveling to three or more countries you’ll want to look into “global SIM” cards such as Telestial or GO-SIM.

    Start by perusing the Pay As You Go SIM Wiki and PrepaidGSM.net which includes a roundup of the options for each country, listing the data and voice rates. It may seem a little daunting at first, so concentrate on the data rate and assume you’ll use Skype for voice calls. Note that the main legacy carriers, such as Vodafone, O2, Orange, and T-Com — the rough European equivalents to AT&T, Verizon, et al — are ubiquitous and feel ‘safe’, but there also exists a culture of “virtual operators” who utilize the big companies’ networks but offer lower rates. Often these VOs (or sometimes MVNOs) will specialize in some ‘angle’ that may not work for everyone, such as cheap data subsidized by more expensive voice calls — which is actually just what you want. (Think of low cost airlines like RyanAir which offer cutthroat prices based on limited services and alternate airports — it’s not entirely mainstream-friendly but it may just suit your needs.)

    Take a moment to peruse the site’s forums for tips on your country and read about people’s experiences, taking into consideration how recent the posts are.Once you’ve narrowed your options down to three or four networks, head over to other travel forums such as FlyerTalk or Lonely Planet’s Thorn Tree and search for the network’s name to see what people have to say.

    Finally, write down three or four operators (on paper or digitally), as well as how/where to buy them, to bring with you on your trip. You can’t be sure exactly which SIMs you’ll actually be able to find, so it’s good to have a backup. You may get a different story from the shop clerk who says you can’t actually use the SIM as you’d expect, or they may be difficult to find in stock. A piece of paper also provides a convenient tool to hand to a non-English speaking clerk (unless you know the Dutch/Hungarian/Romanian/Turkish phrase for “I need a prepaid SIM card for my unlocked phone with a good data rate” and can interpret his or her possibly jargon-laden response).

    Note that the availability of SIMs can vary in both senses of that word. For example, in the UK, SIM cards are practically given away — you can throw a stone in any direction and, after bouncing off a kebab joint, it will land in front of a shop selling £10 SIMs that come with £10 of credit (meaning the SIM is free assuming you use all the credit). Often these can be bought anonymously with cash. In the middle are countries like Spain and Germany which may require a passport and/or in-country address (the standard practice is to use your hotel’s address) to purchase a card. Then there are countries like Turkey, where the security theatre had ascended to the point where the SIM card vendor must verify your national tax ID (similar to an American social security number in both function and sensitivity) and register it with your SIM before it’s activated, meaning a foreigner is basically out of luck unless they have a good friend or family member willing to buy one for them.

  2. AT&T’s International Data Package
    This option is as simple as it gets — just log in to your account on AT&T’s website and add an international data package to your account. Once you’re overseas, you’ll just use your iPhone like you would at home and it will work seamlessly.The catch? It’s not exactly cheap. You can choose from a paltry 20MB for $25, 50MB for $60, or even 100MB for a whopping $120. That’s not much data for a pretty hefty chunk of change. Figure that you’ll use about 50MB a month, or 12-15MB per week, if you’re careful about your usage and stick with the tips discussed above. You don’t want to go over — overage fees are an almost comical $5 per megabyte (though mercifully charged by the kilobyte should you go just a hair over).

    There’s one other point to consider which may or may not work out in your favor. The international data package takes affect immediately and is prorated, which may or may not align with your billing cycle and trip. Consider how the 50MB plan would pan out over the following example:Time line showing a trip from July 7 to July 27, with only 33MB available from July 7 to July 22 when the billing cycle restarts, but then 50MB for the last 5 days of the tripIn this example, notice how inconveniently the amount of data aligns with the actual trip. The first fifteen days, representing a sizable bulk of the trip, only gets 25MB, while the last 5 days have 50MB at their disposal. (True, you will still end up paying for the amount of data you actually use, but remember the overage fees compared to the normal price per MB, not to mention the convenience of having a lot of data available should you unexpectedly encounter a day or two of unavoidable high usage.)

    Here’s how it works, and why part of the trip only has 25MB available. The billing date here is the 22nd of the month, and the data plan began on the same day as the trip, the 7th. Since that’s only half of the billing cycle, you only get half of the data. When your next billing cycle begins, you’ll be reset back to the full 50MB. In this case, you’d be better off signing up on the 22nd of the previous month (June, in the above example) so that you have the whole 50MB available during your two-week trip. I’ve read that you can have this adjusted (so that the data charge aligns with the date of your trip instead of your billing cycle) by calling AT&T; I recommend talking to them first if your dates aren’t aligning in your favor.

  3. Legit iPhone SIM providers
    These aren’t any cheaper per megabyte than AT&T’s plan, and they’re not as dead simple, but they give you a few more options: Mobility Pass,

Conclusion

If you’re comfortable with jailbreaking and unlocking your phone, and the country to which you’re traveling has SIMs available, then a 3rd party SIM is easily the cheapest and most flexible option.

If you don’t want to (or can’t) jailbreak or your country is on SIM lockdown, AT&T provides an easy-as-pie option at a cost.

Either way, you’ll need to follow good data usage practices to keep your usage at more of a minimum than you’re used to. Also be sure you’ve got all the apps you need and prepare them before leaving home.

Above all else, don’t forget to leave the iPhone in your pocket most of the time and enjoy your vacation!

Many news sites, from Wired to my local newspaper, have taken to adding a ‘feature’ to their articles — any text you copy and paste is silently broadcast to another site. That other site, Tynt, keeps track of what you copy and paste to your friends in an effort to track demographics.

Text copied and pasted from a news article into an IM window

While some find it useful that Tynt also appends the URL of the article you’re viewing, many find the behavior obtrusive and a violation of their privacy. Want to share a snippet of a story with a friend? Go ahead, Tynt (and presumably the news site) are watching.

Here’s how to get rid of it, depending on your browser of choice.

Firefox iconFirefox

With AdBlock installed, open the AdBlock preferences — either through the Tools menu or with the shortcut Ctrl-Shift-E. Click Filters > Add new, then paste in this line:

http://tcr.tynt.com/javascripts/Tracer.js

AdBlock preferences window

Google Chrome icon

Chrome

Chrome as a few ad-blocking extensions, such as AdBlock and AdThwart. Once one is installed, go to your extensions page by clicking the wrench icon in the upper right corner of Chrome, then choose Extensions. Open your extension’s options and add the same line shown above for Firefox.

Internet Explorer, and everyone else

First, ask yourself why you’re not using a safer, faster, better browser. Surprisingly, Internet Explorer version 8 does offer ad-blocking. Follow these easy steps from ghacks.net to block this script.

Twitter recently unveiled a new interface for their mobile site located at mobile.twitter.com loaded with the features you’re accustomed to having on the desktop version of the site. However, when you browse to Twitter or follow a link from an email on your mobile phone you’re still shown the older, far less useful interface by default.

To automatically view any page in the new interface, just use the bookmarklet below. If you’re currently on a Twitter page you’ll be redirected to the same page on mobile.twitter.com; or, if you’re anywhere else at all, you’ll simply go to the mobile home page.

The bookmarklet: Mobile Twitter

Or, to install it on an iPhone, follow these steps.

  1. Click here, and bookmark the resulting page once it loads by clicking the + icon at the bottom of Mobile Safari. (It will look just like the page you’re on.) Call it something like “Mobile Safari”.
  2. Tap the bookmarks icon to open your bookmarks, then click Edit
  3. Tap on the bookmark you just made. Then tap on the second line, containing the URL, to edit it.
  4. Hold your finger down on the URL until the magnifying glass appears. Slide your finger to the left until you see “#__javascript”. Put the cursor just before “javascript”, then hit Backspace to clear out everything that comes before it.
  5. Click Done. The URL should now be a bunch of code beginning with “javascript”Edit bookmark dialog, complete

And that’s it. To use it, just open your bookmarks and tap on your new Mobile Twitter bookmarklet while you’re viewing any page.

Google Voice, the service that gives you a universal phone number, free SMS, and text transcripts of your voicemail, is now letting new users keep their current phone number when signing up. On the surface this sounds like a great new addition that will entice users who were scared off by the idea of giving up their current number. But in reality, this is actually a stripped down version of the service that not only removes functionality but actually restricts how users can use their phones. (This new option is not the same as porting your number, something Google expects to roll out in the future.) Google Voice

When a new user receives and accepts their Google Voice (GV) invite, they’re presented with two options:

  1. to keep their current number, or
  2. the ‘classic’ option of getting a new GV number, then associating their phones with that

Choose wisely, because if you pick Option #1, there’s no going back. In other words, you can’t get a new GV number and all the features and options that go with it. Even worse, you’ll be stuck using Google’s voicemail system (and not your carrier’s) whether you like it or not.

That sounds harsh, but fortunately you can get all the features and keep your current number by choosing Option #2.

If you choose Option #2, you simply select a new GV number,  then add your cell phone to your account. You can then optionally activate the voicemail features on your cell phone — the same ones trumpeted under the banner of Option #1 on GV’s sign up page.

Basically, “keep my number” is a lite version of the service with fewer features. There is no good reason to choose it — if you think it’s a hassle to get a new phone number — and it’s really not — just don’t give it out to anyone. No one you call or text will know the difference.

Update: Nearly two months later, Google finally added the option to get your own Google Voice number even if you didn’t choose one initially.

Posted in Web.