Archive for the ‘CSS’ Category

Relative CSS Positioning

Saturday, September 20th, 2008

I learned a couple of CSS positioning rules that are not immediately apparent from reading W3Schools. Web designers are familiar with these rules, but this information needs to trickle down to us brute-force developers.

The position CSS style
Here are some rules I learned from Aucustic Cuckoo.

The position: relative and position: absolute styles don't work the way you might expect as a developer. We expect that absolute means to set the position from the top-left corner of the window, and that relative means to set the position from the container. Both of these assumptions are wrong.

If you don't set a position CSS style on your element, the browser lays it out based on the surrounding elements and reserves space for it. This is called static positioning.

The position: relative setting positions the element based on its static position. The element still takes up space as if it were in its static position. On its own, it's almost useless.

The position: absolute setting positions the element based on its containing block. The containing block is a parent element that is not statically positioned. Most of the time, that means you are placing elements in window coordinates.

To get the most out of these settings, you have to use them together. Set the position of a parent div to relative, but don't touch any of its other positioning properties. This will cause the parent to act as if it were statically positioned, but qualify as a containing block. Then you can set the position of child elements to absolute to position them relative to the parent. Yeah, it blew my mind, too.

The right and bottom CSS styles
Here's one I picked up from watching a video on Chris doesn't explicitly call this out, so I had to pause the video to read his CSS.

I usually move elements by setting their X and Y coordinates. To me, X maps to left and Y maps to top. It never occurred to me that an element has right and bottom properties, too.

If you set the right property and not the left, then the right side of the child element will be positioned relative to the right side of the parent. So if you want to right-align an image inside a div, set the div position to relative, the image position to absolute, and the image right to 0. Same thing for the bottom.

The float and clear styles
And finally, here's one from BarelyFitz.

The float style is usually used to wrap text around an image. But web designers have figured out how to use this property for columns. If you float your main content to the left or right, then your side bar will sit nicely next to it. But be sure that the floating element has greater height, or the other elements will wrap around it at the bottom. That's why the main content is usually floating, and not the sidebar.

To put more content after all of the floating elements, set the clear property to both. This could be used to put a footer on a page, but is not as easy as nesting divs. Put the side bar and the content in one div, and the footer in another.

Ken Burns Effect in Javascript

Thursday, February 28th, 2008

The Ken Burns Effect is a popular way of adding emotional appeal to a slide show. It is named after the documentary film director who used it extensively in his series on the American Civil War and Baseball. It is used in the default OS X screen saver. It even makes an appearance as a presentation technique in the 2006 Tom Hanks movie The Da Vinci Code. I thought this would be a fantastic way to showcase photos in the web.

You can see the result with some family photos. I've included photos of all sizes, aspect ratios, and image qualities. This shows off the versatility of the code, but also demonstrates the tradeoffs between quality and speed. I should warn you that image processing in the browser is quite taxing on the client machine. This looks great on my MacBook Pro, but is not so smooth on a less expensive laptop. Flash or Silverlight would be a better choice for client technology.

To use this effect, download the Javascript file and the CSS file. Create two <div> tags within your HTML that occupy the same area. In the example, these <div> tags take up the entire screen.

Fill an array with the URLs of the images to display. You can optionally pass this list to the randomizeList function to shuffle it. Then call the startSlideshow function with this list and the IDs of the two <div> tags. Show source on the example page for more details.

How does it work
The effect uses the setTimeout function to schedule animation steps. It breaks down the animation into fading and panning. The panning is controlled by an object that converts a time index parameter into offset and size. A set of linear equations determine these properties, so that the effect is a smooth transition from one zoom rectangle to another.

The coefficients of these linear equations are determined randomly such that the beginning and ending points are within the bounds of the picture. Because the equations are linear, all points in between are also within bounds. The aspect ratio of the original image is preserved.

The most interesting part of this project was getting the CSS manipulation correct. The images use "position: relative" to indicate that they move relative to their natural resting place. This allows the containing <div> to crop them to fit. But this also means that the images could not coexist within one <div>. Relative positioning is affected by layout, so the second image would be offset by the size of the first.

Next steps
I've already created a SharePoint view of a picture library using this effect. I plan to package that as a web part and post the code here. I also plan to write code to extract images from Flickr library.

If someone beats me to it, just post a link to your code in the comments. I'll be sure to promote it to a post so that everyone can enjoy.

Composability and orthogonality in language design

Wednesday, February 20th, 2008

Each time I delve into the HTML/CSS world, I am reminded of why I love the Algol-derived languages.

Algol was the ancestor of modern imperative languages like C# and Java. It introduced the concepts of orthogonality and composability to computer language design. Orthogonality is the property of a construct that means it does not intersect with others. There is just one way to express any single idea. Composability is the property of constructs that they can be combined to express larger ideas.

Java is an excellent example of an orthogonal, composable language. Classes, methods, statements, and expressions are all different things (orthogonal). If you want to describe a type of object, you use a class. If you want to describe behavior, it's a method. Through composition, you can describe more complex ideas, like the behaviors of types (class + methods), anonymous types (class + expression), and loops (statement + expressions).

C# relaxes the ideas just a little. For example, a delegate is both a type (class) and a behavior (method). Properties look like members, but act like methods. Since these language constructs serve dual purposes, there is sometimes more than one way to express a simple idea. This was done in the name of convenience, at the expense of language purity.

Contrast this with the two ubiquitous languages of the web.

HTML is composable, since you nest elements to construct pages. But these constructs are not orthogonal. An image, for example, could be represented either by an <img> tag or by a <div> with a background-image style. HTML lack of orthogonality is due mainly in part to legacy, as CSS obsoletes elements like <b>.

CSS lacks both composability and orthogonality. Cascading is a limited set of rules, not a true composition mechanism. And several of the attributes interact such that you cannot control one without influencing another.

The "Ken Burns" effect
For example, I am currently implementing the "Ken Burns" effect in Javascript. Images zoom, pan, and fade into one another. Yes, this would be better done in Silverlight or Flash (both highly composable and orthogonal, by the way). But I'd like a solution that requires no plug-in. And having had success with cover flow, I thought I would give it a try.

For the effect, I need to fade from one image to another. So the two images must overlap. In addition, I need to pan and zoom within the frame. This requires that I crop the images. CSS has constructs for both. Unfortunately, they interact.

There are two interrelated concepts at play in the placement of elements on a CSS-based web page: location and layout. Location is the placement of an element itself, whereas layout determines how an element affects the placement of other elements around it.

Position and overflow
The position attribute in CSS affects both placement and layout. The default position is "static", which means that it is entirely under the control of layout. To move an element, you usually set the position to "absolute". This not only gives you control of its position, but also takes it out of the layout equation. For panning, you set position to "absolute".

Now to get the clipping working. We can put the images inside a <div> to define the clip region. Setting overflow of the <div> to "hidden" causes all child objects that fall outside its borders to be cropped.

Unfortunately, for reasons I have yet to comprehend, "overflow: hidden" does not affect child elements with "position: absolute". One attribute controls clipping, while the other controls placement. They should be orthogonal, but they are not.

To solve this problem, I have to select a strange value for position. The position "relative" is properly clipped. However, it combines the ideas of location and layout. Relative positioning is not relative to the containing <div>, as you might expect. Instead, it is relative to the object's resting place as determined by layout. To further confuse the issue, layout proceeds around the object as if it was not moved.

Since I have two images inside the <div> - one fading into the other - the layout of the second is going to depend upon the size of the first. I have to do some extra math based on the size of the first image to adjust the placement of the second. Furthermore, when I switch to a new image, I need to quickly readjust that compensation. I haven't yet determined how to accomplish this without causing some kind of flicker.

Because the CSS attributes are non-orthogonal, I have to solve a multi-variable problem to determine which CSS properties to use to express any given idea. Maybe a plug-in is not so bad.

Cover flow in Javascript

Monday, April 9th, 2007

My wife is a scrapbook consultant. She was looking for a way to showcase her artwork on her web page. Instead of your typical list of thumbnails, I thought it would be more interesting to put her scrapbook pages in iTunes cover flow. So after a weekend of messing with javascript, this is the result:

It doesn't have the oblique angles, but I think I know how to achieve that effect. There is also a Safari compatibility issue, and a performance improvement I can make. More to come.

Finn Rudolph has added many enhancements to the original script. I highly recommend using his Image Flow.