Next article
On Mechanical Keyboards
Jan 27 2015

On Building This Theme

Some of the philosophy behind the new Solo theme for Webhook and how I normally go about building small design projects.


You can get your own version of this site by installing Webhook and choosing the "Solo" theme in your CMS. Then deploy, attach a domain and you're all set.

One of the hardest problems I've had building Webhook is that I haven't had much time to actually build anything with Webhook. The original themes we launched with the CMS after our Kickstarter were mostly test scenarios to make sure the generator side of the system worked. But people kept installing them, likely because they were just testing things out themselves. That's fine, but people tend to judge a CMS system not by what the admin and code can do, but by the design of the example site, so I've always been embarrassed there wasn't something nice to make a good impression.

full

"Something nice" though takes time. I built our new Solo theme during January over the course of ninety or so hours. Most of that time was making sure it's flexible enough to use by others, not just myself. That said, requirement #1 was always that it would be something I'd actually use myself, hence this site.


Here were some of my loose requirements for the project:

  1. It needed to focus on readability.
  2. It needed to be minimal.
  3. It needed to work great in mobile.
  4. It needed a great image gallery that could let me sort and caption images in the admin. On the design side I wanted to be able to use the arrow keys to navigate through images, but still have URLs I could pass around.
  5. It needed simple articles that still allowed for magazine style layouts. If I could, I wanted this to work both with a Markdown editor (my preference) and a WYSIWYG (the world's preference).
  6. I thought it would be cool to add tumble-style features that allowed me to quickly post videos and links I thought were interesting. It takes awhile to post an article, but quick links can usually give context to your online persona over time.
  7. I wanted to utilize the Webhook API both to introduce people to how fucking rad it is, but also to auto-slurp in content I'm already posting / following on Twitter, Youtube and Pinboard.
  8. I wanted to be able to post code snippets on the site, so I needed syntax highlighting of some kind.
  9. I wanted to use some animations if possible.

Without getting too esoteric, let's break down each of these design ideas and how I ended up solving thme.

Readability / minimalism

I've never been a fan of flashy design. To be fair, I've never been a good enough designer to pull it off. I like boring treatments with high contrast and fewer things to take away from the text. Very broadly here's how I actively go after readability and minimalism.

Pick two good fonts

A good basic rule for picking fonts is to only pick two of them: one for text and one for headlines. Unless you're a Font expert, I usually suggest making one of them serif and one of them sans-serif. Since this is a theme that could be installed anywhere, any custom fonts I use needed to come from Google Fonts, because Typekit requires knowing the domain name (which could be anything).

When reading long form articles I always enjoy a serif font. They only really work with minimal layouts though, because complex layouts usually need smaller text with different colors and serif fonts tend to fall apart the more style you need to add to them. But this site is pretty simple, so I went with Merriweather, a nice newspapery style font.

Following my earlier suggestion that means I need to go with a Sans font for my headlines. Usually Sans fonts come in a little bit more variety and because of their lighter nature you get a lot more choices when it comes to headlines. I went with Noto Sans because I thought it had good weighting to it. I knew I could use it both for thick headlines and paragraph style decks.

Use a single value to calculate the space between elements

Minimal designs usually give quite a bit of white-space to text, headings and nav elements to achieve that spartan look. I base all of my spacing, be it padding or margins, on a magical $base-line-height Sass variable. Usually it's just 1.5x the actual font-size of a <p> tag element in your article. Usually 16px is a good, readable value for the font-size, so we end up with a $base-line-height of 24px. This is a good number because 24 can be broken up into fourths (6px) if need be. Now you have your magic variable for calculations. Every time you make an element, just use a multiple of that number.

.some-design-element
  padding: $base-line-height
  margin: $base-line-height * 2
.some-other-element
  padding: $base-line-height / 4 $base-line-height / 2
 h1
     margin-bottom: $base-line-height

Use it everywhere. Now you can give your design a very different feel just by changing one variable. More imporantly, your elements are now all proportional to one another. The difference between a spartan design and one that looks like just a prototype is that all the lines line up.

Stick to grayscale, then pick one accent color

The very easiest way to achieve minimalism is to work with a flat grayscale color scheme while you build. These days I code, rather than Photoshop my designs so its easier to change colors later. My Sass library of patterns , Wyrm, has a bunch of default grayscale colors that I use for initial coloring. It looks like this.

$black:                               #000
$gray-darker:                         #222
$gray-dark:                           #333
$gray:                                #555
$gray-light:                          #999
$gray-lighter:                        #ccc
$white:                               #fff

That's usually all I need for a site with a light background. Sometimes you'll need more subtle borders or the like, but I can always use Sass's darken() and lighten() attributes on these variables for subtle changes. Working this way just makes everything easy to build. Matching even two colors is very difficult, but gray always go well with gray.

Only when I'm near the end of a project do I start fooling with color. Usually it's as simple as figuring out the default link color (in this case red) and finding different elements to splotch it on. Again, if I need some variation, I just lighten() and darken() that red as necessary.

Mobile

These days it's pretty easy to get your designs working well on mobile as long as you use a decent grid / breakpoint system. I'm a big fan of Thoughbot's Neat system mostly because it keeps the naming scheme at the code layer. I generally set two breakpoints, one for tablets and one for phones. This design is pretty sparse though so the only big difference in the design between devices is the menu system.

Image galleries

I think I've tried just about every lightbox by now. Most of them are pretty terrible. The one I normally use fluidbox is great for single images in articles, but doesn't have great gallery features and would be a little too slow to page through. Eventually I settled on using Swipebox which had nice support for key commands and mobile swiping. Its default styling didn't really match my design so I rewrote a good portion of the CSS layer and added a few features. I also had Ian dig into the JS bits to make it so it would build (admittedly very ugly) URLs that you could pass to someone for just one of the images. The other nice part about Swipebox is that it had pretty decent support for YouTube and Vimeo videos as well, so I ended up using it for that portion of the site as well.

Simple, magazine-style articles

Lately I've become more and more of a fan of composing documents in Markdown. Webhook's WYSIWYG is pretty powerful, but like any WYSIWYG will hiccup from time to time when you want to do something outside the norm. The one problem with markdown though is that it doesn't deal with image alignment very well. Sure, you can put HTML inside your Markdown, but that's usually very messy and not something you want to document for people just installing a theme. So what to do?

Eventually I just decided to hijack the alt attribute on images, which Markdown does allow you to edit. That means that I set up an image in my editor like so...

![left](some-image.jpg)

Now in my CSS I have an attribute I can read against.

  img[alt="left"]
    width: 60%
    max-width: 60%
    margin: 0 $base-line-height $base-line-height -15%
    float: left

Easy enough. Maybe not the best for accessibility, but that allows for pretty easy and clean alignment. The problem was I wanted magazine style layouts for my articles. That kind of design usually calls for images that pop outside the boundary of you text column (which in this case was a max-width of 700px). Usually when you have better control over your markup you'd set up your code like this.

<article>
  {# max-width: 700px #}
  <div class="wall-of-text">
    Lots of words
  </div>

  {# width: 100% #}
  <div class="full-image">
    <img src="some-image.png"/>
  </div>

  {# max-width: 700px #}
  <div class="wall-of-text">
    Lots of words
  </div>
</article>

But I wanted my markdown to stay pretty clean and I didn't want to write any HTML inside it to make those 100% images. Again what to do in this situation with this markdown...

Lots of words

![full](some-image.jpg)

Lots of words

... that would render to this very simplistic HTML.

{# max-width: 700px #}
<article>
  <p>Lots of words</p>
  <p><img src="some-image.jpg all="full" /></p>
  <p>Lots of words</p>
</article>

Obviously negative margins would come into play. I can easily pop the image outside of the 700px container that way, but I wanted the image to fill 100% of the width of the screen. I wanted a CSS solution and after about an hour of fiddling came up with this crazy nonsense.

img[alt="full"]
  width: 100vw
  max-width: 100vw
  position: relative
  left: -50vw
  margin: $base-line-height * 2 0 $base-line-height * 2 350px
  border-radius: 0

If you've never seen them before, vw and vh are viewport units. The code above sets the width of the image to 100vw, which is the size of the viewport. So now we have a giant full-width image inside a tiny 700px container. To get it back to the window's left-most position we need to shift it -50vw (half the viewport) to the left, but that's too far, because we were at the left side of the container to begin with. Luckily we know the size of that container (700px) can offset the image half that value (350px) to the left, which in reality sends it to the right, exactly at the 0px left position on our window. What we end up with is an image that's perfectly full width across the screen, but still sits the same container as our text. Pretty nifty.

Tumble style blog with passive content

right

One of the big advantages that Webhook has over other static site generators, and even traditional CMS systems, is that it has an API to allow you to post data into the CMS from other sources. This is great because it means we can wire up any other service that has an API and build Webhook pages from it as long as we have permission. I use Pinboard for bookmarking and wanted certain links I added there to show up here. Here's the round trip.

  1. I add a Pinboard link to the page I'm on. I tag it "design" and "share".
  2. I've use Zapier as a middleman to watch for additions to my Pinboard account. Specifically I tell it to watch for any additions with the tag "share".
  3. Once triggered, Zapier writes a Web Hook post to the CMS and inserts the bookmarking data, rebuilding my website along the way.

Very cool. I've set up similar Zapier tasks for YouTube, Vimeo and Twitter. Now whenever I post content to those services, that data (if it meets the filters I set up) automatically post to this site, solving at least for me the forever problem of not finding time to post cool stuff to your site.

The possibilities are endless. I think next I'll have it pull in my posts and comments on Reddit. The best part is all of this requires ZERO PROGRAMMING for the end user. They just sign up for Zapier and line up their services to the CMS forms.

Setting up syntax highlighting

Posting code snippets in your CMS is usually a pain in the ass. Webhook's Markdown editor however is prety awesome and will not only handle your syntax highlighting while you compose your document, but will also auto-indent and work in a rudimentary Vim mode. Essentially we wanted something to build something that you wouldn't want to jump back into your editor to compose.

On the Design side though we still need to render that code into something readable. To do that I used Highlight.js, which as far as Javascript syntax renders go is easily the best of the bunch. It's as simple as adding their JS code to the base.html and then picking a CSS theme for the <pre><code> blocks that markdown renders for us. I like reading code on dark backgrounds.

Animation

Last but not least I really wanted to spend some time with the CSS animation layer with this theme. Most of these are simple CSS transforms that I apply with custom keyframes. Here's the one for the avatar using Bourbon's Keyframe mixin.

+keyframes(avatar-in)
  0%
    opacity: 0
    +transform(translateY(-200px))
  60%
    opacity: .8
    +transform(translateY(2px))
  80%
    opacity: .9
    +transform(translateY(-2px))
  100%
    opacity: 1
    +transform(translateY(0px))

Figuring out what works takes a long time and is mostly trial and error. To animate elements that pop in you usually want to give them a little bounce, which is why you see the 2px spread from zero in the above example. That gives it the "oh shit, I've gone too far, head back" feeling.

Likely the most interesting animation is the header, which originally animates in, then disappears as you scroll down, then reappears while you scroll up. I ended up with the following JS to pull it off.

// Sticky header
var el = $('header');

if(!el.length) return true;

var wScrollCurrent = 0;
var wScrollBefore = 0;
var wScrollDiff = 0;

$(window).on('scroll', function() {
  wScrollCurrent = $(window).scrollTop();
  wScrollDiff = wScrollBefore - wScrollCurrent;

  // default state at top
  if(wScrollCurrent <= 0)
    el.removeClass('hide')

  // scroll up
  else if(wScrollDiff > 0)
    el.removeClass('hide')
  // scroll down
  else if((wScrollDiff < 0) && ($('nav .menu.active').length) == 0)
    el.addClass('hide')

  wScrollBefore = wScrollCurrent;
});

The basics are that I add a hide class to the menu, which itself has a transition animation in the CSS to fade in and out as you scroll. Sime we hide it as we scroll down you want it to actually dissapear up. You'll note that I also check to make sure the mobile menu is not active before fading it out. This allows the menu to ignore any miss-scrolls when you're on your phone.

Infinite scrolling

Ian helped to add infinite scrolling to the Homepage and list views. Generally with Tumble style blogs I think it's one of thew few places where infinite scrolling works really well. Essentially his script grabs the content from the next page in pagination and inserts it into the page you're on. For that reason, I keep the footer pretty bare-bones, since you can't count on it to be seen if there are a lot of objects.


Enjoyed this post? Let me know on twitter or grab some RSS.