Skip to main content

CSS File Structure

The project uses a modular CSS architecture with three separate stylesheets, each serving a specific purpose:
css/
├── reset.css       # Browser normalization
├── variables.css   # Design tokens
└── global.css      # Component styles
This separation creates a clear hierarchy: reset styles, design system tokens, then component implementations.

Load Order Matters

The HTML loads stylesheets in a specific order:
index.html:20-22
<link rel="stylesheet" href="css/reset.css" />
<link rel="stylesheet" href="css/variables.css" />
<link rel="stylesheet" href="css/global.css" />
This order ensures:
  1. Reset - Normalize browser defaults first
  2. Variables - Define design tokens
  3. Global - Apply component styles using those tokens

reset.css: Browser Normalization

The reset file removes default browser styles for consistency:
reset.css
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

a {
  text-decoration: none;
  color: inherit;
}

button {
  border: none;
  background: none;
  cursor: pointer;
  font-family: inherit;
}

ul {
  list-style: none;
}

Why Reset Styles?

Browsers apply default styles inconsistently. A reset ensures:
  • No unexpected margins or padding
  • box-sizing: border-box for predictable sizing
  • Clean slate for custom styling
Using box-sizing: border-box means width includes padding and borders, making layouts more predictable.

variables.css: Design Tokens

CSS custom properties create a centralized design system:
variables.css:1-32
:root {
  /* Primary Colors */
  --primary-black: #000000;
  --primary-neutral: #404040;
  --primary-white: #FFFFFF;

  /* Zinc Scale */
  --zinc-100: #f4f4f5;
  --zinc-200: #e4e4e7;
  --zinc-300: #d4d4d8;
  --zinc-500: #71717a;
  --zinc-800: #27272a;

  /* Error */
  --error-500: #ef4444;

  /* Spacing Scale */
  --spacing-4: 4px;
  --spacing-8: 8px;
  --spacing-12: 12px;
  --spacing-16: 16px;
  --spacing-20: 20px;
  --spacing-24: 24px;
  --spacing-28: 28px;
  --spacing-32: 32px;
  --spacing-36: 36px;
  --spacing-40: 40px;

  --outline-width: 2px;
  --max-width: 1280px;
}

Design System Benefits

Single Source of Truth

Change a color once, update everywhere it’s used

Consistency

All spacing uses the same 4px-based scale

Maintainability

Easy to adjust designs without hunting through CSS

Semantic Naming

Names describe purpose, not appearance

Responsive Variables

Some variables change at breakpoints:
variables.css:34-38
@media (min-width: 768px) {
  :root {
    --outline-width: 4px;
  }
}
The outline effect on text becomes thicker on larger screens for visual impact.

global.css: Component Styles

The main stylesheet contains all component implementations:

Organization Pattern

/* Utility Classes */
.outlined { ... }
.section-title { ... }
.section-container { ... }

/* Header Section */
.header { ... }
.header__brand { ... }
.header__nav { ... }

/* Hero Section */
.hero { ... }
.hero__content { ... }
.hero__title { ... }

/* And so on... */
Components are grouped by section with clear comments:
global.css:36
/* --- HEADER SECTION --- */
global.css:124
/* --- HERO SECTION --- */
This organization makes finding and updating component styles straightforward. Each section comment acts as a visual bookmark.

BEM Naming Convention

The project uses a BEM-like (Block Element Modifier) naming pattern:
.block              // Component root
.block__element     // Child element
.block--modifier    // Variation

Real Examples

Header Component:
.header                    // Block
.header__brand            // Element
.header__logo             // Element
.header__nav              // Element
.header__nav--active      // Modifier
Skill Card Component:
.skill-card               // Block
.skill-card__icon         // Element
.skill-card__label        // Element
Project Card Component:
.project-card             // Block
.project-card__image      // Element
.project-card__title      // Element
.project-card--reverse    // Modifier

Why BEM?

The naming immediately shows which elements belong to which components.
Flat structure prevents specificity wars and makes styles predictable.
Class names describe structure and purpose without looking at HTML.
All selectors have equal specificity, avoiding !important hacks.

Utility-First Patterns

Some classes are reusable utilities:

Section Container

global.css:26-34
.section-container {
  padding: var(--spacing-40) var(--spacing-16);
  max-width: var(--max-width);
  margin: 0 auto;
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: var(--spacing-32);
}
Used by every major section for consistent spacing and max-width:
<section class="hero">
  <div class="section-container">
    <!-- Content -->
  </div>
</section>

Outlined Text Effect

global.css:5-18
.outlined {
  font-weight: 800;
  color: var(--primary-white);
  text-shadow:
    var(--outline-width) 0 var(--primary-black),
    calc(var(--outline-width) * -1) 0 var(--primary-black),
    /* ... 8 shadows total for outline effect ... */
}
Applied to text that needs the distinctive outline style:
Frontend <span class="outlined">Developer</span>

Mobile-First Media Queries

All media queries use min-width for progressive enhancement:
/* Mobile styles (no media query) */
.element {
  font-size: 16px;
}

/* Tablet and up */
@media (min-width: 768px) {
  .element {
    font-size: 18px;
  }
}

/* Desktop and up */
@media (min-width: 1024px) {
  .element {
    font-size: 20px;
  }
}
Mobile styles are the default with no media query. This ensures they work even if media queries fail.

Component Encapsulation

Each component’s styles are scoped with class names:
/* Hero styles don't affect other sections */
.hero { ... }
.hero__title { ... }
.hero__image { ... }

/* Project styles are separate */
.project-card { ... }
.project-card__title { ... }
.project-card__image { ... }
No styles bleed between components, even though they use the same element types (h1, img, etc.).

Commented Alternatives

The CSS includes commented-out alternative approaches:
global.css:256-273
/* .skills__grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--spacing-20);
}

@media (min-width: 768px) {
  .skills__grid {
    grid-template-columns: repeat(4, 1fr);
    gap: var(--spacing-32);
  }
}

@media (min-width: 1024px) {
  .skills__grid {
    grid-template-columns: repeat(5, 1fr);
  }
} */
This shows the original approach before switching to auto-fit. Great for learning different solutions!

Performance Considerations

Single CSS Bundle

All three CSS files are separate in development but could be combined in production:
<!-- Development: separate files for organization -->
<link rel="stylesheet" href="css/reset.css" />
<link rel="stylesheet" href="css/variables.css" />
<link rel="stylesheet" href="css/global.css" />

<!-- Production: combine for fewer HTTP requests -->
<link rel="stylesheet" href="css/styles.min.css" />

Efficient Selectors

All selectors use single class names for maximum performance:
/* ✅ Fast: single class */
.skill-card { ... }

/* ❌ Slow: deeply nested */
.skills .skills__grid .skill-card { ... }

No Unused Styles

Every style corresponds to an element in index.html. No bloat or unused code.

Best Practices Demonstrated

Modular Files

Separate concerns: reset, variables, components

Custom Properties

Centralized design system with CSS variables

BEM Naming

Clear, predictable class names

Mobile-First

Default styles for mobile, enhance for desktop

Comments

Section markers for easy navigation

Flat Specificity

Single class selectors, no specificity wars

Quick Reference

FilePurposeKey Features
reset.cssBrowser normalizationZero margins/padding, box-sizing
variables.cssDesign tokensColors, spacing, breakpoints
global.cssComponent stylesBEM naming, mobile-first

Next Steps

CSS Variables

Explore all custom properties in detail

Responsive Breakpoints

Learn the breakpoint strategy

Build docs developers (and LLMs) love