These posts are about tech – mostly PHP (Laravel), Javascript (VueJS) and CSS (TailwindCSS).

How to use Visual Studio Code for web design

To design web pages, you should really use a good text editor. Microsoft’s open source text editor Visual Studio Code (VSC) is such an editor. Here is how I set it up and which plugins help me having a good time while writing HTML and CSS.

I update this article whenever there is a new version of VSCode. (Latest changes reflected: v1.30.2-Novemer 2018


Installing VSC: You can download Visual Studio Code for free here. If you happen to be on a Mac, you should really use Brew to install packages. You can then just install VSC with brew install visual-studio-code. On Windows, chocolatey would be the equivalent package manager and choco install visualstudiocode the command to go for.

Always use latest version: Be sure to always update VSC to the latest version. Microsoft releases great new features every month and you do not want to miss a single one. Just use Code > Check For Updates…

Open Projects: To open VSC, always browse to your project folder on the terminal and fire up the editor with code .. This way, you open your whole project as one.

This is how a HTML5 Boilerplate project looks like after startup via code .

Blank Visual Studio Code window

Use Cmd+P: To switch between files, you would usually use tabs. That might be okay when you have one index.html and one style.css file, but even with our example HTML5 Boilerplate and its many files, it already gets complicated. It is much faster and visually pleasing to use cmd+p with its typeahead functionality to quickly find and edit the file you need. Let me show you what I mean.

Use symbols to jump within file: Wonder, where you hid that h2 heading in your main.css? Well, you could browse the whole file or memorise it. Or you can just hit cmd+shift+o to quickly go to a definition within your HTML and CSS files.

This is how I would find my <h1> definition in main.css:

I just hit cmd+shift+o, type in h and in the typeahead list I already see the h2 definitions. Of course I can switch with the up and down keys.

Visual Studio Code Quick Jump

Use Emmet: To massively speed up typing HTML, use Emmet. It is a shortcut-language which expands to HTML. You write h2>div*2 and hit Tab. It expands to the following.


Use this cheatsheet to learn all the commands Emmet has.


You can customise all your settings in Code > Preferences > Settings. Here are my most important settings:

{ // your settings file must begin like this
      "editor.fontSize": 14, // see note #1    
      "editor.lineHeight": 28, // see note #2
      "editor.wordWrap": "on", // #2
      "workbench.editor.showTabs": "off" // #3
      "editor.minimap.enabled": true, // #4
      "editor.minimap.renderCharacters": true // #4, no comma after the last setting!
  1. I prefer to have some space between my lines, so I double the linespacing. And I increase the font size so I can move away from my monitor a bit more.
  2. By default, words do not wrap at line endings. I prefer that they do.
  3. As described above, cmd+p is so much faster than tabs. Use this, not tabs!
  4. Minimaps helps you to keep a bird’s eye overview


There are a few VSC plugins that I can wholeheartedly recommend to you for web design projects.

Just install them with cmd+shift+p, type install and select Extensions: Install. In the search bar, type in the name and click on the install buttons next to the plugin.

Notable Features

These are a few features that are relatively new and might help you more than they do help me right now…

Other resources

How do you set up Visual Studio Code for web design projects? And which other plugins do you use on a regular base?

Generate PDF invoices from Markdown using Pandoc

TL;DR: You can use Pandoc with wkthmltopdf to generate nice-looking PDF invoices from Markdown files.

The context

I love simplicity, structure and I like good design. When it comes to invoices or other formal documents that you need to generate as a freelancer (such as status reports or fact sheets), these things do not get together easily:

The commercial or complicated way

Of course, you can fire up InDesign or Apple Pages and fine-tune your documents, but this comes at a price: you have to create every new document individually as templating and mail-merging is very basic in both programs. Also, you are stuck with proprietary file formats that you might not be able to open in the future (and your tax office may not be happy about that). On the other side, you have LaTeX which can output fantastic documents from marked up text but has a steep learning curve and also quite some weight (~ 1GB extra). Also, if you want to use system or OTF fonts, you quickly run into problems. Both InDesign and Pages also struggle with the generation of HTML5.

The (rather) easy way

Pandoc to the rescue. Pandoc is a handy command-line tool that converts text files between different formats. I use it to convert markdown files with YAML metadata blocks to PDF and HTML5 files. And I can style these documents via CSS3 so I can use all local fonts. To use Avenir Next, which I installed on my machine, I just need font-family: 'Avenir Neue' in my CSS.

So how would I create a nice looking invoice?

Here is the template markdown for a fixed-budget project that I did:

papersize: a4
margin-left: 20mm
margin-right: 25mm
margin-top: 10mm
margin-bottom: 20mm

![](img/logo.png){ width=13.587mm height=13.559mm}

Martin Betz | Meine Straße 1 | 123456 Berlin

Mein Kunde
Kurfürstenstraße 123
10961 Berlin

Berlin, 07.01.2017

# Rechnung: Neugestaltung Webseite
## Rechnungsnummer: 170101

Guten Tag Herr Kunde,

für Ihren am 01.01.2017 per Mail erteilten Auftrag für die Neugestaltung der Webseite
[]( berechne ich Ihnen entsprechend Abmachung folgenden Pauschalbetrag:


Entsprechend §19 UStG erhebe ich als Kleinunternehmer keine Umsatzsteuer.
Abgaben zur Künstlersozialkasse fallen nicht an.

Bitte überweisen Sie den Rechnungsbetrag innerhalb von 14 Tagen
auf untenstehendes Konto bei der Rich Bank.

Vielen Dank für die sehr gute Zusammenarbeit!

Mit freundlichen Grüßen,

![](img/unterschrift_ex.png){ width=33.8mm }
(Martin Betz)

MARTIN BETZ | Meine Straße 1 | 123456 Berlin | (0000) 000 00 000 |
Steuer-Nummer: 00/000/00000 | Bankverbindung | IBAN DE00 0000 0000 0000 0000 00 | BIC XXXXXXXXXXX

Note that I entered all my personal, the project and the client data manually, but could have queried them from a database as well. Automation is easy in this workflow.

This is how my output PDF (format: A4, black border for contrast only) looks like:

Invoice Example

So how can you make an invoice as pretty or even prettier than this?


  1. Install pandoc. If you are on Mac, get Homebrew and install pandoc via brew install pandoc. Otherwise, head over to Pandoc's website and get a package for your machine.
  2. Install wkhtmltopdf via brew install Caskroom/cask/wkhtmltopdf or via the right package from their website. wkthmltopdf is an invisible (aka headless) browser which saves documents to PDF.
  3. Execute pandoc invoice.m -t html5 d -o invoice.pdf in the terminal to output your first version of the invoice PDF. -t is for 'to' and indicates the format, -o … *.pdf will automatically understand that you want to save it as a PDF
  4. To make the invoice prettier, you can add --css style.css to the pandoc command

Here is my final CSS. I will tell you about some problems, solutions and architecture decisions after the code.

@charset "utf-8";

body {
font-size: 10.5pt;
    "Avenir Next", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
    "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
hyphens: auto;
height: 270mm; /* 297 - 10 (top) - 20 (bottom) */
line-height: 140%;
margin: 0;
padding: 0;

code {
font-family: "Source Sans Code", Courier New, Courier, monospace;
margin-left: 1pt;

a {
color: black;
margin-left: 1pt;

table {
width: 100%;

table:nth-of-type(3) {
border: 1px solid black;
padding: 5pt;

table:nth-of-type(3) td:nth-of-type(2) {
text-align: center;

h1 {
font-size: 13pt;
margin-top: 6pt;
margin-bottom: 0;

h2 {
font-size: 10.5pt;
font-weight: normal;
margin-top: 0;
margin-bottom: 20pt;

p {
width: 100%;

p:first-of-type {
font-size: 9pt;
word-spacing: 1pt;

p:nth-of-type(2) {
margin-top: 20mm;

p:nth-of-type(3) {
text-align: right;

p:nth-last-of-type(3) {
margin-top: 10mm;

p:last-of-type {
text-align: justify;
font-size: 9pt;
position: absolute;
bottom: 2mm;
margin-bottom: 0;
padding-bottom: 0;
color: #444;

hr {
border: 1px solid #eee;

hr:last-of-type {
position: absolute;
bottom: 14mm;
width: 100%;

figure {
margin: 0;

And now the making-of:

  1. Positioning elements was harder than expected: You set the paper size via the YAML metadata, so I thought I could just derive absolute values from there
  2. I believed that body height should be: 297 (A4 height) - 10 (margin-top) - 10 (margin-bottom) = 277mm.
  3. I tried to position a fold line at 99mm (297/3) via .foldline { position: absolute; top:99mm; }, but when I printed it, it showed up at 105mm.
  4. CSS understands mm and pt as values, so I used mm for positioning and pt for font sizes (exactly as in traditional DTP programs)
  5. Footer: I first thought about a Flexbox layout with fixed footer, but quickly settled on a position: absolute; solution as it is enough for my purpose. The calculations, however, were not working as expected so I had to tweak the bottom: xx mm settings by hand
  6. I tried to justify my footer, but… CSS cannot justify one-line paragraphs easily. Ouch…
  7. As you cannot set ids or classes in your markdown for the HTML, you end up with a lot of <p>s. I had to make excessive usage of :nth-of-type(), :first-of-type(), :last-of-type() and :nth-last-of-type. It would be nice to have a template for the HTML output (it's possible, more on this later)
  8. My logo is *.svg but that got totally skewed when getting rendered to PDF. I had to generate a high-resolution PNG to get around that.
  9. I made dozens of iterations of the CSS to get the design that I wanted. First I did it the hard way: Change CSS, run Pandoc command, open PDF. Then I found out that PDF Expert re-renders when the PDF has changed. Still, I had to fire Pandoc after each CSS change manually. So I was looking for "live reloading" and ended up with fswatch on Mac (or inotifywait on Linux). I put the actual Pandoc command in a Bash script and started the watcher with fswatch -o . | xargs -n1 ./ It worked. The only downside I encountered was that the PDF would reload in PDF Expert every 2 seconds no matter whether there was a change in the CSS not. Flicker, flicker, flicker.

Make it safer

Now you have a neat invoice PDF from a very simple Markdown file. But: The client could easily edit this PDF, change the cost or copy my signature. You cannot entirely prevent this to happen, but let`s make it a bit more secure.

  1. Get the command-line tool pdftk brew install
  2. pdftk invoice.pdf output invoice-protected.pdf allow printing owner_pw "mysecretpassword"

The client can still print the secured invoice, but not to change it. Funnily, PDF Expert is ignoring these settings and still able to edit the file. I have no idea why.

Next steps

The invoice PDF is nice, but of course, we can make it even better. Here are some ideas:

  1. Set a base font size in pt and set the other sizes relative with em
  2. Switch the whole styling to Sass, predominantly for nesting the p { %:nth-of-type {} }
  3. Tables are a big thing in most non-fixed-price invoices. And a big CSS design challenge
  4. Tinkering with p:nth-of-type(10)-ish selectors is not too much fun, so probably using an HTML template with some smarter defaults would be good. I did not have much success with loading a new template from a different --data-dir but brew's, so I copied my template to /usr/local/Cellar/pandoc/
  5. Also, I found another nice template that I might learn a trick or two from
  6. Finally, for cross-media usage, I might add another stylesheet for the web or maybe media queries (but I have no clue whether that works…)



Do you use Pandoc in varying ways for invoice generation? Or do you have other comments or tips? I am very looking forward to your feedback!

CSS blur test

TL;DR: To evaluate the hierarchies on your website, use the filter: blur(5px) style on your <body> element.

Why hierarchies matter

Not everything is equally important on your website: Every single page should have one single goal (signing up for a newsletter, click the buying button, display the one information everyone looks for).

Also, some elements belong together to give the reader orientation (image and label, intro and list). Whitespace at the right amount and place is what gives orientation, and structure.

How to test hierarchies

To test your hierarchies, it helps to get a bird's eye view over your website.

The best way to test your hierarchies is the blur test. By blurring out the specific content, you will quickly recognize borders, space and sizing.

How to apply blur effect in CSS

The quickest way to do the blur test is by using the blur CSS filter.

You can either create an own class and apply it when testing:

.blurtest {
    filter: blur(5px);
<body class="blurtest">

Or you simply create an on-the-fly class using Chrome's DevTools or Firefox' Inspector

Host Jigsaw static content on Netlify

Jigsaw is a very lean static page generator and especially easy to learn for everyone familiar with Laravel and its blade templating language.

netlify is a fantastic host for static pages with a generous free tier and nice tooling.

One of the coolest features is Continuous Deployment: You create and preview your site locally, commit changes to your Git repo — and Netlify builds static pages using their build image.

Node, Ruby and Python based tools have been well supported for a long time, but PHP just got first class support lately: Netlify’s Bryce Kahle updated PHP to version 7.2, improved composer support and made sure that essential extensions like mbstring are in the base image.

Thanks to these changes, it is now super easy to have a continuous Jigsaw (PHP) build that reacts to commits to your Github, Gitlab or Bitbucket repos.

Let me walk you through an example site (see: minthemiddle/jigsaw-netlify-test):

Install Jigsaw locally.

As I have had problems installing Jigsaw globally, I always install it locally

Set up Git

Set up Netlify page

Create deployment script

Netlify needs to know how to build your site. You can tell it by creating a netlify.toml config file:

command = "gulp --production"
publish = "build_production"

This will use PHP7.2, run gulp which will compile assets and build your site using Jigsaw and deploy the static page to the /build_production folder from where Netlify publishes it to the web.


Try it out:

Speed it up

# netlify.toml


command = "./vendor/bin/jigsaw build production"
publish = "build_production"

Quick tools with VueJS

Before: Tools with Excel

I used to write down the total number of tasks in a row in Excel and add a row for my done tasks. I would add a ratio row and do the math to see my progress.

That setup is flexible and worked pretty well, but it looked boring. Well, just like an Excel sheet looks like.

Excel tool

I need to confess that visuals make a huge motivation difference for me.

After: Tools with JS, CSS, LocalStorage

That is why I need a good toolbox for creating helpers that are…

The modern web universe has such tools:

Here is how my little example task progress tracker looks like using these tools:

VueJS Todo Counter

Let me do a quick tour of the feature that I use frequently to build tools like this task tracker:

The actual power comes from a few lines of JavaScript. Let me explain with inline comments

var app = new Vue({},
computed: { /* Calculate the ratio */
    ratio: function() {
        return Math.floor(this.tasks.done / * 100) + '%'
watch: { /* Observe changes and write to LocalStorage */
    tasks: {
        handler() {
            console.log('Tasks changed');
            localStorage.setItem('tasks', JSON.stringify(this.tasks));
        deep: true,
mounted() { /* Load values from LocalStorage and load */
    console.log('App mounted');
    if (localStorage.getItem('tasks')) this.tasks = JSON.parse(localStorage.getItem('tasks'));

Write endless simple tools with this setup

The combination of the three technologies (HTML + CSS Framework, JavaScript, LocalStorage) makes it super easy to create simple yet flexible and beautiful tools.

Other tools that I built the same way:

There are endless opportunities to create flexible and good-looking tools for your specific needs in very little time!

Here is the source for the todo tracking tool