The Cardinal Sins of Website Design & Development (Ultimate List)

After years of auditing websites, consulting on projects, and cleaning up other people’s messes, I’ve compiled this definitive list of web design and development sins.

This list covers the most damaging practices in web design and development. Some destroy user experience. Others kill the website’s end goals. Many do both.

Every mistake here is preventable with proper knowledge and discipline. Every one represents a choice to take shortcuts instead of doing the work correctly.

Use this as a checklist for your projects. If you’re committing any of these sins, fix them. Your users, search rankings, and conversion rates depend on it.

And yes, I plan on keeping this updated. I’ll even take suggestions if you have them. Just ping me on X with any “sins” that you think should be added to the list.

Magic Numbers

When padding values are 22px on one component, 26px on another, and 31px somewhere else, there’s no predictable pattern for users to understand.

Regardless of how the spacing “feels” at the time of development, this inconsistency creates visual noise and makes your interface feel more and more unpolished as you continue to make up numbers out of thin air.

Magic numbers also make updates difficult. When you need to adjust spacing across your site, you’re changing dozens of unrelated values instead of updating a scale or design system.

Professional design systems use logical relationships. Whether based on typography line heights, modular scales, or simple multiples of a base unit, rhythmic spacing creates visual harmony.

How to fix: Set up your spacing and sizing scales before building. Use incremental values based on a logical math scale. Common scales are 1.25 (Major Third), 1.33 (Perfect Fourth), 1.5 (Perfect Fifth), 1.618 (Golden Ratio). Tokenize everything so consistency is baked in from the start.

Using Raw Values Instead of Tokens

Hard-coding design values throughout your stylesheet (aka “raw dogging your CSS”) makes global changes difficult and creates inconsistencies.

When colors, spacing, and typography values are statically scattered and repeated throughout your CSS, updating the site becomes a low-profitability and high-rage game of scavenger hunt.

Variables create a single source of truth for design decisions. They hold the place for an important value that can be deployed an infinite number of times without issue (assuming they’re named properly and used contextually).

How to fix: Instead of using #333 everywhere, map that value to var(--base). Then you can go a step further by contextualizing that into var(--bg-dark). This gives you two important layers of scalability and maintainability: a tokenized palette color with a context nod to where and how it’s being used.

Development Disconnections

Using relational values without connecting them through variables forces manual updates and introduces inconsistencies and breakages.

Let’s say you set a button height to 48px, then manually calculate icon size as 24px and padding as 12px. Later, when the button height changes to 52px, you must remember to update three separate values. Miss one, and your buttons break.

This pattern repeats throughout codebases. Border radius values, font sizes that should scale together, colors with specific relationships—all defined as separate, unconnected numbers.

CSS custom properties, especially when locally scoped, solve this by creating single sources of truth. Define relationships once, reference them everywhere they apply.

How to fix: Skip the static values—create tokenized relationships using locally scoped variables and ‎calc() functions. This way, when you tweak one value, everything else stays in sync and your codebase doesn’t implode.

.button {
  --button-height: 48px;
  --button-icon-size: calc(var(--button-height) / 2);
  --button-padding: calc(var(--button-height) / 4);
  block-size: var(--button-height);
  padding: 0 var(--button-padding);
}

.button-icon {
  inline-size: var(--button-icon-size);
  block-size: var(--button-icon-size);
  aspect-ratio: 1;
}

Ignoring Component-Based Development

Building interfaces without reusable components creates maintenance nightmares and inconsistent user experiences.

While a class-first workflow, especially one organized with BEM principles, creates a single source of truth for styling a block of elements, you still don’t have a single source of truth for the HTML, JS, or PHP involved in handling that block of elements.

Component-based development solves this problem and ensures consistency while reducing overall development time. And it makes maintenance feel effortless.

How to fix:

  1. Use a modern development environment that makes proper component-based development fast and simple. You should be able to quickly and easily add props, conditional logic, and loop interactivity with modular CSS, JS, and PHP.
  2. Build reusable components for common interface elements like buttons, cards, lists, and navigations and use them consistently throughout the site.

Components are a hallmark of modern, standards-based development.

Inconsistent Use of Color

Random color choices—different blues for different buttons, various grays for text, inconsistent accent colors—make interfaces feel chaotic and unprofessional. Users can’t predict what different colors mean or which elements are interactive.

Color systems provide semantic meaning. Primary colors for main actions, secondary for supporting actions, specific colors for success, warning, and error states. Consistent application helps users understand your interface intuitively.

How to fix:

  1. Define a limited color palette with specific use cases for each color. Document when to use primary vs secondary colors, how to handle hover states, and what colors indicate different types of feedback.
  2. Use a framework like Automatic.css that standardizes palette names, generates tokens, and creates inherent guidelines for contextual color usage.
  3. Stick to your defined colors and resist adding new ones without justification. When new ones are added, use relative color syntaxes to guard against disconnection.

Styling Everything at the ID Level

Using ID selectors for all styling (a practice encouraged by most traditional page builders) creates overly specific, individualized CSS, that’s difficult to override and maintain.

IDs have higher specificity than classes, making them nearly impossible to override without using !important or more IDs. This creates specificity wars where CSS becomes increasingly difficult to manage.

IDs also can’t be reused. Each styled element needs its own unique ID, creating bloated HTML and redundant CSS rules.

How to fix:

  1. Ditch traditional page builders that actively discourage a class-based workflow. These “beginner friendly” tools are destroying your projects and putting a low ceiling on your knowledge and abilities.
  2. Use classes for styling, preferably with an organization methodology like BEM.
  3. If you need one-off styling, use a randomly generated class name instead of an ID.
  4. Reserve IDs for scenarios like anchor linking and aria compatibility, where an ID is actually required.

Using “!important”

The !important declaration forces CSS rules to override natural specificity, creating maintenance problems and specificity conflicts.

When multiple !important declarations conflict, CSS reverts to normal specificity rules, making the behavior unpredictable.

Overuse of !important usually indicates underlying problems with CSS organization, specificity management, or understanding of the cascade.

How to fix:

  1. Commit to dealing with specificity problems through proper CSS organization, not force.
  2. Use CSS methodologies like BEM to “componentize” and flatten your CSS.
  3. Use modern techniques like @layer, @scope, and tokenization to naturally avoid conflicts.

Reserve !important for true edge cases, like overriding third-party, external library styles that you can’t modify directly.

Using Margin & Padding Incorrectly

The improper use of margin and padding creates layout and styling nightmares. Here’s a refresher:

Margin creates space outside an element’s border, affecting the element’s relationship to surrounding elements.

Padding creates space inside an element’s border, affecting the internal spacing around content.

Of course, there’s also Gap, which intelligently creates space between elements.

Using margin when you need padding (or vice versa) creates spacing that doesn’t behave as expected, especially when you factor in background colors, border styles, collapsing margins, and responsive layouts.

How to fix:

  1. If you need to space an element in relation to another element, use a gap-first, margin-second approach.
  2. If you need to space an element in relation to the boundaries of its parent, use padding.
  3. When using padding, always aim for balanced values. Since padding affects the dimensions of the element’s box, it’s important to make symmetrical changes. This preserves the box for future styling. And for elements like buttons and links it creates a symmetrical click target.

Final tip: If you ever find yourself setting non-symmetrical padding, there’s a very good chance that you shouldn’t be using padding. Gap, margin, and even translation are likely a better fit.

Using Margin on Sections

Using margin for section spacing creates a “no man’s land” between sections that can’t be styled. Since sections are the base method for defining page structure other than the main, body, and html tags, you should avoid creating space between them.

Not only is spacing between top-level page sections unnecessary, it creates dramatic limitations and the potential for massive and a very expensive refactor.

How to fix it: Make sure sections always touch each other. Styling should happen inside of sections, not outside.

Using Min-Height for Sections Instead of Padding

This is another tactic encouraged by traditional page builders that should be relentlessly tarred and feathered.

Min-height creates unpredictable section spacing that doesn’t adapt well to different content lengths or screen sizes.

Min-height sets a minimum size but doesn’t control how content is positioned relative to the boundaries of the section.

This approach also breaks down with varying content lengths. Short content creates excessive white space, while long content extends into the white space. And every time content length changes, adjustments have to be made to the min-height value to protect symmetry.

It’s an unmitigated disaster and a clear sign that the “developer” has no idea what they’re doing.

How to fix:

  1. Use padding to create predictable internal section spacing that adapts to content length. This ensures consistent spacing above and below content regardless of how much content exists.
  2. Use min-height only when you specifically need minimum dimensions (like making a hero section fill the entire screen), but always use it in conjunction with consistent section padding and not in place of section padding.

Spacer Elements

Oh look, yet another tactic encouraged by traditional page builders!

Spacer elements, or empty HTML elements created solely for visual spacing, are completely unnecessary and create major maintenance headaches.

Modern CSS layout methods handle spacing without additional markup. Gap, margin, and padding provide precise control over element spacing without DOM pollution.

Spacer elements also tend to break responsive design. Fixed-height spacers that work on desktop often create massive gaps on mobile or invisible slivers on large screens.

Finally, spacer elements are nearly impossible to adjust globally with any degree of predictability. They litter the site with hard-coded spacing decisions that have to be manually and individually tweaked or removed, which is a maintainability nightmare.

How to fix it: Handle all spacing through CSS properties (gap, margin, and padding). Keep your HTML focused on content structure and meaning, not visual presentation.

Physical Elements That Should be Pseudo Elements

Creating extra HTML elements for decorative effects that CSS pseudo-elements can handle clutters markup and reduces maintainability.

Decorative icons, dividers, quotation marks, or visual flourishes added as separate HTML elements mix presentation with content structure. This makes markup harder to read and increases the chance of inconsistencies.

Pseudo-elements (::before and ::after) handle decorative content through CSS, keeping HTML focused on semantic meaning.

How to fix: Use pseudo-elements for decorative content that doesn’t carry semantic meaning. Reserve HTML elements for content that adds meaning or structure to your document.

Bad Typefaces

Typography choices communicate brand personality and affect readability before users process any written content.

Using novelty fonts like Comic Sans for professional sites or decorative fonts for body text destroys credibility instantly.

Additionally, there’s a common problem of mixing too many typefaces, which creates visual chaos that distracts from your message.

Poor font choices also impact performance. Custom fonts increase load times, and poorly optimized web fonts cause layout shifts as they load.

How to fix: Limit yourself to one or two font families for most projects. Three max. Choose fonts that match your brand personality while prioritizing readability, and optimize for performance.

Using Heading Levels to Adjust Font Size

Choosing heading elements (h1, h2, h3) based on desired appearance rather than content hierarchy breaks document structure and accessibility.

Screen readers and other assistive technologies use heading levels to understand content organization. Using h4 for its smaller size when the content should be h2 creates confusing document outlines.

Search engines also use heading hierarchy to understand content importance and relationships, so bad heading structure hurts SEO and content discoverability.

How to fix: Choose heading levels based on content hierarchy, then use CSS to achieve the desired visual appearance. Your h2 can look like an h4 if that serves your design—just maintain proper semantic structure.

Wide Text Sections

Text lines that exceed optimal reading length reduce comprehension and increase reading fatigue.

Lines longer than 75 characters force readers to make large eye movements and increase the chance of losing their place when returning to the beginning of the next line. This slows reading speed and reduces comprehension.

Research shows optimal reading occurs with line lengths between 50-75 characters, including spaces. This creates comfortable reading rhythm without excessive eye movement.

How to fix: Use max-inline-size on text containers to control line length. The ch unit represents character width and provides precise control. For example, max-width: 70ch; creates lines of approximately 70 characters.

Additionally, you can consider multiple columns for wide screens rather than allowing text to span the full viewport width. The columns property in CSS creates flow-based columns for this exact purpose.

Centering Multiple Text Paragraphs

Center-aligning multiple paragraphs reduces readability and makes text harder to scan and follow.

Centered text works for short phrases, headlines, or single sentences. For multiple paragraphs, it creates uneven left edges that make it difficult for eyes to track from line to line and paragraph to paragraph.

Readers rely on consistent left alignment to quickly move between lines. Centered text forces readers to find the beginning of each line, slowing reading speed and increasing cognitive load.

How to fix: Use center alignment for short, standalone text like headlines, captions, or calls-to-action. Keep body text and multiple paragraphs left-aligned for optimal readability.

Note: Right-aligned text has similar readability problems and should be used sparingly for design emphasis only.

Ignoring Semantic HTML

Let’s all say this together: everything shouldn’t be a div.

Using generic div elements instead of semantic HTML elements reduces accessibility and makes code harder to read, styling harder to apply efficiently, and debugging more difficult.

Additionally, you shouldn’t attempt to fix poor semantic structure with attributes:

For example, <div role="list"> is a dumb and annoying way to fix the fact that <ul> wasn’t used.

How to fix: Use semantic elements like nav, main, article, section, header, and footer appropriately. Choose heading levels based on content hierarchy, not visual appearance. Make lists of things have proper ul > li structure. And ditch traditional page builders that don’t adhere to semantic HTML and don’t give you access to outputting semantic HTML.

Low-Resolution Logo & Images

Blurry images on high-density screens immediately signal unprofessional quality and poor attention to detail.

Standard resolution images (1x) look fuzzy on modern devices with high pixel densities. This is especially damaging for logos and key visual elements that represent your brand.

How to fix: Implement responsive images (srcset) with multiple resolutions. Use 2x and 3x versions for high-density screens, or switch to vector formats (svg) for logos and simple graphics that scale perfectly at any size.

Using the Wrong Image Formats

Choosing inappropriate image formats is one of the best ways to destroy site performance and graphical integrity.

Using jpg for images with transparency, png for photographs, or gif for static images creates unnecessarily large file sizes. Modern formats like webp and avif provide better compression with equivalent or superior quality while maintaining transparencies.

Wrong formats also limit functionality. svg provides crisp vector graphics that scale perfectly, but bitmap formats become blurry when scaled up.

How to fix: Choose the format based on the known factors of the file and how the file will be used. There’s no way around a lack of education in this area—there is pre-requisite knowledge required to do this properly.

Lack of Image Optimization

Unoptimized images slow page loading and increase bandwidth costs without providing any payoff whatsoever.

Large image files are often the biggest contributor to slow loading times. Images that load slowly or cause layout shifts create poor user experiences and hurt search engine rankings.

Modern image formats and compression techniques can reduce file sizes by 50-90% without noticeable quality loss, dramatically improving loading performance.

How to fix: Compress images appropriately for web use, implement responsive images for different screen sizes, and use modern formats like webp and avif.

Additionally, consider lazy loading for images below the fold to prioritize initial page rendering speed.

Using Image Edits Instead of CSS

Using image editors to create visual effects that CSS can handle creates major problems with respect to performance, responsiveness, and maintainability.

Rounded corners, drop shadows, gradients, and simple overlays created in an image editing program add unnecessary file size, prevent responsive adaptation, and fail to scale across large groups of images.

Imagine using an image editor to round the corners of every photo on the website (a very basic example, but there are dozens).

  1. You’re now forced to use an image format other than jpg , which has performance implications.
  2. If the decision is ever made to go away from rounded corners, every image has to be re-sourced, re-uploaded, and manually replaced.

How to fix: Always use CSS when possible.

Modern CSS handles most visual effects natively. Border-radius, box-shadow, gradients, transforms, and filters create the same effects with better performance and flexibility.

Text as Part of Images

Overlaying text on images with an image editor program prevents responsive behavior, hurts SEO, and creates accessibility problems.

Text in images can’t be selected, copied, translated, or read by screen readers. Search engines can’t index the content, reducing your SEO value. The text also can’t adapt to different screen sizes or user font preferences.

This approach also creates maintenance headaches when text needs updates—you’re editing images instead of changing copy in your CMS or code.

How to fix: All critical text should be HTML. Use CSS for styling, positioning, and visual effects. It’s quite easy to overlay text on an image with basic CSS.

Text Over Images With No Regard for Contrast

Text placed over images often becomes illegible and frustrates users trying to read your content. This is a common problem in Hero sections and overlay headers (it’s even worse when the user can’t read the navigation links).

Light text over light image areas or dark text over dark areas disappears entirely. In some cases, parts of the text is readable when it happens to overlay a darker part of the image, but the rest is lost as light areas of the image collide with your text.

Another common scenario is that overlay text is designed based on a dark image, not realizing that other pages using the same design might use much lighter images.

How to fix: Use semi-transparent overlays to darken images, get assistance from text shadows, or deploy background shapes behind text to ensure consistent contrast. CSS backdrop-filter can also blur background areas behind text for improved readability.

Make sure you test text overlays with various images and on different devices. What looks readable on your monitor might be invisible on mobile screens in bright sunlight, for example.

No Images When Visuals Are Necessary

Have you ever been reading about a product, service, or person, only to find yourself thinking, “I’d love to see a picture or image of this?”

It’s very common on the web when designers, developers, or brands get lazy or try to cut costs.

Text-only content that would benefit from visual explanation or illustration misses opportunities to improve comprehension and engagement.

Complex processes, data comparisons, or abstract concepts often benefit from visual support. Pure text descriptions of visual products or services don’t provide enough information for user decision-making.

How to fix: Strategic use of images, diagrams, or screenshots can significantly improve user understanding and reduce support requests. Yes, it often takes more time, effort, and money to produce visuals, but it’s well worth it.

Pop-ups

A pop-up is a timed or interaction-based modal that shows up on the screen, covers content, and demands to be interacted with, without user consent.

Intrusive pop-ups prioritize short-term conversion tactics over user experience and often reduce overall site performance.

Pop-ups that appear too soon, block content access, or use deceptive close buttons create negative first impressions. Users who close pop-ups are often more likely to leave your site entirely than users who never encountered them.

Generic discount offers or newsletter sign-ups might “convert,” but they don’t justify the disruption they create and often only succeed at capturing low-quality visitors.

How to fix: Say “no” to pop-ups. Consider less intrusive alternatives like smaller corner panels, top or bottom notification bars, or user-triggered call-to-action modals.

Auto-Play Audio and Videos

Auto-playing media violates user control principles and creates negative first impressions.

Many users will immediately leave sites that auto-play media rather than searching for pause controls. The negative impact often outweighs any engagement benefits.

Google also penalizes sites with intrusive auto-play content, affecting search rankings and discoverability.

How to fix: Provide clear play controls and let users choose when to start and stop media. Use muted auto-play sparingly for background video that enhances the visual experience without disrupting the user. You can also use auto-play thumbnails on video embeds which preview the video without playing audio.

Bad Animations

Poorly implemented animations only serve to distract from your valuable content. They do not make the site more engaging or sticky and they often come with performance pitfalls.

Good animations provide feedback, guide attention, or smooth transitions between states. They should be subtle, purposeful, and respectful of user preferences.

Keep animations under 300ms for micro-interactions, use appropriate easing curves, and always implement prefers-reduced-motion support. Animation should enhance usability, not showcase technical capabilities.

How to fix: Less is more with animation. Use it sparingly, or not at all. Animation adds cost and rarely delivers real returns—sometimes it even tanks your conversion rates by annoying users.

Here’s a reality check: most people who think they’re animation wizards are actually just distracting visitors. So, make data-driven decisions. Launch your site without animations, gather at least 90 days of analytics, then add your desired effects. If bounce rates go up or conversions drop, yank those animations faster than you can say “CSS keyframes.” Let the data call the shots.

Scroll-Jacking Effects

Have you ever been scrolling down a page when suddenly you’re forced into some heavily animated area or a horizontal slideshow of some sort? That’s scroll-jacking. Instead of being free to scroll around a page, you’re forced into various “visual experiences” as you scroll.

Your scroll ability has been hijacked!

Of course, overriding natural scroll behavior confuses users and breaks fundamental web interaction practices.

Scroll-jacking also causes performance problems. JavaScript-heavy scroll listeners can create janky, unresponsive interfaces. This doesn’t impress users, it annoys them.

How to fix: Respect default scroll behavior. Enhance it carefully when there’s clear user benefit, and always provide ways to disable custom scroll effects.

Smooth scrolling to anchors, parallax effects that don’t interfere with navigation, or progress indicators that respond to scroll position add value without breaking expectations.

Single View Sliders

Carousels and sliders that show only one item at a time are WILDLY popular among clients and know-nothing users.

Problem is, they hide critical content, reduce usability, degrade performance, and very often break accessibility.

You can also look at interaction analytics to see that they’re a bad idea. Most users never interact with slider controls, meaning content after the first slide goes largely unseen.

Auto-rotation doesn’t really help with this because visitors don’t stay in one spot long enough to see the slides change. And if they do, they often have a frustrating experience trying to return to the slide they wanted to see.

How to fix:

  1. Follow the general rule of thumb: If the content is important, it shouldn’t be hidden.
  2. Show multiple items (carousel) instead of a single item so it’s clear there’s more content to see.
  3. Use clear navigation controls that respect accessibility.
  4. Consider whether a slider adds value or is just there for visual effect.

Sliders and carousels are often added by designers, devs, and clients purely for visual interest. This puts an irrelevant metric ahead of relevant metrics. If you want to add a carousel, you should have good reasons beyond “visual interest.”

Fancy, Convoluted Navigations

Complex navigations (aka “menus,” but that’s the wrong term) confuse users and hide important content behind unclear interaction patterns.

Multi-level mega “menus,” burger-hidden navigations on desktop (when the audience is non-technical), or navigations that require multiple clicks to access basic pages create unnecessary barriers to content discovery.

This is yet another area where designers try to win design awards, devs get way too cute, and clients fawn over fanciness, instead of considering user experience and important site goals.

How to fix:

  1. Keep navigation simple and predictable. Use clear labels, logical grouping, and established patterns.
  2. Try to limit hierarchy to one or two levels (top level and a dropdown). If you need a third level, use a flyout, but never go beyond three levels.
  3. If an item has children, it should not also be a navigation link. This is a terribly confusing and unpredictable interaction pattern for users and makes accessibility a nightmare.

The best navigation is the one users don’t notice because it works exactly as expected. While users might notice “fancy,” the risk of frustrating users is too high. Nobody is going to buy a product or service because they thought your navigation was fancy—they’ll certainly leave your site if you frustrate them, though.

Infinite Scroll

Have you ever reached the “end” of a page, only to watch the page dynamically load more content and allow you to keep scrolling? This is “infinite scroll.”

The main problem with infinite scroll should be obvious—it blocks access to the real end of the page (the footer) where users often go to find specific and important things.

It’s also common for users to lose their place in infinite scroll interfaces and they can’t bookmark specific areas, reducing return rates and shareability.

Infinite Scroll also makes it difficult to return to previously viewed items, which makes things like product and service comparison difficult.

Lastly, there are definite performance hits. As the page size grows, pages can get laggy. Infinite scroll loading can also feel janky, which is a basic interruption pattern.

How to fix:

  1. Always default to pagination. Pagination is common, easy, linkable, and predictable. This is why Google uses it for the most popular search engine of all time.
  2. If you want an infinite-scroll type experience while limiting the downsides, consider an Ajax “load more” button. This is a consent-based infinite scroll mechanism.
  3. If you use Ajax load more, make sure you also have paginated archives so users always have the option to link to specific groups or collections of items.

Poor Use of White Space

Insufficient white space creates cramped, overwhelming interfaces that are difficult to scan and process.

Dense layouts with minimal spacing between elements force users to work harder to distinguish different sections, read content, and understand relationships between elements.

White space isn’t wasted space—it’s functional. It provides visual rest, creates grouping and hierarchy, and makes interfaces more approachable and professional.

How to fix: Make sure there’s generous spacing around headings, inside of sections, and around interactive elements. Don’t be afraid of empty space—embrace it as a design tool.

Non-Existent or Inconsistent Gutter

The “gutter” of your website is the space between your content and the edge of the screen on mobile devices. Imagine a bowling lane. The lane is the content of your website, and the gutter on each side is the voided space that you try to keep things out of.

Have you ever been to a site on a mobile device where the text was literally touching the edge of the screen? Or where certain areas of content were closer to the edge than others? That all comes from having no gutter or an inconsistent gutter.

How to fix:

  1. Establish a consistent gutter variable. Automatic.css uses var(--gutter). Never set gutters with static values because there’s going to be a gazillion of them.
  2. Make sure your header, footer, and all top level section elements use the gutter variable as their inline padding value. This is preferably done through a global styling rule as manual application leads to inconsistency or forgetfulness.
  3. Ditch any traditional page builder that encourages you to set gutters manually. This is a direct encouragement of bad practice.

Building Without a Framework or Design System

Nobody who knows anything about CSS writes from scratch without a framework. They may not use a commercially available framework like ACSS, but they still use a framework. This is because a framework is required for efficient, scalable, maintainable, and predictable web design.

If you’re styling without a framework of some kind, you’re engaging in objectively bad styling practices. Period, end of discussion.

How to fix: Pick a flexible, but opinionated framework (“opinionated” is a good thing when it comes to frameworks!) and use it on every single project, every single time.

Color Contrast Issues

Insufficient contrast between text and backgrounds reduces readability and excludes users with visual impairments.

Low contrast affects everyone, not just users with disabilities. People using devices in bright sunlight, on low-quality monitors, or with tired eyes all struggle with poor contrast.

WCAG guidelines specify minimum contrast ratios for a reason—they’re based on research about human vision and readability.

How to fix: Use contrast checking tools to verify that all text meets minimum requirements. Ensure sufficient contrast for all interactive elements and their various states (hover, focus, active).

Good contrast isn’t just about compliance—it’s about ensuring everyone can actually read your content.

Using the Wrong Units

There are a lot of units in CSS: px, rem, em, ch, ex, ch, vw, dvw, vmin, and more. And there are functions like calc(), clamp(), min(), and max() that allow for calculating units or scaling between various values.

Why are there so many? Because units are situation-specific, and if you don’t know what you’re doing it’s very easy to make bad choices.

For example, using pixels for font sizes completely destroys accessibility. Yet, that’s the go-to unit for font-size in most traditional page building tools. Go figure.

Using viewport units in certain situations can destroy layouts.

Using em units, not realize that they cascade, can foul up typography and spacing across a website.

Using rem for things like borders can create major UI issues when users scale up their preferred font-size.

How to fix: This is another situation where there’s no way to avoid learning and practice. You have to study! You have to know what you’re doing! And there’s no interface in existence that can stop you from making these mistakes. In fact, most interface tools encourage mistakes!

Poor Content Management

We use “content management systems” (CMS) for a reason—to manage and organize content.

Yet, so many people create everything as a generic “page.” No custom post types, no custom taxonomies, no relationships—just the digital equivalent of a giant junk drawer.

This is a content management disaster. It kills the practical use of loops, facets, filters, proper archive pages, templating, and more.

How to fix: Embrace custom post types. Use them to group associated content like services, testimonials, team members, and even policy pages.

Your site will instantly become more organized, easier to manage, and a lot friendlier to users (and your future self). After all, this is proper content management.

Static Data & (No Loops)

Hard-coding content that should be database-driven creates maintenance nightmares and scaling limitations.

The first sign of an amateur is static instances of things like product/service cards, review cards, team member cards, etc. These things should almost always be looped, which requires:

  1. The knowledge of looping.
  2. A development tool/workflow that enables looping.
  3. The knowledge and ability to use custom fields.
  4. The knowledge and practical use of dynamic data.

Nobody who knows looping chooses to avoid it. The people who avoid it either don’t know what they’re doing or they’re using a beginner tool that doesn’t make looping practical or possible.

Loops instantly solve major website nightmares with no meaningful downside. They provide a single source of truth for how data is rendered; they enable the use of facets, filters, Ajax load more, and pagination; and they make it possible to update sites from the CMS rather than the codebase.

How to fix: Architect your sites properly. Use custom post types and taxonomies. Learn how to loop through objects and arrays. Use a fully-powered visual development tool like Etch to make looping feel effortless and ditch any tool that has a non-existent or underpowered loop element.

Significant Layout Shifts

Content that moves during page loading creates jarring user experiences and hurts Core Web Vitals scores.

Layout shifts occur when elements load and change size after initial render, pushing content around the page. This is especially problematic when users are trying to click or interact with content.

Images without defined dimensions, web fonts loading and changing text metrics, or ads injecting content are common causes of layout shift.

How to fix: Reserve space for images with proper width and height attributes, use font-display: swap wisely, and avoid injecting content that changes page layout after initial render.

Google’s Core Web Vitals includes Cumulative Layout Shift as a ranking factor, making this both a user experience and SEO issue.

Form Problems

Using inappropriate form inputs or poor form design creates usability barriers and increases abandonment.

Generic text inputs for email addresses, phone numbers, or dates don’t provide appropriate mobile keyboards or validation. Poor label association makes forms inaccessible to screen readers.

Complex forms without clear structure or progress indication overwhelm users and increase abandonment rates.

Even simple and seemingly obvious mistakes like using checkboxes instead of radio inputs for single-choice fields can cause data nightmares on the back end.

Imagine needing to compile users’ answer on a question but you accidentally let them make more than one choice and you let in 1000 submissions before you discovered the error. You now have 1000 submissions full of bad and unusable data.

How to fix: Use a reputable and fully-featured form system like WS Form that handles validation, accessibility, and a laundry list of other technical requirements. Make sure you know what you’re doing when you build a form. And finally, test, test, and test again before you deploy a form. So many issues can be discovered during proper testing—don’t be lazy!

Lazy Copy

There’s a big problem that exists in copywriting: Bad copywriters think they’re “good enough” at writing copy.

But “good enough” copy is precisely the kind of copy that’s instantly forgettable.

I can’t tell you how many websites I go to where I read the headline, hero copy, features copy, product copy, etc. and think to myself, “Yeah, literally every single business in this industry could say the exact same thing.”

Copy across the web is so terribly generic that you could literally copy it from one competitor and paste it on another and there would be zero difference.

This violates the number one rule of marketing and copywriting, which is USP—Unique Selling Proposition. The keyword being, “unique.” If you’re not saying something unique, then the visitor has no reason to care. And if the visitor has no reason to care, they have no reason to choose you.

How to fix: Write copy that explains exactly what you do differently and why it matters. Use concrete examples, specific benefits, and unique value propositions that only apply to your offering. If the copy you’re writing could be pasted on any other competitor website, then re-write it!

P.S. For the love of God, stop using the word “solutions” for everything. When I see the word “solution” or “solutions,” especially in a navigation or headline, I instantly know that the copywriter is a complete and total amateur.

Jargon Copy

Complex business jargon and abstract language alienates users and obscures your actual message.

“Leverage synergistic paradigms to optimize vertical integration” sounds impressive but communicates nothing useful. Abstract language forces users to work harder to understand basic information about your products or services.

Corporatespeak also creates distance between you and your audience, making your brand seem unapproachable or disconnected from real problems.

How to fix: Write in plain language that your target audience uses and understands. Explain complex concepts in simple terms. And, unless you’re speaking to a very technical audience, avoid “inside baseball” terms that require pre-requisite knowledge.

Non-Dashed URLs

Using underscores, camelCase, or spaces in URLs creates SEO problems and reduces usability.

We don’t need to go into detail here. The standard for writing urls is kebab case—lowercase words separated by dashes.

How to fix: Always use kebab case, keep URLs succinct, avoid stop words (and, the, of, to, etc.), and make your URLs human readable and easily shareable.

Creating Blog Posts With a Page Builder

Using page builders for blog posts is one of the most common disaster scenarios in WordPress.

Blog posts often number in the dozens, hundreds, or thousands and they share the same basic architecture. Know what this means? They should be templated, with the actual article content dynamically injected into the template.

Failure to use templating in this scenario creates tons of URLs that must be manually re-configured when things change in the future and create the possibility for widespread content corruption. This is a very expensive and time consuming process to fix!

Proper templating creates a single source of truth for all blog posts, with content remaining where it should be—inside the content management system.

How to fix: You can use a page builder to build the blog post template, but never use a page builder for building out a literal blog post instance.

DIYing the Site

Building websites without sufficient expertise almost always costs far more than hiring a professional.

Wix, Squarespace, Framer, et al. are lying to you in their marketing when they tell you that you can just click, click, click your way to a great website.

I call this The DIY Lie. Definitely read up about it before you try to DIY a site. It could save you a ton of money, time, and stress.

How to fix: Like any technical field, hire pros who get both the tech and the business side of web design. DIY is great for crafts, not for your digital storefront.

What’s missing?

Is there a “cardinal sin” of web development that you think I should list? Just ping me on X with your suggestion and I’ll consider including it with a link to your site or profile.