Posts tagged css

Photo URL is broken

Building on Tags and Pages, I've added one more navigation tool. Now, if you hover over Blog in the header, you'll get a drop down menu of some popular tags. Since I don't really have any readers, by popular, I mean what I think is important.

Implementation-wise, I store the list of tags that I want to display in Redis as a JSON array. I can edit that list by going to Application Settings without doing a redeploy.

For the front-end, there's no JavaScript. The HTML looks something like

<ul id="header-menu">
    <li class="header-link blog"><a href="/" class="header-link">Blog</a>
         <ul class="header-dropdown-menu">
            <li class="header-dropdown-link header-link blog"><a href="http://www.phillypham.com?tag=math" class="header-dropdown-link header-link">Math</a></li>
            <li class="header-dropdown-link header-link blog"><a href="http://www.phillypham.com?tag=cooking" class="header-dropdown-link header-link">Cooking</a></li>
            <li class="header-dropdown-link header-link blog"><a href="http://www.phillypham.com?tag=algorithm" class="header-dropdown-link header-link">Algorithms</a></li>
            <li class="header-dropdown-link header-link blog"><a href="http://www.phillypham.com?tag=stat" class="header-dropdown-link header-link">Statistics</a></li>
            <li class="header-dropdown-link header-link blog"><a href="http://www.phillypham.com?tag=meta" class="header-dropdown-link header-link">Meta</a></li>
        </ul>
    </li>
</ul>

As for the CSS, the key part is

ul.header-dropdown-menu {
  position: absolute;
  list-style: none;
  padding: 0px;
  margin: 0px;
  overflow: hidden;
  max-height: 0px;
  transition: max-height 0.5s ease;  
  background: rgba(254, 254, 254, 0.9);
}

li.header-link:hover > ul { 
  max-height: 252px;
}

We have that the position is set to absolute, so it displays on top of everything without affecting the layout of the rest of the page. We set overflow to hidden and max-height to 0px, so that it's not displayed. Then, we use a child selector, so when we hover over the parent element, li.header-link, we select the child ul and adjust its max-height. The transition property just pretties things up.

Here's the full CSS.

ul#header-menu {
  align: bottom;
  list-style: none;
  padding: 0px;
  margin: 0px;
}

li.header-link {
  display: inline-block;
  line-height: 28px;
  padding-top: 0px;
  padding-bottom: 0px;
  margin: 0px;
  min-width: 140px;
}

a.header-link {
  color: #003b52;
  display: block;
  margin: 2px;
  font-variant: small-caps;
  text-decoration: none;
  font-size: 125%;
}

a.header-link:hover {
  color: #d02027;
  outline: 2px solid #d02027;
}

ul.header-dropdown-menu {
  position: absolute;
  list-style: none;
  padding: 0px;
  margin: 0px;
  overflow: hidden;
  max-height: 0px;
  transition: max-height 0.5s ease;  
  background: rgba(254, 254, 254, 0.9);
}

li.header-link:hover > ul { 
  max-height: 252px;
}

li.header-dropdown-link {
  display: block;
  width: 100%;
}

a.header-dropdown-link { 
  outline: 1px solid rgb(34, 34, 34);
}

See how it smoothly expands and contracts. Very cool, right? I think so. Even the animation is done in CSS. Since the number of items in the drop down is dynamic, I would like to set the height to auto. Unfortunately, CSS transitions don't work in that case, so I instead set the max-height to a number large enough. This has the disadvantage that the time of the transition is based on the max-height, so it will transition faster than desired.


Perhaps the funnest part about this blog was writing the commenting system. One may want to comment on a comment. I found a way to support this behaviour with recursion.

In the layout, using Jade mixins, we have something like

mixin commentView(comment)
    - var children = comments.filter(function(child) { return comment.id === child.commentId; })
    .wmd-preview!= comment.bodyHtml
    .children
        .inner-children
            each child in children
                +commentView(child)

We need the inner-children div to create the smooth transitions when you expand the sub-comments. Apparently, CSS transitions only work when the height is specified, so you can calculate the new height of children with inner-children.

We can also expand comments recursively with JavaScript:

function expandParent(node) {
    if (node.classList.contains('comments')) return; // we've reached the top level
    if (node.classList.contains('children')) {
        node.parentNode.querySelector('.reply-expander').classList.add('expanded');
        node.classList.add('expanded');
    }
    expandParent(node.parentNode);
}

I've left some sample comments below to show off the features. Apparently, transitions are only smooth in Chrome and Internet Explorer. Leave a comment below and try it out!