# Craft Behind Polished Interfaces

> Practical UI craft notes: font smoothing, text-wrap balance and pretty, concentric corner radii, subtle image edges, and other details that make interfaces feel finished.

Canonical HTML: https://www.edwinvakayil.info/writings/craft-behind-polished-interfaces
Markdown mirror: https://www.edwinvakayil.info/writings/craft-behind-polished-interfaces.md
Author: Edwin Vakayil
Published: 2026-05-08
Reading time: ~8 min
Topics: UI craft, interface design, typography, CSS, frontend, font smoothing, border radius, micro-details

## Subtitle

From pixels to interactions: the details that transform a working UI into a thoughtful experience.

## Outline

- Make text feel lighter
- Better text wrapping
- Keep nested corners in sync
- Give images a subtle edge
- Prefer shadows over borders
- Make exits quieter
- Bring things in piece by piece

## Interactive demos on the page

- text-wrap: balance comparison
- text-wrap: pretty comparison
- text-wrap: balance + pretty combined
- Concentric corner offset comparison
- Concentric radius playground
- Subtle 1px image edge / outline
- Border vs soft shadow comparison
- Exit motion comparison
- Staggered enter motion comparison

## Article

A great interface is rarely about one big idea. More often, it’s the little things that quietly add up and make the experience feel right. Here are a few details I keep coming back to when designing interfaces.

Make text feel lighter

Typography is one of those things you notice without necessarily knowing why. On macOS , text can sometimes look a little heavier than expected, especially when you’re using lighter weights or smaller text.

A simple way to change that is to use grayscale antialiasing instead of the browser’s default font smoothing.

Interface details

The little things quietly add up and make the experience feel right.

Interface details

The little things quietly add up and make the experience feel right.

Use -webkit-font-smoothing: antialiased , or Tailwind’s antialiased class, and the type usually comes out a bit thinner and cleaner.

layout.tsx

<html lang="en"> <body class="font-sans antialiased"> <main> {children} </main> </body> </html>

The cleanest approach is to set it once on the root layout so every text element inherits it automatically.

Better text wrapping

One of the easiest upgrades for headings is text-wrap: balance . It spreads the words more evenly across each line, so titles look less lopsided.

text-wrap: balance spreads words evenly across lines so the last one isn’t left hanging alone.

You can also use text-wrap: pretty to keep a single word from sitting alone at the end of a sentence. It’s a quieter fix, and it works better for body text than for titles.

text-wrap: pretty keeps a single word from sitting alone at the end of a paragraph. Just note: Firefox doesn’t support it yet.

Most of the time, you’ll combine them: text-wrap: balance for the title, text-wrap: pretty for the body.

Keep nested corners in sync

Concentric offset is a simple way to keep nested elements looking balanced. It’s one of those quiet details that make an interface feel right, and most people never notice it.

There’s a simple formula for this:

Outer radius = inner radius + padding

A lot of apps still get this wrong and mix mismatched corner radii. If you’re not already doing it, start. Your interfaces will feel noticeably better.

Change the values to see how the border radius adapts.

Give images a subtle edge

A small tweak I use often: give images a 1px outline (black or white, depending on the mode) at about 10% opacity.

It adds a little depth and keeps a soft, even outline around the image.

global.css

.border-overlay { outline: 1px solid rgba(0, 0, 0, 0.1); outline-offset: -1px; } .dark .border-overlay { outline-color: rgba(255, 255, 255, 0.1); }

Prefer shadows over borders

Instead of a border, I often use a soft box-shadow . It gives the element a bit more depth. You’ll notice it most in light mode, but it works in dark mode too, where the shadow almost reads like a border.

This example stacks three shadows on top of each other.

global.css

.border-shadow { box-shadow: 0px 0px 0px 1px rgba(0, 0, 0, 0.06), 0px 1px 2px -1px rgba(0, 0, 0, 0.06), 0px 2px 4px 0px rgba(0, 0, 0, 0.04); } @media (prefers-color-scheme: dark) { .border-shadow { box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.08); } }

On hover, use the same box-shadow , just a little darker. Add transition-[box-shadow] so the change feels smooth.

Make exits quieter

Things usually feel better when they leave more quietly than they arrive.

Toggle the animation to compare the subtle and full exits side by side.

Things leaving don’t need as much attention as things coming in. On the left, we only animate x between 0 and calc(-100% - 4px) , which is the drawer’s full width plus a little padding, so it slides all the way off screen.

panel.tsx

<motion.div key="menu" className="container" initial={{ x: "calc(-100% - 4px)" }} animate={{ x: 0 }} exit={{ x: "calc(-100% - 4px)" }} transition={{ type: "spring", duration: 0.45, bounce: 0 }} />

In the second example, the exit doesn’t move x at all. It just fades out with opacity and filter .

panel.tsx

<motion.div key="menu" className="container" initial={{ x: "calc(-100% - 4px)" }} animate={{ x: 0 }} exit={{ opacity: 0, filter: "blur(4px)" }} transition={{ type: "spring", duration: 0.45, bounce: 0 }} />

That makes the exit softer and less abrupt, so it doesn’t pull as much attention as the enter.

Bring things in piece by piece

Enter animations often mix opacity , blur , and a little translateY . It usually feels better if you break the UI into smaller pieces and animate those one by one, instead of moving the whole block at once.

Try Block, Sections, and Individual to see how the same hero enters three different ways.

Block animates the title, description, and buttons as one container. Everything shares the same enter, so the whole hero arrives together.

Sections keeps those three pieces separate. The title starts first, then the description, then the buttons as a group, with a 200ms gap between each section.

hero.tsx

<div className="animate-enter animate-enter-sections" style={{ "--stagger": 0 }}> <Title /> </div> <div className="animate-enter animate-enter-sections" style={{ "--stagger": 1 }}> <Description /> </div> <div className="animate-enter animate-enter-sections" style={{ "--stagger": 2 }}> <Buttons /> </div>

Individual goes one step further on the title. Each word is its own span and enters with a 100ms delay between them. After the words, the description still enters as a single block. Then each button enters on its own, also spaced by 100ms .

global.css

@keyframes enter { from { transform: translateY(8px); filter: blur(8px); opacity: 0; } } .animate-enter { animation: enter 600ms cubic-bezier(0.25, 0.46, 0.45, 0.94) both; animation-delay: calc(var(--delay, 0ms) * var(--stagger, 0)); } .animate-enter-sections { --delay: 200ms; } .animate-enter-individual-title { --delay: 100ms; }

So in Individual, the cascade is words, then the paragraph, then each button. The description never needs to split. The buttons do, because two separate controls feel clearer when they don’t arrive as one chunk.

## FAQ

### What is “Craft Behind Polished Interfaces” about?

Practical UI craft notes: font smoothing, text-wrap balance and pretty, concentric corner radii, subtle image edges, and other details that make interfaces feel finished. Read it at https://www.edwinvakayil.info/writings/craft-behind-polished-interfaces.

### Who wrote “Craft Behind Polished Interfaces”?

Edwin Vakayil wrote “Craft Behind Polished Interfaces”. Canonical page: https://www.edwinvakayil.info/writings/craft-behind-polished-interfaces.

### What sections are in “Craft Behind Polished Interfaces”?

The article covers: Make text feel lighter; Better text wrapping; Keep nested corners in sync; Give images a subtle edge; Prefer shadows over borders; Make exits quieter; Bring things in piece by piece.

### What makes a polished interface feel better than a working one?

Usually small compounding details: cleaner type rendering, balanced headings, nested corners that stay in sync, and subtle image edges. None of them are dramatic alone, but together they make the UI feel intentional.

### Why use antialiased font smoothing on macOS?

Default browser font smoothing can make lighter weights look heavier than expected. Setting -webkit-font-smoothing: antialiased (or Tailwind’s antialiased class) often makes text feel thinner and cleaner, especially on dark backgrounds.

### When should you use text-wrap: balance vs text-wrap: pretty?

Use text-wrap: balance on titles so lines feel even. Prefer text-wrap: pretty for body copy so a final orphan word is less likely to sit alone. Many layouts combine both.

### What is the concentric corner radius formula?

Outer radius = inner radius + padding. Matching nested radii this way keeps cards, buttons, and containers visually balanced instead of looking mismatched.
