I'm Dudley Storey, the author of Pro CSS3 Animation. This is my blog, where I talk about web design and development with HTML, CSS and SVG. To receive more information, including news, updates, and tips, you should follow me on Twitter or add me on Google+.

my books

Pro CSS3 Animation, Apress, 2013

Using SVG with CSS3 and HTML5, O'Reilly, 2017

my other blogs

Massive Head Canon: Intelligent discussion of movies, books, games, and technology.

my projects

The New Defaults — A Sass color keyword system for designers. Replaces CSS defaults with improved hues and more memorable, relevant color names.

CSSslidy — an auto-generated #RWD image slider. 3.8K of JS, no JQuery.

javascript

A blog that covers web development, including works in progress and technologies like CSS3; travel (especially solo bike touring); critiques of books, films and plays.

May 26 2009

CSS 3 Transforms and JavaScript

The end of the fall semester was particularly disappointing, at least in regards to my second year students . While the usual factors were at play – lack of attention to detail (or lack of any kind of attention at all), tiredness, stress, and rushed, last-minute work – there was something else missing in the final project. I saw a lack of creativity that reflected not just those factors, but a general lack of confidence and fluency in CSS itself.

In response, I started the last winter semester in the completely opposite direction from normal, breaking out multi-colored posterboards and glitter pens and glue, and giving the students only one command: “design!”

Again, some of the results were disappointing (mostly because of lack of innate talent, or because they were terrified of (or unfamiliar with) holding a pen in their hand and being asked to draw), but less so than the efforts of the previous semester.

As part of the goal to inspire and free up their designs, I showed both classes draft pages of my portfolio website – which were inspired, in turn, by their own portfolio sites, and the entirely justified goading of the 1st years to “show us what you can do.” You can see a mockup of the basic design to the left: essentially, I wanted the large portfolio images to appear like Polaroids in a scrapbook. My goal in sharing this with the class was to emphasise that not everything in web design has to be at rigid right angles, or standard top-left navigation configuration, if the changes were logical, consistent, and warranted.

Of course, some of the students took this a little too literally, and started to design everything on their pages at an angle, but on the whole the experiment seems to have been a success. After SAIT’s reading week, my goal is to critique those designs, then turn them into PhotoShop work, and from there explore the CSS and markup necessary to turn them into full web sites.

In the meantime, I continued to work on my own portfolio site. It occurred to me very quickly that the technology behind the design was crude and inefficient. For each image, I was forced to go into PhotoShop, rotate the image, stroke the outside to place a border on it, generate a dropshadow, and place “Scotch tape” layers on the corners, before slicing and exporting it. Of course, PhotoShop actions could automate part of this process, but not all – I wanted the rotation to be essentially random, within a range of 4 degrees positive or negative. Naturally, in order to gain the full effect and preserve the background image in the body behind it, the portfolio image had to be exported as a 24-bit PNG, which ramped up file sizes dramatically.

Considering the problem, I knew I could generate the photo border easily enough with a CSS border property. I also knew that CSS3 supported box-shadow, albeit implemented slightly differently between Safari and Firefox, while the spec remains in draft. I wasn’t sure that drop-shadow would take into account the border (as it turns out, it did), but my first real problem was rotating the image in the browser.

A glance at a mention of “CSS transforms” and a little research revealed that CSS3 is also pushing towards scale, skew and rotational transforms of elements. Again, easy enough to implement as a fixed style:

<img src="assets/images/milk-and-cookies.jpg" style="-moz-transform:rotate(5deg); -webkit-transform:rotate(5deg);" />

The visual quality of the rotation in the browser was not as good as doing the same routine in PhotoShop, but it was close enough – and the difference in file size (since I could now save just the portfolio image as a JPEG, without border, Scotch tape or drop-shadow) and workflow efficiency was huge.

But I wanted the rotation to be random, to avoid the website looking predictable and staid. Well, it was easy enough to generate a random number in JavaScript, in this case between -4 and 4:

  1. var obj = document.getElementById('bigpic'); // large image always has an id of "bigpic"
  2. var min = -4; // maximum negative rotation of the picture
  3. var max = 4; // maximum positive rotation of the picture
  4. var randomRot = Math.floor(Math.random()*(max-min+1)+min); // provides a random number between -4 and 4.

The problem then became applying the transformation to the element via JavaScript, rather than CSS. I could have used a library like JQuery to speed things up, but I was determined to do it myself, in just a few lines of code, and this is what I found:

  1. var rotate = "rotate(" + randomRot + "deg)"; // formats the rotate amount for the CSS
  2. obj.style.webkitTransform = rotate; // transform for Safari
  3. obj.style.MozTransform = rotate; // transform for Firefox

Success! I could now watch the portfolio iamge happily twist from side to side with each page refresh. Then, I had to put the Scotch tape in the corners. This proved to be the challenging part. There is talk of future CSS specs allowing element position based on calculation from another element, but that is still very much in draft, and not implemented in any browser that I’m aware of. Lacking that, I needed to find a whole bunch of information about the position of the large portfolio image - it’s height, width, left and right - via JavaScript.

This was made more complicated by the fact that I did not have the large image absolutely positioned: keeping with the tenets of fluid design, I wanted it relative to the list of smaller thumbnails beside it. Future design revisions could also see it nested inside elements, or below others. A little bit of webcrawling brought me to this page, which provided a function, which under most (but not all) circumstances, would find the left and top of any element on a page. I also used getPropertyValue to gain the width and height. (And if you’re interested, the width, height, left and right of an object do not change just because an element is rotated – JavaScript draws its data from the original box of the object).

  1. var yPos = findPosY(obj); // finds the vertical position of the big picture
  2. var xPos = findPosX(obj); // finds the horizontal position of the big picture
  3. var height = parseInt(document.defaultView.getComputedStyle(obj,null).getPropertyValue("height")); // height of the big pic
  4. var width = parseInt(document.defaultView.getComputedStyle(obj,null).getPropertyValue("width")); // width of the big pic

With that known data – the top and left of an object, along with its width and height - I could quickly calculate the corners of the large image (pre-rotation), and absolutely position Scotch tape images in those locations (as a test, I used vector rectangles exported as PNGs from PhotoShop).

The result was great if the portfolio image only rotated a degree or so, but the Scotch tape was visibly out of place if the large image was rotated to its maximum extent. I knew the rotation amount, but the problem was that all transformations happen from the visual center of an object by default. In other words, the Scotch tape images would rotate like a propeller if the same transformation was applied to them – I needed rotation around the center of the large portfolio image.

After a silly moment of working out the trigonometry to achieve this, I realized that the wizards of CSS do allow for repositioning the transformation origin of an element anywhere. There are a bunch of keywords for positioning the origin inside the element, but I wanted it outside, in the center of the large image. I knew the width and height of the image, so finding its midpoint was easy:

  1. var bigoriginy = (height/2);
  2. var bigoriginx = (width/2);
  3. // gets the center of bigpic horizontally and vertically

Then, I just needed to set the origin of the Scotch tape pieces appropriately and rotate them the same amount as the large image.

The script I had written thus far worked for my test cases of the top left and bottom right pieces of Scotch tape, but repeating lines of code for each transformation would be wasteful. Instead, I made an array based on the ids of the scotch tape pieces. Based on this, a logical naming scheme, and a search to find appropriate words in the id values of the elements, I then had the ability to apply the transformations I needed in a single for loop:

  1. var tape =
  2. new Array('top_left_corner_tape', 'top_right_corner_tape', 'bottom_left_corner_tape', 'bottom_right_corner_tape');
  3. for (var i = 0; i < tape.length; i++ ) { // do this to all the pieces of tape
  4. thistape = document.getElementById(tape[i]);
  5. if (tape[i].match("left")) {
  6. // if element ID has the word "left" in it, calculate left of tape as being close to left of bigpic
  7. thistape.style.left = (xPos - 30)+"px";
  8. var originx = bigoriginx;
  9. // the x distance of the origin for pieces of tape on the left is the horizontal midpoint of the bigpic
  10. }
  11. if (tape[i].match("right")) {
  12. // if element ID has the word "right" in it, calculate left of tape as being close to right of bigpic
  13. thistape.style.left = (xPos + width - 40)+"px";
  14. var originx = "-" + bigoriginx;
  15. // the x distance of the origin for pieces of tape on the right is the horizontal midpoint of the bigpic
  16. }
  17. if (tape[i].match("top")) {
  18. // if element ID has the word "top" in it, calculate top of tape as being close to top of bigpic
  19. thistape.style.top = (yPos - 40)+"px";
  20. var originy = bigoriginy;
  21. // the y distance of the origin for pieces of tape at the top is the vertical midpoint of the bigpic
  22. }
  23. if (tape[i].match("bottom")) {
  24. // if element ID has the word "bottom" in it, calculate top of tape as being close to bottom of bigpic
  25. thistape.style.top = (yPos + height - 20)+"px";
  26. var originy = "-" + bigoriginy;
  27. // the y distance of the origin for pieces of tape at the bottom is the vertical midpoint of the bigpic, signed negative
  28. }
  29. thistape.style.MozTransformOrigin = originx + "px " + originy + "px"; // origin format for Mozilla
  30. thistape.style.webkitTransformOrigin = originx + "px " + originy + "px"; // origin format for Webkit
  31. thistape.style.webkitTransform = rotate; // rotate the tape by the same amount as the bigpic, for Webkit
  32. thistape.style.MozTransform = rotate; // rotate the tape by the same amount as the bigpic, for Mozilla
  33. }

There are a few improvements I’d like to make: obviously, this only works for very recent versions of Firefox and Safari. I’d like to include IE, but it looks as if IE8 won’t even attempt to support CSS3 transformations; instead, it will presumably fall back on the old matrix operations of IE6. That will require significantly more code, and a separate blog entry.

Tags

Jul 27 2009

Precis: Web Developer Guide

I have decided to use this blog to publish the professional web developer guide (covering XHTML, CSS, PHP, JavaScript, and applications) I have written over the last six years. Until now this work was only available on location, at my institution. I am making it freely and publicly available (under a Creative Commons license) for study by students, graduates, and anyone else, while I remain in control of presentation and editing. The blog format will allow subscribers to comment and suggest changes and improvements as I add features to this site.

The first entry in each section of the guide will be a course overview, something not terribly relevant to the general public but vital for my students. I encourage casual readers to skip to the introduction of each section they are interested in. Additional navigation will be introduced as the entries grow more numerous in each section.

Tags

Dec 30 2009

Lightbox Can Bite Me

Update: the demo for this technique has been removed in preparation for a rewritten article with better code; this entry remains only as a reference.

A significant number of my 2nd year students use Lightbox when creating their portfolios. Don’t get me wrong: I appreciate the code; it’s a nice piece of JavaScript that works well. However, those same qualities are a curse: Lightbox is ubiquitous, especially among the aforementioned students, who use it constantly in their portfolios. Some at least go the extra mile in attempting to customise it, but most merely slap the code into place… and if I see it again, I fear my eyeballs are going to roll right out of their sockets and onto the floor.

This over-use is especially egregious because the very same effects can easily be created using CSS alone. (At this point, if you haven’t read through the Simple CSS Gallery, I suggest you do so before proceeding, as many of the concepts in that example are expanded upon here.)

First, the markup. This will be somewhat different from the XHTML used for the simple gallery, primarily because we want the large images to appear after a click, rather than being triggered by a hover over the thumbnail. The pseudo-selector to capture mouse clicks or key presses in CSS is :focus.

Unfortunately, unlike :hover, :focus cannot be applied to arbitrary elements. The central intent of :focus was to capture the state of form elements: when you click inside a text box, for example, that element is said to have :focus. The :focus pseudo-selector can be applied to form elements and links, but not much else.

That makes the chain of selectors in our CSS a little more complicated: links must be inside other elements. Semantic, valid markup is still possible – it just takes a little more creativity:

  1. <ul id=”gallery”>
  2. <li><a href="#"><img src="wintertree_thumb.jpg" alt="A tree in winter" title="A tree in winter" /></a>
  3. <div><img src="november.jpg" alt="A tree in winter" title="A tree in winter"/></div></li>
  4. </ul>

(I’ve used just one thumbnail and large image pair in this example – you could, of course, add as many pairs as you wished, but I wanted to keep things simple. I’ve left out the size of images for the same reason).

This markup still makes semantic sense: our thumbnails remain part of a list; it’s just unordered, rather than a definition list. The <div> that surrounds our large image serves much the same purpose as the <dd> did in our simple gallery example. We’ve used the “null” trick in the href attribute value as we want the <a> tag to nominally look and act like a link, but not actually go anywhere: we want to remain on the same page after the user clicks on the thumbnail.

Let’s add the basic markup for our body, unordered list, and list items:

  1. html, body { height: 100%; min-height: 100%; }
  2. ul#gallery { list-style-type: none; }
  3. ul#gallery li a img { border: none; outline: none; }

We discussed the min-height trick previously; you’ll see why we use it in this example in a moment. We’ve also removed the bullet points from the unordered list by setting list-style-type to none, and I’ve made sure that linked images do not receive an ugly border in the third line. (I’ll talk more about list-style-type in a future entry: it’s a fun property, and incredibly versatile).

Now we need to style and hide the <div> that contains our large image:

  1. ul#gallery div { position: absolute; visibility: hidden; top: 0; left: 0; width: 100%; min-height: 100%; margin-left: 0; background-color: rgba(0, 0, 0, 0.85); }

The start of this style declaration is very much like that used for the <dd> elements in the simple gallery: we position the <div> absolutely to remove it from the flow of the document, use top and left to position it on our page, and hide it by setting the visibility property to hidden. There are several differences, however: because there is no containing element with position: relative set on it, this div will be positioned in reference to the body. That means that top:0; left: 0 will place the <div> in the very top left corner of the page.

We’ve also made this <div> the full height and width of the page. We’ve used min-height so that we’re not limited by the height of the browser: if our contained image is larger than the browser, our <div> will continue past the bottom of the browser window.

Finally, we’ve provided a background-color for the <div> with some transparency, using a rgba color value.

Next, we’ll style the large image inside the <div>:

  1. ul#gallery div img { background-color: white; padding: 2em; }

This isn’t anything terribly special: we’ve simply applied a background-color and padded the image so that we see it. border: 2em solid white would work just as well as an alternative.

Finally, we need to capture the click on the a link and use it to make the container <div> visible:

  1. ul li a:focus + div { visibility: visible; }

Go ahead and try what we have so far, unless you’re using Safari. That browser has a problem capturing :focus on elements outside of forms, including our link. Ironically, to fix it, we’re going to have to add some JavaScript. Fortunately, it’s only a single line. (If you’re using another browser, you can ignore this part, although adding it won’t hurt anything, and will make our example work across all modern browsers.)

To the <head> section of your page, add the following:

  1. <script type="text/javascript">
  2. function getfocus(id) {document.getElementById(id).focus()}
  3. </script>

And adjust your XHTML code, specifically, the <a> element, to the following:

  1. <a href="#" id="image1" onclick="getfocus(id)">

The code is pretty simple – the JavaScript simply forces Safari to acknowledge the click (focus) on our link. The only major downside is that we have to use that onclick="getfocus(id)" in every a link in our list, and each of the links must have a different id value. Not a big deal: we’re only using the id for JavaScript, not CSS.

Now go ahead and take your page for a test spin in the browser.

“Neat, Dudley,” you might say. “But my big image covers up my thumbnails now. I want it in the middle of this div.”

A perfectly valid request. Add text-align: center; to the style for the <div> and take another look at the page.

“But Dudley,” you object. “I meant that I want to have the image in the center of the page – not just horizontally centered, but also vertically. You know, just like Lightbox.”

Ah. There, we encounter a problem. CSS does have a vertical-align property, but its use is pretty much limited to images lined up against text, which is not the situation here. There is a solution – there is always a solution – but it’s tricky, and a little ugly. It involves adding two more divs nested inside the one we have. Generally speaking, nesting divs should be avoided, but in our situation - images of varying sizes inside a div that itself could be almost any size, since it scales to the browser window – it’s the best solution at hand.

I’ll leave the complete explanation of the CSS we are going to use for another entry. For now, let’s add to our markup:

  1. <ul id=”gallery”>
  2. <li><a href="#"><img src="wintertree_thumb.jpg" alt="A tree in winter" title="A tree in winter" /></a>
  3. <div class=”container”><div class=”position”><div class=”content”><img src="november.jpg" alt="A tree in winter" title="A tree in winter"/></div></div></div></li>
  4. </ul>

What’s changed? We’ve added a class of container to our original div, then added two more divs immediately inside it, each with their own class value. That demands some changes to our CSS too, which now becomes:

  1. html, body { height: 100%; min-height: 100%;  }
  2. ul#gallery { list-style-type: none; }
  3. ul#gallery li a img { border: none; outline: none; }
  4. div.container { position: absolute; visibility: hidden; width: 100%; height: 100%; top: 0; left: 0; margin-left: 0; background-color: rgba(0, 0, 0, 0.85); display: table; }
  5. div.position { display: table-cell; width: 100%; text-align: center; vertical-align: middle;  }
  6. div.content { margin: 0 auto; }
  7. div.container img { background-color: white; padding: 2em; }
  8. ul li { width: 105px; height: 101px; }
  9. ul li a:focus + div { visibility: visible; }

Pretty cool so far – but I know you’re jonesin’ for the slick fade-in effect that Lightbox uses. I can supply what you need, but only if you’re using Safari or ChromeFirefox doesn’t (yet) support CSS3 animations.

We’re going to add to the CSS for our large image:

  1. div.container img { background-color: white; padding: 2em; opacity: 0; -webkit-transition: opacity 4s linear; }

And just before the final CSS line that makes our div visible, add the following:

  1. ul li a:focus + div img { opacity: 1; }

Try that in Safari or Chrome. (We can use either as they use the same Webkit rendering engine under their hoods.) Nice, right?

We can make it even better, if you’re using Safari 4 or the latest build of Chrome. I’m going to show you all the CSS again, with extra-special sauce added:

  1. @-webkit-keyframes grow {
  2. 0% { -webkit-transform: scale(0, 0.01); }
  3. 50% { -webkit-transform: scale(1.0, 0.01); }
  4. 100% { -webkit-transform: scale(1.0, 1.0); }
  5. }
  6. html, body { height: 100%; min-height: 100%; }
  7. div.container { position: absolute; visibility: hidden; width: 100%; height: 100%; top: 0; left: 0; margin-left: 0; background-color: rgba(0, 0, 0, 0.85); display: table; }
  8. div.position { display: table-cell; width: 100%; text-align: center; vertical-align: middle;  }
  9. div.container div img { background-color: white; padding: 2em; opacity: 0; }
  10. ul li a:focus + div.container img { -webkit-transition: opacity 5s linear; -webkit-transition-delay: 5s; opacity: 1; }
  11. ul li a:focus + div.container div {
  12. -webkit-animation-name: grow;
  13. -webkit-animation-duration: 5s;
  14. -webkit-animation-timing-function: ease-in-out;
  15. }
  16. ul li a:focus + div { visibility: visible; }

This does require that each <div> with a class of content be given its own inline style for width, otherwise the white box it represents will stretch all the way across the browser window. This is a little inelegant; if I come up with a better solution, I'll add it to the code here.

The CSS gracefully degrades: recent-build Safari and Chrome users will receive the full “LightBox” experience; Firefox users will get a “lighter” but still fully-functional version.

If you wanted to give IE8 some love as well, you could add the following to the declaration for the container div:

-ms-filter: "progid:DXImageTransform.Microsoft.Gradient
(startColorstr=#cc000000,endColorstr=#cc000000)";

The IE version has a small quirk that requires a mouse-move after focus to initiate the LightBox effect - I'll fix that presently, and take the time to explain Microsoft-proprietary filters.

Further Resources:

Tags

Apr 21 2010

Some Summer Suggestions For Students

As I write this, students in my full-time and night courses are winding up their classes in the final two weeks of the winter semester, working to complete their assignments. The temperature in the sunshine is 20°C, and everyone is eager to be outside.

I do not teach over summer: I need to retain (or recover) what sanity I have left. Instead, I travel, work in my shop, take in conferences, seminars and courses; and study. I will continue to update this site, not only with the best of these experiences, but with content that was either covered in class and did not have a matching article, or new content that will get the blog ahead of the demands of the fall semester. I also hope to add a few new features to the site, and (with luck and perseverance) a design refresh.

This means that there is a break of four months between courses for students. For those who are new to web development, that discontinuity creates a gap in which the skills and knowledge you have developed may become creaky, rusty and forgotten with disuse.

To counter this, I would encourage students, both full and part-time, to make three resolutions for the summer:

  1. Check back often here for new articles, or information that you might have missed in class.

  2. Work on something web-related over the summer. This does not have to be anything serious – I don’t expect you to sit inside for eight hours a day while the weather in Calgary is warm, the sun is out, and flowers bloom – but something you can come back to for a few hours a week, just to keep your skills sharp. A personal blog is a good project; a portfolio site is another popular suggestion. I’d love to have a “what I created over summer vacation” showing on the first day of class next semester.

  3. Make a habit of reading a few articles a week on web development and/or design – not just here, but from other sites. A few suggestions:

Inspiration
Web Development
Browser Development
Color
PHP
Typography
Validation, Accessibility & Testing
Tools & Toys

Sticking to these resolutions will make your life far easier in the fall semester – not only will our review period be shorter and less demanding when classes restart, but we’ll also get to new, exciting material faster.

If you discover new resources that you’d like to share with other students over the summer, feel free to contact me so I may add them to this list. Most of all, have a good, safe vacation, and I look forward to seeing you in September.

Tags

Sep 22 2010

Comments in HTML, CSS, JavaScript and PHP

It is a very good working practice to comment your code in every language you use. Comments serve two major functions:

As notes and reminders

Comments allow you leave yourself notes as to what sections of code do, and what they are there for. It is common, as both a freelance and full-time developer, to return to code that you have not seen in six months or more: comments allow you to quickly remember what each piece of code does.

As “traffic cones” around code that is problematic.

Code surrounded by comment markup immediately ceases to work. Because code on a web page is read from the top down, you can narrow down the cause of problems by removing sections from execution by means of comments, moving the start and ending comment markup around to analyse problems via a process of elimination.

Content, markup and code within comments does not appear on a web page, but can still be read by anyone what access to your source code. (In HTML, CSS and JavaScript, that is as easy as using View / Source in the browser).

HTML

  1. <!--   this is an HTML comment -->

Note that HTML comments are not tags; this can be confusing to many neophyte coders, as they appear to break all the rules of XHTML. Comments may be placed over multiple lines.

  1. <!-- this is a comment
  2.       over multiple lines -->

CSS

  1. /* This is a CSS comment */

CSS comments may also be broken over multiple lines:

  1. /* p { font-color: black; }
  2.      hr { color: red; }
  3.       both of the above lines, plus these two
  4.  will be ignored */

You will find that some web development text editors and WYSIWYG tools insert HTML comments immediately inside embedded styles and JavaScript in an odd way:

  1. <style type=”text/css”>
  2. <!--
  3. -->
  4. </style>

or

  1. <script type=”text/javascript”>
  2. <!--
  3. -->
  4. </script>

This is an old trick employed to protect very early browsers that only understood HTML from possible misinterpretation of CSS and JavaScript. The technique is largely irrelevant now, but it does no harm to use it. What is important to remember is that (a) the JavaScript and CSS will still work in compatible browsers (HTML comments only block HTML, not CSS or JavaScript), and (b) you must still use the appropriate JavaScript and CSS comment code once you start writing in those languages.

JavaScript

Comments in JavaScript code are the same as for CSS:

  1. /* this is a JavaScript
  2.       comment */

It is also possible to do single-line JavaScript comments:

  1. // this is a single-line JavaScript comment

I don’t recommend the single-line comment format, as it is too easy for an errant carriage return to sneak into a comment and force the remnant into your code, breaking it.

PHP

PHP comments are exactly the same as JavaScript comments:

  1. /* this is a PHP
  2.       comment */
  3. // so is this

For the same reasons given in JavaScript comments, I do not recommend the single-line format for PHP comments.

Tags

Oct 13 2010

Evolution of JavaScript

JavaScript came out of the development of the Netscape 2 browser in 1995. Originally called LiveScript, its name was changed to JavaScript because of the attention the Java programming language was receiving at the time, and because of some superficial similarities in programming syntax. However, Java is not JavaScript: the two are entirely different languages. Java is a fully-fledged programming language with the ability to create stand-alone programs. It has found its niche mostly in server-side solutions and embedded software. JavaScript is not a programming language: it is a scripting service, and cannot create an executable program. In fact, JavaScript will not have little functional use without a web page to run it on. Please do not get Java and JavaScript confused: it is a newbie’s mistake, and a quick way to terminate a job interview.

During the browser wars of the late 90’s, several different flavors of JavaScript were developed. Netscape continued with its version, while Microsoft released an alternative called JScript. Finally, a standard version called ECMAScript was released. Technically, we should be referring to JavaScript as ECMAScript, but there was one more hurdle for the scripting language to overcome before it could be accepted as a robust web development tool: the DOM.

Tags

Oct 14 2010

The JavaScript DOM

DOM (for Document Object Model) is a way of conceptualizing the contents of a web page. You can think of this as an agreed-upon way of describing elements in the document, just as there is an agreed-upon way of describing houses on your street in English. We all acknowledge, for instance, that the long strip of tarmac dividing houses on one side from the other is called the “road”. Each house is numbered, but we might also address them by position: “The third house on the left”, for example, or “The house after the red house”. While each house or building will be entered in a slightly different way, we call that entry by the same name: “door”.

In just the same way, the DOM allows us to describe the content of web pages. DOM Level 0, created in 1997, was a basic page description language, but it grew rapidly in complexity. Both Netscape and Microsoft created completely different and incompatible DOMs in order to compete with each other, forcing developers to code for one browser or another if they wanted to add JavaScript to their pages.

In 1998, the W3C released DOM Level 1, a standardized API for referring to the content of web pages, and modern graphical browsers now support it to a high degree. The DOM has now become so ubiquitous that the scripting we are about to look into has been given yet another term: DOM Scripting.

The DOM is strongly reliant on validated, structured, semantic HTML code. Just as you might struggle to make sense of a city that has grown without any plan, reason, or building codes, JavaScript will have a very hard time working with a page that is invalid. For that reason, you should have a strong understanding of XHTML 1.0 Strict before attempting to add JavaScript to a page. Just like CSS, JavaScript loves clean code.

Tags

Oct 15 2010

Four Principles of Effective JavaScript

Graceful degradation

If JavaScript is turned off, or fails to run, the user should still be able to access the site. (This is the same rule for CSS and images). The user may not experience all the bells and whistles you would wish them too, but the basic functionality of the site should remain unchanged. Features that are heavily dependent on JavaScript should not be vital to one’s use of the site.

Progressive enhancement

JavaScript is used to enhance content that is already present, not create new content. For example, the navigation on the side of this page uses an “accordion” script written in JavaScript for its animation. That’s a nice feature to have, but if JavaScript is blocked, the user still has access to the entire navigation; without JavaScript, the “natural” state of the menu is to be completely expanded, showing all options. (This is deliberately done on the Search page).

Keep data, appearance and behavior separate

Returning to our original table for the uses of web technology and adding to it:

Web Technologies
XHTMLCSSJavaScript
contentappearancebehavior (client-side)
what something ishow something lookshow something acts on the page
semantic markup of datarules for appearance of contentrules for the behavior of content

Mixing the roles of these technologies leads to frustration and confusion.

Don't use JavaScript when CSS will do

Most web developers believe you have to use JavaScript to make an image gallery. You don’t. Most web developers believe that you must use JavaScript to create a drop-down menu. You don’t.

JavaScript still very much has its place and role: but with solid support for CSS Levels 1 and 2 in all modern browsers, you don't need it for many of the effects that people think the technology must be used to create. This becomes increasingly true with CSS3 and HTML 5, which have support for animation. CSS is, generally speaking, faster, lighter, and easier to code and maintain than JavaScript.

Tags

Oct 18 2010

How To Write JavaScript On An HTML Page

JavaScript is executed client-side, on the browser. Like CSS, it can be written either inline, embedded, or linked, and (just like CSS) those methods are in order of preference in terms of power and adaptability. A link to a JavaScript file is written inside the <head> section of the page on which it is used:

  1. <head>
  2. <title>An HTML Page With Linked Javascript<title>
  3. <script type="text/javascript" src="assets/scripts/prettify.js"></script>
  4. </head>

Independent JavaScript files must have a .js extension in the filename. (You will occasionally see a language attribute used when linking to a JavaScript file, but that is now deprecated, and is not valid in XHTML.)

It is also possible to link to a JavaScript file outside of your own domain: this is frequently done with JavaScript frameworks such as jQuery or Prototype, both to centralise code and to potentially speed up load times. (Cross-domain files like the jQuery library sourced from Google will be cached by the browser: if the user has previously visited a site that uses the same technique for the same file, the cached version of the file will be used instead, rather than downloading it again.)

  1. <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>

The second and less preferable option is to write the JavaScript embedded, again in the <head> section:

  1. <script type="text/javascript">
  2. /* JavaScript code goes here */
  3. </script>

Note that you cannot write HTML or CSS directly inside JavaScript; like CSS, using another language between the opening and closing <script> tags, or in the linked JavaScript file, will cause it to stop working. The only HTML you can use in embedded script is a very special case:

  1. <script type="text/javascript">
  2. <!--
  3. /* JavaScript code goes here */
  4. -->
  5. </script>

The HTML comment around embedded JavaScript code accomplishes two things:

  1. It protects very old browsers that may not understand JavaScript, and will attempt to run the code as HTML.

  2. More practically, it allows us to continue to validate the HTML page without confusing the validator.

You do not, as a general rule, write JavaScript code inline, for reasons we shall cover shortly.

Resources

We will get into writing actual JavaScript code shortly. If you are an experienced programmer, you might want to jump ahead by reading the cheat sheet at infogami or playing with the UI demos at JQuery UI.

Tags

Mar 13 2011

The Six Most Common Mistakes Made In Writing JavaScript

While there are many possible errors made in JavaScript, these are the most common mistakes made in day-to-day use:

Writing embedded or inline JavaScript, rather than linked

We link JavaScript files for much the same reasons we write the majority of our CSS in an external style sheet: doing so separates behavior from presentation, makes the code earlier to maintain, and allows the same script to be used on multiple pages without replication or redundancy. There are reasons and causes for embedding your JavaScript code directly on a page, but they should be rare.

Not wrapping HTML comments around your embedded code

If you cannot avoid writing embedded JavaScript, you should write it within an HTML comment:

<script type=”text/javascript”>
      <!—
      alert(“Active JavaScript”);
      -->
</script>

This achieves two things:

  1. It shields the embedded JavaScript from the W3C Validator, which ignores anything contained within comments; otherwise, there is the possibility that the validator will confuse JavaScript for HTML, and throw errors.

  2. It protects the JavaScript from confusion in older browsers that do not understand JavaScript at all (now a rarity, but still present).

This the only point at which HTML may be used directly inside a script: any other comments or code used must be JavaScript.

Not delaying the execution of scripts

When you run the code above on a page, the alert window appears before any body content: you must click the “OK” button to get past the alert window. This is a frequent problem with neophyte JavaScript programmers: JavaScript written without a delay means that it has nothing to work on, as no body content has appeared when it executes. In traditional JavaScript, this delay is written as the following:

window.onload=function(){ 
      // JavaScript code written here
}

In JQuery:

$(document).ready(function() {
// JavaScript code written here
})

Changing case in JavaScript

JavaScript is case sensitive. This is not only true of JavaScript code, but also of any variables or constants you create within it. tokenOne is a different variable from TokenOne. Scripts often break because you are trying to test or set the value of a variable that does not exist.

Confusing Concatenation & Addition

Concatenation is the joining of two or more strings. Addition is what you learned in school. In JavaScript both operators use the same + symbol to achieve their ends. It’s important to remember what you are joining together, how and why, and anticipate the result, in order to avoid errors:

In JavaScript:

alert(10 + 12);
 // result is 22

alert(10+”2”);
// result is “102” – note that this is a string, not a numeral

alert(“There is no “ + “cake”);
// result is “There is no cake”

token = 2;
alert(10 + token)
// result is 12

token = “Two”;
alert (10 + token);
// result is “10Two”

Confusing single and double quotes

Single or double quotes can be used in JavaScript operations with strings. This works out well until you get them confused, use one to start a string and the other form to end it, or use a single quote in place of an apostrophe character.

alert('Two’);
 // result is Two

alert("Two's");
// result is Two’s

alert ('Two's');
// result is an error

Tags

Mar 27 2011

Essential Animation Concepts: Ease-In & Ease-Out

With the arrival of CSS3 Transitions and the popularity of JavaScript frameworks, animation is now completely at home on web pages. In animation we need to refer to the properties of momentum, and central to this are the principles of “ease in” and “ease-out”.

Consider a regular mechanical motion, like the movement of a minute hand on a clock, or an automatic metal stamping machine. After one minute passes, the hand on the clock will tick forward suddenly, and the metal stamp will crash down on a plate. If we took this motion and graphed it, with time on the horizontal axis and distance on the vertical, the motion would look something like this:

Note that the units of time and distance are arbitrary: we could be talking about seconds or hours, millimeters or kilometers. What is important is that the graph shows that the object is under constant linear motion. It starts suddenly, remains at a constant speed, and stops just as abruptly.

Movement like this has only been seen since the Industrial Revolution: even now, we tend to consider this kind of motion soulless, mechanical, and jarring. In every other human experience of movement – the swinging of a pendulum, the tossing of a ball, trees bending in the wind – we see a very different kind of movement:

The curve you can see at the start of the graph – plotting the movement of the golfer's club as he begins to swing it, for example – is called “ease-in”. The curve at the end, representing the motion as the object comes to rest (the golf club coming to a stop after the ball flies away) is known as “ease out”. We see this movement as organic, fluid, friendly and natural.

It should be noted that this kind of movement is also true of many mechanical devices. A car does not start at 100kph, and it does not stop on a dime (unless it crashes headfirst into a wall). Rather, it accelerates from a standing start, reaches a certain speed, and then slows down as the brakes are applied. Ease-in and ease-out are still in effect.

Sometimes the ease-in or ease-out portion of a movement may be so fast it is imperceptible to human beings: for example, a golf ball driven from the tee moves too fast to have appreciable “ease-in”, but it definitely has ease-out when it hits the ground and rolls across the green before coming to a rest. If we were to graph that kind of motion, it would look something like this:

The red line on the graphs is known as a “Bezier curve”, and it is used in many programs, both as a mechanism for drawing (for example, in Adobe Flash and Illustrator) and as a means of characterising movement over time (Autodesk 3DSMax, along with most other applications that have an animation component). What is important is not the means of portraying the concept but the idea itself. By manipulating ease-in and ease-out you can create the impression that an object is slow, heavy and lumbering, or spritely, agile and quick, smooth and fluid or hard and mechanical… and this movement imparts an association in every presentation you make.

Further Resources

Joe Lambert has an excellent series of prebuilt custom timings and easing functions for browsers that support CSS3 keyframe animation

Tags

Apr 18 2011

Electronica Site Navigation, Part 2: HTML5 Audio Events

Inspired by soundboard sites such as iDaft, I wanted to add audio events to the HTML5 animated menu bar I made in part one of this series. As a rule, I feel that web sites should only “speak when spoken to”, i.e. the majority of web pages should not play audio by default, and leave initiation of playback up to the user. Auto-playing background music on sites makes me angry. I was willing to craft an exception for this example for two reasons: (a) it’s for a music site, in which audio could be reasonably expected to play a part and (b) the code is a proof-of-concept, not an actual site.

Sans Flash or other plugin, we can add sound to a webpage in two ways: either instancing the audio solely through JavaScript, or by embedding the sound on the page with the <audio> tag. In this case, we need to add four sounds: one for each link, with different codecs to cover the current browser incompatibles. Anywhere in the body, I’ll place the following:

  1. <audio preload="auto" id="harder">
  2.     <source src="assets/audio/harder.mp3"></source>
  3.     <source src="assets/audio/harder.ogg"></source>
  4. </audio>
  5. <audio preload="auto" id="better">
  6.     <source src="assets/audio/better.mp3"></source>
  7. <source src="assets/audio/better.ogg"></source>
  8. </audio>
  9. <audio preload="auto" id="faster">
  10.     <source src="assets/audio/faster.mp3"></source>
  11. <source src="assets/audio/faster.mp3"></source>
  12. </audio>
  13. <audio preload="auto" id="stronger">
  14.     <source src="assets/audio/stronger.mp3"></source>
  15.     <source src="assets/audio/stronger.ogg"></source>
  16. </audio>

Note that we have effectively hidden the sounds on the page by not adding a controls attribute.

I’ll also need to add an id to each link, in order to be able to address them specifically with JavaScript:

  1. <nav id="equalizer">
  2. <a href="#" style="left: 20px;" id="beats"><span>Beats</span></a>
  3. <a href="#" style="left: 170px;" id="samples"><span>Samples</span></a>
  4. <a href="#" style="left: 320px;" id="loops"><span>Loops</span></a>
  5. <a href="#" style="left: 470px;" id="rhythms"><span>Rhythms</span></a>
  6. </nav>

The next part is addressing each audio source and linking it to the mouseover state of each link. I’ll use JQuery to do so, just because it is a little easier to write. In the head section of the page, add:

  1. <script>
  2. $(document).ready(function() {
  3. var harder = $("#harder")[0];
  4. var better = $("#better")[0];
  5. var faster = $("#faster")[0];
  6. var stronger = $("#stronger")[0];
  7. $("#equalizer a#beats")
  8.     .mouseenter(function() {
  9.         harder.play();
  10.     });
  11. $("#equalizer a#samples")
  12.     .mouseenter(function() {
  13.         better.play();
  14.     });
  15. $("#equalizer a#loops")
  16.     .mouseenter(function() {
  17.         faster.play();
  18.     });
  19. $("#equalizer a#rhythms")
  20.     .mouseenter(function() {
  21.         stronger.play();
  22.     });
  23. });
  24. </script>

This works, with a few caveats.  Critically, the code is lengthy and heavily repetitious. I’ll clean it up by adding a class to each link that signifies the sound I want to associate with it. The value of that class will match that of the id on the audio tags, so I can cross-reference them easily. So the nav is altered to:

  1. <nav id="equalizer">
  2. <a href="#" style="left: 20px;" class="harder"><span>Beats</span></a>
  3. <a href="#" style="left: 170px;" class="better"><span>Samples</span></a>
  4. <a href="#" style="left: 320px;" class="faster"><span>Loops</span></a>
  5. <a href="#" style="left: 470px;" class="stronger"><span>Rhythms</span></a>
  6. </nav>

And the JavaScript becomes:

  1. $(document).ready(function() {
  2. $("#equalizer a")
  3.     .mouseenter(function() {
  4.         var link = $(this);
  5.         var ref = link.attr("class");
  6.         $("#"+ref)[0].play();
  7.     });
  8. });

The JavaScript could be shortened down even further:

  1. $("#equalizer a")
  2.     .mouseenter(function() {
  3.         $("#"+$(this).attr("class"))[0].play();
  4.     });

I could make a true graphic equalizer effect with the proposed Web Audio API, but support for that is limited to Firefox 4 at the moment.

There are a few other issues with the menu, mostly to do with browser support for HTML5 audio: depending on the browser version you use, the sound from the first hover may come after a small delay, and the audio clips may not “step” on each other the way one might expect. I’ll address those problems in a future article.

Final note

My fulltime students may respond with glee when they find that this page has validation errors, believing that they have discovered a source of income from the “$10 per validation error” open bounty I have on the site. I am sorry to be the bearer of bad tidings, but the errors are known and deliberate: rather than trying to recode the Electronica menu bar in XHTML 1.0 Strict, I have placed the HTML5 code directly in the page.

Tags

May 18 2011

JQueryUI Theme CSS Now Hosted On Google's CDN

Some web developers know that Google, Microsoft and Yahoo host copies of popular frameworks on their Content Distribution Networks, and that using code that draws from these sources means that visitors to our websites will not have to download the scripts again, as they already have them cached (due to visiting other websites that use the same technique) which means faster download times for our web pages.

You can link to a particular version of a framework (HTML5 version of the script tag shown in order to save space):

  1. <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js" /><script>

Fewer people know that Google also hosts the popular JQueryUI plugin:

  1. <script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.2/jquery-ui.min.js" /><script>

Almost no-one, it seems, is aware that Google also hosts CSS themes for JQueryUI, which are necessary for elements generated by JQueryUI to appear correctly (again, HTML5 version shown):

  1. <link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.2/themes/base/jquery-ui.css" />

Note that the CSS delivered from Google has not been minified: i.e.  it still has comments, spaces, and line breaks. To get other themes, simply replace the word base in the URL with another theme, such as mint-choc, trontastic, ui-lightness, ui-darkness, or vader.

Further Resources

A nice overview of what common web development resources are hosted where can be found at the CDN Catalog, maintained by Andrew Davey

Tags

May 25 2011

Functions

Functions are a key component in making your dynamic web page more efficient: they are used for any procedure you wish to use more than once from an arbitrary point in your code.

The basic structure of a function is written in exactly the same way in both JavaScript and PHP. First, the function itself must be declared, and its steps defined:

  1. function format_title() {
  2. /* procedure inside function */
  3. }

Functions are “self-contained”: that is, the code within them, between the opening and closing braces, is not executed until the function is explicitly called.

The name of the function should be clear and understandable, and may be any word or combination of words, so long as they are not reserved by the language, start with a number, or include any spaces.

Note that the parentheses immediately after the name of the function are required: they are used to contain variables passed to the function; even if you are not using this feature the parentheses must be present.

I strongly recommend that functions be written at the start of your code; that way they are easily identified and available to every line of code that comes after them.

To call the function, simply use its name:

format_title();

It's important to understand that actions in the function are reflected where the function is called from. In other words, an echo inside a PHP function will print out its results where it was called.

Variable scope

If a variable is created inside a function, that variable is only accessible within the context of that function, and is inaccessible outside of it. A variable created outside a function is accessible from within any function.

Tags

May 26 2011

A Simple JQuery News Ticker With CSS3 & Generated Content

  • Improve pagination
  • Work on comment system
  • Add favorites
  • Allow users to add a profile
  • Redesign blog theme

Problem: you have too many items in a group – Twitter/Facebook messages, news headlines, spotlighted articles, etc. Including all of the items on a page would overwhelm the design, but you don’t wish to limit the items to a selection of just two or three.

Solution: limit the visible area of the group via CSS, and change the order of the items via JavaScript over time.

First, the basic HTML:

  1. <h3>To-Do List For demosthenes.info</h3>
  2. <ul id="to-do-list">
  3. <li>Improve pagination <a href="to-do.html#pagination"></a></li>
  4. <li>Work on comment system <a href="to-do.html#comments"></a></li>
  5. <li>Add favorites <a href="to-do.html#favorites"></a></li>
  6. <li>Allow users to add a profile <a href="to-do.html#profiles"></a></li>
  7. <li>Redesign blog theme <a href="to-do.html#redesign"></a></li>
  8. </ul>

We would normally never place height on an element (the body tag, images and container div being exceptions) but in this case we want to show a limited number of items, and hide the rest:

  1. ul#to-do-list {
  2. border: 2px solid #000; padding: 1em;
  3. height: 3em; overflow: hidden; width: 16em;
  4. }

Note that you could “even out” the perception of padding around the three visible list items by using a CSS3 count selector to influence the third list item:

  1. ul#to-do-list li:nth-child(3) { margin-bottom: 1.2em; }

Normally we want to direct the user to read more information on each news item on another page. If I wanted those words to accompany each link, I could use some generated content:

  1. ul#to-do-list li a:before { content: "read more"; }

Now we need to remove the first list item using JavaScript. We’ll load in JQuery, then add an embedded script that does just that (HTML5 formatting is used on tags for brevity)

  1. <script src=”http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js”></script>
  2. <script>
  3. $(document).ready(function(){
  4. function removeFirst(){
  5.     first = $('ul#to-do-list li:first').html();
  6.     $('ul#to-do-list li:first')
  7.     .fadeOut('slow', function()
  8.     {$(this).remove();});
  9.     addLast(first);
  10. }
  11. interval = setInterval(removeFirst, 3000);
  12. });
  13. </script>

The first variable will be used to contain the content of the first list item, which will then be faded out. This will occur every 3 seconds (3000 milliseconds).

If you ran the code as it exists right now, you would find that the list was gradually consumed from the top until it disappears; you would also find that the JavaScript console window in your browser supplied a repeated error message that it could not find an addLast function. The role of that function is to take the content that we removed from the top (first) and append it to the bottom of the list. Let’s add that function above removeFirst():

  1. <script>
  2. $(document).ready(function(){
  3. function addLast(first) {
  4.       last = '<li>'+first+'</li>';
  5.       $('ul#to-do-list ').append(last);
  6. }
  7. function removeFirst(){
  8.     first = $('ul#to-do-list li:first').html();
  9.     $('ul#to-do-list li:first')
  10.     .fadeOut('slow', function()
  11.     {$(this).remove();});
  12.     addLast(first);
  13. }
  14. interval = setInterval(removeFirst, 3000);
  15. });
  16. </script>

The addLast() function takes the content of the first list item as a variable called first, concatenates <li> tags around it, and adds the result to the bottom of the list. In this way, the animation of the list is an infinite loop.

You could easily make the list items appear side-by-side, replace the text in the list with images, move the list elsewhere on your page, etc: that is all CSS and markup, not JavaScript.

Tags

Oct 27 2011

Applying ChromeFrame

ChromeFrame is an Internet Explorer plugin that essentially “zombifies” the browser: installing a plugin (which does not require an administrator name or password) that replaces IE’s own rendering engine, transforming the browser into “Chrome with an IE face”. In my opinion ChromeFrame remains the best and most complete way of bringing IE 6 – 9 “up to speed” with current web standards. (Popular alternatives take the form of JavaScript “shims” such as Modernizer, requiring far more work).

Indicating that you want Internet Explorer users who visit your site with ChromeFrame already installed to use the Chrome component is easy: it’s just a meta tag in the <head> section of your document:

  1. <meta http-equiv="X-UA-Compatible" content="chrome=1" />

If you want to have ChromeFrame render the page only if the version of IE is 8 or lower, the meta tag becomes:

  1. <meta http-equiv="X-UA-Compatible" content="chrome=IE8" />

Prompting the user to install ChromeFrame is a little trickier, but not difficult. First, you must link to the following script, again in the <head>:

  1. <script type="text/javascript"
  2. src="http://ajax.googleapis.com/ajax/libs/chrome-frame/1/CFInstall.min.js">
  3. </script>

Finally, you need to check if ChromeFrame is installed, and if not, prompt the user to do so. You’ll probably want to delay this until IE has presented the page to the best of its ability, so under the script above, write:

  1. <script>
  2. window.onload=function(){
  3.      CFInstall.check({ mode:"overlay", destination:"http://www.domain.com" });
  4. // where the user will be sent after installation
  5. } </script>

If you’re using JQuery instead:

  1. <script>
  2. $(document).ready(function() {
  3.      CFInstall.check({ mode:"overlay",
  4. destination:"http://www.demosthenes.info" });
  5. })
  6. </script>

The screen that is generated by JavaScript prompting the user to install ChromeFrame has some CSS hooks. If you want to customize the appearance of the window, add the following classes and declarations to your stylesheet:

  1. .chromeFrameOverlayContent { }
  2. .chromeFrameOverlayContent iframe { }
  3. .chromeFrameOverlayCloseBar { }
  4. .chromeFrameOverlayUnderlay { }
Tags
  • Showing 19 of hundreds
  • >
  • Oldest
This content by Dudley Storey is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 2.5 Canada License.
Site written in XHTML 1.0 Strict, CSS Levels 1, 2 & 3

This site helps millions of visitors while remaining ad-free. For less than the price of a cup of coffee, you can help pay for bandwidth and server costs while encouraging further articles.