As a small business, it can be difficult to devote the amount of funds needed to hire a designer who can create a stand out brand for your business. Yet, having a powerful and impressive brand look is arguably THE most important element of a small business, next to customer service and smooth operations, that is. When most small businesses use unoriginal fonts, a boring logo, unimpressive color scheme, a common WordPress website layout, and stock images, the one small business that chooses the unique route is that one that will get noticed, and more importantly, be remembered long after the initial encounter.
Functional programming is the mustachioed hipster of programming paradigms. Originally relegated to the annals of computer science academia, functional programming has had a recent renaissance that is due largely to its utility in distributed systems (and probably also because “pure” functional languages like Haskell are difficult to grasp, which gives them a certain cache).
Stricter functional programming languages are typically used when a system’s performance and integrity are both critical — i.e. your program needs to do exactly what you expect every time and needs to operate in an environment where its tasks can be shared across hundreds or thousands of networked computers. Clojure1, for example, powers Akamai2, the massive content delivery network utilized by companies such as Facebook, while Twitter famously adopted3Scala4 for its most performance-intensive components, and Haskell5 is used by AT&T for its network security systems.
These languages have a steep learning curve for most front-end web developers; however, many more approachable languages incorporate features of functional programming, most notably Python, both in its core library, with functions like map and reduce (which we’ll talk about in a bit), and with libraries such as Fn.py6, along with JavaScript, again using collection methods, but also with libraries such as Underscore.js7 and Bacon.js8.
Functional programming can be daunting, but remember that it isn’t only for PhDs, data scientists and architecture astronauts. For most of us, the real benefit of adopting a functional style is that our programs can be broken down into smaller, simpler pieces that are both more reliable and easier to understand. If you’re a front-end developer working with data, especially if you’re formatting that data for visualization using D3, Raphael or the like, then functional programming will be an essential weapon in your arsenal.
Finding a consistent definition of functional programming is tough, and most of the literature relies on somewhat foreboding statements like “functions as first-class objects,” and “eliminating side effects.” Just in case that doesn’t bend your brain into knots, at a more theoretical level, functional programming is often explained in terms of lambda calculus9 (some actually argue10 that functional programming is basically math) — but you can relax. From a more pragmatic perspective, a beginner needs to understand only two concepts in order to use it for everyday applications (no calculus required!).
First, data in functional programs should be immutable, which sounds serious but just means that it should never change. At first, this might seem odd (after all, who needs a program that never changes anything?), but in practice, you would simply create new data structures instead of modifying ones that already exist. For example, if you need to manipulate some data in an array, then you’d make a new array with the updated values, rather than revise the original array. Easy!
Secondly, functional programs should be stateless, which basically means they should perform every task as if for the first time, with no knowledge of what may or may not have happened earlier in the program’s execution (you might say that a stateless program is ignorant of the past11). Combined with immutability, this helps us think of each function as if it were operating in a vacuum, blissfully ignorant of anything else in the application besides other functions. In more concrete terms, this means that your functions will operate only on data passed in as arguments and will never rely on outside values to perform their calculations.
Immutability and statelessness are core to functional programming and are important to understand, but don’t worry if they don’t quite make sense yet. You’ll be familiar with these principles by the end of the article, and I promise that the beauty, precision and power of functional programming will turn your applications into bright, shiny, data-chomping rainbows. For now, start with simple functions that return data (or other functions), and then combine those basic building blocks to perform more complex tasks.
If we want to use a chart or graphing library to compare the average temperature to population size, we’d need to write some JavaScript that makes a few changes to the data before it’s formatted correctly for our visualization. Our graphing library wants an array of x and y coordinates, like so:
[
[x, y],
[x, y]
…etc
]
Here, x is the average temperature, and y is the population size.
Without functional programming (or without using what’s called an “imperative” style), our program might look like this:
Even in a contrived example, this is already becoming difficult to follow. Let’s see if we can do better.
When programming in a functional style, you’re always looking for simple, repeatable actions that can be abstracted out into a function. We can then build more complex features by calling these functions in sequence (also known as “composing” functions) — more on that in a second. In the meantime, let’s look at the steps we’d take in the process of transforming the initial API response to the structure required by our visualization library. At a basic level, we’ll perform the following actions on our data:
add every number in a list,
calculate an average,
retrieve a single property from a list of objects.
We’ll write a function for each of these three basic actions, then compose our program from those functions. Functional programming can be a little confusing at first, and you’ll probably be tempted to slip into old imperative habits. To avoid that, here are some simple ground rules to ensure that you’re following best practices:
All of your functions must accept at least one argument.
All of your functions must return data or another function.
No loops!
OK, let’s add every number in a list. Remembering the rules, let’s make sure that our function accepts an argument (the array of numbers to add) and returns some data.
function totalForArray(arr) {
// add everything
return total;
}
So far so good. But how are we going to access every item in the list if we don’t loop over it? Say hello to your new friend, recursion! This is a bit tricky, but basically, when you use recursion, you create a function that calls itself unless a specific condition has been met — in which case, a value is returned. Just looking at an example is probably easiest:
// Notice we're accepting two values, the list and the current total
function totalForArray(currentTotal, arr) {
currentTotal += arr[0];
// Note to experienced JavaScript programmers, I'm not using Array.shift on
// purpose because we're treating arrays as if they are immutable.
var remainingList = arr.slice(0,-1);
// This function calls itself with the remainder of the list, and the
// current value of the currentTotal variable
if(remainingList.length > 0) {
return totalForArray(currentTotal, remainingList);
}
// Unless of course the list is empty, in which case we can just return
// the currentTotal value.
else {
return currentTotal;
}
}
A word of caution: Recursion will make your programs more readable, and it is essential to programming in a functional style. However, in some languages (including JavaScript), you’ll run into problems when your program makes a large number of recursive calls in a single operation (at the time of writing, “large” is about 10,000 calls in Chrome, 50,000 in Firefox and 11,000 in Node.js12). The details are beyond the scope of this article, but the gist is that, at least until ECMAScript 6 is released13, JavaScript doesn’t support something called “tail recursion14,” which is a more efficient form of recursion. This is an advanced topic and won’t come up very often, but it’s worth knowing.
With that out of the way, remember that we needed to calculate the total temperature from an array of temperatures in order to then calculate the average. Now, instead of looping over each item in the temperatures array, we can simply write this:
var totalTemp = totalForArray(0, temperatures);
If you’re purist, you might say that our totalForArray function could be broken down even further. For example, the task of adding two numbers together will probably come up in other parts of your application and subsequently should really be its own function.
Excellent! Returning a single value from an array is fairly common in functional programming, so much so that it has a special name, “reduction,” which you’ll more commonly hear as a verb, like when you “reduce an array to a single value.” JavaScript has a special method just for performing this common task. Mozilla Developer Network provides a full explanation15, but for our purposes it’s as simple as this:
// The reduce method takes a function as its first argument, and that function
// accepts both the current item in the list and the current total result from
// whatever calculation you're performing.
var totalTemp = temperatures.reduce(function(previousValue, currentValue){
// After this calculation is returned, the next currentValue will be
// previousValue + currentValue, and the next previousValue will be the
// next item in the array.
return previousValue + currentValue;
});
But, hey, since we’ve already defined an addNumber function, we can just use that instead.
var totalTemp = temperatures.reduce(addNumbers);
In fact, because totalling up an array is so cool, let’s put that into its own function so that we can use it again without having to remember all of that confusing stuff about reduction and recursion.
function totalForArray(arr) {
return arr.reduce(addNumbers);
}
var totalTemp = totalForArray(temperatures);
Ah, now that is some readable code! Just so you know, methods such as reduce are common in most functional programming languages. These helper methods that perform actions on arrays in lieu of looping are often called “higher-order functions.”
Moving right along, the second task we listed was calculating an average. This is pretty easy.
function average(total, count) {
return count / total;
}
How might we go about getting the average for an entire array?
function averageForArray(arr) {
return average(totalForArray(arr), arr.length);
}
var averageTemp = averageForArray(temperatures);
Hopefully, you’re starting to see how to combine functions to perform more complex tasks. This is possible because we’re following the rules set out at the beginning of this article — namely, that our functions must always accept arguments and return data. Pretty awesome.
Lastly, we wanted to retrieve a single property from an array of objects. Instead of showing you more examples of recursion, I’ll cut to the chase and clue you in on another built-in JavaScript method: map16. This method is for when you have an array with one structure and need to map it to another structure, like so:
// The map method takes a single argument, the current item in the list. Check
// out the link above for more complete examples.
var allTemperatures = data.map(function(item) {
return item.temperatures;
});
That’s pretty cool, but pulling a single property from a collection of objects is something you’ll be doing all the time, so let’s make a function just for that.
// Pass in the name of the property that you'd like to retrieve
function getItem(propertyName) {
// Return a function that retrieves that item, but don't execute the function.
// We'll leave that up to the method that is taking action on items in our
// array.
return function(item) {
return item[propertyName];
}
}
Check it out: We’ve made a function that returns a function! Now we can pass it to the map method like this:
var temperatures = data.map(getItem('temperature'));
In case you like details, the reason we can do this is because, in JavaScript, functions are “first-class objects,” which basically means that you can pass around functions just like any other value. While this is a feature of many programming languages, it’s a requirement of any language that can be used in a functional style. Incidentally, this is also the reason you can do stuff like $('#my-element').on('click', function(e) … ). The second argument in the on method is a function, and when you pass functions as arguments, you’re using them just like you would use values in imperative languages. Pretty neat.
Finally, let’s wrap the call to map in its own function to make things a little more readable.
function pluck(arr, propertyName) {
return arr.map(getItem(propertyName));
}
var allTemperatures = pluck(data, 'temperatures');
All right, now we have a toolkit of generic functions that we can use anywhere in our application, even in other projects. We can tally up the items in an array, get the average value of an array, and make new arrays by plucking properties from lists of objects. Last but not least, let’s return to our original problem:
var data = [
{
name: "Jamestown",
population: 2047,
temperatures: [-34, 67, 101, 87]
},
…
];
We need to transform an array of objects like the one above into an array of x, y pairs, like this:
[
[75, 1000000],
…
];
Here, x is the average temperature, and y is the total population. First, let’s isolate the data that we need.
var populations = pluck(data, 'population');
var allTemperatures = pluck(data, 'temperatures');
Now, let’s make an array of averages. Remember that the function we pass to map will be called on each item in the array; so, the returned value of that passed function will be added to a new array, and that new array will ultimately be assigned to our averageTemps variable.
var averageTemps = allTemperatures.map(averageForArray);
Obviously, we want only one array, so let’s write a function to combine them. Our function should make sure that the item at index 0 in the first array is paired with the item at index 0 in the second array, and so on for indexes 1 to n (where n is the total number of items in the array).
function combineArrays(arr1, arr2, finalArr) {
// Just so we don't have to remember to pass an empty array as the third
// argument when calling this function, we'll set a default.
finalArr = finalArr || [];
// Push the current element in each array into what we'll eventually return
finalArr.push([arr1[0], arr2[0]]);
var remainingArr1 = arr1.slice(0,-1),
remainingArr2 = arr2.slice(0,-1);
// If both arrays are empty, then we're done
if(remainingArr1.length === 0 && remainingArr2.length === 0) {
return finalArr;
}
else {
// Recursion!
return combineArrays(remainingArr1, remainingArr2, finalArr);
}
};
var processed = combineArrays(averageTemps, populations);
Last but not least, let’s look at one more real-world example, this time adding to our functional toolbelt with Underscore.js17, a JavaScript library that provides a number of great functional programming helpers. We’ll pull data from a platform for conflict and disaster information that I’ve been working on named CrisisNET18, and we’ll use the fantastic D319 library to visualize that data.
The goal is to give people coming to CrisisNET’s home page a quick snapshot of the types of information in the system. To demonstrate this, we could count the number of documents from the API that are assigned to a particular category, like “physical violence” or “armed conflict.” This way, the user can see how much information is available on the topics they find most interesting.
A bubble chart might be a good fit, because they are often used to represent the relative sizes of large groups of people. Fortunately, D3 has a built-in visualization named pack for just this purpose. So, let’s create a graph with pack that shows the number of times that a given category’s name appears in a response from CrisisNET’s API.
Before we go on, note that D3 is a complex library that warrants its own tutorial (or many tutorials, for that matter). Because this article is focused on functional programming, we won’t spend a lot of time on how D3 works. But don’t worry — if you’re not already familiar with the library, you should be able to copy and paste the code snippets specific to D3 and dig into the details another time. Scott Murray’s D3 tutorials20 are a great resource if you’re interested in learning more.
Moving along, let’s first make sure we have a DOM element, so that D3 has some place to put the chart it will generate with our data.
<div id="bubble-graph"></div>
Now, let’s create our chart and add it to the DOM.
// width of chart
var diameter = 960,
format = d3.format(",d"),
// creates an ordinal scale with 20 colors. See D3 docs for hex values
color = d3.scale.category20c(),
// chart object to which we'll be adding data
var bubble = d3.layout.pack()
.sort(null)
.size([diameter, diameter])
.padding(1.5);
// Add an SVG to the DOM that our pack object will use to draw the
// visualization.
var svg = d3.select("#bubble-graph").append("svg")
.attr("width", diameter)
.attr("height", diameter)
.attr("class", "bubble");
The pack object takes an array of objects in this format:
We see that each document has a tags property, and that property contains an array of items. Each tag item has a name property, which is what we’re after. We need to find each unique tag name in CrisisNET’s API response and count the number of times that tag name appears. Let’s start by isolating the information we need using the pluck function that we created earlier.
However, what we really want is one array with every tag in it. So, let’s use a handy function from Underscore.js named flatten21. This will take values from any nested arrays and give us an array that is one level deep.
We can use pluck again to get the thing we really want, which is a simple list of only the tag names.
var tagNames = pluck(tags, 'name');
[
"physical-violence",
"conflict"
]
Ah, that’s better.
Now we’re down to the relatively straightforward tasks of counting the number of times each tag name appears in our list and then transforming that list into the structure required by the D3 pack layout that we created earlier. As you’ve probably noticed, arrays are a pretty popular data structure in functional programming — most of the tools are designed with arrays in mind. As a first step, then, we’ll create an array like this:
Here, each item in the array has the tag name at index 0 and that tag’s total count at index 1. We want only one array for each unique tag name, so let’s start by creating an array in which each tag name appears only once. Fortunately, an Underscore.js method exists just for this purpose.
var tagNamesUnique = _.uniq(tagNames);
Let’s also get rid of any false-y (false, null, "", etc.) values using another handy Underscore.js function.
tagNamesUnique = _.compact(tagNamesUnique);
From here, we can write a function that generates our arrays using another built-in JavaScript collection method, named filter22, that filters an array based on a condition.
function makeArrayCount(keys, arr) {
// for each of the unique tagNames
return keys.map(function(key) {
return [
key,
// Find all the elements in the full list of tag names that match this key
// and count the size of the returned array.
arr.filter(function(item) { return item === key; }).length
]
});
}
We can now easily create the data structure that pack requires by mapping our list of arrays.
Finally, we can pass our data to D3 and generate DOM nodes in our SVG, one circle for each unique tag name, sized relative to the total number of times that tag name appeared in CrisisNET’s API response.
function setGraphData(data) {
var node = svg.selectAll(".node")
// Here's where we pass our data to the pack object.
.data(bubble.nodes(data)
.filter(function(d) { return !d.children; }))
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
// Append a circle for each tag name.
node.append("circle")
.attr("r", function(d) { return d.r; })
.style("fill", function(d) { return color(d.className); });
// Add a label to each circle, using the tag name as the label's text
node.append("text")
.attr("dy", ".3em")
.style("text-anchor", "middle")
.style("font-size", "10px")
.text(function(d) { return d.className } );
}
Putting it all together, here’s the setGraphData and makeArray functions in context, including a call to CrisisNET’s API using jQuery (you’ll need to get an API key23). I’ve also posted a fully working example on GitHub24.
function processData(dataResponse) {
var tagNames = pluck(_.flatten(pluck(dataResponse.data, 'tags')), 'name');
var tagNamesUnique = _.uniq(tagNames);
var packData = makeArrayCount(tagNamesUnique, tagNames).map(function(tagArray) {
return {
className: tagArray[0],
package: "cluster",
value: tagArray[1]
}
});
return packData;
}
function updateGraph(dataResponse) {
setGraphData(processData(dataResponse));
}
var apikey = // Get an API key here: http://api.crisis.net
var dataRequest = $.get('http://api.crisis.net/item?limit=100&apikey=' + apikey);
dataRequest.done( updateGraph );
That was a pretty deep dive, so congratulations on sticking with it! As I mentioned, these concepts can be challenging at first, but resist the temptation to hammer out for loops for the rest of your life.
Within a few weeks of using functional programming techniques, you’ll quickly build up a set of simple, reusable functions that will dramatically improve the readability of your applications. Plus, you’ll be able to manipulate data structures significantly more quickly, knocking out what used to be 30 minutes of frustrating debugging in a couple lines of code. Once your data has been formatted correctly, you’ll get to spend more time on the fun part: making the visualization look awesome!
Retouching pictures of human beings is one of the most common tasks in image editing. Beauty needs to be perfect these days. We don’t want to see how people actually look, but how we imagine them to look. Only superlatives suffice. If you like that or not, chances are if you are part of our industry, you’ll have to deal with these tasks more often than not. The variety is wide – from removing pimples, whitening teeth and establishing a noble paleness to butt reductions and breast enlargements. Create your own beau ideal. If you want or need or have to get skilled in virtual plastic surgery, these 40 tutorials will do the job. You’ll have to bring Photoshop, though.
There are many strategies to choose from when developing a modern, device independent website nowadays. How should capabilities of the device or browser be determined? Should the presentation logic be server side or client side? Traditionally, mobile optimization had to happen server side.
Over the last couple of years, Responsive Web Design and tools like Modernizr1 have become very popular. Recently, combination techniques (often called RESS2), where optimization is done both server-side and client-side, has become a trend. The recently launched WURFL.js3 tool, fits into this category.
In this article, we will look at some basic use cases of how to use WURFL.js to optimize the user experience both in HTML and CSS, and an example of how to choose the right ads to display on different devices. We will also see how WURFL.js is different from, but complements, the popular feature-detection library Modernizr.
Once Upon A Time, Device Detection
Whether we are using regular expressions in JavaScript, Modernizr or a complete device-description repository4 (DDR) for server-side detection, the purpose is usually the same: to give users a better experience. This typically happens at two levels:
presentation of content and interaction with the service,
analysis of user behavior to determine usage patterns.
The challenge is to do this in ways that are both scalable, maintainable and, as much as possible, easy to implement. For some projects, the cost and complexity of deploying third-party tools on servers is too high. Yet a low-maintenance solution that lets a website look good and perform well is possible, despite the constant diversification of devices. This is where WURFL.js plays a role, by providing a scalable alternative to traditional server-side device detection, all the while complementing other client-side techniques and tools.
Before diving in, let’s look at the basics.
Copy, Paste, Done
No registration is required, and WURFL.js is free to use5. So, the first thing to do is copy and paste this line of HTML into your page:
Both HTTP and HTTPS are supported. If you plan to use the device information provided by the script to make rendering decisions, then you might want to include the script in the element. Otherwise, you can load it asynchronously.
Now that the script is in your HTML page, you can access the WURFL object in JavaScript. The WURFL object looks like this and is ready to use:
complete_device_name
This is the name by which the device is known — typically, the make and model or a category of devices or a more generic definition.
form_factor
desktop
app
tablet
smartphone
feature phone
smart TV
robot
other non-mobile
other mobile
is_mobile
This is true or false — true if the device is a tablet or other mobile device.
Of course, you can immediately do things like this:
console.log(WURFL);
Or this:
alert(WURFL.complete_device_name);
Under The Hood
Because WURFL.js detects the device based on the User-Agent string and other information provided in the HTTP header, the contents of the JavaScript file will depend on the device. So, you can’t just copy the contents of the file and put it inline in the HTML or combine it with another JavaScript resource.
To understand this in detail, let’s look at the illustration above. The browser makes a request for example.com (1). The markup returned by the Web server (2) contains the reference to WURFL.js. Next, the browser renders the HTML and starts fetching assets — among them, wurfl.io/wurfl.js (3). When the request reaches WURFL.io, the HTTP request is analyzed by WURFL. Usually, based on that request, there will be an instant hit, and the device is identified without further ado, and a single WURFL JavaScript object is returned. However, in certain cases when the device cannot be identified on the server side alone (notably, in the case of iOS devices), the JavaScript file will contain a few more checks to determine the device. The browser then evaluates the JavaScript, and the WURFL object is ready to use (4).
WURFL.js is capable of, for example, distinguishing between an iPhone 5 and an iPhone 5S, thanks to this extra client-side logic. This is a big deal because this use case is supported neither by sheer User-Agent analysis7 nor by Modernizr tests.
A Note On Performance
If you use WURFL.js to make rendering decisions or, for some reason, you need to place the tag inside (without deferring it), then the browser will wait for the script to be downloaded and evaluated before rendering the page. Depending on the use case, this might be the only way; but, for the record, WURFL.js can also be loaded asynchronously to increase rendering performance.
The size of the returned JSON object will be fairly small, varying from 0.5 to 3 or 4 KB, depending on the device. Compared to Modernizr (about 14 KB) and jQuery (96 KB), WURFL.js is arguably light.
Use Cases
Assuming that you have WURFL.js up and running, let’s look at some cases in which using WURFL.js makes the most sense, either by itself or in conjunction with Modernizr and/or other solutions. To illustrate, we’ll refer to the WURFL.io website8 itself, which utilizes WURFL.js in multiple ways.
Optimizing the User Experience
When it comes to mobile, responsive and adaptive design and all that, the most common thing to do on a website is improve the user experience for certain device families or form factors. Much can be handled by media queries, of course, but sometimes you need the help of some JavaScript.
When you visit WURFL.io9 on your laptop, the top section of the page has a video background, some simple parallax scrolling and text that changes dynamically according to the device or browser. It looks very cool on a laptop, but video backgrounds, not to mention parallax scrolling, would not be ideal on a tablet or smartphone, to put it mildly.
We could use Modernizr, of course, or decide whether to implement these features in other ways. But in many cases, knowing the physical device is just as important as — perhaps more important than — knowing whether the browser claims support for a feature. We might encounter a problem whereby the browser claims support, but the support is actually not good enough to make a great user experience.
To avoid these situations, you would use WURFL.js and Modernizer together. Note also that comparing WURFL.js and Modernizr directly is not quite fair. Modernizr detects features claimed by the browser, whereas WURFL.js categorizes the device in different ways. So, if you don’t know whether a particular device or form factor supports a certain browser-detectable feature, then you are better off with Modernizr or a full-fledged device-detection solution11.
However, in this example, we’ll rely on WURFL.js and demand that only non-mobile clients get the video background and parallax scrolling:
The example above simply checks whether the device is mobile (a phone or tablet) and introduces features accordingly. Of course, we could also leverage the more fine-grained WURFL.form_factor.
Put More In CSS?
The examples above show how to make use of the device’s data in JavaScript. However, we can make the device’s information available in CSS, too. We can assign different styles depending on the device, form factor and whether it is mobile. The first technique we will look at is similar to how Modernizr works. Modernizr adds a certain class to the HTML document depending on whether its test returns true or false.
Let’s say you want some specific behavior defined in the CSS for mobile devices. You would need to add the following JavaScript snippet to your page:
In this simple example, we’ve increased the padding on menu items so that they are easy to tap with a fat thumb.
This method can be used for all of WURFL.js’ capabilities. However, because complete_device_name and form_factor are not boolean values (like is_mobile), the CSS part can become quite a headache. A bit more flexibility might come in handy, then. Here is an example using data- attributes:
This will put data attributes with WURFL capabilities in the html element. We get several cool features with this method: We can target specific devices, form factors and even groups of devices combined with form factors by using CSS selectors:
The CSS above will match Nokia feature phones of any model.
The screenshot above illustrates what the DOM looks like with the two methods implemented — in this case, with an iPhone 5S.
Help With Banner Ads
Many different ad networks are out there, each with its own specialization. Some are good for mobile, others for desktop. Some support text ads, other have ads of fixed size. If you are beyond a beginner’s level in ad networks, then you might want to assume some control over this. WURFL.js can help you make your own decisions or influence the network to make the right decisions for you.
The obvious approach is to ask WURFL.is_mobile to choose networks or ads that are good for mobile and others that are good for non-mobile.
Moreover, from a design perspective, being able to fit the sizes and proportions of ads to your breakpoints and to design for different form factors of ads is nice. In the extreme, you could do something like this:
switch(WURFL.form_factor){
case "Smartphone":
if(WURFL.complete_device_name.indexOf("Apple") !=-1){
showAppStoreAds();
}else(
showWebAds();
)
break;
case "Tablet":
showSpecificProportionAds();
break;
case "Feature Phone":
showTextAds();
break;
default:
showGoogleAdwords();
break;
}
Conclusion
If you’ve tackled the diversity of devices in the past, then you’ll know that many developers have been looking for JavaScript tricks to detect browsers, devices and their respective features. Traditionally, a DDR required server-side libraries and data to be installed and for the device-description repository to be updated. WURFL.js improves on this by making the power of WURFL available to web developers free of charge13.
Whether for analytics, optimization of the user experience, advertising or something else, consider WURFL.js when developing a modern, mobile-aware and device-independent website. WURFL.js complements Modernizr nicely. While Modernizr detects support for certain features of the browser, WURFL.js provides information about the user’s physical device that is not detectable through browser APIs.
WURFL.js is a bridge between the server side and the client side, making it easier for front-end Web developers to take advantage of functionality that used to belong on the server. It can even be used for current websites that have been designed responsively or that enhance progressively.
“I hate that client”, how often have these words come out of your mouth. Often enough! Don’t worry; most web designers have a list of clients they’ve absolutely hated working with. These are clients who made working with them an agonizing experience, with no redeeming features whatsoever. Collaboration with such clients becomes a torturous exercise, which means you don’t enjoy working on their projects. This is a real tragedy because designers must feel invested in their web design projects, in the absence of which their designing decisions will be found wanting. Some clients are just plain difficult, others are rude and abrasive, there are a few who are penny pinchers and there are others who arrogantly assume they know way more about web design than you do.