cott Cheng

CSS Multi-Transition Trick

It’s one thing to know a tool, another to make the most of it.

Transition is one of my favorite features that CSS3 has brought to the front-end toolkit. Smooth color change on hover can be achieved as easily as the following (see links on this site for live examples):

Smooth hover color change (anchor)
1
2
3
4
5
6
7
a {
  color: #555;
  transiton: color .25s;  /* vendor prefix emitted */
}
a:hover {
  color: #ed6812;
}

This is how I’ve always learned to use the transition property – only apply one transition rule to the element. However, what if we declare another different transition property in the :hover block?

Turns out it does magic. Try moving your mouse in and out of the bar:

Gentle-growing & rapid-dropping
1
2
3
4
5
6
7
8
9
10
11
12
13
#bar-inner {
  width: 5%;

  /* transition rule when not hovered */
  transition: width .5s .5s ease-in;
}

#bar:hover > #bar-inner {
  width: 100%;

  /* transition rule when hovered */
  transition: width 10s 0 ease-out;
}

Here I defined different transition properties on the different “states” (hover and non-hover) of the same element, and made the bar move much slower when hovered (growing) than otherwise (dropping). Also, different delays and timing functions are applied to the different states.

I also used this multi-transition trick to create the trailing dots effect of this experiment, where the dots fade in fast and fade out slowly.

It’s just exhilarating to explore new power of familiar tools.

Elegantly Highlight the Current Nav Item in Template

It’s one of the most common practices in web design to highlight the current navigation tab that the user is browsing. See my latest work for a live example:

Some suggest a CSS solution, which introduces additional coupling between CSS rules and navigation HTML markup. Some use simple JavaScript hacks and match the current location against the nav link, something like:

A jQuery solution
1
2
var link = window.location.pathname.match(/\w+/)[0];
$('nav li > a[href*="' + link + '"]').parent().addClass('active');

Which brings, well, additional script to run.

A JavaScript fan though I am, I believe that this “active” style is static, and all static styles should be accomplished by the server, rather than by client-side script. None of the templating languages that I’ve used, however, natively provides an graceful way of doing this ordinary task (they should!).

I’ll take my current favorite templating engine, Jade, for example. Here is a most direct method:

Straightforward method
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
nav
  ul

    //- Suppose we have a local variable `menu`
    //- indicating the nav item to highlight

    if menu === 'home'
      li.active
        a(href='/') Home
    else
      li
        a(href='/') Home

    if menu === 'blog'
      li.active
        a(href='/blog') Blog
    else
      li
        a(href='/blog') Blog

    if menu === 'about'
      li.active
        a(href='/about') About
    else
      li
        a(href='/about') About

Too much duplication! When the code is WET, we can almost always DRY things up a bit with loops (inspired by Peter’s solution):

Loop method
1
2
3
4
5
6
7
8
9
10
11
nav
  ul
    each nav in ['home', 'blog', 'about']
      if menu === nav
        li.active
          a(href='/#{nav}')= nav
          //- Use CSS to control case, e.g.,
          //- `text-transform: capitalize`
      else
        li
          a(href='/#{nav}')= nav

Lookin’ neat, except the “Home” link should point to root instead of /home. A dirty hack will do:

Revised loop method
1
2
3
4
5
6
7
8
9
nav
  ul
    each nav in ['home', 'blog', 'about']
      if menu === nav
        li.active
          a(href='/#{nav === 'home' ? '' : nav}')= nav
      else
        li
          a(href='/#{nav === 'home' ? '' : nav}')= nav

This looks good, as long as it meets the need. However, what if we want some anchor text wildly different from the links? We can further tweak it:

Further revised loop method
1
2
3
4
5
6
7
8
9
10
11
12
13
nav
  ul
    each nav in [{link: '', caption: 'home'}, {link: 'blog', caption: 'Essays'}, {link: 'about', caption: 'Bio'}]

      //- Suppose we have a local variable `navlink`
      //- indicating the link of the nav item to highlight

      if navlink === nav.link
        li.active
          a(href='/#{nav.link}')= nav.caption
      else
        li
          a(href='/#{nav.link}')= nav.caption

Works, with one caveat: Jade doesn’t support multi-line array literal or JavaScript code, which means the entire navigation array (all the links and captions) has to be packed into a single line of code! Unreadable, hard to maintain – not so appealing to me.

Here I’d like to propose a solution without too much in a line. It requires some repetition, but doesn’t feel too WET:

My favorite method
1
2
3
4
5
6
7
8
9
10
11
12
13
nav

  //- pass `menu` to li class attribute
  //- through a dictionary `nav`
  - var nav = {}; nav[menu] = 'active'

  ul
    li(class='#{nav.home}')
      a(href='/') Home
    li(class='#{nav.blog}')
      a(href='/blog') Essays
    li(class='#{nav.about}')
      a(href='/about') Bio

I love it because (a) it’s truly flexible, and (b) it’s clever enough to take out the if. The key here is “invert mapping” – from menu -> <nav-item> to <nav-item> -> active, made possible by a “dictionary” (Python jargon, I think more appropriate than “map” or “object” here).

Not perfect, but more elegant than the rest.

“S” in CSS

By “S” I’m not referring to “style” or “sheets”… I’m talking about the “S” in my logo – I remade it with CSS (Take a look at upper left if you haven’t noticed it). It’s largely inspired by Nicolas Gallagher’s genius pure CSS GUI icons.

A closer look:

It’s one HTML element!
1
<div id="s"></div>

Tags and #Hashtags

Karri Saarinen from Kippt hates tags, and brought #hashtags to his bookmarking service.

I do agree that hashtagging is superior to tagging in some way. Hashtags can be defined right inside the item body, whereas tags are conventionally separate from the content. So instead of noting “Nice color scheme” and tagging “color scheme”, I can just write “Nice #colorscheme”. For a brief note on a link, in Kippt’s case, this simplifies the bookmarking workflow. However, is hashtagging universally applicable? Imagine taking an detailed lecture note in Evernote, and hashtagging some keywords which are scattered over the 1,000 words. See the point? Hashtagging is good only if the content is short. It’s perfect for Twitter and Instagram for this very reason.

Besides that, hashtags and tags are almost the same thing. Karri says users should not be required to “describe the content” with tags, but lets them “channel or filter” the links with hashtags, which sounds pretty messed up to me. Tags and hashtags are both created to describe the content, and can both be used to channel or filter information. Describing comes in when you attach the tag / hashtag to an item, and channeling and filtering come in when tags / hashtags get indexed and become searchable. These are two intrinsic properties of both tags and hashtags.

Though hashtags can be a good choice for Kippt (since bookmark notes are usually short), they are not making the most of it. One important reason is that hashtag list is missing. I cannot find my frequently used hashtags; I cannot find any of my hashtags. I can only search them. But how is searching a hashtag anything different from searching the keyword without that hash? Well there is a difference: searching hashtags requires strict match, meaning you have to get the entire hashtag right before you can find what you are looking for.

Karri also disputes tags because some tags only have one item in them. Yes it happens, but how does hashtag alleviate the problem in any way? It makes things worse if Kippt does not prompt my existing hashtags when I hit # (and in fact it doesn’t; Evernote does good on this). Am I expected to magically remember the entire set of my Kippt hashtags, or am I expected to log into Kippt and find out whether I used #idea or #ideas in my previous bookmarks every time I add new ones? If I don’t, I’ll end up having multiple synonym hashtags, and bookmarks that belong to the same channel fall apart.

To make tags or hashtags work efficiently in an information management system, they have to be listed, and they have to auto-complete. Twitter doesn’t list hashtags or auto-complete them because tweets aren’t meant to be managed, at least not in the way bookmarks are. In other words, the purpose of hashtags in Kippt and in Twitter are fundamentally different.

Karri is right that tags are not ideal for “channeling and filtering” information, but it’s not because they are inherently broken or they miss a hash, but because they are often not used in the optimal way. It’s okay to have synonym tags, and it’s okay to have some one-item tags. We are not born librarians, and we are not supposed to precisely categorize stuffs the first time they land in our collection. But we should revisit our tag list (or tag hierarchy in Evernote). We should keep them organized by merging synonyms and by removing the rarely used and the meaningless. Our desk needs to be tidied regularly, so does information. We need to remind ourselves to come back and put things in order every once in a while, and we need an easy way to put them in order.

P.S. speaking of Kippt, I suddenly realized a couple of days ago what Jori Lallo meant by creating GitHub for links – make lists just like repos! Now Kippt lists are already collaboratable and watchable, let’s see when they’ll become forkable.

(Probably) the Easiest Way to Test Websites on Mobile

This is probably the easiest way to test your websites on a mobile device, especially if you don’t have a server to host your site: (and it came to me when I wanted to test mine last night)

  1. Run a localhost on your machine, may it be express, Apache, or anything that responds to HTTP requests.
  2. Find out your machine’s IP address in its local network.
  3. Connect your phone or tablet to the same local network with your “server” in it.
  4. Visit <host_ip>:<port> on your mobile browser.

That’s it – start playing with your site on the mobile device! The best part is, every time you update something, just refresh on your mobile browser and the change is there. How can that be any simpler!

Below is how this post looks on my Xperia S. I’m using Octopress preview, and it runs on port 4000 by default.