Details That Make Interfaces Feel Better
quality 1/10 · low quality
0 net
AI Summary
A design-focused guide covering practical CSS and animation techniques to improve interface quality, including text wrapping, border radius calculations, icon animations, typography rendering, and interruptible animations.
Tags
Entities
Tailwind
Motion
Inter
iOS
macOS
Details That Make Interfaces Feel Better Details that make interfaces feel better Great interfaces rarely come from a single thing. It's usually a collection of small things that compound into a great experience. Below are a few small details I use to make my interfaces feel better. Text wrapping A quick way to improve how text behaves in your app is to use text-wrap: balance . It distributes text evenly across each line, avoiding orphaned words. wrap Designing interfaces that feel natural and intuitive Great design is invisible. It guides users without them ever noticing. balance Designing interfaces that feel natural and intuitive Great design is invisible. It guides users without them ever noticing. Width 220 px Hide guides text-wrap: balance distributes text evenly across lines, preventing orphaned words. You can also use text-wrap: pretty to get a similar result, but it's a bit slower because it uses a different algorithm. Concentric border radius Concentric offset is a technique used to create a balanced visual look when nesting elements inside one another. This is one of the more important concepts that make interfaces feel great and it often goes unnoticed. padding: 8px 12px 12px 20px 12px Show Values There is a formula to calculate the correct values and it's very simple. The outer radius equals the inner radius plus the padding. outer radius inner radius padding There's still a surprising number of apps and interfaces that don't do this and instead mismatch border radii. If you're not already doing this, I'd recommend starting. It will make your interfaces feel much better. Outer Radius 20 px Inner Radius 12 px Padding 8 px Change the values to see how the border radius adapts Animate icons contextually Animating opacity , scale and blur on icons when they are shown contextually makes the transition feel better and more responsive. Motion CSS No Animation Opacity All < button onClick = {handleCopy} className = "button" > {isCopied ? < CheckIcon /> : < CopyIcon />} button > You can achieve the same effect with CSS only as well. I personally prefer Motion, because it allows me to use spring animations easily. Make text crispy On macOS , text rendering can sometimes appear heavier than intended. Subpixel rendering Default font smoothing uses subpixel antialiasing on macOS. Antialiased rendering Grayscale antialiasing produces thinner, crisper light text. Setting -webkit-font-smoothing: antialiased or just antialiased in Tailwind makes text render slightly thinner and crisper. < html lang = "en" > < body class = "font-sans antialiased" > < main > {children} main > body > html > The best way to apply this is to add it to the entire layout. That way it applies to all of the text elements in your app. Use tabular numbers If your numbers shift when they update, use font-variant-numeric: tabular-nums or just tabular-nums in Tailwind. 1000 1000 Click the play button to make the numbers run up It makes the digits equal width. Keep in mind that some fonts such as Inter change the look of numerals when this property is used. Make your animations interruptible When it comes to interruptibility, CSS transitions and keyframe animations behave differently. Transitions interpolate toward the latest state and can be interrupted, while keyframe animations run on a fixed timeline and don’t retarget after they start. keyframe transition Rotate Click the rotate button rapidly to see the difference Users often change their intent mid-interaction. For example, a user may open a dropdown menu and decide they want to do something else before the animation finishes. Animate Try to toggle the animation again while it's running If animations aren't interruptible, it can make the interface feel broken. For example, on iOS, interruptibility is quite prevalent for this very reason. Menu Menu Fast Interrupt the animation while it's running to see the difference A rule of thumb that can help you decide when to use CSS transitions vs keyframe animations is that CSS transitions are great for interactions, while keyframe animations are better for staged sequences that run once. Toggle Toggle Interrupt the animation while it's running to see the difference Split and stagger entering elements Enter animations often combine opacity , blur and translateY . It helps to break the animated components into smaller chunks and animate them individually instead of animating a big block at once. Track expenses, build lasting habits Budgeting turned upside down. Focus on what matters and keep your spending intentional. Primary Secondary Single Sections Individual The first variant animates a single container containing the title, description, and buttons. The second variant animates the title, description and buttons individually, with a 100ms delay between each section. < div className = "animate-enter" style = {{ "--stagger" : 1 }}> < Title /> div > < div className = "animate-enter" style = {{ "--stagger" : 2 }}> < Description /> div > < div className = "animate-enter" style = {{ "--stagger" : 3 }}> < Buttons /> div > The third variant animates the title by splitting it into individual spans. Each span contains a word and is animated individually with an 80ms delay between them. @keyframes enter { from { transform : translateY ( 8 px ); filter : blur ( 5 px ); opacity : 0 ; } } .animate-enter { animation : enter 800 ms cubic-bezier ( 0.25 , 0.46 , 0.45 , 0.94 ) both ; animation-delay : calc ( var ( --delay , 0 ms ) * var ( --stagger , 0 )); } .animate-enter-individual-title { --delay : 80 ms ; } The description remains a single block and the buttons are also animated individually rather than their entire container. Make exit animations subtle Exit animations usually work better when they're more subtle than enter animations. Subtle Full Animate Swap between the modes and toggle the animation to see the difference Exiting elements don’t need the same amount of movement and attention as entering elements. In the full example, the exit y value is calc(-100% - 4px) , which is the height of the container plus the padding. < motion.div key = "menu" className = "container" initial = {{ opacity: 0 , y: "calc(-100% - 4px)" , filter: "blur(4px)" }} animate = {{ opacity: 1 , y: 0 , filter: "blur(0px)" }} exit = {{ opacity: 0 , y: "calc(-100% - 4px)" , filter: "blur(4px)" , }} transition = {{ type: "spring" , duration: 0.45 , bounce: 0 }} /> In the subtle mode, we use a fixed value of -12px . Some subtle motion should still remain to indicate the direction, so I wouldn't recommend removing the animation completely. < motion.div key = "menu" className = "container" initial = {{ opacity: 0 , y: "calc(-100% - 4px)" , filter: "blur(4px)" }} animate = {{ opacity: 1 , y: 0 , filter: "blur(0px)" }} exit = {{ opacity: 0 , y: "-12px" , filter: "blur(4px)" , }} transition = {{ type: "spring" , duration: 0.45 , bounce: 0 }} /> By doing this, the exit animation becomes much softer, less jarring and doesn't demand the same amount of attention as the enter animation. Align optically, not geometrically Aligning items geometrically works great most of the time, but there are instances where it just looks off. When that happens, it is best to align items optically instead. Geometric Optical Button Show Padding For example, when a button has both text and an icon, it is better to have a slightly smaller padding on the side of the icon to optically align the content. Geometric Optical Show Margin Change the alignment mode and click the button to see the difference. In this example only the Play icon is optically aligned. This often happens with icons. While a lot of icon packs already account for this, there are shapes that need to be optically aligned. I usually fix it by adding margin or padding depending on the container. Geometric Optical Show Margin Change the alignment mode and click the button to see the difference For icons, the best way to fix it is in the svg itself, so no additional margin or padding needs to be added. Use shadows instead of borders Instead of borders, I often prefer to use a subtle box-shadow , that adds more depth to the element. Border Shadow The difference here is only noticeable in light mode The shadow in this example is comprised of three different shadows. .border-shadow { box-shadow : 0 px 0 px 0 px 1 px rgba ( 0 , 0 , 0 , 0.06 ), 0 px 1 px 2 px -1 px rgba ( 0 , 0 , 0 , 0.06 ), 0 px 2 px 4 px 0 px rgba ( 0 , 0 , 0 , 0.04 ); } For the hover state, it is the same box-shadow just slightly darker. To transition between the shadows, we can add box-shadow to the transition property transition-[box-shadow] . .border-shadow { box-shadow : 0 px 0 px 0 px 1 px rgba ( 0 , 0 , 0 , 0.08 ), 0 px 1 px 2 px -1 px rgba ( 0 , 0 , 0 , 0.08 ), 0 px 2 px 4 px 0 px rgba ( 0 , 0 , 0 , 0.06 ); } It also helps when using images or multiple colors as backgrounds. Shadows are versatile and adapt well to any background since they use transparency. Border Shadow Solid colors, on the other hand, don't work well when used on backgrounds other than the ones they were designed for. Add outline to images A visual tweak I use a lot is adding a 1px black or white (depending on the mode) outline with 10% opacity to images. Show Border This creates a sense of depth and a somewhat consistent outline around the element. .border-overlay { outline : 1 px solid rgba ( 0 , 0 , 0 , 0.1 ); outline-offset : -1 px ; } .dark .border-overlay { outline-color : rgba ( 255 , 255 , 255 , 0.1 ); } I mostly use this in design systems where other elements also use borders. Show Border More If you have any questions you can reach me via email , see more of my work on X (Twitter) or subscribe to my newsletter below. Newsletter I share stuff that I'm working on, new posts and resources here. Email address Subscribe Next Using Gestures in Motion