Monday

CSS Only Loader Animation

As I test out code changes in my local environment, I always run through this interstitial/waiting page that contains a loading animation. This animation is generally done via an animated .gif, or a .swf movie. Today while waiting for my app to load some backend stuff, it occurred to me that I could pretty easily replicate this same thing in pure HTML + CSS, thus making changes to color or shape super simple.

Here's a screenshot of what I'll be replicating:

NOTE: I'm doing this assuming Chrome browser, and so will be leaning heavily on CSS3, and the -webkit- prefix. At the end of this post, there's a link to site that does a bunch of awesome automated stuff for all this, so I'm eliminating all the complexity for the sake of this talk.
Update: Just added some -moz- support too, though Firefox doesn't animate as nicely as Chrome.

HTML

First, the markup. I figure I'm looking at a div that contains 5 objects. I'm going to call this thing "loader", and each object will just be a span (because they're inline) with a class of "frame" (though I probably don't need a class on these, I wanted to add them for clarity).

So, our HTML markup will look like this:

CSS

Basic Stuff

Let's now add in some basic styling for this thing. I really don't need to do anything with my #loader container, though I certainly could add some margin offsets or whatever I want. But my frames do need some love. I'm starting by defining a light grey background:

.frame {
    background: #999;
}
I'm going to set these to display: inline-block, because I want them still inline like spans want to be naturally, but also want them to have the dimension properties of block. I also want to set the size of these to 20px square, and add a right margin to offset them from one another:
.frame {
    background: #999;
    display: inline-block;
    width: 20px;
    height: 20px;
    margin-right: 10px;
}
That should get us looking like so:
Now let's make those squares into circles by simply defining a border-radius that's half as big as our width and height dimensions, and because I want to animate opacity too, I'm going to define something nice and light as a starting point:
.frame {
    background: #999;
    display: inline-block;
    width: 20px;
    height: 20px;  
    margin-right: 10px;    
    border-radius: 10px;
    opacity: .3;
}

Animation

Alright, now comes the really fun stuff. First, some additional reading as a point of reference: W3Schools.com: CSS3 Animations.

I need to define a name for my animation (sort of like a javascript function; I'll call ours "loader"), a duration for my animation (in this case I want my animation to last one second), and how many times I want this thing to repeat (in our case, I want it to repeat forever):

.frame {
    background: #999;
    display: inline-block;
    width: 20px;
    height: 20px;  
    margin-right: 10px;    
    opacity: .3;
    border-radius: 10px;
    -webkit-animation-name: loader;
    -webkit-animation-duration: 1s;
    -webkit-animation-iteration-count: infinite;
}
Nothing is going to happen yet though because we need to define what, specifically our animation is supposed to DO. Essentially, I want these circles to:
  1. Fade in/out
  2. Change color
  3. Grow slightly
So what I really want to define is a starting point (the base style for each where each .frame starts from), a middle point (how I want each of these to look my change), and and end point that gets us back to the start again. Each of these points are referred to as "keyframes", and we must define WHERE each of these keyframes take place in our animation. I like to think of animations like cells of a movie reel, or pages in a flip book, only instead of having to define every tiny movement between each .frame, the browser (via CSS3 animation) handles that for us. We can define our keyframe positions with a percentage:
@-webkit-keyframes loader {   
    0%   {}
    50%  {}
    100% {}
}
Now that we have our keyframes for our animation defined, we can define WHAT we want to happen at 0%, 50%, and 100% of our animation. Recalling my list of things I want to do (fade in/out, color change, size change), I'll add those in my keyframes. Note I don't need to define every property of my starting and ending points, because that's handled with our .frame styles we defined earlier. As such, I just need to define how these look in the middle of the animation, in this case opacity of 1, background-color of red, and I want to scale them up just a touch:
@-webkit-keyframes loader {   
    0%   {  }
    50%  {  opacity: 1.0; 
            background-color:red; 
            -webkit-transform: scale(1.2); }
    100% {  }
}
Now We have a nice set of circles that all sort of pulse together from slightly transparent light grey to a full opaque and slightly larger red. But we want each of these to sort of follow each other in the animation; that is, we don't want all of them pulsing simultaneously, but rather independently, and one right after the other. I can do this using nth-child selection and a keyframe animation delay for each of my 5 .frame objects. Because my animation is 1 second long, and I have 5 objects, I'll just divide 1/5 and set each animation delay to offset by .2 seconds; that CSS will look like this:
.frame:nth-child(1) {
    -webkit-animation-delay:0.2s;
}

.frame:nth-child(2) {
    -webkit-animation-delay:0.4s;
}

.frame:nth-child(3) {
    -webkit-animation-delay:0.6s;
}

.frame:nth-child(4) {
    -webkit-animation-delay:0.8s;
}

.frame:nth-child(5) {
    -webkit-animation-delay:1s;
}
Sweeeeeet. Now we're cooking with fire! So, what I've done is just delayed when the animation is supposed to start for each of my .frame objects, and presto - we've replicated our loader.

Changing color or shape

Before, my loading page used either an animated .gif/.swf, which if I wanted to change the color of these circles means I'd have to have extra software, or at the very least spend a little time re-working my graphics so I can output the new file. But now, if we wanted to change this to say, blue and square, all we need to do is edit some CSS:

.frame {
    border-radius: 0;
}

@-webkit-keyframes loader {   
    50%  {  opacity: 1.0; 
            background-color:blue; 
            -webkit-transform: scale(1.2); }
}

Demo


The above demo won't animate unless you're using a Mozilla or Webkit browser

Demo with Full Code (Demo currently works only in Webkit or Mozilla browsers)

Automated Way!

Of course, after having gone through this whole exercise, it's important to note that the internet saves the day by having online generator tools that do this for us; like this, totally awesome site cssload.net. Even still, it's fun to figure this stuff out so I better understand how it works.

Tuesday

How many travelers are there?

The travel industry is a pretty complex (and weird) one. I've been working in travel for over 20 years now, much of it through the lens of online travel. Now that I've spent some time in web development in this space, I'm beginning to better appreciate all the nuanced logic that goes into many of the things I've personally taken for granted.

For example, I've always just sort of understood that "nonstop" and "direct" aren't the same things (Nonstop literally means the airplane is not scheduled to make any intermediate stops between your origin and your destination. This is distinctly different than direct flights, which ARE scheduled to stop en route to your destination, but there is no change in flight number), but for a programmer to figure out this distinction programmatically can be a real challenge. I'm not going to talk about this stuff here though, instead I'm going to talk through how to figure out a traveler count for display on the front end.

In this case, my task was to add a list of traveler types based on the user's search criteria. Something like:
"2 Adults, 1 child".

Definitions

To start out, we need to identify the types of travelers that exist in the world of travel. We're dealing with 2 sort of base types:

  • Adults
  • Children
But in each there are variants, based primarily on age. For example, an adult means what exactly? To the airline industry it means a person that is 12 years old or older. But UNDER like 63 years old, when that adult is then called a Senior. For travel products this is often very important because pricing is dependent upon traveler type. I won't go into the labyrinth of crazy that is a typical airline fare filing which goes quite a lot deeper, but for now let's just say this:
  • Senior (63+)
  • Adult (12-62)
  • Child (<12)
Oh yeah, there's also Infants, for when a child is typically under 2 years old (for the airlines again, there's also the complexity of infants that sit in your lap, and infants that have their own seat)...So, it really turns out looking like something like this:
  • Senior (63+)
  • Adult (12-62)
  • Child (2-12)
  • Infant (<2) - Note: I'm combining both infants-in-lap, and infants-in-seat here

Essentially, assuming we have each travelers age, we can make the above definitions in whatever language we're using. In my case, that was true, because we have a Java object someplace that defines that for me. Also, the above rules vary a bit for Hotels and Cars (e.g. you have to be 18 to rent a car), etc, but for our example, we'll use what I've outlined above.

Labels

We say "2 Adults" or "3 Children" or "1 Senior"...in other words, our labels change based on if we're talking plural or singular. So, our labels are going to be like this:
SingularPlural
AdultAdults
SeniorSeniors
ChildChildren
InfantInfants

Logic

From here it's pretty straightforward:
  1. We map our passenger type counts
  2. We define an Array of travelers
  3. We figure out how many of each traveler type there is, and based on the traveler type count, we add to our Array the count and appropriate label (either singular or plural)
  4. We output our Array as a string, concatenating each count with a comma

We map our passenger type counts
What I mean by this is we need to get number of Adults, number of Seniors, number of Children, and number of Infants from Java. Something like:
private int getNumAdults() {
  return getSearchData().getAdults();
}
Repeat this for each traveler type. This gives us a nice set of variables to work with.
We define an Array of travelers
Here we want to define a container (an Array) to collect all of our traveler info. It'll be a String type, and we'll be collecting all our traveler information in here. In addition, because we have TWO types of infants (infants in seat or in lap), we'll just add those together because we're just summarizing traveler types here. As such, we'll have an integer that is the sum of getNumInfantsInLap() + getNumInfantsInSeat(), which we'll call "infants"
We figure out how many of each traveler type there is, and based on the traveler type count, we add to our Array the count and appropriate label (either singular or plural
This is where our logic lives. I won't output the full Java code we used here, but essentially we're just doing this (I'm going to use "travelerType" as a proxy for each of my types of travelers):
IF <travelerType> is greater than 0 
   (IF <travelerType> = 1, 
    THEN add "1 " + <singularTravelerTypeLabel>" 
    ELSE add N + <pluralTravelerTypeLabel>")
ELSE do nothing.
Hopefully that reads in a sensible way to you. But what we're trying to do is check the values for our traveler types and only add stuff to our Array when there IS something to add (i.e. we don't want to say "0 Adults"), and add the appropriate label based on singular vs. plural counts. Whew!
We output our Array as a string, concatenating each count with a comma
Here we basically transform our Array items into a comma separated string. Java has something nice for us:
StringUtils.join(travelers, ", ")

Closing

So what? Well frankly, I'm not particularly sure why I thought this would make a nice blog post. Only that it's something that continually comes up for me while I implement new UI features, and I thought I'd collect my thoughts and findings somewhere I could reference later. It also occurred to me that it may be neat for other sort of non-developers like me to walk through something like this with me. Particular programming language syntax aside, the above illustrates that even something seemingly very simple, like telling the user how many travelers they've searched for, is in reality a pretty complex set of considerations and logic we have to define before we can show that information accurately to the user.

Wednesday

CSS Outline

The other day at work someone asked me if I'd ever used the CSS Outline property. My answer was no; in fact I never even really consider Outline because border seems to be plenty. The best detail of this feature I found was at w3schools.com; there are some good examples there, but I thought I'd walk through this a bit too. To wit...

I'll start with a quick description of what it is. Essentially it's nearly identical to the border property, with a big difference; Outline is drawn OUTSIDE the borders of an element and doesn't take up any space in your document. Apparently they also don't have to be rectangular, though I haven't seen or can think of cases (yet) where that may be useful:

http://www.w3schools.com/css/css_outline.asp
Let's take a bit and walk through an example and play with it a bit. We'll being with a really basic list - For your reference, I've included the styling I'm using for these li elements below:
li {  
   list-style: none;
   display: block;
   float: left;
   height: 40px;
   width: 60px;
   line-height: 40px; 
   text-align: center;
   vertical-align: middle;
   background: #eee; 
}
Now, let's add a blue border:
li { border: 5px solid blue; }
Looks pretty familiar right? Each box is bounded by a blue border, which butts directly against one another. This is exactly what we should expect, but what happens when we add a red OUTLINE?
li { outline: 5px dotted red; }
Now this is something new. Specifically, we're seeing that each box is bounded by a red outline, but that red outline is sort of overlaying some of the blue border we added earlier...what the heck? Let's dig deeper. Quirksmode says this about Outline:
The outline is not actually a part of the box, it does not count in any way towards the width or height of a box.
Which is exactly what we're seeing here. That is, while our boxes are technically sitting directly against each other (as is evident with only our blue border applied), the red OUTLINE is applied outside those boxes, and thus doesn't have any affect on the layout of the boxes themselves. Seems like that could be useful, but let's for fun add some additional styles to our boxes to further see what's going on:
li { margin-right: 5px; }

ul {background: #ccc; padding: 5px; overflow: hidden; }
I first added a grey (#ccc) background and a 5px padding to my UL, and then added a 5px right margin to my boxes. Here's the result (the first set of boxes is with only the blue border, the second is with both the blue border and the red outline applied):
Knowing what we've just learned about how Outline behaves, this should make sense right?

Other stuff


Block vs. Inline elements

You can expect your outline to contain block or inline elements just like borders do.

outline-offset

You can define a distance from the outside the borders of your element to draw the outline. For example, "outline-offset: 2px" means your outline will start an additional 2 pixels outside the edges of your element...cool. It's important to note that there is not an equivalent offset property for borders.

outline-width

Presumably because outline isn't really intended as decorative functionality, or maybe because we already have borders, you can only effect the width of your outline in its entirety; that is, you can't selectively have only say a outline-top, or an outline-width of 0 5px 5px 0...

border-radius

Has no effect on outline at all. Think of outline as just drawing a box around the edges of your element, regardless of how you might decorate that element.

Usage ideas

Document inspection
You could add some ultra quick and easy firebug-esque element highlighting by just adding the below, which will highlight every element you hover over without breaking the document flow or layout at all.
*:hover { outline: 1px solid red; }
Wireframe view
Just change your outline selector a little, and you'd see outlines of every element on your page:
body * { outline: 1px dotted red; }
A bit heavy handed with the wildcard, but changing your selector to just an element type (e.g. div, p, a, img, etc) you could instantly see all components of that type on your page. Kinda nifty.
Inline edits
Maybe we could make edit-in-place-able elements a bit more obvious on hover by adding a nice, wide outline of the same color as your element's hovered background color.
Inline form error highlighting
Similar to that last idea, we could add a nice wide outline to our form fields that have some field validation issue, thus better visually calling out the offending field(s) to the user.
Others?
There seems like we could come up with lots of potential uses for this feature (e.g. maybe tabbed interfaces, which I haven't played with yet); what are your thoughts?

UPDATE

Turns out Firefox likes to show the outline outside of a box-shadow, whereas Chrome likes to show it at the edge of the actual box (inside the box-shadow). Terrific! Another example of browser fun.