A Work in Progress

developer's blog by Wei
lots of work in progress notes

Magazine Layout for Viola Site

November 19, 2020

Recently I ran into this website Violins and Violinists and I immediately fell in love with its design, layout, and interactions. So I try to replicate the UI on my site for my hobby playing the viola - wei and the viola.

Violins and Violinists is visibly a site for an artist. Its site master self-identifies it as a magazine:

The occasional magazine of Benjamin Hebbert, Violin Dealer & Expert

The site features an astonishing layout that is rarely seen in platform-structured sites. Its list of articles streams down columnized. And when you hover on the card of an article, it kind of slides up as if some mystic force floats it up in the air upon your attention.

Screenshot for the site Violins and Violinists
Screenshot for the site Violins and Violinists

I thought this design is really cool and natural. And I want to replicate it in my own viola site, because the topic is fairly close and I really want to try multi-column layout for listing. I'm faily confident about the animation part because of a few recent build such as the flashing effect on this site I'm building with my friend Huijing. It's the multi-column layout that will be causing a bit hair pulling, as the browser spec for the multi-column layout does not allow elements to span certain number of columns, which is what is implemented in the original site (it's not using CSS multi-column). And the overall support of multi-column layout isn't great.

Hover animation

First I worked on the hover animation. The implementation on the original site uses BEM, which thankfully makes it very readable. The .card_wrap wraps the whole card, where a .card__hover wraps around the same children and carries the hover event. Then the .card__hover:hover pseudo-selector will be used to target covered children for their respective animations.

Take a look at the original animation behavior. I see it as two parts. First, the image is shifted upper left, leaving a shadow behind. Second, the title box is lifted upper left but mainly up, the left component only to match the image's displacement. And some extra content is displayed inside the title box.

Original hover animation

The original animation implementation is what in my opinion a bit overly complex. It implements a pseudo-element for the shadow, which is by default translated bottom-right, and this transformation is removed upon hover. The remaining of the card translates upper-left when hovering. And because of this offset transformation, the title box is transferred directly up. So altogether it has 3 things that are moving during the transform: the image, the title box, and the shadow.

Also worth mentioning in its original implementation is the use of will-change. This is a CSS property to hint browsers how an element is expected to change. It is intended to improve performance and responsiveness, but actual usage can be tricky, see here.

Original hover implementation
Original hover implementation

I've taken a simpler approach (I think). Instead of using a pseudo-element for the shadow, I make the card wrapper black in background and that stays stable. When hover happens, I have two transformations only, corresponding to the two animations. I translate the image and the title box upper left together, with their respective dislocation. Here's my DOM structure, without adding the further detail yet, I have only one element each for the image and the title only, and I'm not using a pseudo-element.

My hover implementation
My hover implementation

As to the animation CSS, here are the two transforms:

li:hover > .image-card {
  transform: translate(-8px, -8px);
li:hover > .title-card {
  transform: translate(-8px, calc(-50% - 30px));

I copied the transition function from the original implentation directly. But if you are interested in understanding Bézier Curves better, I have a talk earlier The Obscurities of Bézier Curves Explained to My Computer Engineer Friends at SingaporeCSS #52.

li > .image-card,
li > .title-card {
  transform 0.25s cubic-bezier(0.785,0.135,0.15,0.86)

And here's how it looks (without the detail info, for now):

Refine title box layout

Some refinement work here at the title box.

In the magazine site, the title box reveals a bit further information when hovered such as category, author and date. I have a similar information structure, except that all posts are written by myself, so I can leave out author and save some space.

I've pretty much reused all the styling here, with a little bit of eyeballing the colors. Relevant here is that I decided to keep using my previous font – I like its classy touch. I've added a 1.1px letter spacing here because it looks more comfortable with a little bit more space between the letters. Text rendering is a magic in browsers. It's the only case where even a .1px will visibly make a huge difference.

title box info display
title box info display

I've also updated the styling here to place the title box more precisely 50% sitting on the bottom of the card. Once again I think my implementation is arguably more performant here. The problem is that we don't know how tall the title box will be. If the title is very long, then the box can grow quite tall. So we can't tell the browser in advance how much below the bottom line the box should go. I'm using a CSS solution here, namely translateY(50%). translate is one CSS property that won't cause browser reflow, so that's very good for performance. And it kind of acts like it'll move the element after it's already been placed on the screen, so the browser knows how wide or tall the element is already.

title box vertical center
title box vertical center

The more interesting part is the animation of the detail info. I had a naïve solution as well. But this time not as great as the original site. My solution was to set display: none to hide the extra row when not hovering, and reveal it when hovering. The opacity part is the same. The problem is with the transition from display: none to display: block causing an instant jump of the height of the title box. This is because you can't give it a timing function as "to display or not" is not a measurable dimension that can be stretched over time.

To describe the "appearing" animation more specifically, what we do is a combination of change in transparency and growth of the box height. Initially, we set zero transparency and negative margin to hide the element. The negative margin is such that the element is "retrieved" a little bit so that the box is shorter. This doesn't matter because it has zero opacity and is therefore invisible. When hover, we change opacity to completely opaque and remove the negative margin to unhide it and move it in place. Both the change in height and opacity can be parametrized and therefore we can see a growth in the title box height and the text to appear from transparent. If I uncheck the opacity change, you can see the card height mechanism here:


work in progress

  • column layout
  • ? mixing grid layout