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
###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:
- 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.
- 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.
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.
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)
<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
<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.