Featured image of post Epic Web Dev (EWD) - Styling [Part 1]

Epic Web Dev (EWD) - Styling [Part 1]

Learning Styling

Key Concepts:

  1. Guna Remix

  2. Remix ada benda dipanggil links export

  3. Beza guna daripada usual React way basically

    • Links are route-based rather than component-based

    • Links are automatically managed (added/removed) based on route activity

    • More granular control over resource loading

    • Granular means instead of loading all the CSS for your app at once, Remix only loads the styles needed for the specific part of the app. Just imagine you have a book with 100 chapters, and you only read Chapter 5. Granular loading is like opening just Chapter 5 instead of carrying the whole book with you. It makes things faster and lighter!

  4. Why This Matters for React Dev yg guna Remix:

    • Mental Model Shift → Instead of thinking about styles at the component level (macam in React), Remix encourages thinking about styles at the route level

    • Basically wit this way better performance as styles are loaded/unloaded with routes

  5. Common Pitfalls to Avoid:

    • Don’t think about styles as just component-level concerns

    • Jgn assume all styles need to be globally available

    • Remember that route-based styling can affect how you structure your CSS


favicon image

favicon black

favicon network

So the issue above is

  • Initially the SVG color is black

  • So I update the color svg with original code color and saved the file

  • However the favicon not being updated, this is bc when updating static assets browsers cache them based on cache-control headers

  • This is error-prone and requires manual intervention so it is tedious

Solution

  • I moved the favicon.svg from app/public folder to app/assets

  • Import the assets to the root.tsx accordingly and replace href from href: '/favicon.svg' to href: {imported name asset}

What I did not know

Asset Fingerprinting:

1
2
3
4
5
Before:
public/favicon.svg → /favicon.svg

After:
app/assets/favicon.svg → /build/_assets/favicon-[HASH].svg

What is Asset Fingerprinting?

asset-fingerprinting

  • It’s a technique where a file’s name includes a hash based on its contents (refer image above can see the hash is happening every time I update my SVG icon WITHOUT hard refresh)

Why It Matters:

1
2
3
4
5
6
7
// Old way (problematic)
favicon.svg?v=1  // Manual cache busting
favicon.svg?v=2  // Have to remember to change this

// New way (automatic)
favicon-[HASH1].svg  // Original content
favicon-[HASH2].svg  // Automatically changes when content changes

How It Works in Different Frameworks:

1
2
3
4
5
Remix: Uses built-in asset imports
React + Webpack: Uses asset modules
Next.js: Uses public directory + Image component
Vue: Uses asset modules in Vite/Webpack
Angular: Uses asset configuration in angular.json

Why This Matters:

  1. Cache Optimization

    • Browsers can cache aggressively (1 year+)

    • Cache automatically invalidates when content changes

    • No manual cache busting needed

  2. Development Experience

    • No manual version management

    • Automatic updates when files change

Common Gotchas:

  1. Don’t mix approaches:
1
2
3
4
5
6
// Don't do this
<link href="/favicon.svg" /> // Direct reference
<link href={faviconUrl} />   // Asset import

// Do this
<link href={faviconUrl} />   // Always use asset imports
  1. Directory Structure:
1
2
3
4
5
app/
  assets/           // Put source assets here
    favicon.svg
public/            // Only for truly static files
  robots.txt       // Files that don't need fingerprinting

This pattern works across modern web development - the implementation details might differ between frameworks, but the concept of asset fingerprinting for cache optimization is universal.


Problem 2 : Compiling CSS

PostCSS and Tailwind CSS configuration is part of this section

postcss vs tailwind vs tailwind config

It basically asked you to created

  • postcss.config.js

  • tailwind.css

  • tailwind.config.ts

I never care about

  • postcss and autoprefixer for god knows who even cares what even do lol but it does thing

Whutdaheck is PostCSS

army knives

Postcss is like swiss army knives

  1. What PostCSS Actually Is:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// PostCSS converts this:
.box {
  &:hover {
    transform: rotate(45deg);
  }
}

// Into this (browser-compatible CSS):
.box:hover {
  -webkit-transform: rotate(45deg);
  -ms-transform: rotate(45deg);
  transform: rotate(45deg);
}
  • Core Functions:

    • Transforms modern CSS into browser-compatible CSS

    • Adds vendor prefixes automatically

    • Enables CSS nesting and modern features

    • Works as a platform for plugins (like Tailwind)

Why We Need It:

1
2
3
4
5
6
7
8
9
Without PostCSS:
- Write vendor prefixes manually
- No CSS nesting
- Limited CSS features

With PostCSS:
- Automatic vendor prefixes
- Modern CSS features work everywhere
- Plugins enhance CSS capabilities

The relationship in Remix:

1
2
3
4
5
6
7
8
// postcss.config.js
module.exports = {
  plugins: [
    require('postcss-nested'), // Enables CSS nesting
    require('tailwindcss'),    // Processes Tailwind directives
    require('autoprefixer')    // Adds vendor prefixes
  ]
}

Simply means it works like a pipeline:

  1. I write Tailwind classes

  2. Then PostCSS processes them

  3. So Browser gets optimized (minify version) CSS

Real-World Example**

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// What I usually write:
<div className="transform hover:rotate-45">
  Skibidi
</div>

// What PostCSS + Tailwind generate:
.transform {
  -webkit-transform: translateX(0);
  -ms-transform: translateX(0);
  transform: translateX(0);
}
.hover\:rotate-45:hover {
  -webkit-transform: rotate(45deg);
  -ms-transform: rotate(45deg);
  transform: rotate(45deg);
}

Autoprefixer is like a translator that makes your CSS work across different browsers. Here’s what it does:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
/* What you write */
.myElement {
  display: flex;
  user-select: none;
}

/* What Autoprefixer generates */
.myElement {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}

Why Autoprefixer Matters

  1. Browser Compatibility

    • Without Autoprefixer → CSS might work on Google Chrome but breaks Safari (ofc its safari)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
/* Without Autoprefixer - Manual prefixing */
.box {
  -webkit-transform: rotate(45deg);
  -moz-transform: rotate(45deg);
  -ms-transform: rotate(45deg);
  transform: rotate(45deg);
}

/* With Autoprefixer - Write once */
.box {
  transform: rotate(45deg); /* Autoprefixer handles the rest */
}

Smart Processing

  • Only adds prefixes when needed

  • Removes outdated prefixes

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
1. Write Source Code
   │
   â–¼
2. Bundler (webpack/vite) finds CSS
   │
   â–¼
3. PostCSS Processing Starts
   │
   ├── Tailwind processes @apply and classes
   │
   ├── Nested CSS gets flattened
   │
   ├── Autoprefixer adds vendor prefixes
   │
   └── Other PostCSS plugins run
   │
   â–¼
4. Final CSS Bundle Created
   │
   â–¼
5. CSS Minification (in production)

Why This Process Matters:

  • Consistent output across different environments

  • Optimized for production

  • Maintainable development experience

Common Gotchas:

  1. Plugin Order Matters
1
2
3
4
5
6
7
8
// postcss.config.js
module.exports = {
  plugins: [
    'tailwindcss',    // Must come before autoprefixer
    'autoprefixer',   // Must come after Tailwind
    // Order affects final output!
  ]
}

Though according to PostCSS creator Andrey Sitnik ,

Order doesn’t matter in PostCSS 8 since plugins run simultaneously'

The current file’s configuration follows these best practices with postcss-import first, followed by nesting support, Tailwind, and finally Autoprefixer.

Built with Hugo
Theme Stack designed by Jimmy