That ain’t rhetorical: I’m really interested in finding great use cases for CSS multi-column layouts.
The answer seems straightforward. Use columns when you want to split any content into columns, right? Here is generally the sort of example you’ll find in articles that show how CSS mutli-column layouts work, including our very own Almanac:
Right on. But is this an actual use case? Mmmmmaybe. If the text is relatively brief, then perhaps it’s a nice touch. That’s how I sold it to myself when redesigning my website a few years ago. It’s not that way today, but this is what it looked like then:
But an entire long-form article split into columns? I love it in newspapers but am hesitant to scroll down a webpage to read one column, only to scroll back up to do it again.
I suppose we can use it to place two elements side-by-side, but flexbox is way more suited for that. Plus, a limitation prevents us from selecting the columns to size them individually. The columns have to be the same width.
One thing columns have going for them is that they are the only CSS layout method that fragments content. (That is, unless we’re counting CSS Regions… what happened to those, anyway?!) So, if you wanna split a paragraph up into columns, it’s already possible without additional wrappers.
When else might you need to split a continuous block of content into columns? I remember needing to do that when I had a big ol’ unordered list of items. I like the way lists can make content easy to scan, but long lists can make one side of the page look super heavy. Let’s say, for example, that we were listing out all the post tags for CSS-Tricks in alphabetical groups. A multi-column layout works beautifully for that:
Go ahead and try resizing the viewport width. Three columns are defined but the number will change based on the amount of available space. Gotta love all that responsive goodness without the media query work!
I was working on a demo for the :left pseudo-class and reached for columns because it’s a great way to fragment things for printing demos. So, I guess there’s another use case. And while making a demo, I realized that a multi-column layout could be used to create a masonry grid of items, like an image gallery:
But what else? Are we limited to short paragraphs, long lists, and free-flowing grids?
If the thought of handwriting code seems silly, it might surprise you to know that it’s inevitable. If you’re unsure, think about the last job interview you did, and remember how there was no computer around in the interview room — just your interviewers, a blank sheet of paper, and a blue ball-point pen.
For the students among you, it’s even a bigger deal as your grades hang in by the lines of code you had strategically squeezed into the available space in your answer sheet.
And not just that, experienced programmers can point you to the bundle of A4 sheets they had removed from the office copy machine to scribble down a particularly complex algorithm they had been working on.
So whether you’re an exam student, potential job interviewee, or someone wanting to resolve their programming dead ends, I hope this article helps you out when you put your pen to the paper to code.
Although I will focus on the analog aspect of writing code, you can apply these steps to coding in any form or language. So consider this to be also like a generic coding guideline that works specifically for me but can also be very useful to you in your work.
Why write it down?
Before we start, it’s essential to understand that no one expects you to jot down production-ready code in a notebook. It’s not like you can drop that into a code editor and compile it without an error. If producing perfect code was the goal, you would be seated in front of a computer in the interview rooms and exam halls.
The purpose of handwriting code is to work through logic in advance. There’s s desire to “get in the browser” as soon as possible in design, but there is conventional wisdom in sketching designs by hand. A low-fidelity medium encourages quick experimentation and inexpensive mistakes.
The toil of trying to figure out how to affect surrounding items with one click (from my last article)
The same can be true of code, mainly when working out syntax and semantics. That said, getting the correct syntax and semantics is always a plus point, though not the sole focus of the whole handwriting exercise.
Let’s see where we can start when it comes to handwriting code.
Know your question
During my final year in college, I couldn’t do an internship or even attend campus interviews because of health reasons. As a result, my very first job interview was quite literal with high stakes.
When I look back now, the interview was pretty easy. But having never attended one before, I was anxious beyond reason. The first thing the interviewers asked about programming was if I could output an inverted triangle made of asterisks. As I said, it was easy — nothing a for loop can’t handle, right? But like I said, my anxiety was through the roof as well.
I took a deep breath, pressed my palm against the blank sheet of paper they had laid out for me, slid it as slow as possible towards me on the table (buying time, of course), clicked the pen, and then I did something right.
I first drew an inverted triangle made of asterisks. That’s how I found my feet on the ground to start answering their question.
I’ve seen otherwise brilliant developers get something wrong simply because they never fully grasp what it is they are solving.
The questions we work with are not like the questions physicists or mathematicians solve. They get a set of parameters and find the missing ones; our questions are also our results. We are already told what our results are — we have to figure out how to reach them. That’s why it’s imperative to know the question well because you’ll see the result.
Writing down or drawing out what you want to output is one of the best ways to start your coding. I understand that in our fast-paced industry, the expectation is that we have to jump right into the programming by running a “hello world” demo. And that’s great to familiarize yourself with an unfamiliar syntax and shake off your anxiousness about trying something new.
But when someone asks you a question and gives you a result to work up to, wouldn’t it just be better to put that down first? That question/result is not only your starting point but also your point of reference. At any step in your coding, you can look at it to ensure you’re working towards it and that you’re on the right track.
So whether in your answer sheets or in that blank A4 paper you’re about to write in, start by taking a second and writing down what it is you’re trying to output. You can put it in the margins or a corner if you don’t want it to be a part of your answer. Just make sure it’s somewhere where you can keep referencing it.
Outline your code
This step is like a double-edged sword. It can get you a roadmap to your program or waste your time. My job is to make sure it’s the former.
So, first and foremost, I like to say: outlining code is unnecessary if the scope of your problem or question is small. Again, this practice is neither prescriptive nor universal to all projects or situations. Imagine I’m your interviewer, and I ask you to write how to center an element in a web page using CSS in as many ways as possible. You won’t exactly be needing an outline for this. The code snippets are relatively small for each method.
But now, let’s say I assign you to write a web application that captures user signatures via a touchscreen interface and then saves the signature on the server. Not so straightforward, right? You’ve more than one thing to figure out. Perhaps, a little outline can help.
UI for capturing signature — HTML Canvas? WebGL?
Disable pointer events on the rest of the web page when the user is signing
Convert and save the captured image to a PNG file — JS
Then convert it to blob (maybe) and save it to the visitor’s log data table.
I’ve written a rough sequence of actions I think I might have to code. It could’ve been shorter or longer, depending on what I wanted from it.
I highly recommend outlining code for client projects. Write the outline along with your user requirements or on the back of wireframes you’ve printed out.
Your quick snapshot of bullet points gives you a map, a to-do list, and a checklist to verify against when you reach the end of the project — pretty much your whole project’s summary in a low-fidelity list. It can also become a template to start your next similar project.
But like I said before, this step is like a double-edged sword. You’ll have to keep this short for examinees and interviewees when there are time constraints.
If you don’t know where to start, write down just three essential functions you’ll have to code in your application, and if you have got the time, make it five.
But that’s about it. Spend as little time as possible on this, and don’t sweat over the details. The outline is not going to score you extra points. It’s there only to help you make sure you have everything covered. It captures your initial gut reaction and keeps you honest throughout the project’s life.
Longhand vs. shorthand
A quick reference to disable text selection
Time to start coding. So, what do you write? “Bdrs” or “border-radius“; “div -> p” or “<div><p></div></p>“; “pl()” or “println()“; “q()” or “querySelector()“?
If someone else is grading your code, then there’s no choice. Leave out abbreviations, pseudo-codes, Emmet shortcuts, and any other form of shorthand writing. Otherwise, there’s no reason to assume that anyone reading this knows what your abbreviations mean.
It’s really up to you.
If you’ve gotten out of touch with writing by hand — and many of us have — it’s better not to go overboard with the longhand notations, as they get tedious. At the same time, there’s no such thing as being too frugal with your writing. Not if you want to be able to look back on it one day and understand what you’d written down.
I have an open file in my note-taking app and a lined notepad on my desk where I write down code snippets I want to save for later reference. They are unorganized, just a long stream of snippets. That’s why when I browse through older notes, I wouldn’t know what I meant to write if I had not written them down clearly.
I forget syntaxes all the time. For instance, I’ve been using the arrow notation for JavaScript functions since it was introduced (because it’s shorter), and I’m pretty sure if someone suddenly asks me to define a function using the function keyword, I might even misplace the parentheses or the function name, inciting a syntax error.
It’s not unusual for us to forget syntaxes we haven’t used in a while. That’s why it’s better to write your notes clearly when you know you need them for future reference.
The non-sequential flow of code
Unlike the last step, which doesn’t apply to those of you interviewees and test-takers, this one is catered especially to you.
Most programming languages are interpreted, compiled, and executed so that sometimes pre-written code in the source is executed later when called. We do it in JavaScript, for example, with function calling — functions can be defined initially, then executed later. Examinees and interviewees can use this to start working on the critical point of your answer first.
As I’ve said from the very beginning, the purpose of handwriting code is to work through or test the logic of whatever it is you program. It’s best when you focus on resolving that first.
Let’s take a classic textbook example — a program to find the nth Fibonacci number. If I were to write a simple outline for it, it would be something like this:
Get the input.
Calculate the Fibonacci number.
Summarise the output.
Print the output.
All the steps in that outline are essential; however, 1, 3, and 4 are more obligatory. They are necessary but not important enough to focus on right away.
It’s better to start writing down the code to calculate the Fibonacci number rather than to fetch the input. Wrap it in a function, then go ahead and write the code sequentially and write down a line to call that function where appropriate.
Spend your time writing code that focuses on the heart of the problem.
Real professionals can skip ahead. Let’s say I have a client project, and I have to work with some triangle geometry — got two sides, opposite angle, and gotta find the third side’s length. And I’ve decided to scribble on paper to get started rather than opening my IDE.
First, I would draw the triangle, of course (that’s something I’m very experienced with, as you can tell). I would write down some sample lengths and angles. Then I’d write the formula (compliments of online searching, for sure), and then I’d jump right to the code for the function.
There’s no point in me writing down the obligatory steps even though I’ll need them in production-ready code. But it would be different if I had to write that on an answer sheet in an exam. I can’t skip the other steps; however, I can still start with the code for the formula.
For all those professionals who feel like the whole handwriting code thing doesn’t seem like your cup of tea but still might be curious if it can help you, then pseudo-code might be the balance you’re looking for.
It’s similar to outlining the code, as I mentioned in one of the previous steps. However, it’s briefer and feels more like shorthand coding. It’s sometimes also referred to as “skeleton code.”
Here’s some quick pseudo-code for a CSS grid layout:
Grid
5 60px rows
6 100px columns
There isn’t much to write! So, even though putting a pencil to paper is excellent for this sort of thing, it’s just as effective, fast, and inexpensive to jot some pseudo code into whatever program you’re using.
Space and comments
I believe code is 90% keywords and 10% tabs. Withoutspacesthereadabilityofwordsdecreases. Indentations are necessary for handwritten code as well. However, please don’t use it for every level because the width of the paper will limit you. Use spaces judiciously, but use them.
Prized OG snippet, written with extra TLC
If you’re writing code for your use, I also believe that if you’ve followed everything I’ve mentioned so far and have already written down your output and an outline on the page, you may not even need to include comments. Comments tell you quickly what its following set of code does. If you have already written and read an outline for the code, then comments are redundant notes.
However, if your judgment says to put down one, then do it. Add it to the right side of the code (since you won’t be able to insert it between already written lines the way you could in, say, VS Code). Use forward slashes, brackets, or arrows to denote that they are comments.
For examinees who are unconfident with a certain syntax, write down comments. This way, at least, you’re letting the person grading your paper know your intention with that incorrectly formatted code. And use only the correct delimiters to denote comments — for example, that would be the forward slashes for JavaScript.
Analog vs. digital
As I mentioned earlier, everything I’m providing here can is generic coding advice. If you don’t want to try this with physical paper, any note-taking application also works.
But if you’re going to try the digital route, my recommendation is to try using something other than a straight note-taking app. Work with more visual digital tools — flow diagrams, mind maps, wireframes, etc. They can help you visualize your result, the outlines, and the code itself.
I am not much of a digital citizen (except for working on the web and recently converting to reading e-books), so I stick to physical notebooks.
My favorite tools for handwriting code
Any pencil and paper will do! But there are lots of options out there, and these are a few choice tools I use:
I hope, if nothing else, my little way of handwriting code with pencil and paper makes you evaluate the way you already plan and write code. I like knowing how other developers approach their work, and this is my way of giving you a peek into the way I do things.
Again, nothing here is scientific or an exact art. But if you want to give handwritten code planning a try, here’s everything we’ve covered in a nice ordered list:
Start by writing down (with sample data, if needed) the output of your code.
Write an outline for the code. Please keep it to three steps for small projects or ones that are less complex.
Use longhand notations. Developers writing for themselves can use shorthand notations as long as the writing is legible and makes sense to you when you refer to it later.
When under a time constraint, consider writing the code that tackles the heart of the problem first. Later, write down a call to that code at the right place in your sequential code.
If you feel confident, try writing pseudo code addressing the main idea.
Use proper indentations and spaces — and be mindful of the paper’s width.
That’s it! When you’re ready to try writing code by hand, I hope this article makes it easy for you to start. And if you’re sitting down for an exam or an interview, I hope this helps you focus on getting the questions right.
Like, what if the images aren’t perfectly square but instead are shaped like hexagons or rhombuses? Spoiler alert: we can do it. In fact, we’re going to combine CSS Grid techniques we’ve looked at and drop in some CSS clip-path and mask magic to create fancy grids of images for just about any shape you can imagine!
Let’s start with some markup
Most of the layouts we are going to look at may look easy to achieve at first glance, but the challenging part is to achieve them with the same HTML markup. We can use a lot of wrappers, divs, and whatnot, but the goal of this post is to use the same and smallest amount of HTML code and still get all the different grids we want. After all, what’s CSS but a way to separate styling and markup? Our styling should not depend on the markup, and vice versa.
This said, let’s start with this:
<div class="gallery">
<img src="..." alt="...">
<img src="..." alt="...">
<img src="..." alt="...">
<img src="..." alt="...">
<!-- as many times as we want -->
</div>
A container with images is all that we need here. Nothing more!
CSS Grid of Hexagons
This is also sometimes referred to as a “honeycomb” grid.
There are already plenty of other blog posts out there that show how to make this. Heck, I wrote one here on CSS-Tricks! That article is still good and goes way deep on making a responsive layout. But for this specific case, we are going to rely on a much simpler CSS approach.
First, let’s use clip-path on the images to create the hexagon shape and we place all of them in the same grid area so they overlap.
Nothing fancy yet. All the images are hexagons and above each other. So it looks like all we have is a single hexagon-shaped image element, but there are really seven.
The next step is to apply a translation to the images to correctly place them on the grid.
Notice that we still want one of the images to remain in the center. The rest are placed around it using CSS translate and good ol’ fashioned geometry. Here’s are the mock formulas I came up with for each image in the grid:
Each image is translated by the --_x and --_y variables that are based on those formulas. Only the second image (nth-child(2)) is undefined in any selector because it’s the one in the center. It can be any image if you decide to use a different order. Here’s the order I’m using:
With only a few lines of code, we get a cool grid of images. To this, I added a little hover effect to the images to make things fancier.
Guess what? We can get another hexagon grid by simply updating a few values.
If you check the code and compare it with the previous one you will notice that I have simply swapped the values inside clip-path and I switched between --x and --y. That’s all!
CSS Grid of Rhombuses
Rhombus is such a fancy word for a square that’s rotated 45 degrees.
Same HTML, remember? We first start by defining a 2×2 grid of images in CSS:
The first thing that might catch your eye is the grid property. It’s pretty uncommonly used but is super helpful in that it’s a shorthand that lets you define a complete grid in one declaration. It’s not the most intuitive — and not to mention readable — property, but we are here to learn and discover new things, so let’s use it rather than writing out all of the individual grid properties.
grid: auto-flow var(--s) / repeat(2,var(--s));
/* is equivalent to this: */
grid-template-columns: repeat(2, var(--s));
grid-auto-rows: var(--s);
This defines two columns equal to the --s variable and sets the height of all the rows to --s as well. Since we have four images, we will automatically get a 2×2 grid.
After setting the grid, we rotate it and the images with CSS transforms and we get this:
Note how I rotate them both by 45deg, but in the opposite direction.
.gallery {
/* etc. */
transform: rotate(45deg);
}
.gallery > img {
/* etc. */
transform: rotate(-45deg);
}
Rotating the images in the negative direction prevents them from getting rotated with the grid so they stay straight. Now, we apply a clip-path to clip a rhombus shape out of them.
We are almost done! We need to rectify the size of the image to make them fit together. Otherwise, they’re spaced far apart to the point where it doesn’t look like a grid of images.
The image is within the boundary of the green circle, which is the inscribed circle of the grid area where the image is placed. What we want is to make the image bigger to fit inside the red circle, which is the circumscribed circle of the grid area.
Don’t worry, I won’t introduce any more boring geometry. All you need to know is that the relationship between the radius of each circle is the square root of 2 (sqrt(2)). This is the value we need to increase the size of our images to fill the area. We will use 100%*sqrt(2) = 141% and be done!
Like the hexagon grid, we can make things fancier with that nice zooming hover effect:
CSS Grid of Triangular Shapes
You probably know by now that the big trick is figuring out the clip-path to get the shapes we want. For this grid, each element has its own clip-path value whereas the last two grids worked with a consistent shape. So, this time around, it’s like we’re working with a few different triangular shapes that come together to form a rectangular grid of images.
The three images at the topThe three images at the bottom
We place them inside a 3×2 grid with the following CSS:
The final touch is to make the width of the middle column equal 0 to get rid of the spaces between the images. The same sort of spacing problem we had with the rhombus grid, but with a different approach for the shapes we’re using:
grid-template-columns: auto 0 auto;
I had to fiddle with the clip-path values to make sure they would all appear to fit together nicely like a puzzle. The original images overlap when the middle column has zero width, but after slicing the images, the illusion is perfect:
CSS Pizza Pie Grid
Guess what? We can get another cool grid by simply adding border-radius and overflow to our grid or triangular shapes. 🎉
CSS Grid of Puzzle Pieces
This time we are going to play with the CSS mask property to make the images look like pieces of a puzzle.
If you haven’t used mask with CSS gradients, I highly recommend this other article I wrote on the topic because it’ll help with what comes next. Why gradients? Because that’s what we’re using to get the round notches in the puzzle piece shapes.
Setting up the grid should be a cinch by now, so let’s focus instead on the mask part.
As illustrated in the above demo, we need two gradients to create the final shape. One gradient creates a circle (the green part) and the other creates the right curve while filling in the top part.
--g: 6px; /* controls the gap */
--r: 42px; /* control the circular shapes */
background:
radial-gradient(var(--r) at left 50% bottom var(--r), green 95%, #0000),
radial-gradient(calc(var(--r) + var(--g)) at calc(100% + var(--g)) 50%, #0000 95%, red)
top/100% calc(100% - var(--r)) no-repeat;
Two variables control the shape. The --g variable is nothing but the grid gap. We need to account for the gap to correctly place our circles so they overlap perfectly when the whole puzzle is assembled. The --r variable controls the size of circular parts of the puzzle shape.
Now we take the same CSS and update a few values in it to create the three other shapes:
We have the shapes, but not the overlapping edges we need to make them fit together. Each image is limited to the grid cell it’s in, so it makes sense why the shapes are sort of jumbled at the moment:
We need to create an overflow by increasing the height/width of the images. From the above figure, we have to increase the height of the first and fourth images while we increase the width of the second and third ones. You have probably already guessed that we need to increase them using the --r variable.
We created the overlap but, by default, our images either overlap on the right (if we increase the width) or the bottom (if we increase the height). But that’s not what we want for the second and fourth images. The fix is to use place-self: end on those two images and our full code becomes this:
Here is another example where I am using a conic gradient instead of a radial gradient. This gives us triangular puzzle pieces while keeping the same underlying HTML and CSS.
A last one! This time I am using clip-path and since it’s a property we can animate, we get a cool hover by simply updating the custom property that controls the shape.
Wrapping up
That’s all for this first part! By combining the things we’ve already learned about CSS Grid with some added clip-path and mask magic, we were able to make grid layouts featuring different kinds of shapes. And we used the same HTML markup each time! And the markup itself is nothing more than a container with a handful of image elements!
In the second part, we are going to explore more complex-looking grids with more fancy shapes and hover effects.
I’m planning to take the demo of expanding image panels we made together in this other article:
…and transform it into a zig-zag image panels! And this is only one example among the many we will discover in the next article.
If you use VS Code, you might have enabled the setting for re-opening a previously open file next time the app launches. I do. I like that.
Hey, thanks for remembering, buddy! 🤗
But sometimes you really, really don’t want that to happen.
I recently ran into one of those times! I had to reinstall my local copy of this site and, with it, the 3GB+ database that accompanies it. Being a WordPress site and all, I needed to open up the SQL database file to search-and-replace some stuff.
If you’ve ever tried to open a super duper large file in VS Code, then you know you might need to jiggle a few settings that increase the memory limit and all that. The app is super flexible like that. There’s even a nice extension that’ll both increase the memory and perform a search-and-replace on open.
Anyway, that big ol’ database file crashed VS Code several times and I wound up finding another way to go about things. However, VS Code keeps trying to open that file and inevitably crashes even though I nuked the file. And that means I wait for the MacOS beachball of fun to spin around before the app crashes and I can reopen it again for reals.
Well, I finally decided to fix that today and spent a little time searching around. One Stack Overflow thread suggests disabling extensions and increasing the memory limit via the command line. I’m glad that worked for some folks, but I had to keep looking.
Another thread suggests clearing the app’s cache from the command palette.
Nice, but no dice. 🎲
I wound up going with a scorched earth strategy shared by Jie Jenn in a helpful YouTube video. You’ve gotta manually trash the cached files from VS Code. The video walks through it in Windows, but it’s pretty darn similar in MacOS. The VS Code cache is located in your user folder.
Notice that I have the Backups folder highlighted there. Jie removed the files from the CachedData folder, but all that did was trigger a prompt for me to re-install the app. So, I took a risk and deleted what appeared to be a 3GB+ file in Backups. I showed that file the door and VS Code has been happy ever since.
Ask me again in a week and maybe I’ll find out that I really screwed something up. But so far, so good!
Designing a beautiful “article” is wrought with tons of considerations. Unlike, say, a homepage, a long-form article is less about designing an interface than it is designing text in a way that creates a relaxed and comfortable reading experience.
That’s because articles deal with long-form content which, in turn, tends to be valued by a ”time on page” interaction with users. We want someone to read a complete narrative. There’s a natural space between the time someone lands on an article and reads all the words. And hopefully, that space is immersive enough to not only hold a user’s, but provoke thoughts, ideas, and, possibly, actions. At least that’s what I’m hoping as I have your attention and you make your way through the very article you’re reading.
There’s a balance. On one hand, we hear that “no one reads the Internet.” On the other, a long-form article demands careful attention. Considering the current value of content marketing and the growing impatience in users, captivating readers for as long as possible should be a key concern. Let’s take a look at some best practices and examples of incredible article pages to get a better idea of what makes a visually appealing reading experience for long-form articles (without sacrificing user experience), and how we can replicate the effects.
Quick wins
Let me quickly list out what I think might already be obvious to many of you, but are effective things for content legibility:
Increase the font size: We know that 16px is the default and is perfectly fine in many designs, but a larger font size is inviting in that it implies the user is free to lean back and settle in without having to angle forward with the screen in their face to read.
Aim for characters per line: Very few people I know like to work harder than they need to, and that goes for reading too. Rather than using the full viewport width, try to narrow things down and balance that with your larger font size to get fewer characters on each line of text. Your sweet spot may vary, though many folks suggest somewhere between 45-75 characters per line to help limit how far the reader’s eye has to work to go from left to right. Chris has a bookmarklet to help count characters, but we also have the ch unit in CSS to get predictable results.
Bump up the line height: A default line height is going to feel smashed. It’s funny, but more space between lines (up to a point, of course) is less work for eyes, which seems antithetical to the characters-per-line advice where we generally want eyes to travel a shorter distance. A line height between 1.2 and 1.5 seems to be a pretty typical range for long-form content.
You may be accustomed to designing “above the fold” where real estate is a prime commodity. That’s sort of like beach-front property in the web world because it’s where we’re used to packing in high-value things, like hero banners, calls to action, and anything else to help sell a thing. Above the fold can be a lot like a dense urban downtown with high traffic and high-rise buildings.
Articles are different. They allow you to stretch out a bit. If we want to take the city development analogy a little further, articles have the acreage to lean into a “less is more” sort of design approach. That’s what makes seemingly small design choices — like type — so important to the overall experience.
Check out the example below. The link underlines have a little more room to breathe (specifically, they appear below the descenders). This is actually something that you can enable sitewide but looks especially nice on article pages since it increases readability. That’s the sort of subtle design choice that contributes to extra breathing room.
text-underline-position: under; is the line of CSS that makes this work. Naturally, text-decoration must be set to something other than none (underline in this case), too.
The example above also features text-decoration-thickness, which alters the thickness of underlines (and other line types). You can use this CSS property to match a line’s thickness to a font’s size and/or weight.
Here’s a full example:
a {
text-decoration: underline;
text-decoration-thickness: 2px;
/* or */
text-decoration: underline 2px;
text-underline-position: under;
}
But before you reach for the text-decoration shorthand, Šime Vidas has a few “gotchas” when it comes to using it that are worth reviewing.
Leading into the content
Drop caps are stylized letters that can be placed at the beginning of a document or document section. They were once used in Latin texts, but today they’re mostly used for decorative reasons.
Personally, I think that drop caps hinder readability. However, they can be a nice way to “lead” a reader into the main content, and they shouldn’t introduce any serious accessibility issues as long as you’re using the ::first-letter pseudo-element. There are other (older)methods that involve more HTML and CSS as well as the use of ARIA attributes in order for the content to remain accessible.
Using ::first-letter, the CSS would look something like this:
/* select the first letter of the first paragraph */
article > p:first-child::first-letter {
color: #903;
float: left;
font-family: Georgia;
font-size: 75px;
line-height: 60px;
padding-top: 4px;
padding-right: 8px;
padding-left: 3px;
}
It sure would be nice if we could use the initial-letter property, but there’s pretty much no support for it at the time I’m writing this. If we had it, all that math for font size and line height would be calculated for us!
CodePen challenged folks to show off their drop-cap-styling skills several years ago and you can see a whole bunch of neat examples from it in this collection.
Skip to main content
Screen readers allow users to skip to the main content as long as it wraps it within a <main> element. However, those who navigate websites by tabbing don’t benefit from this. Instead, we must create a “skip to main content” anchor link. This link is customarily hidden but revealed once the user makes their first tab (i.e. show on focus).
It would look something like this:
<!-- anchor -->
<a id="skip-link" href="#main">Skip to main content</a>
<!-- target -->
<main class="main">
<!-- main content -->
</main>
#skip-link {
position: absolute; /* remove it from the flow */
transform: translateX(-100%); /* move it off-screen so that it appears hidden but remains focusable */
}
#skip-link:focus {
position: unset; /* insert it back into the flow */
transform: unset; /* move it back onto the screen */
}
.main {
scroll-margin: 1rem; /* adds breathing room above the scroll target */
}
There are other ways to go about it, of course. Here are a couple of deeper dives on creating skip links.
I love the illustrations in this article. Despite how incredible they look, they don’t demand too much cognitive attention. They introduce brief moments of delight but also suggest that the article itself has something more important to say. Partly, this comes down to the use of transparency, whereas rectangular images capture more negative space and therefore demand more attention (which is fine if that’s the desired effect and images are crucial to the story).
However, it’s important to know that the images aren’t actually transparent at all, but instead are non-transparent JPEGs with the same background color as the content. I’m presuming that’s to keep the size of the images smaller compared to PNGs that support transparency.
The downside to “faking” a transparent background like this is that it would require additional trickery (and maintenance) to support a dark mode UI if your site happens to offer one. If the illustrations are pretty flat and simple, then SVG might be the way to go instead since it’s small, scalable, and capable of blending into whatever background it’s on.
But if you’re bound to using raster images and would rather work with PNG files for transparency, you’ll want to look into using responsive images and the loading="lazy" attribute for faster loading times.
Put the focus on the type and semantics
You may have very little say over how or where someone reads content on the web these days. Whether the user receives it in an RSS feed, gets it delivered by email, sees it copy-and-pasted from a colleague, finds it on a scraped site, or whatnot, your content might look different than you prefer. You could design what you think is the most gorgeous article in all the land and the user still might smash that Reader Mode button to your dismay.
That’s ok! The discoverability of content is very much as important as the design of it, and many users have their own ways of discovering content and preferences for what makes a good reading experience.
But there are reasons why someone would want a Reader Mode. For one, it’s like “not seeing any CSS” at all. By that, I mean Safari’s Reader Mode or Brave SpeedReader, which use machine learning to detect articles. There’s no fetching or executing of CSS, JavaScript, or non-article images, which boosts performance and also blocks ads and tracking.
This sort of “brute minimalism” puts the focus on the content rather than the styles. So, you might actually want to embrace a browser’s opinionated reading styles specifically for that purpose.
The way to do that is not by using CSS, but by paying closer attention to your HTML. Reader modes work best with markup that uses simple, semantic, article-related HTML. You’ve got to do more than simply slapping <article> tags around the article to get the most from it.
You might just find that a minimal design that emphasizes legibility over slickness is actually a good strategy to use in your site’s design. I’d strongly suggest reading Robin’s post on the “smallest CSS” for a solid reading experience.
Roundup of long-form articles!
I’ve shared a lot of what I think makes for a great reading experience for long-form articles on the web. But seeing is believing and I’ve rounded up a bunch of examples that showcase what we’ve covered.
Polygon uses a strong, provacative visual to hook readers into the ain content. Notice how the drop cap, larger font size, and increased line height make this feel like a page you can sit back with and relax.
The TASTE website uses transparent images that blend into the background color of the content. There’s plenty of space between elements and bold accents — like thick borders and a heavy drop cap — pull the reader’s eye down the page.
The Outline is a prime example of minimalism. Notice how something as subtle as a squiggly horizontal rule can be an eye-catching embellishment when there are fewer things competing for attention.
The brutalist style of the Dropbox blog is probably a controversial one. The colors, fonts, and use of space are all over the place, and the content being floated to the right just feels unfamiliar. But does it break any design ‘rules’? Nope. I could grow to like it in time, especially in a milder form.
Urban Beardsman’s design is extremely linear. As somebody that has difficulty concentrating and is easily distracted by sidebars, in-article CTA boxes, and even blockquotes, I very much enjoy how easy it is to read this blog like a book. The perfect example of “less is more.”
There’s nothing unique about the GoSquared blog, but it managed to include pretty much all of the things we discussed in the article — a better underline design, seamless images, and some very readable typography. Quite impressive.
The Smart Passive Income blog proves how far you can get just by choosing a legible font and using readable font sizes, line heights, letter spacings, and paragraph spacings.
Recipe pages are consistently sucky, but not Little Fat Boy. The lack of sameness throughout the page makes it easy jump to different parts of the recipe without getting lost. Plus, the ingredients are pinned to the top-right for your convenience.