About this page
This is a hand-written <100kB vanilla HTML page that depends on no external resources beyond fonts. It's
designed primarily to look good in print, but also scales to desktop browsers, mobile, and TUI browsers
such as lynx
.
A content and styling editor as well as a selection of preset themes are available from the Tools menu if you happen to have JavaScript enabled. These have been tested to work even in mobile browsers.
Hosted as part of my website on GitHub pages, with source available here.
How we got here
There are lots of commonly-cited guidelines for building a resume. For example:
- Know your audience: Tailor the specific content of your resume to the opportunity at hand.
- Keep the layout simple: Colorful multi-column layouts confuse ATS and peeve hiring managers.
- Stand out: It should be memorable, though not like overzealous marketing copy.
- Expect it to be skimmed: Make sure each line says something significant about you as a prospect. Use action verbs and numbers to draw in the eye and highlight your accomplishments.
- Don't exceed a page, barring >10yr industy expertise or low-volume detail-oriented sectors.
My Google Docs resume met the standards. Friends even asked to borrow my template and some of my phrasing. But I found that to adapt it to different postings, I was using different styles and altering content frequently enough that I had issues keeping multiple copies of the document in sync. (In hindsight, this seems to be somewhat of an invented problem.) Additionally, I wanted a short URL I could hand out linking to my latest resume. This began to look like a problem to be solved with software, and soon enough I fell into the power user trap.
So we arrive at requirements elicitation:
- The resume MUST fit within a single page of US letter. Tools to adjust font size and spacing to keep the contents within the page are RECOMMENDED.
- The resume MUST be quickly convertible to machine-parseable PDF.
- The resume's source file MUST be human-readable plaintext for use with git.
- The resume software MUST support some form of templating, where typesetting parameters can be applied document-wide or to groups of objects rather than line by line.
- The resume SHOULD use a single column layout that looks good in print and on screen. A professional but non-default typeface is RECOMMENDED.
- The resume SHOULD be easy to view and link to on the web. A workflow to publish changes automatically is OPTIONAL.
- The resume SHOULD NOT require a complex toolchain to build.
- The resume MAY scale down nicely to a mobile device for easy reading, for uses such as QR code business cards.
- The resume software MAY support inline editing for quick changes.
The most obviously solution would involve Pandoc. I could write a basic markdown file, then create a LaTeX template for typesetting to PDF and an HTML template for outputting to a file I could upload to my website. I'd have divergent styles, which could be desirable, but I can already see this adding to my headache when one looks good and the other doesn't. And how long would it take to set up that process to where I like it, considering my lack of experience with TeX? Maybe there is a simpler way.
HTML/CSS for print
Modern web browsers are remarkably capable typesetting engines. Gone are the days of table layouts, web-safe colors, polyfills, and CSS preprocessors (did you know CSS has native nesting now?). Sure, it isn't commonly used for books, though that is changing thanks to the CSS paged media spec. But we only have one page to typeset. I had found my solution, and I set to work laying it out.
I added it to my GitHub-hosted site and used @media screen
& print
queries to adapt it by device:
on desktop emulating the look of
a PDF viewer; on smaller screens collapsing responsively; in print removing extraneous elements and margins. This is
easier than you might expect. CSS is happy to give you a width: 8.5in; height: 11in
box with
0.25in x 0.5in padding and 11pt type. With variables, you can easily alter aspects
like color and text weight across multiple elements and place those common values at the top of your stylesheet.
Initially, I figured I would use the browser developer tools to alter styles and content to tailor my resume to specific positions. Perhaps I could swap the stylesheet. One line of CSS could change the spacing across all my bullet points and paragraphs, without futzing about with the format painter.
contentEditable and the Tools Panel
Shortly after embarking on this project, I discovered a curiosity. Adding contentEditable
to an HTML tag lets you edit its contents (including children) live, inline, with no scripts required.
(Try it here.) It respects
your existing styles, it creates new list entries when you press [ENTER], in modern browsers it even uses the spell
checker. I decided this would make things easier and added a button with a bit of inline JavaScript to toggle
this on and off.
I also wanted to be able to toggle light/dark mode, so I created a little control panel and hid it behind a toggle button in the corner. And now that I had the menu, I thought it would be pretty easy to control the base font size with a slider. This seemed rather nifty, so I kept adding.
Many iterations later, the tools panel is a consistent cross-platform style editor for my resume.
Body text, headings, and my name all have font and space/size controls. Ligatures (like the combined letters ffi
in many typefaces) can be disabled for easier
parsing of the exported PDFs, bullets can be replaced with diamonds, the header style can be swapped out. Most of
the controls make an inline JavaScript call, usually to modify a CSS variable of the :root
<html> element.
The theme switcher calls a longer function that alters each of the fields and calls their attached
onchange/oninput functions. Form elements have entirely custom styling to ensure they look consistent across browsers
and platforms (and as exercise making nice-looking UI out of CSS gradients).
And since CSS has a zoom
attribute and I want the experience to seem like a PDF viewer, I added zoom buttons to the corner as well:
<button id="zoominbtn" onclick="javascript:document.documentElement.style.setProperty('--zoom', 0.2+1*getComputedStyle(document.documentElement).getPropertyValue('--zoom'))">
+
</button>
main#resume {zoom: var(--zoom);}
#zoominbtn {position: fixed; bottom: 60px; right: 10px;}
Of course there's more to be done, but you can see a completed example by viewing the source of this page.
Markdown conversion
Markdown is in essence the least common denominator of rich text today. GitHub, LLMs, note-taking platforms like Obsidian use it as their native language. It's common to use Markdown as a source for a website generator, but here, I use the webpage as a markdown generator.
Rather than solving the general case, my solution uses assumptions about the types of tags my website uses. Starting at the main resume element, it evaluates each of its child nodes. From there:
- If the node is text, add the text.
- If the node is an HTML tag, call the markdown generator recursively to evaluate its children and add the result as text.
- If the node is a recognized formatting-relevant HTML tag such as a #heading or **bold**, add markdown tags and call the markdown generator recursively, adding its result as text.
- If the node is neither text nor an HTML tag, or if it contains nothing but whitespace, do nothing.
There is some additional special handling for tabs and line breaks that you can easily see by viewing the source for this page and searching for markify
.
Other hacks involved
Firefox doesn't dither gradient backgrounds, so using it to view this resume on a large monitor used to result in distracting banding in the background. I initially attempted to use a noisy SVG texture to alleviate this issue, and while it produced some visually interesting results at different scales, it resulted in poor performance on some devices. Instead, I opted for a set of repeating linear gradients at opposing shallow angles to add a paper-like texture to the background. In dark mode, you can still see banding in Firefox, but it looks better as part of a more complex background pattern.
background: repeating-linear-gradient(6deg, #3331 3px, #0000 6px), repeating-linear-gradient(-15deg in oklch, #0f0605, #1e151b 100vh, #0f0605 200vh)
The zoom buttons use the deprecated CSS zoom
attribute. This messes up all sorts of things, such as measuring
using viewport units. I also use it to resize the resume on large screens so that on load it takes up most of the screen. This
mimics the behavior of a PDF viewer but is certainly not something I'd like most websites to do.
What's next?
Here's the TODO list:
- Theme selection based on URL parameter
- Create tailoring profiles, e.g. endpoint administrator, security analyst, network engineer
- Group bullet points and paragraphs
- Share via URL parameter
- Add editor features
- Move entire H2s and their contents up/down and between sections
- Move sections up and down
- Automatically assign new sections an ID based on their H1 text
- Insert/remove dates
- Support indented bulleted lists
- Support printing with an accent color
- Toggle color on/off
- Toggle accent color for: name(box), date, section separators, bold text
- Determine a balance between use of modern CSS and old browser support
- Swap use of deprecated CSS zoom attribute for
transform: scale(var(--zoom))
- Standardize button UX
- Standardize and reduce color palatte
- Release as an open-source solution
- Come up with a solution to replace the content with dummy content
- Provide instructions for the less technically skilled to use it
- (longshot) offer managed hosting including domain for a small fee