Posted on November 18, 2008 08:32 by swilliams

Everybody does things differently. When it comes to designing web applications, there is no single Right way to do things (though there are many Wrong ways). This is the first in a series of how I design an application.

John Gruber coined a great phrase, "Ronco Spray-on Usability" when referring to the practice of treating the UI work as something that can be applied at any point, typically the end. This is how crummy designs happens. If you've ever found yourself thinking did they put ANY effort into this at all? this is probably how it went down.

If you do not put forth a significant amount of thinking about your design, and not just at the beginning, it will be being sub-standard at best, and abysmal at worst. That doesn't mean you need to spend all of your project time thinking about the design, work in baby steps.

The 37Signals guys state that you should do the UI first, before coding, and I tend to agree. Perhaps the biggest benefit of this approach is that it keeps you from avoidable work. Say you thought you needed to sort an array of objects on different properties. But, while making the UI, you realized this was unnecessary. You just saved yourself the time that would have spent writing, debugging, and testing that feature.

The opposite can happen as well. In the process of designing the UI, it may become apparent that two previously separated components need to be more tightly integrated. This may create more work, but pays off by improving the user's experience. And ultimately, it saves you the time of implementing the incorrect model, then going back and changing it. Additionally, it is far cheaper to make corrections earlier in a design than later.

In order to marshal my thoughts about a design, I'll make simple lists detailing what will be on the page before drawing anything or opening an editor. If the page contains a basic CRUD form, I'll quickly jot down the needed fields, if only to keep from forgetting one when it comes time to write the code.

I prefer using a pen and paper, though a basic text-editor is fine too. I like paper here because mucking around is easier; I can scribble tiny notes next to my points, or cross things off. The key though is to keep it as simple as possible, so that it is easy to throw away. If you immediately dive into Photoshop or Visual Studio, you can become too attached to a bad design. A piece of paper or a .txt file is of no consequence and can be thrown out with only 15 minutes of lost time.

Once you have some basic ideas ready to go, it is time to proceed to the next step, The Sketch.



Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted on November 10, 2008 13:48 by swilliams

One thing that every developer can agree on is that code readability and maintainability is a Good Thing. Nobody wants to come back to a project several months later only to find the critical piece of it is poorly formatted, uses three separate programming paradigms, and Oh My Goodness why is it using Exceptions as GOTO statements?

Wars have been fought over whether the opening curly brace goes on the same line as the expression, or a new one*. However, I am always surprised to see that the markup created by many developers is a tangled mess of HTML, CSS, and JavaScript. In a sufficiently large project, doing something as simple as moving a <div> from one corner to another is tantamount to sending a rocket to the moon.

[* The answer is the same line, as God intended.]

The common justification is the old "Well, I'm not a designer" routine. And again, yes, that is probably true, but do you actually like wasting hours figuring out why things aren't lining up the way they should?

Something that I've found helps enormously is to just treat your markup, style, and script as first class citizens. Here's how I do it:

Keep Your Stuff Separate

Keep your HTML, CSS, and JavaScript in separate files. Just like it's a bad practice to embed database logic in your UI, it's a bad practice to use the style="" attribute on an HTML tag*.

Why is this bad? It all comes back to readability, in both a human and machine sense. Fixing markup is easier when you don't have to account for styling and JavaScript embedded throughout. Programmatically parsing HTML is same way.

[* I'm using absolutes here for emphasis, there are always exceptions.]

To accomplish this, I use a file structure I call "The Cradle." It consists of my main HTML page (index.html, or a Master Page, or whatever), and all of the .js and .css files I will be needing. Its contents are:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Title</title>
    <link type="text/css" rel="stylesheet" href="css/master.css" />
</head>
<body>

<!-- Content goes here -->

<script type="text/javascript" src="js/framework.js"></script>

</body>
</html>

The reference to the master.css file is the only time CSS is ever mentioned in the page. The CradleFramework.js is replaced by whichever JavaScript framework I am using, usually Prototype or jQuery. I'll also add another JavaScript line to reference custom JavaScript for the page. Again, this is the only time JavaScript is ever mentioned on the page. I do not use any of the onclick, onmouseover, onwhatever event attributes here. This keeps the HTML light and easy to scan.

Additionally, all CSS file references are at the top of the page, since the styles won't be applied otherwise, and JavaScript at the bottom to avoid as much of a delay as possible when the page is rendered.

Split up your CSS

Why only one css file referenced? Because with the @import directive, you can call separate CSS files from the master.

This means my master.css file looks like:

@import url('type.css');
@import url('layout.css');
@import url('color.css');

If I feel that a CSS reset is needed, I'll include a reset.css above all of that. As you can probably guess, type.css contains styling for text, and text only. Layout determines the positioning and sizing of things, and color.css makes them pretty. I try to avoid spillover as much as possible; type does not define font color. Borders are kind of a wildcard since they deal with both layout and have a color component, so I keep them in color.css.

Additionally, these can split up further for the various media types out there. @importing a print_layout.css in the layout file can help if you need to maintain a print version of the page. Same with a mobile version. They are not kept in the Cradle since I rarely use them.

An added benefit of splitting CSS is that file sizes become shorter. A smaller line count makes it easier to scan and find selectors.

One Off Styles

All of these tips have applied to a global style. But what happens if you have a separate page that needs various elements specific to just it to be styled? If the page only has a minimum set of elements, I'll throw them in with the global style. If not, I'll use a separate file and include it on just that page.

Use JavaScript To Wire Up Events

I mentioned earlier that you should avoid using the onevent attributes that HTML provides. When I first heard this, I thought it was silly, since it meant I wouldn't be able to have all the fancypants Web 2.0 things that all the hip kids were doing.

It turns out that you can have your cake and eat it too. One convention I use with my JavaScript is to have an init() method like so:

var MYAPP = function() {
  return {
    init: function() {
      // put stuff here
    }
}();

$(document).ready(MYAPP.init);

If this syntax looks a little screwy to you, that's ok, read up on some of JavaScript's awesome functional roots.

This bit of code runs the init() function when the page loads. Inside init() is where other functions are called, including createEvents():

var createEvents = function() {
  $('#new').click(function() {
    alert('You clicked the new link!');
  });
};

This attaches a function to an element with the id "new." When it is clicked a friendly dialog pops up providing some useful text.

Both of these examples use the jQuery library, though you can do the same thing with Prototype, YUI, MooTools, or plain old JavaScript.

Once you have The Cradle set up to your specifications, it is easier to keep designs up to date. If someone tells you, "The font in the header needs to be bigger" you automatically know that it is in type.css, and won't be difficult to find from there. No more poking through various HTML and CSS files to find it.

I keep my version of The Cradle in my documents folder and copy it to each new project at the beginning. You can download your very own copy and use it however you would like. I included a recent copy of jQuery and Prototype, but you can use whichever library suits you.



Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted on July 23, 2008 15:08 by swilliams

I gave a presentation last night on the topic of improving web design for developers. On the topic of CSS I gave a very simple demonstration on using a non-table based layout. It went well over all, but I didn't have a ton of time to get it perfect and resulted with this.

It works, but wasn't the best I could do (the right column noticeably doesn't extend to the bottom of the content). Christian asked a great question about this, but my brain froze and I wasn't able to come up with a quality answer. Of course this one detail plagued me through the night.

Well, the answer is very simple. Wrap the two columns in a container element (another <div> in this case). Set the overflow property to auto or hidden, adjust the width, accounting for padding, and use the same background color as the sidebar. And presto, you get what I meant to do.

If you'd like to see the markup and style, just view the source of the page.



Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted on July 18, 2008 15:04 by swilliams

Confession time: I love Panic software. They put tons of effort into the UI of their products, and it shows. Even their website shows astonishing attention to detail, and web design isn't even a service that they offer. What gets me the most are the sliding panels on the page for Coda. I peaked at the source code for it and saw:

// Not for redistribution

Hrmph. And then I thought that I could probably reverse engineer what they were doing without copying and pasting their code. Just to be clear, I did not copy a byte of their code; everything here was written entirely by me (except in one case where labeled). To do some of the lifting, I used the Prototype JavaScript library, though you could just as easily do it with JQuery, YUI, or no library at all.

First, the Markup

This is the simplest part. The tabs are just a horizontally positioned list with the bullets removed. And the panels are divs floated sequentially. The idea is that there is a "window" div that displays one of the divs behind it. When a link is clicked, the floated divs slide in the proper direction.

scroller_image

Here is the markup to make it happen:

<div id="main">
    <ul>
        <li><a href="#" rel="scroll">Panel One</a></li>
        <li><a href="#" rel="scroll">Panel Two</a></li>
        <li><a href="#" rel="scroll">Panel Three</a></li>
        <li><a href="#" rel="scroll">Panel Four</a></li>
    </ul>
    <div id="scroll_container">
        <div id="scroller">
            <div>
                <h1>Panel 1</h1>
            </div>
            <div>
                <h1>Panel 2</h1>
            </div>
            <div>
                <h1>Panel 3</h1>
            </div>
            <div>
                <h1>More</h1>
            </div>
        </div>
    </div>
</div>

The only other thing worth mentioning is the rel="scroll" attribute on the anchor tags. This is just used to identify that these links cause a scrolling action to occur, and are used by the JavaScript to easily grab them.

The Style

Styling the HTML isn't too tricky, though there were a couple of small gotchas. My first thought was to set the position of scroller to relative and then use the JavaScript to adjust its left property. This would have worked, but then IE displays all of the scroll panels even if scroller's overflow is set to hidden.

After a bit of snooping I found that I could get the same behavior by adjusting the scrollLeft property on scroller. This manipulates the [invisible] scrollbar.

Scroller's width is large to accomodate all the panels, but could be set to anything greater than or equal to the aggregate width of the panels.

div#main
{
    width: 600px;
    margin: 0 auto;
    height: 800px;
    overflow: hidden;
}
div#main > ul
{
    margin: 0;
    padding: 0;
    width: 100%;
}
div#main > ul li
{
    font-size: 1.4em;
    margin-right: 20px;
    display: inline;
    list-style-type: none;
}
div#scroll_container
{
    width: 600px;
    overflow: hidden;
    height: 740px;
    background: #eee;
}
div#scroller
{
    width: 5000px;
}
div#scroller > div
{
    width: 600px;
    height: 740px;
    float: left;
}

JavaScript - where the magic happens

I took an iterative approach for the JavaScript. First, the most basic way to get "sliding" functionality. The initial design didn't even slide at all, it just moved the panels without an animation.

var scroller = function() {

    var scroll = function(index) {
        var totalOffset = index * scroller.scrollPanelWidth;
        var scrollee = $(scroller.scrollPanel);
        scrollee.scrollLeft = totalOffset;
    }

    var getScrollLinks = function() {
        var links = $$('a[rel=scroll]');
        links.each(function(elem, index) {
            elem.observe('click', function() {
                scroll(index);
            });
        });
    };
    
    return { 
        scrollPanel: '',
        scrollPanelWidth: 0,
    
        init: function(panel, panelWidth) {
            scroller.scrollPanel = panel;
            scroller.scrollPanelWidth = panelWidth || 600;
            getScrollLinks();
        }
    };
}();

This does exactly that. Some of the conventions I'm using here may seem a little weird, but it allows the scroller object to have private fields. To learn more about it, see here.

You can see this in action here.

Functional, but not fancy. I was going to use Script.aculo.us to do the animation, but it does it using the position: relative method described a few paragraphs ago, making IE render incorrectly. Which is kind of a bummer.

So, we'll have to animate this by ourselves. I arbitrarily decided that 500 milliseconds was an adequate time for the animation to take, in 25 frames (for simplicity's sake, pick a number that divides the duration evenly). To accommodate for these values, a couple of properties were added to the scroller object and the scroll() function now does the animating:

    var currentPosition = 0;   
    
    var scroll = function(index) {
        var totalOffset = index * scroller.scrollPanelWidth;
        var desiredOffset = totalOffset - currentPosition;
        var scrollee = $(scroller.scrollPanel);
        var tick = scroller.scrollTime / scroller.ticks;
        var timeIndex = 0.0;
        var inter;
	    
        function animate() {
            timeIndex += tick;
            var delta = desiredOffset / scroller.ticks;
            if (timeIndex > scroller.scrollTime) {
                clearInterval(inter);
                currentPosition = scrollee.scrollLeft;
                return;
            } 
            scrollee.scrollLeft += delta;
        }
        
        inter = setInterval(function() { animate(); }, tick);
    }

See it in action here.

With each tick of the timer the scroller div is moved a little bit in the proper direction. Since the duration remains constant, this has the neat effect of scrolling divs quicker the further apart they are.

At this point we could pat ourselves on the back and call it a day, but there is still a little bit more we could do. If you'll notice in Panic's design, the animation starts slowly, speeds up, then eases into the final position. Kind of like a train leaving the station, and then arriving at the next stop. Script.aculo.us's Effect.Move has the same property. It is these little things that really amp up the aesthetics of an app.

comparison How did they do it? Math! A sine curve has the function of what we're looking for. Our current example has a linear progression. Meaning each tick moves the scroller the same amount. With a sine curve, we get the behavior that Panic and Script.aculo.us have.

Since I haven't actually calculated the sine of anything since school, I decided to just steal borrow someone's code. As mentioned, Script.aculo.us has a sinoidal function. But grabbing a 100k library for a 3 line function is just silly, so I copied it to my own file directly.

var sinoidal = function(val) {
   return (-Math.cos(val * Math.PI) / 2) + 0.5;
}

sinoidal returns a value between 0 and 1, so we just need to multiply it by our desiredOffset to get our delta and tweak how the scrollLeft moves.

var delta = sinoidal(timeIndex / scroller.scrollTime) * desiredOffset;
/* ... */
scrollee.scrollLeft = currentPosition + delta;

And voila, smooth and fancy animation.

Lastly, I created a simple locking mechanism to keep the scroller from getting confused if a link is clicked before the animation is finished. There is still probably work left to be done, but that goes beyond the scope of what I wanted to discuss. So go forth and make great apps!

See the final example in motion.



Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5