Tạo chủ đề động mà không cần CSS-in-JS

Tôi từng là một fan lớn của styled-components. Tôi yêu sự linh hoạt của nó. Rồi tôi vấp phải một rào cản.

Một dự án cần phải giảm trọng lượng runtime. Tôi quyết định thử dùng CSS Modules và CSS thuần. Kết quả khiến tôi ngạc nhiên. Tôi đã xóa styled-components, Emotion và goober khỏi các dự án của mình. Tôi không hề mất đi bất cứ thứ gì thực sự cần thiết.

Chiến thắng lớn nhất không chỉ là hiệu năng. Đó là việc loại bỏ sự phụ thuộc vào styling. Trong một dự án, runtime của CSS-in-JS chiếm tới 30% client bundle.

CSS thuần đã phát triển rất nhiều. Bạn không còn cần các thư viện JS nặng nề cho những tác vụ này:

• Nesting: Sử dụng native CSS nesting. • Color shifts: Sử dụng color-mix(). • Specificity control: Sử dụng @layer. • Responsive components: Sử dụng container queries.

Dưới đây là cách bạn xây dựng một chủ đề (theme) chỉ với một tệp duy nhất và các thuộc tính tùy chỉnh (custom properties).

  1. Định nghĩa các token trong một tệp CSS.
:root {
  --color-bg: #ffffff;
  --color-text: #1a1a1a;
  --color-accent: #3c7dc4;
}

[data-theme="dark"] {
  --color-bg: #14161a;
  --color-text: #f5f5f0;
  --color-accent: #6aa6e8;
}
  1. Sử dụng các biến đó trong các component của bạn.
.button {
  background: var(--color-accent);
  color: var(--color-bg);
}
  1. Chuyển đổi chủ đề bằng cách thay đổi một thuộc tính duy nhất.
function setTheme(theme) {
  document.documentElement.dataset.theme = theme;
  localStorage.setItem("theme", theme);
}

Các component không cần ThemeProvider. Chúng cũng không cần phải re-render. Trình duyệt sẽ xử lý việc cập nhật thông qua cơ chế cascade. Điều này giúp giữ hầu hết ứng dụng của bạn ở dạng Server Components.

Để tránh hiện tượng "nháy" (flash) sai chủ đề khi tải trang, hãy sử dụng một đoạn script inline nhỏ trong thẻ head của HTML:

Hãy ngừng sử dụng JS để tạo style tại runtime. Hãy sử dụng các biến CSS thuần cho các token của bạn. Điều này giúp giảm lượng code và tăng tốc độ tải trang.

Nguồn: https://dev.to/kirill_c_7b35589230/dynamic-theming-without-css-in-js-d7e