Luke Winikates

29 December 2012

Frontend Craftsmanship (part 2)

To write my own autocomplete-based navigation component for this page, I had to pick up a couple of different tricks and develop some opinions about HTML and CSS.

I’d come this far because I did’t want to introduce a dependency as large as Bootstrap or jQueryUI, and because I wasn’t entirely satisfied with the out-of-the-box Bootstrap typeahead or jQueryUI autocomplete. But since my main objection was simply that they weren’t solving the same specific problem that I was, I was fortunate enough to be able to refer to both extensively to find smart ways of solving the various problems I encountered.

In Bootstrap, for example, there are plenty of examples of using data-* attributes to provide data to Bootstrap’s various JavaScript components. I played with this for a moment, but ultimately decided I’d rather build up an array of JSON objects to represent my data. I may never set out to support old browsers, but I also didn’t want to pursue an approach that inherently couldn’t work in older browsers, even for something that could be considered a progressive enhancement.

Initially I didn’t even know if generating Liquid templates for JSON was possible, but as it turned out, it’s relatively simple (the basics are covered well here)— Jekyll will template JavaScript just like anything else; Your only complaint may be that the resulting blend of JSON & chunks of Liquid syntax is a weird half-JavaScript, half-Ruby unlanguage that looks prety nasty.

###Loading the JSON Document Actually, even taking the JSON array as the starting point, there are several ways of getting the JSON array into the code:

  1. Bake the initialization of the JSON array directly into the page layout, within an HTML <script> tag. This was my first reflex, coming off of a Backbone.js project where it’s called ‘bootstrapping’ a collection, but in that context an HTML document load is quite rare, because an SPA buit with Backbone probably only loads that HTML once. In my Jekyll-based site, anything in the default HTML template would be downloaded for every individual page on the site, creating overhead that would grow with each new post added to the site.
  2. What I actually did in the first live version of the site, which was to create a ‘posts.json’ file, then fetch that via an ajax request after the page had loaded. On the plus side, this kept it separate from the rest of the assets, but it does require an extra http request on every page load.
  3. Rather than treat the posts as a separate JSON resource, build that array inside the main JavaScript file for the site reducing the number of HTTP requests per page view by 1, and allowing the site’s main .js file to be a bit simpler. On the minus side, the JS file woul dnow be a bit bigger and slightly less cache-friendly (since .js file will change each time a new post is added).

Most likely there’s barely any performance difference between any of these options, particularly with such a small number of posts– but I find the idea of doing fewer http requests appealing, so I think I’ll end up with option 3 as the final implementation.

###The jQuery plugin Jumping from Jekyll to the JavaScript that was actually going to bring the autocomplete behavior to life, I started digesting the code for Bootstrap’s autocomplete as well as the markup used for Bootstrap’s dropdowns and jQueryUI’s autocomplete.

Bootstrap is great source code to read. It’s not extensively annotated; maybe because some of the things I learned from it are probably common knowledge to plenty of experienced front-end developers. But the fact that I had to stare at it in the Chrome developer tools, deactivating different css rules to figure out how certain things worked, probably also helped add to the satisfaction of figuring them out.

One of Bootstrap’s tricks was extremely simple:

(from lines 74-84 in twitter/bootrap, dropdowns.less)

setting an <a> tag’s display to block makes it fill its entire line within the parent container, making the entire line clickable and causing :hover styling to affect the entire horizontal line. At times this is incredibly desirable to do–it gives a list of horizontally stacked links a consistent appearance and forgiving click targets, so it’s valuable when building a the static parts of a site’s layout. To see a more visual explanation, take a look at this JSFiddle

###Lining things up I looked closely at the Bootstrap markup and CSS as I was implementing my autocomplete plugin—- but at the basic dropdown, rather than at the typeahead. (In part, it’s easier to look at the static dropdowns first, because they have show-hide toggles where the typeahead auto-hides itself whenever the input loses focus).

In particular, I borrowed the way that the Bootstrap dropdown uses parent containers (such as a <div> or <li> to do most of the heavy lifting of positioning the hideable “menu” part of the dropdown inline with the always visible “toggle” part of the dropdown. Neither Bootstrap nor jQueryUI use this with their autocomplete components (in both cases the component does some math about position and height of the <input> box, using that as part of an inline style for the newly inserted <div>). The math makes them adaptable to any site’s CSS, so they’re well suited for the more general case.

In my case, I was explicitly trying to make a sort of built-to-purpose, bespoke UI component, so no such general-purpose code was necessary and in true TDD fashion, it never came up. Rather than do that sort of math dynamically within the component code, mine wraps the <input> in a <div> with no margins or padding. Most positioning then happens for free, and the fine-tuning is done in the site’s own CSS file, which will change naturally as the site design evolves.

This is the second post in a series – you can see the first post here. In the next entry, I’ll talk about about how writing a few hundred lines of JavaScript changed my perspective on writing UI code in general.