Lawn Care / Landscaping Work Log and Invoice

My step-dad runs a lawn care business and uses a work log similar to the one I share here to track his work for a given contract. He was working off of copies, and I wanted to make an electronic version so he could get a crisper print. When I went looking for other examples online to see if I could make some improvements, I mostly just found people looking for something like this, rather than sharing it. So, I wanted to share what I put together.

On my printer, at least, this prints perfectly in landscape mode onto a single page. It’s shared for views on comments, so feel free to suggest improvements, make your own copy and share it, or just use what I put together.

View the invoice here!

Uninsured Expense Reimbursement Form for Separations Involving Children

I am recently divorced, and among the exhibits included in the judgement is a form that the other parent and I must fill out when requesting reimbursement from each other for medical costs. I looked around online because the copy I received is just a flattened page among many inside a lengthy PDF document. I found a few different versions, but none of them were fillable, so I created one. This will calculate your totals for each type of cost and then use the number you put into the Percentage field to calculate how much you are requesting from the other parent.

Please let me know in the comments if you find any issues. Also to note, I recreated the form, but did not fix any of the poor wording or grammar issues.

UninsuredExpenseReimbursementForm – Fillable

Styling Code with Line Numbers using CSS

My team struggled for a long time with how to include code snippets and other text (such as the contents of a CSV file) in our documentation because we use a single source of content for web-based and PDF output. I have spent a good chunk of time over the past couple months searching the Internet for solutions, and now that I have one, I want to share it with the world. In a perfect world, we could meet this list of requirements:

  • Single source of content for both web-based and print-friendly output.
  • Line numbers are kept to the left of the page with the numbers columns (ones, tens, hundreds) lining up vertically, like you would see in a nice text editor or integrated development environment (IDE).
  • A line of code can wrap as-needed according to whatever container it is in (html body, pdf page margins, list item, table, etc.).
  • A wrapped line of code left-aligns with its first character.
  • Authoring in a WYSIWYG editor is simple and intuitive.
  • The content is organized semantically as much as possible.
  • The reader can copy and paste the code from our documentation, straight into their text editor without having to clean it up.
  • The reader can easily discern between a deliberate carriage return and a line of text wrapped because of space constraints.

First, special thanks goes to the following two pages for sending me in the right direction:

  • (NOTE: I did not end up using a gradient in my final product because of the lack of support in the authoring tool I use, but it worked just as well as the pseudo element approach I decided on)
    CSS-Tricks has proven to be my favorite resource for learning about CSS. I only wish they showed up on the top of my search results, over w3schools.
    Another great resource for some cool CSS usage.

A Not-so-much List

The Internet loves it some lists, so here is one of some things we tried and why they didn’t work out.

1. Word Wrap Indicator Icon

The most recent solution we used was to insert a small icon at the end of a line where text was wrapping. This option is functional, but not the most intuitive. It also requires manual upkeep with the equivalent of inline formatting; a significant change to our style guide will require, at the very least, a review of every code sample to make sure things still line up appropriately.

2. Preserving White Space

Web browsers are designed to ignore extra white space, such as tabs, carriage returns, and sequential spaces. This allows coders to format their code in a way that is easy to read without messing up what the user sees, but it can complicate coding when you need to display text as-is. HTML and CSS both have style options for preserving white space when you need to; here are the reasons they don’t work for us (a list within a list!): (1) wrapped lines don’t align with the left margin of where the line started, (2) authoring is complicated and requires manual layout manipulation, and (3) the lines are not organized semantically or at all, really.

3. Scrollable Regions

Scrollable regions in a page are pretty handy for specific cases on the web–especially with code samples. However, they do not convert well to print outputs. Since we do not produce pop-up books for our users, this is not an option.

What Worked

Lists! An ordered list works well for a few reasons:

  • The content is tagged in a reasonably semantic fashion. Each list item correlates to a line number, and typically when you want code to indent, it is a child of the previous line, which correlates well with nested lists in the code.
  • A list item can contain any flow content, which made the alignment against the line numbers possible.
  • In a WYSIWYG editor, creating and nesting lists is typically well-supported.

Here is a glorious screenshot for anyone who just cannot handle the anticipation:


There were three tricky parts to getting this to work:

  • Automatically numbering each line, including lines in a nested list, with a single sequence.
  • Styling the line numbers separately from the content of the line.
  • Keeping indentation aligned on the left side when lines wrap.

To create the line numbers, I used a CSS counter paired with the CSS pseudo-element ::before. I used the CSS counter instead of the default list style type because it is a simple way to number each list item, regardless of where it is nested, in a single sequence. It also offers more flexible styling options for the numbers, separate from the content.

Here is a snippet of the CSS used to create the line number:

ol.CodeSample li:before
counter-increment: linecounter;
/* increments the line counter 1 integer for each instance of this pseudo element */
content: counter(linecounter);
/* inserts the text of the line counter into the page content */
width: 2em;
/* ensures that there is enough space for 3 characters for the line numbers and enough space for the numbers to align to the right */
float: left;
/* floats the counter to the left so the code starts lined up next to it instead of on the next line */
text-align: right;
/* aligns the counter to the right so that the numbers columns line up properly */

You must also reset the counter at the top-level list so that two code samples in the same page keep their own line numbers, for example:

counter-reset: linecounter;
/* Restarts the counter used to generate line numbers */

We only had two requirements for styling the line numbers apart from the content. The first is that they are right-aligned, which is handled in the CSS shown above. The second is that they have a different background color from the content. I solved the latter by using another ::before pseudo-element, this time on the top-level ordered list. With this method, I was able to add a background that only filled the width of the pseudo-element container. Using absolute positioning and a negative z-index, I seat the background underneath the line numbers.

Here is a snippet of the CSS used to create the background for the line numbers:

ol.CodeSample:before /* pseudo element with a null content to create the background for the line numbers (print uses an image instead) */
content: "";
position: absolute;
/* because the parent element is set to relative, the absolute setting is contained within the parent element (ol.CodeSample) */
z-index: -1;
/* moves the background color behind the text of the line numbers */
width: 2.2em;
/* allows enough space for 3 character line numbers */
height: 100%;
/* stretches the background from the top of the ol to the bottom */
background: #CCCCCC;

For the absolute positioning to stay within the list container, you must set the list position to be relative, for example:

position: relative;
/* because there is no other position setting, this will act as if it is set to static (the default), but this is required for the child elements to stay within the ol when they are set to use absolute positioning */

To keep content properly aligned on the left requires a paragraph element to act as a container within each list item. This way, I can style the paragraphs with a margin and as lines wrap, each line respects that margin. I use complex selectors to add indentation levels based on the level in which the list item is nested. In our case, four levels are enough, but the pattern to create more is easily discernible.

Here is a snippet of the CSS used to style the paragraph margins:

ol.CodeSample > li > p /* indents the first level of code */
margin-left: 2.6em;

ol.CodeSample > li li > p /* indents the second level of code */
margin-left: 4.5em;

ol.CodeSample > li li li > p /* indents the third level of code */
margin-left: 6.3em;

ol.CodeSample > li li li li > p /* indents the fourth level of code */
margin-left: 8.2em;

ol.CodeSample p
padding-right: 0.5em;
/* adds space between the right border and text that reaches the far right boundary of the ol container */
margin: 0em;

And here is a snippet of what the HTML looks like:

<ol class="CodeSample">
<p>1st line of code.</p>
<p>2nd line of code.</p>
<p>3rd line of code, indented 1 level.</p>
<p>4th line of code.</p>
<p>5th line of code, indented 1 level.</p>
<p>6th line of code, indented 2 levels.</p>
<p>7th line of code.</p>

See the attached stylesheet and html page for a working sample. If you have anything similar you have done, any questions, or any modifications and improvements to my solution, I would love to hear from you!

Outstanding Problems

Since putting this code into production, I’ve run into the following issues:

  • Some breaking characters do not have a non-breaking counterpart, so your code samples will wrap at weird points. Underscores are an example that causes us issues.

Write the Docs Conference 2014

This previous Monday and Tuesday I attended Write the Docs. If nothing else, it was inspiring enough to get me installing WordPress so I could write this single post. Fortunately, it went far beyond if nothing else for me.

I have attended a handful of conferences in my past, most-memorably were RightNow‘s Summit conferences–before the company was purchased by Oracle. The Summits were fun and hosted at a fancy hotel that I would never have stayed at otherwise. And I suppose I liked them enough that I didn’t notice what was missing until attending Write the Docs years later: my kind of people. My career as a technical writer is in infancy, and I sometimes fret that it was not the best move, but experiencing the community and attitude and passion at Write the Docs was madly affirming.  In-fact, not more than an hour or so after I thought to myself, “these are my people,” I found this:

I agreed; I felt like I was at home.

I also learned a lot of great stuff.  Common among many of the presentations and discussions was the idea that something is better than nothing, even when it’s bad (this is likely to become the tagline for my blog because self-deprecating humor is sort of my thing). This fits in nicely with a saying I learned from an instructor I had at Warner Pacific College, Michael Demkowicz: sometimes it’s not done, it’s just due. Also, Twitter shows that I have solidarity in my struggle with impostor syndrome.

The winner of my personal award in the category of I wish that everyone who ever had to present anything to me for any reason would watch this video is: Christina Elmore — Death by Documentation. Seriously. Go watch it. Now. (Please?)

If you are into this kind of thing, I put together a sort of TOC for my notes from the conference, which is probably far more useful than the notes themselves.

I don’t feel like this post is finished or as good as it can be–I am going to let that happen because that’s what I learned from my people.