Category Archives: Design

How I prepare data-merged designs for print using open source software

I co-organize some popular conferences in Amsterdam with a few friends/colleagues. As the resident designer, I’m often tasked with making the name badges that everybody wears. I used to make these in Adobe InDesign, which has a mail merge function that, while kind of weird (I seemed to be required to use UTF-16 CSV files to merge with), worked pretty well.

Since I switched my OS to Ubuntu a while back, I haven’t had a need for InDesign. Really, the only thing I ever used it for was for making badges. That doesn’t justify the cost to me, not only financially, but also in disk space. :-) So I’ve set out to make these badges in one of my favorite drawing tools: Inkscape. Since Inkscape is an SVG drawing program, and SVGs are text, I figured there might be some flexibility there.

That flexibility and freedom have a price, though. Instead of doing everything in one GUI app, a few different programs are involved. The workflow involves using the command line. It’s not a perfect process, but it works fairly quickly and well for me. That said, feel free to laugh at my awkward process. Open your copy of InDesign now. By the time you’ve finished reading this, InDesign should be open and ready to go.

Note that I’m not doing book design here; my use case is fairly simple. If print design were still my profession, I would most likely use the best software for the job.

My biggest problem with this workflow is that I kept forgetting what I did the previous time. That’s the main reason for me writing this, and for a couple of people who requested it. It’s essentially documentation for me, so I don’t forget again. That said, someone else somewhere might find it useful. This is for informational purposes only, and may not work on your system. I am unable to provide any support. It’s probably best not to follow along at all if you’re not somewhat comfortable in the command line.

I mainly work on a Linux machine, and this description is written from that point-of-view. Anyone following along on other systems might have to work out discrepancies or weirdness in their own environment.

With the disclaimer out of the way, let’s look at the process. This might seem a bit complex, but from my perspective the process is simple, and the following things are true:

  1. I draw my artwork in Inkscape.
  2. I have a CSV with attendee data.
  3. I type one command to generate a file for each badge.
  4. I type one command to combine those files into a single PDF.
  5. I send the PDF to the printer.

Note that in a GUI, instead of typing a command, I would probably choose various commands from one or more menus. So, to be clear, from my perpective, this is not more work than doing this all in a GUI program. I will concede to the fact that there is more complexity in the tools I use, as you have to install three, and they might not work the same on every OS. This process assumes a Linux-like OS, and enough knowledge on your part to recognize things you might need to change to get them to work on you particular OS. Instead of InDesign (and a tool to convert a UTF-8 CSV into UTF-16), I need three tools, which I’ll describe below. These tools are freely available and don’t take up much space. The time it takes to generate the badges is not longer (and often shorter) than doing the same with commercial tools.

Badges are made in Inkscape, and data from CSV is merged using a Ruby gem called inkscape merge. It’s not ideal, but it works fairly well in that Inkscape can be used and I’m not locked in to a specific software vendor’s software and workflow. The process outlined here is simple and has kinks, but lots of things could be scripted to do more complex stuff, like customizing visual differences between speaker badges and attendee badges, etc.

1 Things you’ll need

We’re using the following open source tools (please refer to the individual sites for installation instructions):

  • Inkscape, for doing the badge artwork in SVG
  • inkscape merge, a Ruby gem, for doing a “mail merge” of a CSV file with the artwork, which results in separate files for each (side of each) badge
  • Ghostscript, to merge all the files you generated into a single PDF, if you’ve exported those files themselves as PDFs. If you’re on OS X or Linux, there’s a good chance this is already on your machine.
  • ImageMagick (specifically `convert`), to merge all the files you generated into a single PDF, if you’ve exported those files as bitmaps, e.g. PNG.

If you’re using OS X or Linux, there’s a good chance Ghostscript is already on your machine. The last three tools are command line tools, and even Inkscape can be run from the command line (and in fact, inkscape_merge does exactly that). Don’t be afraid to try it out, if you’re so inclined. That’s how one gets more comfortable with the command line.

2 Creating the Inkscape and CSV files

Badges are made in Inkscape any way you want. You’ll have to have a separate file for each side of the badge, unless both sides will be identical.

I draw my own crop marks for the printer in my document, put them in their own Inkscape layer, and lock it. Then I draw the rest. You can also do this after the artwork, but I like to get it out of the way at the beginning. If I want to show my colleagues what a badge will look like, I’ll make a selection of the printed area and use Inkscape’s “Export bitmap” function to make a PNG of it to show. Obviously, I’ve already consulted with the printer about what they need to receive from me before I even start. I’ve worked with printers for whom InDesign was literally the only option. We like our current printer.

Conference name badge in Inkscape GUI
A layout in Inkscape with variables

Text that is to be replaced by CSV data should be indicated like so: %VAR_csvColumnName%, where csvColumnName corresponds to a column in the CSV. The CSV might look like this:

Stephen,Zero Interface,@stephenhay,

This is essentially the following structure:

name company twitter
Stephen Zero Interface @stephenhay
PPK Quirksmode @ppk
Krijn Qontent @krijnhoetmer
Martijn   @Martijnvduuren

If I were to have a bit of text in my Inkscape SVG file with %VAR_name%, then when I run inkscape_merge with the above CSV file, that variable would be replaced with “Stephen”, “PPK”, “Krijn”, and “Martijn”, each in their own file.

The CSV file should be UTF-8 encoded.

2.1 A caveat about the CSV file

Some weird bug I’ve been getting using inkscape_merge prevents me from changing the column separator to something other than a comma, which is the default. This is a pain, because sometimes you’ll have a field in the CSV that uses commas, like “ACME, Inc.”.

I don’t know enough Ruby to figure it out. For future reference, this is an example of the type of error I get:

inkscape_merge --csv_col_sep='|' -f badge.svg -d data.csv -o batch/badge_%d.pdf
/var/lib/gems/1.9.1/gems/inkscape_merge-0.1.3/bin/inkscape_merge:33:in `block (2 levels) in <top (required)>': undefined method `csv_options' for #<OptionParser:0x00000002322088> (NoMethodError)
        from /usr/lib/ruby/1.9.1/optparse.rb:1360:in `call'
        from /usr/lib/ruby/1.9.1/optparse.rb:1360:in `block in parse_in_order'
        from /usr/lib/ruby/1.9.1/optparse.rb:1347:in `catch'
        from /usr/lib/ruby/1.9.1/optparse.rb:1347:in `parse_in_order'
        from /usr/lib/ruby/1.9.1/optparse.rb:1341:in `order!'
        from /usr/lib/ruby/1.9.1/optparse.rb:1432:in `permute!'
        from /usr/lib/ruby/1.9.1/optparse.rb:1453:in `parse!'
        from /var/lib/gems/1.9.1/gems/inkscape_merge-0.1.3/bin/inkscape_merge:11:in `<top (required)>'
        from /usr/local/bin/inkscape_merge:23:in `load'
        from /usr/local/bin/inkscape_merge:23:in `<main>'

The only workaround I have right now, since I currently don’t encounter many fields containing commas, is to create separate SVGs with hand-entered data for each row in the CSV that uses in-field commas, and convert these separately. It’s an awful workaround, but my last set of badges only had two instances, so no one dies.

BTW, no, using double-quotes in the CSV doesn’t work, as inkscape_merge seems to skip rows containing them. Joy.

3 Running inkscape_merge

First, make sure there’s a directory to put the batch input. inkscape_merge is going to create one file for each row in the CSV. This might be a lot. Let’s say that directory’s name is batch.

inkscape_merge is then run as follows:

inkscape_merge -f sourcefile.svg -d datafile.csv -o batch/badge_%d.pdf

Where sourcefile and datafile are the names of your SVG artwork and CSV file, respectively. The %d will be replaced, for each file, by the number of the CSV row.

This will put as many files in the batch directory as there are rows in your CSV. Remember that rows containing in-field commas should simply be exported by hand from handmade SVG copies of the artwork in which you’ve entered the actual data of that row instead of %VAR_whatever%. You can do that from the command line:

inkscape --without-gui --export-pdf=outputfile.pdf --export-dpi=300 sourcefile.svg

where sourcefile is the specific SVG file and outputfile is the name of the file you want to end up with.

A little trick I use is to leave double-quotes around fields containing commas in the CSV. Since inkscape_merge doesn’t output these, I know which ones I have to do manually, and I also know how I should name them according to row, and these filenames are missing from the batch directory since they haven’t been generated.

3.1 A caveat about exporting to PDF

Inkscape allows you to do lots of stuff with SVGs, and these things don’t always export well to PDF. It’s hard to say exactly what, but sometimes I notice problems with transparency and masking/clipping. If you run a batch to PDF and open one and see that it’s not as you intended, you can export all your rows to PNG instead. Since the DPI is set to 300, this should suffice for most print work:

inkscape_merge -f sourcefile.svg --format png -d datafile.csv -o batch/badge_%d.png

This will give you a bunch of PNG files instead of PDF. You’ll also have to export your infield-comma exceptions to PNG manually.

OS window containing 4 files
A separate file is created for each row in the CSV file.

4 Combining the batch files into a single PDF

Printers generally want PDFs, so whether our batch consists of PDFs or PNGs, we’re combining them into a PDF.

Make sure you’re in the batch directory first.

4.1 Combining multiple PDFs into a single PDF

To do this with PDFs, we use ghostscript:

gs -sDEVICE=pdfwrite \
    -sOutputFile=combined.pdf \

For more info and variations, see

The `ls` turns the output of the ls command into input for the gs command. You could also use * or $(ls) instead, in this case. If you’re in the batch directory, the output of ls is a list of all the files that we generated before.

4.2 Combining multiple PNGs into a single PDF

For PNGs, we’ll use ImageMagick’s convert command:

convert -limit memory 2MB `ls` combined.pdf

We’re limiting memory usage to 2MB here, because otherwise with many files, sometimes the system will kill the process because it’s using too much memory.

Window of a PDF viewer program showing 4 pages
The separate files are now combined into a single PDF file


That’s it! This is how we’ve been making most of our conferences badges for over a year now (except for one which involved HTML, CSS and PHP). The above process is pretty painless once you’ve run through it a few times, and generating a file with about 300 badges only takes a few minutes. Since SVGs are text, and inkscape_merge variables can replace any text in the SVG, you can customize colors per badge or practically anything else. You could potentially do any kind of scripting you like. And of course, you could wrap all of this in a tidy bash script for easy execution.

I’m in the process of making a demo video of this workflow, in which I also demonstrate using variables for colors. This should be done in a day or two, and I’ll post a link here when it’s done!

Choosing between min-width and max-width media queries

I’m often asked a variation of the following question:

Should I use min-width or max-width media queries?

The obvious answer is, of course, “yes”. But you know what they’re asking: which of the two is better?

Those for whom responsive design has become second nature might find it an odd question, and will know that the answer is, “it depends”. But having seen lots of responsive design implementations, it’s clear to me that many designers and developers aren’t quite sure. And I’m happy to share my own opinion of what “it depends” means regarding this particular question.

Desktop first and max-width

There’s a decent number of designers/developers that still think of “the desktop” as their primary design manifestation, with other (generally smaller) sizes as secondary; often these appear as afterthoughts, since there can be significant visual clues as to the amount of effort that has gone into these other screen sizes when compared to their desktop counterparts. Often, when one examines the CSS of these sites, `max-width` is the media feature of choice.

This makes sense. If a design is built desktop-first, then all the CSS for the desktop-ish version of the design has been written, and must be overridden with more CSS for any other breakpoints. If a given desktop-ish width is our baseline and we are unwilling or unable to refactor our CSS, then it seems logical to override what is now our base CSS for all viewport widths with those we only want to apply to smaller widths.

This can lead to a situation I’ve often joked about: writing styles only to undo them later. This is an example I often use (assume .related takes the form of a sidebar):

.content {
  width: 60%;

.related {
  width: 40%;

@media screen and (max-width: 37.4em) {
  .related {
    width: 100%;

The above example omits a lot, but I’m sure you get the idea. This approach, when used over a bunch of components, can greatly increase the amount of CSS needed to complete the project. But the main problem is how illogical it is, because when embracing the fact the block-level elements are 100% of their parent by default, then the following makes much more sense:

@media screen and (min-width: 37.5em) {
  .content {
    width: 60%;

  .related {
    width: 40%;

Here, we’re making use of the default state of block-level elements, and overriding them when they need to change from the default. Again, it might seem clear to some readers, but it doesn’t take looking at the source of many websites before you understand why I’m clarifying it here.

Using max-width against your better judgement

There are a couple of reasons why, even when you know better, you might deliberately choose to use an approach similar to max-width approach above:

  1. You’re a developer and you received desktop-only, desktop-first, or other-sizes-as-an-afterthought comps from the designer. How can you know? If you’ve only designed or received designs for desktop-ish widths, this is what you’re dealing with. If you’ve got nice detailed desktop-ish designs with a few “mobile” or “tablet” examples thrown in there, this is what you’re dealing with. In these cases, may the max-width be with you, unless you have a budget and/or schedule that allows you to refactor during development.
  2. You’re making an existing website responsive, and the existing CSS is design baggage you’ve inherited and cannot change, for whatever reason.
  3. You’re compensating for the fact that we don’t currently have element queries, and you’re handling this with CSS instead of using a JavaScript polyfill for a non-existent spec.

So, what’s the best to use?

Here’s my clarification of “it depends” for this particular question. And remember it’s just my own opinion based on my own experiences: look at default display of a given element. If you have to override this default for smaller screens, use max-width. If the default is usable on small screens, use min-width, and only when the element needs to deviate from the default. And of course, I recommend letting the content determine where that happens.

A good example of using max-width to override an element’s default display so that it works better on smaller screens is when using tables. Imagine a table that contains too much content to display in its default form on small screens. One approach might be:

@media only screen and (max-width: 30em) {
  .big-table tr,
  .big-table td {
    display: block;

This turns each row (and cell) into a block on narrow screens. The table can become quite long vertically and more styling is usually required, but it’s often better than the back-and-forth horizontal scrolling that would otherwise be required to read the content.

In this case, it makes all the sense in the world to leave the table in default form, except for in browsers that understand the media query and where the screen is no larger than, in this case, 30em.

Other elements (I would venture to say most other elements) that have defaults that work fine on smaller screens, only need changing when necessary on larger screens; using min-width is then a solid choice.

In short: let element defaults help determine which media feature to use in your media queries.

Thanks to Brad Frost for reviewing this. He also has a post with related topics.

Put the “designers should code” debate to rest

Note (September 14, 2015): this post has also been translated into Chinese.

My acting coach in college used to say something to the effect of, “Be. Don’t show.” It was frustrating. He wanted us not to do the things that symbolized what was supposed to be happening in the scene; he wanted us to live the scene. A good example is acting like a drunk person. We see drunk people, and a natural tendency when doing a scene as a drunk person is to act the way you’ve seen drunk people act. But in many cases, that comes across as fake and obvious. Because people who are drunk often try to act sober.

I worked in an art gallery when I was in college, and once a year we would put on an exhibition of children’s art. One thing you notice when hanging hundreds of paintings and drawing by kids, especially the younger ones, is that many tend to draw symbols of what they see. The don’t draw the sun, they draw a circle with lines around it. Or squiggles. Mountains are triangles. Basic forms are used as symbolic depictions of objects.

This often continues into adulthood, unless one learns to draw at least at a basic level. And while perhaps repeated once too often, it is true to an extent that learning to draw realistically is learning to see. Learning to look carefully at what’s really there. What’s really happening. Circles on a wine glass become ellipses. The hard lines of the sun become gradations of color. Are you unable to draw, and don’t think you can? Grab an image, turn it upside-down, and draw what you see exactly. Don’t symbolize the image by thinking about the subject of it. Draw what’s actually there. For those inexperienced with drawing, it will be one of the best drawings you’ve ever made up to that point.

As designers for the web, depending on what type of designer you are, you are researching, structuring, adapting, testing, laying out, wireframing, setting type for, composing, and [fill in the blank]ing something that people will read, interact with, love, hate, tell others about, and perhaps take with them everywhere they go. And the medium is right in front of you, every day, so you as a designer for this medium have the opportunity to use it to prototype what you’re designing.

I’ve gotten my share of criticism for being one of those people to publicly state that it might be a good idea for web designers to learn some code. It took me several years to come to that opinion and it hasn’t changed much, but it wasn’t the coding that was important. It was the movement away from symbolic representations of that which we were designing. It was about not using flat images as a poor proxy for something that’s different for different people on different devices in different browsers. When I wrote Responsive Design Workflow, which describes a content and prototype-based approach to responsive design, people either loved it or hated it. Those who hated it did so because it was outside of their comfort zones, and because it involved learning basic HTML and CSS and getting into the browser as quickly as possible.

You can’t give me a wireframe, detailed as it may be, and tell me that you’ve designed the interaction of a particular product. You’ve just drawn a circle with squiggly lines around it, and you hope that reality will match. Good luck with that. Visual design influences interaction. Typography influences interaction. Content influences interaction. You either work together, as a team, or your bubble will burst at some point. You want to influence interaction? Get the thing into a browser and interact with it. Sculpt it. Shape it. Tweak it. Be, don’t show.

That’s what it’s about. Not about coding for the sake of coding. During the period of time leading up to my book’s publication, a lot of the tools we have available today to get into the browser quickly didn’t exist. I advocated code because I literally could not find tools that would get me to useful and realistic prototypes as quickly as code would. I had to use JavaScript and the command line to automate screenshots. We have tools that do that today. They do the same thing I did in the past, but they do it behind the scenes. There are now tools all over the place that can help get you get your product into the browser quickly. Even two years ago, we didn’t have many of those tools. That’s why many of us advocated learning to code.

Every so often there are articles and tweets about whether designers should learn to code. I think very little of it is constructive anymore; arguments swirl down into sewers of discussions on semantics, like whether coding is a profession or a trade, or whether HTML and CSS can actually be considered coding. It doesn’t matter.

Must designers learn to code? No. Would it benefit them in some ways? Yes. Is the code needed for much of prototyping more difficult than learning something like Photoshop? No. Can it become more difficult than Photoshop if I decide to dive deep? Yes. Are there ways to prototype effectively without learning to code? There are now. Can you still keep using Photoshop (or Sketch, or whatever) even if you learn some code? Absolutely.

It’s not about the code. It’s not even about the tools. Prototyping is about asking reality for feedback.