Showing posts with label CSS3. Show all posts
Showing posts with label CSS3. Show all posts

Quicktip: Skewing an image with JavaScript and CSS3

Have you ever found yourself in a situation where you needed to skew a rabbit? If you haven't, you'll probably enter this place soon, so here I am to prepare you. The task is to skew an image on a HTML page using CSS and JavaScript. This could be attached to for instance a button click event. This is a one liner..
document.getElementById('myImage').style.transform = "skew(-15deg)"
The «skew» property of the «transform» CSS method takes degrees of skew as an input. Negative numbers will skew the image top right, bottom left and positive numbers..the other way around.
Note that in order for this to actually work, you will need to use vendor prefixes as the time of writing this post. For Safari (desktop and iOS) and Chrome (and Android) you would use «webkitTransform» for FireFox «mozTransform» and so on.

The Peacekeeper

Peacekeeper on an iMac 3.0 Ghz
I decided to try out Futuremaks spanking "new" Peacekeeper browser tester today. In contrast to other more "nerdy" tests like Acid3 and SunSpider which are useful for people like me, Peacekeepers tests are more targeted at actual normal usage of a browser, making it slightly more interesting for users without a degree in computer science.

On the other hand, if you want to understand the six test, well.. it gets a bit technical. The first test «rendering» is a test of how fast the browser can draw stuff to the screen, while doing other calculations and operations at the same time. The second test which Futuremark calls «social networking» is actually a test in how fast the browser can create a SHA1 hash, parse some XML and filtering and sorting the elements of an array. Thirdly we arrive at the «complex graphics» test, which is a test on canvas drawing operations, canvas being part of the new HTML 5 standard. The «data» test which I have renamed to "arrays" does work on exactly that, array manipulation. The «DOM manipulation» test, is one of the most important tests as this tests the browsers ability to look up elements in the DOM fast. This should be of particular interest to jQuery fans. The last test «text parsing», is what its name suggests, parsing and searching in strings. To get a full detailed explanation of what the individual test entails, see Futuremarks FAQ site.

My testcomputer was an iMac 3.06 GHz, with 8GB of RAM and an ATI Radeon HD 4670 graphics card running OS X 10.6.7. It matters, because these tests will very, much, depending on your computer and OS.

As for the results one can clearly see that the WebKit browsers beat the snot out of Firefox. Chrome is clearly the fastest browser overall, however for DOM manipulation Safari is slightly faster than Chrome. Again, beware of this one jQuery fans because this is where all those selectors come into play. Chrome is ruling the array manipulation speed, this might be due to the V8 JavaScript engine. All the browsers basically suck when it comes to rendering HTML 5 Canvas graphics. As a side-note, I observed a test that was run on a Windows based computer as well. To our surprise, both Chrome and Opera beat Internet Explorer 9 into the slippers when it came to canvas performance. Beauty of the web my ass, in your own tests internally made tests perhaps.

Conclusion
So, judging from this Google Chrome is the browser your should go for. And in my opinion, it is. For me, I'm sticking with Safari for my day to day use, but I'm using Chrome when writing this blog post.

Scaling and rotating an elephant using JavaScript

This second post about «touch» is somewhat an extension to my previous post «Drawing by touching using JavaScript». However in this post the focus will be on «gesture events». A gesture event is an event which will fire when more than one finger is present on the screen. Due to the somewhat complex nature of the accompanying demo, I will not walk through it line by line, but rather focus on some key ares which are important when dealing with touches and gestures.
Step 1 is to take a look at the demo and read through my comments. To understand this you will need a basic understanding of object oriented JavaScript and I will not walk through that part of the demo in this post. What I will explain in some detail is how the gesture events work (to see how touch events work, refer to my previous post) and some nifty tricks you can do with event handlers and transforms. Oh..and you will be needing a touch device to test this thing. Let's get cracking then.

The basic functionality of this demo is to place images on the page which have some touch and gesture events applied to them. This will allow us to move, scale and rotate the images using gestures. An array «elephants» is used to keep track of all the images on the page. On line 70 (in the demo JavaScript file) an Object called «TouchImage» is defined. This object will keep track of all events and transforms associated with one image. We create a new «TouchImage» on line 52. This happens for every time you hit the «Create elephant» button. Then on line 99 - 104:
tImage.image.addEventListener('gesturestart', tImage, false);
tImage.image.addEventListener('gesturechange', tImage, false);
tImage.image.addEventListener('gestureend', tImage, false);
tImage.image.addEventListener('touchcancel', tImage, false);
tImage.image.addEventListener('touchstart', tImage, false);
tImage.image.addEventListener('touchend', tImage, false);

Now, this might look a bit strange, we're passing «this» («tImage» is a closure for «this») as the event handler for the listeners. This is because at line 117 we define a method called «handleEvent» on the «TouchImage». This is a magical method in JavaScript which will basically handle any event passed to it's object. Within this method we check to see if the caller is a function and if it is, we simply call it.
TouchImage.prototype.handleEvent = function(event)
{
 if(typeof(this[event.type]) === "function"){
  return this[event.type](event);
 }
}
This way we can extend the «TouchImage» object with methods called «gesturesstart» and so on, the same names as the events. An additional plus is that we stay within scope of the object, avoiding to pass closures around like rag dolls. Now to the gesture handlers. In contrast to «touch» handlers, there are only three «gesture» handlers: «getsurestart», «gesturechange» and «gestureend». Each of these will trigger only if there are more than one finger on the screen.
TouchImage.prototype.gesturestart = function(event)
{
 event.preventDefault();
 this.startRotation = this.rotation;
 this.startScale    = this.scale;
}
In «gesturestart» which triggers when a second finger is placed on screen, we capture the current scale and rotation values of the «TouchImage» in question.
TouchImage.prototype.gesturechange = function(event)
{
 event.preventDefault();
 
 this.scale    = this.startScale * event.scale;
 this.rotation = this.startRotation + event.rotation;
 
 this.applyTransforms(); 
}
In «gesturechange» we calculate the scale and rotation by using the start values and the changed values. The scale is multiplied with the new scale and the rotation is calculated by adding the start rotation to the current rotation. This works because both values in the change handler will give us the amount changed since the start event. Then we call the «applyTransforms()» method where the actual transform is done.
TouchImage.prototype.applyTransforms = function()
{
 var transform = 'translate3d(' + this.posX + 'px,' + this.posY + 'px, '+this.posZ+'px)';
 transform += ' rotate(' + this.rotation + 'deg)';
 transform += ' scale(' + this.scale + ')';
 this.image.style.webkitTransform = transform;  
}
The transform is done on all properties at the same time. You cannot separate them from each other, because we are in effect overwriting the entire transform style element each time something is changing. Do also note that we are in fact using «transform3d», which is quite different from the regular «transform». The reason for this is twofold. First, the «transform3d» will render the image on it's own 3D layer, at times triggering hardware rendering. This will yield a significant performance increase. Secondly, the «transform3d» allow us to stack elements in the «z-axis», hence we can move the active element to the front. We do this sorting by  calling the «sortDepth» method, which only sorts the «elephants» array.

That's the gesture events. Now, there are regular touch events in this application as well. These are used to move the «TouchImage» objects around the screen. I won't cover how this is done in detail here because it's much the same as in the previous post. However one thing to notice is that an offset is calculated in the «touchstart» handler. This is done so that when moving the image it tracks from the point where the user places her finger on the image. If we didn't do this the image would snap to 0,0 under the users finger when moved, making for an unexpected user experience. That's it and that's that!

Quicktip: Flipping an image with JavaScript


Let's say you wanted to flip an image in you web-app horizontally or vertically. By using a tiny bit of JavaScript and CSS 3 this is really easy.

//Get the image
var img = document.getElementById('myimage');
//Flip it horizontally
img.style.webkitTransform = 'scaleX(-1)';


And you're done! Note that this will only work in webkit browsers. The equivalent for Mozilla browsers would be «img.style.MozTransform». To flip the image vertically you could use: «scaleY(-1)». And to flip both horizontally and vertically at the same time: «scale(-1,-1)».

[edit 17.03.2011]
You can of course do this in other browsers besides Gecko or WebKit based browsers, as pointed out in the comments. Safari will actually support both the «webkit» and the «Moz» prefix, but this will most likely go away soon. So what you'll need to use is feature detection. This will still not work in ALL browsers, but the usable ones will most likely support it.
if(img.style.webkitTransform){
  img.style.webkitTransform = 'scaleX(-1)';
}else if(img.style.MozTransform){
  img.style.MozTransform = 'scaleX(-1)';
}else if(img.style.OTransform){
   img.style.OTransform = 'scaleX(-1)';
}else if(img.style.msTransform){
   img.style.msTransform = 'scaleX(-1)';
}else{
   img.style.transform = 'scaleX(-1)';
}

9 things I've learned about web-development

I've been a developer for quite some time now, meddling with both the web-centric and the native side of things. As of lately, that is for the last 3 months or so I have focused more in depth on "standards" based web development. Meaning HTML, CSS and JavaScript. Even if I've been writing HTML since 1996 (yeah, I'm getting old), I have never really bothered to really focus in depth on the basic building blocks of HTML, CSS and JavaScript, until now. 4 books and many many hours of training videos later I feel that I've learned something, which is that an iPad make for a lousy pillow if you keep trying to sleep on it! But more than that, I found 9 things that I have learned, which may be blatantly obvious to you if you are a fancy pantsy web-developer, but then again, maybe you'll learn something new?

1. Web-designers and web-developers think differently.
What do I mean by that? Consider of how you're tagging your HTML with classes and id's. The designer approach to this would be classes all the way, then using the clever selector syntax of CSS to reach the nested areas of the document. This makes sense when working with formatting. Developers tend to view the HTML as a framework with components. Classes are used for formatting while id's are used to identify areas of the markup one would need to reach via JavaScript. Designers will prioritize the "flow" of the «document» whilst developers don't consider it a document at all. I don't think either approach is «correct» or «wrong», it's just two ways of approaching the same challenge.

2. CSS is not a layout language.
Almost all layout in modern HTML based webpages are done using CSS, so how can anybody claim that it's not a layout language? I too was somewhat surprised when time and time again the "people who knew what they are talking about" kept repeating this. From the WHATWG to W3C and several books on the topic kept driving this home..«not a layout language». Turns out, CSS is a formatting language with some layout features. Semantics? Well, not really. If you compare CSS 2.1 to a "real" layout language like MXML you'll soon notice a big difference. Layout languages, or UI markup languages have special layout components to group element, flow elements, sort elements both horizontally and vertically. CSS 2.1 does not have this, it's totally reliant on either floats or absolute positioning. This will better with the introduction of the flexible box model in CSS3, but still it will remain a formatting language at heart.

3. CSS selectors are incredible powerful...stuff
This is one of the areas on which I have discovered most new stuff. CSS 2.1 embodies most of them, but with the introduction of the CSS 3 standard, selectors can now do some amazing stuff. Conditional child selection, substrings within attributes while traversing child elements are just some examples. And the best part is that they are largely supported in all modern browsers, including Internet Explorer 8. If I where to recommend one area on with to focus you attention, if you don't already know this, it would be CSS selectors. It's not complicated or hard to understand, there are just so much under the hood which can make your CSS writing a lot more enjoyable.

4. Things will look different in different places.
If you try to create pixel perfect designs across all browsers and platforms you will go bonkers, that is unless you are a technophile machochist whom derives enjoyment from banging your head up against the gigantic wall of Internet Explorer inconsistency. You're much better off using either the progressive enhancement or the graceful degradation approach where you serve different users the same content, only wrapped in a slightly different presentation. This way Internet Explorer users can sit and stare at that black and white page of rich text all day long, while us WebKit fanboys can swim in the loveliness that is a modern browser with animations and shit.

5. A position is not the same position elsewhere, or everywhere.
Since this is more or less an extension of point 4, I can't be bothered to find a pretty picture for this one. (As a side note, if you use Google image search for the term "position", turn safe search on!) What this point is concerning, what I've found is: Firefox and Chrome (or any other browsers) does not have the same interpretation when it comes to rendering a point at, say x: 100, y: 100. Since it's up to the user agent (browser) to parse your CSS and HTML and then draw it on the screen, you will at certain points end up in a situation where an absolute point in the top left coordinate system will differ from user agent to user agent and even on the same user agent on different operating systems. This can be avoided by using floats and containers instead of using absolute positioning. But, it's better to accept that things might not look exactly the same everywhere.

6. Modernizer Rocks!
If you ever need to use conditional CSS 3 or HTML 5, Modernizer is by far the best solution I've found. The way Modernizer works is actually twofold. You can first use it with CSS directly. Lets say you want to take advantage of the RGBA color model found in CSS 3, but you also need to support those pesky Internet Explorer users. All you need to do in your stylesheet is to prefix your class or id selector with ".rgba". Let's say I wanted to apply a style via the selector «h2[class*="onkey"]», but only for browsers supporting RGBA. It would look like this: «.rgba h2[class*="onkey"]». The RGBA class simply adds itself as a ascendant class. This style would then only apply if RGBA was supported. The other way of using Modernizer is with JavaScript. To check for support for H.264 video playback abilities, simply use «Modernizer.video.h264» and it'll return false, "maybe" or "probably". Yep, that is the HTML 5 spec for video format detection..

7. jQuery selectors are convenient, JavaScript is fast!
If you don't know what jQuery is, you should go find out! Someone once wrote that jQuery is Gods gift to JavaScript. Where God is of course John Resig and I was the one that wrote that, just now in fact. jQuery is seriously awesome, it allows for fast and easy cross browser development. Underscoring cross browser, which is what it does really really well. It is just a JavaScript framework, a tiny one at that, but crammed with neat functionality, from animations, ajax loading and the usage of CSS selectors to get a hold of DOM elements. You can say things like: «jQuery('div.donkey')» which would give you all the donkey divs in the page. This is really convenient, because you can find stuff in the DOM with the same syntax used in the CSS. There is a downside however. When using CSS selectors in a CSS file or in the HTML file, the user agent takes care of all the heavy lifting required to traverse the DOM and find those elements. This is fast because the user agent does this natively using a compiled language such as C. However, jQuery is not written into the native part of the browser and will therefore need to use JavaScript to traverse the DOM to find the elements based on the CSS selector. Hence using the build in JavaScript functions «getElementById», «getElementsByTagName» or the spanking new «getElementsByClassName» is much faster than using the jQuery selectors. What you can do is combine them like so «jQuery(getElementById('id-name'))». Then you would get the speed of the native JavaScript functions while keeping all the jQuery goodness as well.

8. There are datatypes in JavaScript!
!!Nerd alert!! Even if you don't explicitly declare datatypes in JS, there is a difference between for example «"2"» and «2». If you where to add these two values together «"2" + 2», you'd get «"22"», while «2 + 2» returns «4». Now, what if «a = [2,3,"a"]» and «b = 2». What would «a + b» give you? That's right «a + b => "2,3,a2"». JS has a lot of functions for dealing with this. You have «toString()» to convert a number to a string, «parseInt(strNum)» to convert a string into a whole number and so on. The important thing is to be astutely aware of it, even if you can't declare a strict datatype.

9. The WebKit Web Inspector is your most important tool
If you're in any WebKit browser, Safari, Chrome so on you have access to the build in "Web Inspector". This tool is your best friend when working with HTML, CSS and JavaScript. It will do anything the more famous Firebug does and more. Don't get me wrong, I'm not railing on Firebug which is an awesome tool, I am however highly recommending the WebKit Web Inspector because of it's speed, advanced profiling tools and unsurpassed JavaScript debugger. Try it and you'll see why I'm praising it!

So that's it, or more likely, that's some of it. If you have actually read all the text down to this I truly hope that this post have contributed in some small way to your blah blah blah blah..you know the drill. Now get back to work, those recursive functions won't be creating themselves ;-)

Shifting the attention - facing forward.

“Innovation is the ability to see change as an opportunity - not a threat”. - Unknown

This is not where I'm going to announce to the world that I'm leaving the FlashPlayer platform behind all together. Nor is this where I'll tell you to forget everything you know, gather you wits about you and start over. No, this is where I'll tell you what I've learned, how I've learned this and why this is.

Like Borland Delphi back in the days, the Adobe FlashPlayer architecture is dying without itself being aware of it. It's not because Flash content is evil, nor because the FlashPlayer is particularity crappy. Still, many sites, like YouTube are heavily dependent on the FlashPlayer in order to display their content. This will be true for quite some time. However, at the same time, all these sites still depending on the FlashPlayer do not express enthusiasm for it, it's seen more as a necessary evil in order to get the job done while we are waiting for something better. Well, change has come to the interwebs..and it's called HTML 5.

HTML 5 is acctually a standard being developed by the World Wide Web Consortium. Like HTML 4 it's a specification used by browser vendors to integrate the support into their browsers. This by it self means that  individual browser vendors are responsible for the performance of HTML content in their browsers, effectively launching a race to be the fastest browser. This is a win for HTML 5 over Flash, seeing as Flash Player has no real competitors, because Adobe is the sole vendor. However, HTML 5 and it's companions CSS 3 and JavaScript cannot accomplish the same as the content you create using Adobe Flash, or so many people think. Actually, it can. Both 2D animations, 3D animations, advanced text layout and so on is readily available using HTML 5. So is advanced interactions. What HTML 5 does not have, that Flash do have, is an advanced authoring tool. Using HTML 5 may require more development skills, longer production time and more work to achieve the same result as using Flash authoring, today. This will change in time as HTML 5 skills grow more common amongst web-developers and the marked for great tools enlarges.


“Innovation distinguishes between a leader and a follower.” - Steve Jobs

Let's not forget the devices. The iPad, the iPhone, Android devices and the Google Chrome OS. These are the platforms of the future, the PC is not. Yeah, PCs will still be around, we as developers will still adhere like superglue to our Macs and Chrome computers. But, the normal users, aka. "most people" will not. Flash belongs to the PC era, HTML 5 is build for the touchscreen generation. This is kinda hard to see if you don't look closely, but think about it. How many iPads and iPhones does Apple sell? A lot! How many Android devices are there? A lot! Granted, Android phones do have a FlashPlayer, but have you tried it? Yes, it really sucks. And that is the most devastating blow to the FlashPlayer, the experience on future devices sucks or it simply isn't supported like on iOS devices.

Change is one of the most difficult things for humans to endure. We don't play well with it at all, but sometimes it's for the better. Remember, there is nothing wrong with plugin based technologies like FlashPlayer or Silverlight, like there was nothing wrong with the horse and carriage. But, now we drive cars, even if they can't do everything horses can do. This does not, however, mean that we hate horses, does it?

Resulting from my contemplation is an understanding that my attention will focus on the utilization of standard based technologies in the foreseeable future. I believe HTML 5 and all its companions will be the way of future web-based solutions. Flash is not dead, will perhaps never die, but if you're starting out today as a greenhorn developer, go for the future. And if you are a seasoned web-developer like myself, embrace this opportunity to learn new things, to start from "scratch".

Some great HTML 5 demos can be found here: