This article is part of a series about building my personal website:

  1. The idea and choosing the right tool
  2. SEO essentials: meta tags and base head element
  3. Content management with Markdown and Frontmatter
  4. Semantic HTML for accessibility and external readers
  5. Minimalist CSS: styling and native-like design
  6. Adding color themes with JavaScript
  7. Astro plugins: RSS, Sitemap, Word count
  8. SVG icons and Favicon
  9. Building resume with XeLaTeX
  10. Extras

When building apps for desktop or mobile, “native look” usually means using the platform’s built-in components (SwiftUI on iOS, Jetpack Compose on Android, etc.), so the UI feels familiar.

The web doesn’t have a true native toolkit - just bare HTML, which looks very plain by default. My goal was to make HTML feel native using as little CSS as possible - no recreating Apple or Material components, just small touches for comfort.

Minimal “native-like” CSS choices

Here’s what I focused on:

  1. System font stack - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
    This ensures the site uses the same font your OS uses.
  2. Simple color scheme - Default to black, gray, and white with blue links. Extra color themes can be added later.
  3. Respect system preferences - Use prefers-color-scheme: dark to match the OS theme.
  4. Consistent spacing - Stable 1em margins and a slightly increased line-height for readability.
  5. No overcomplicated styling - Keep it simple and let the browser’s defaults work for you.

Styling without classes

Instead of adding dozens of class attributes everywhere, I prefer semantic HTML with smart CSS selectors. This keeps markup clean, uncluttered, and improves accessibility by ensuring structure is meaningful.

If you’ve seen a “classless CSS framework” - that’s the same idea: make the base HTML look good without custom classes.

Theme variables

To make theming easier, I define each theme using just four CSS variables:

Example:

/* themes */

:root {
  --primary-color: #454545;
  --secondary-color: #EAEAEA;
  --background-color: #FFF;
  --link-color: #007AFF;
  color-scheme: light;
}

@media (prefers-color-scheme: dark) {
  :root {
    --primary-color: #DCDCDC;
    --secondary-color: #414141;
    --background-color: #1E1E1E;
    --link-color: #2DA1FD;
    color-scheme: dark;
  }
}

[data-theme="light"] {
  --primary-color: #454545;
  --secondary-color: #EAEAEA;
  --background-color: #FFF;
  --link-color: #007AFF;
  color-scheme: light;
}

[data-theme="dark"] {
  --primary-color: #DCDCDC;
  --secondary-color: #414141;
  --background-color: #1E1E1E;
  --link-color: #2DA1FD;
  color-scheme: dark;
}

[data-theme="sepia"] {
  --primary-color: #5B4636;
  --secondary-color: #E0D7C3;
  --background-color: #F5ECD8;
  --link-color: #D19600;
}

How it works

This method means light/dark switching still works even if JavaScript is disabled or fails to load.