03 Dec 2011

Warning! This article might crash Internet Explorer!

This is the first in - what I hope will be - a series of articles on the useful information I received from visiting the Fronteers 2011 conference in Amsterdam last October. Like my articles of last year's conference, I will not give a talk-by-talk summary, but rather pick out the subjects that interest me most and expand on those subjects, while referring to the original talks to give credits due.

I will make a small exception for the talk by Lea Verou on CSS because it was so excellent and informative, I have instead chosen to convert her online slides to an (interactive) demo, which you'll find below. The original talk included these slides but were interactive, which doesn't seem to have made it to the online slides.

The demos below should work on all latest stable versions of the major browers, except IE 9. You can check for support of individual features on caniuse.com.

Bouncing transitions

In this article I already covered pure CSS transitions, but Lea has an extension on this by adding easing and even bouncing. First off, transition can be applied to lots of things outside position or size. Background color and text-shadow are also supported, just to name a few. A complete list can be found here. When applying it to position (hover over the red balls below to see demos), it's easier to discriminate between the different forms of easing. The default setting is "ease", which eases at the start and the beginning of the transition. Try the two examples below to see the difference.
transition: 1.5s ease;
transition: 1.5s linear;
There is support for making the transition follow the shape of a cubic bezier curve, which gives the transition a bouncing appearance. This bounce is not supported in Chrome 15, because of this bug.
transition: 1.5s cubic-bezier(0, 1, 1, 2);

You can use Lea's tool to calculate nice/useful beziers.

Box-shadow-o-rama

In this article I already mentioned box-shadow, in it's most basic form resulting in something like this:

But it is also possible to add shadow spread, the "20px" in the example below. As a reminder, the first two zeroes are the horizontal and vertical offset respectively and the 10px is the blur radius.

box-shadow: 0 0 10px 20px white;


In contrast to increasing the blur radius, increasing the spread will not make the shadow lighter. It is even possible to define a zero blur radius and a (high) spread, making the shadow solid and essentially emulating a border.

But unlike borders, multiple box-shadows can be defined. Creating this example using only the border attribute would have required three divs (or other HTML elements), but using multiple box shadows it can be done with just one div:

box-shadow: 0 0 0px 5px white, 0 0 0px 8px red, 0 0 0px 11px white;
The downside of using a box-shadow as a border is that you can't use border-style properties, like dashed or dotted. And writing this article, I've also experienced some alignment issues as the box-shadows are not counted in computing the element width like borders are (box model headache, anyone?)

Pass through

Working with transparency in webdesign has caused lots of troubles, one example being semi-opaque overlays. If such an overlay is rendered over an object that should be clickable (see the examples below for clarification) it is often only possible by taking a set of images or resorting to Flash. But using the attribute pointer-events, clicks can be "passed through" to the underlying element.

default:
pointer-events: auto;
pointer-events: none;This is also useful for customizing the styling of dropdown selectors by overlaying images, because these elements are normally unstylable, making it necessary to make the dropdown transparent so you'll see an image below the dropdown as a workaround. Even so, support for pointer-events is quite limited but Lea offers a workaround, compatible with a feature detection based approach, for this in her slides.

Structural pseudo classes

Something I have yet to cover are CSS structural selectors. Assuming you're in a small shock now, confused by these terms, let me clarify. Aside from HTML elements by id or CSS class, ever since CSS 2.1 there are more specific selectors, like :not (e.g. div:not for selecting all elements that are not a div) or :empty (e.g. div:empty for selecting all empty divs). And also structural selectors, selecting based on the place of an element in the structure of the page, such as :first-child for selecting the first child of an element, see this example:

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9


Selected with this statement:

#struc1 li:first-child {   background: navy; }

The more specific :nth-child() selector can be used to select any specific child, e.g. the second, by using :nth-child(2)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9


Or :nth-last-child(2), i.e. the second last child.

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9


But :nth-child has a more complex syntax, to be exact :nth-child(an+b), and also allows the keywords even and odd, so :nth-child(odd) results in:

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9


And :nth-child(3n+1) matches all elements y for the n is the set of integers from 0 to infinity.
Please keep in mind that I'm not a mathematician, far from it, but y = 3n + 1 for n = 1 or higher matches children: 3 x 0 + 1 = 1, 3 x 1 + 1 = 4, 3 x 2 + 1 = 7, 3 x 3 + 1 = 10 and 10 is already beyond the total number in my example, so:

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9


is selected by:

#struc1 li:nth-child(3n+1) {   background: navy; }

This is of course wonderful for selecting odd rows in a table, for instance. The formula is explained in greater detail here.

Lea describes in her talk how these selectors can be chained, e.g. li:only-child is equivalent to li:first-child:last-child. This will never match in my example, because I have 9 items, but I can select an item that is the 8th child and the 2nd last item, with this statement li:nth-child(8):nth-last-child(2)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9


If the list is dynamic and the 9th item would be removed, the 8th item would still be the 8th child but no longer the 2nd last and therefore it would no longer match. Test by clicking here and removing the 9th item.

Using the ~ operator, for items preceded by another item, I can select all items preceded by the 7th item using

li:nth-child(7) ~ li

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9



I've managed to select the range from item 3 through 6 in this example:

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9


by using these selectors

#struc8 li:nth-child(3),
#struc8 li:nth-child(3) ~ li
{
  background: navy;
}
#struc8 li:nth-child(6),
#struc8 li:nth-child(6) ~ li
{
  background: red;
}
The use that Lea offers is modifying the layout of your page based on the number of elements that have to be accommodated. Instead of relying on flowing the elements on the page by setting fixed widths and floating elements, you can adjust the width based on the amount of elements.

Imagine a shopping cart in an online shop that shows a preview of the contents of the cart. The preview window has a fixed size. When one item is added you want it to fill up the entire preview window, but as more items are added, you want to scale them. When more items are added than can be displayed reasonably, the first 8 items are shown, plus an indicator of the remaining amount of items in the cart.

Your Cart

  • +
  • -

Using nothing more for the styling of the cart items than this:

/* at least 1 child */
div.cartitem:first-child:nth-last-child(n + 1),
div.cartitem:first-child:nth-last-child(n + 1) ~ div {
  background-position: 0 0;
  height: 165px;
  margin-left: 80px;
  width: 165px;
}
/* at least 2 children */
div.cartitem:first-child:nth-last-child(n + 2),
div.cartitem:first-child:nth-last-child(n + 2) ~ div {
  margin-left: 5px;
}
/* at least 3 children */
div.cartitem:first-child:nth-last-child(n + 3),
div.cartitem:first-child:nth-last-child(n + 3) ~ div {
  background-size: 80px;
  height: 80px;
  margin-top: 40px;
  width: 80px;
}
/* at least 5 children */
div.cartitem:first-child:nth-last-child(n + 5),
div.cartitem:first-child:nth-last-child(n + 5) ~ div {
  background-position: -40px -40px;
  background-size: 165px;
  margin-top: 5px;
}
Very elegant, even if I do say so myself.

Background patterns

Linear-gradient can be used to make a CSS only gradient background, instead of having to work with background pictures. The official syntax can be found here, but let me show some examples. For all the following examples: click on the code snippet to activate the demo! By the way, if you think I've gone insane in choosing the colors for this demo, I must apologize for making you feel nauseated, but it's the only non-grayscale color with the right amount of contrast I could find. Using non-grayscale is essential to make the transition between colors in the gradient clearly visible.

background: linear-gradient( 90deg, navy, rgba(100,100,100,0.5) );

Where the first (optional) parameter is the direction of the gradient, followed by the two colors of the gradient. All normal color formats are accessible, in this case I've used a color keyword and a transparency supporting rgba value.

Placing values (px or % are valid) after the colors, places a color stop at that position. In the example below navy will stop at 60% of the width, counting from the left of the page and gray will start at 90% of the width, also from the left of the page. The space between 60% and 90% is the gradient.

background: linear-gradient( 90deg, navy 60%, #343434 90% );

Using color stops, the transition area of the gradient can be made very wide (such as the default, in the first example) or so narrow that it looks like there are just two adjacent colored planes.

background: linear-gradient( 90deg, navy 60%, #343434 60%

When adding background-size, background images can be resized, this also works for gradients, so a repeating background appears.

background-size: 200px 200px;

By rotating the gradient to 45°, this does not (yet) yield diagonal alterating bands of navy and gray, because the gradient exists in (repeating) 200x200px squares, and is only rotated within does squares.

background: linear-gradient( 45deg, navy 50%, #343434 50% );

Lea solves this by using a photoshop trick, adding several color stops, essentially creating multiple gradients within the 200x200px square that blends into its neighbours. Compared to this example it just looks like narrower lanes, but remember the background size is still the same size, so now there are 4 lanes in one square.

background: linear-gradient( 
  90deg,
  navy 25%, #343434 25%,
  #343434 50%, navy 50%,
  navy 75%, #343434 75%
);

Rotating that gives the diagonally striped background.

background: linear-gradient( 
  45deg,
  navy 25%, #343434 25%,
  #343434 50%, navy 50%,
  navy 75%, #343434 75%
);

This wraps up this interactive demo, I plan to cover the rest of the CSS related material in my next article.