IlmHamroh
JavaScript Full-stack/23-qism. Next.js33/43-dars16 daqiqa
Mundarija (35)

Next.js'da stil va tema: global CSS, CSS Modules, Tailwind va qorong'i rejim

Qisqacha: App Router'da uch asosiy yo'l bor. Global CSS — root layout'da bir marta import qilinadi, tartib import tartibiga bog'liq. CSS Modules (*.module.css) — klass nomlari build'da noyob bo'ladi va faqat shu komponentga tegadi. Tailwind v4 — utility klasslar; create-next-app uni sukut bo'yicha qo'shadi. Runtime CSS-in-JS (styled-components, Emotion) faqat Client Component'larda va maxsus "registry" bilan ishlaydi. Qorong'i rejim — <head> dagi kichik skript + data-tema atributi, hydration xatosisiz.

Bu darsda

  • Global CSS, CSS Modules va Tailwind farqini va qachon qaysi birini tanlashni bilasiz.
  • portfolio ning loyiha kartasini CSS Module'ga o'tkazasiz va Next yasagan haqiqiy CSS'ni o'qiysiz.
  • Kanon nega Tailwind'ni olib tashlaganini o'lchov bilan asoslaysiz (18 MB, 20 paket).
  • CSS-in-JS nega Server Component'larda ishlamasligini tushuntirasiz.
  • Qorong'i rejimni next-themes siz — o'z TemaProvider bilan — qanday qilinganini va "chaqnash"ning oldi qanday olinganini bilasiz.

Oldin bilishingiz kerak: Provider'lar App Router'da, Hydration xatolari, Kaskad qatlamlari, Tailwind CSS, Qorong'i rejim.

1. Nega bu kerak?

React'da stil yozishning o'nlab usullari bor — 20-qismda bir nechtasini ko'rgansiz: oddiy CSS, Tailwind, CSS-in-JS. SPA'da ularning hammasi bir xil joyda ishlaydi — brauzerda.

Next.js'da yangi savol paydo bo'ladi: komponent qayerda chiziladi? Server Component serverda bir marta chiziladi va JS'siz HTML bo'lib ketadi. JS ichida, render paytida CSS yaratadigan kutubxona (styled-components) uchun bu muammo: serverda yaratilgan stillar HTML'ga qanday tushadi? Server Component'da useState, useContext yo'q — kutubxona ishlay oladimi?

portfolio uchun yana bir savol bor: v1 da 04–06-qismlarda qurilgan CSS bor — tokenlar (--rang-*, --masofa-*), qatlamlar (@layer). Uni Tailwind'ga qayta yozish kerakmi yoki shundayligicha ko'chirish yetadimi?

Hayotiy o'xshatish: uyni bo'yash. Global CSS — butun uyga bitta bo'yoq rejasi. CSS Module — har xonaning o'z devor qog'ozi: qo'shni xonaga o'tmaydi. Tailwind — tayyor bo'yoq qutilari to'plami: tez, lekin qutilarni uyga olib kirish kerak (va ular joy egallaydi).

2. Global CSS

Avval umumiy xarita — qaysi stil qayerda ishlaydi:

flowchart TB
  Q{"Stil qayerda yaratiladi?"}
  Q -->|build vaqtida| B["Global CSS, CSS Modules,<br/>Tailwind, vanilla-extract"]
  Q -->|brauzerda, render paytida| R["styled-components, Emotion"]
  B --> SC["Server va Client Component — ikkalasi"]
  R --> CC["faqat Client Component + registry"]

Bu darsning asosiy g'oyasi shu rasmda: stil build vaqtida tayyor bo'lsa — Server Component unga hech narsa demaydi.

2.1 Root layout'da

portfolio da butun sayt CSS'i — app/globals.css, root layout'da bir marta:

tsx
import "./globals.css";

Ichida v1 ning hammasi: tokenlar, reset, qatlamlar. Fayl boshida qatlamlar tartibi e'lon qilingan:

css
@layer tokenlar, reset, asos, layout, komponentlar;

Kaskad qatlamlari darsidan bilasiz: keyingi qatlam oldingisidan kuchli, specificity'dan qat'i nazar. Bu qator butun loyihaning "konstitutsiyasi".

O'lchov: globals.css — 7.2 KB xom, 2.4 KB gzip. Butun saytning CSS'i — shu.

2.2 Import tartibi

Next production'da CSS fayllarni birlashtiradi va bo'laklarga ajratadi (chunk). Hujjat ogohlantiradi: CSS tartibi — kodda import qilinish tartibi. Tugma komponenti o'z CSS'ini import qilsa va sahifa undan keyin o'zinikini — sahifa CSS'i keyin keladi va ustun.

Hujjatning tavsiyalari:

  • global stil va Tailwind — ilovaning ildizida (root layout);
  • CSS import'larini avtomatik saralaydigan linter qoidalarini o'chiring (sort-imports) — tartib o'zgarsa, stil buziladi;
  • dev va production'da tartib farq qilishi mumkin — build'ni tekshiring.

portfolio da bu muammo deyarli yo'q: tartibni @layer hal qiladi, import tartibi emas. Bu — qatlamlarning yashirin foydasi.

3. CSS Modules

3.1 Nima uchun

Global CSS'da .karta klassi bitta. Ertaga blogda boshqa .karta yozsangiz — ikkalasi to'qnashadi. CSS Module — fayl nomi *.module.css bo'lgan CSS: undagi klass nomlari build'da noyob nomga aylanadi va faqat uni import qilgan komponentga tegadi.

3.2 portfolio dagi o'zgarish

Kanon (holat 33) loyiha kartasini global CSS'dan modulga o'tkazdi. LoyihaKartasi.module.css (kanon izohi qisqartirilgan):

css
/* CSS Module: klass nomlari faqat shu komponentga tegishli.
   Tokenlar globals.css dan — o'zgaruvchilar modulga o'tadi. */
@layer komponentlar {
  .karta {
    display: grid;
    gap: var(--masofa-s);
    block-size: 100%;
    padding: var(--masofa-m);
    border: 1px solid var(--rang-chegara);
    border-radius: var(--burchak-m);
  }

  .karta > * {
    margin: 0;
  }

  .karta {
    align-content: start;
  }

  .karta h2 {
    font-size: 1.25rem;
  }

  @media (hover: hover) {
    .karta:has(a:hover) {
      border-color: var(--rang-asosiy);
    }
  }
}

Komponentda:

diff
+import stil from "./LoyihaKartasi.module.css";
 …
-    <article>
+    <article className={stil.karta}>

stil — oddiy obyekt: stil.karta — build'dagi noyob nom. Uch muhim detal:

  1. Tokenlar ishlaydi. CSS o'zgaruvchilari (var(--masofa-s)) — klass emas, ular :root dan meros bo'lib keladi. Modul ularni bemalol ishlatadi.
  2. Qatlam ichida. Modul qoidalari @layer komponentlar da — global qatlam tartibiga bo'ysunadi. Modul "hammadan kuchli" bo'lib qolmaydi.
  3. .karta > * va align-content: start — vizual tekshiruvda topilgan nuqson: kartadagi p/ul o'z margin'larini olib kelib, grid'da bo'sh qatorlar hosil qilardi. Kanon 3 sahifani × mobil/desktop × yorug'/qorong'i (12 ta skrinshot, natijalar/surat/33-*) ko'rib, tuzatdi.

3.3 Next nima yasadi

Build'dan keyingi CSS bo'lagi (holat 33 o'zgarishlari bilan nusxa, next build, biz ishga tushirdik):

text
@layer komponentlar{.k4BiaG_karta{gap:var(--masofa-s);block-size:100%;padding:var(--masofa-m);border:1px solid var(--rang-chegara);border-radius:var(--burchak-m);display:grid}.k4BiaG_karta>*{margin:0}.k4BiaG_karta{align-content:start}.k4BiaG_karta h2{font-size:1.25rem}@media (hover:hover){.k4BiaG_karta:has(a:hover){border-color:var(--rang-asosiy)}}}

.karta → .k4BiaG_karta: fayl nomidan yasalgan prefiks. Boshqa modulda .karta bo'lsa, u boshqa prefiks oladi — to'qnashuv yo'q. Fayl — alohida bo'lak: bizning build'da 352 bayt (gzip 250), kanon o'lchovida 302 B (232 gzip). U faqat kartalar bor sahifada yuklanadi.

Tekshirib ko'ring: CSS Module ichida body { margin: 0 } yozsangiz nima bo'ladi?

Javob

Next uni rad etadi: CSS Module'da faqat lokal selektorlar bo'lishi kerak — kamida bitta klass yoki id bilan. body, h1 kabi "sof" teg selektorlari global ta'sir qiladi, modulning ma'nosi yo'qoladi. Global qoida — globals.css ga. Modul ichida .karta h2 mumkin, chunki u .karta bilan cheklangan.

4. Tailwind — kanon o'lchovi

4.1 Sukut bo'yicha bor edi

create-next-app 16.4 Tailwind v4 ni sukut bo'yicha qo'shadi (Loyiha yaratish). Kanon topilmasi: 16.4 shablonida Tailwind PostCSS orqali emas, Turbopack loader'i (@tailwindcss/turbopack) orqali ulanadi. Next hujjati esa hali PostCSS yo'lini (@tailwindcss/postcss + postcss.config.mjs) ko'rsatadi — ikkalasi ham ishlaydi, shablon yangirog'ini tanlagan.

4.2 Narxi

Kanon o'lchadi (natijalar/tajriba/33-tailwind.txt):

text
tailwindcss+@tailwindcss/turbopack: 18M, 20 package.json
457M	node_modules
Tailwind bilan Tailwind'siz (kanon)
node_modules 463 MB (skelet) 457 MB
Paketlar +20 —
Sayt CSS'i (gzip) o'lchanmadi 2.4–2.7 KB
v1 markup'i utilitalarga qayta yozish o'zgarishsiz

Diqqat: 463 va 457 MB — turli paytdagi o'lchov (skelet va holat 33; orada boshqa paketlar, masalan zod va marked, qo'shilgan). Shuning uchun ularning farqi Tailwind hajmi emas; Tailwind'ning o'zi — birinchi qatordagi 18 MB.

Brauzer uchun Tailwind CSS ham kichik bo'lardi (u faqat ishlatilgan klasslarni chiqaradi). Asosiy narx — qayta yozish: v1 dagi har class="karta" ni class="grid gap-2 p-4 border rounded-lg" ga aylantirish. 20-qismda vazifalar ni Tailwind'ga o'tkazgansiz (Tailwind CSS) — u loyiha uchun bu to'g'ri edi. portfolio da esa tayyor dizayn tizimi bor.

Kanon qarori: CSS qoladi, Tailwind olib tashlandi. Bu "Tailwind yomon" degani emas — bu "mavjud tizimni sababsiz almashtirmang" degani. Next hujjatining o'zi Tailwind'ni ko'p vazifalar uchun tavsiya qiladi; yangi loyihada u ko'pincha eng tez yo'l.

4.3 Tailwind Next'da qanday ulanadi

Agar ishlatsangiz (hujjat bo'yicha):

css
/* app/globals.css */
@import "tailwindcss";

@theme {
  --color-asosiy: oklch(45% 0.1 155);
}

Root layout globals.css ni import qiladi — tamom. Server Component'larda ham ishlaydi: Tailwind — oddiy klass nomlari, runtime JS'i yo'q. Shrift o'zgaruvchisini ulash — next/font darsida.

5. CSS-in-JS va Server Components

5.1 Muammo

Runtime CSS-in-JS (styled-components, Emotion) — stil komponent render bo'lganda JS ichida yaratiladi va <style> tegiga qo'shiladi. Buning uchun kutubxona React Context va effektlardan foydalanadi. Server Component'da esa ular yo'q (Server Components).

Next hujjati shunday deydi: CSS-in-JS kutubxonalari App Router'da faqat Client Component'larda qo'llab-quvvatlanadi. Sozlash uch qadam:

  1. style registry — bitta render davomidagi hamma stillarni yig'adi;
  2. useServerInsertedHTML hook'i — yig'ilgan stillarni HTML'ga, kontentdan oldin qo'yadi;
  3. ilovani registry bilan o'raydigan client komponent.
tsx
// app/registry.tsx — styled-components uchun (hujjat naqshi)
"use client";
import { useServerInsertedHTML } from "next/navigation";
import {
  ServerStyleSheet,
  StyleSheetManager,
} from "styled-components";
// … registry stillarni yig'ib, useServerInsertedHTML bilan beradi

Hujjatdagi ro'yxat: styled-components, styled-jsx, MUI, Chakra, Panda, vanilla-extract va boshqalar qo'llab-quvvatlanadi; Emotion — "qo'llab-quvvatlash ustida ishlanmoqda".

5.2 Nima tanlash kerak

Yo'l Server Component'da Runtime JS Izoh
Global CSS / CSS Modules ha 0 portfolio tanlovi
Tailwind ha 0 build'da yasaladi
Zero-runtime CSS-in-JS (vanilla-extract, Panda, StyleX) ha 0 build'da CSS faylga
Runtime CSS-in-JS (styled-components) yo'q, faqat client bor registry kerak

Zamonaviy yo'nalish aniq: stil build vaqtida yasaladigan yechimlar. Ular Server Component'lar bilan to'qnashmaydi va brauzerga JS qo'shmaydi.

6. Qorong'i rejim

6.1 Uch talab

Qorong'i rejim darsida v1 uchun to'liq yechim qurgansiz: data-tema atributi, tokenlar, prefers-color-scheme. Next'da yana ikkita qiyinchilik qo'shiladi:

  1. Chaqnash (FOUC). Server foydalanuvchi qorong'i rejim tanlaganini bilmaydi (u localStorage da). HTML yorug' keladi, JS yuklangach qorong'iga o'tadi — oq "chaqnash".
  2. Hydration farqi. Server tizim deb chizadi, brauzer qorongi ni o'qiydi — React mismatch ogohlantirishini beradi (Hydration xatolari).
  3. Statiklik. Cookie ishlatsangiz, server mavzuni bilardi — lekin har sahifa dinamik bo'lib qolardi (Request API'lar).

6.2 Kanon yechimi — ikki qism

<head> dagi skript — React'dan oldin, birinchi bo'yashdan oldin:

tsx
const KOD = `try{var t=localStorage.getItem("tema");if(t==="yorug"||t==="qorongi")document.documentElement.dataset.tema=t}catch(e){}`;

export function TemaSkripti() {
  return <script dangerouslySetInnerHTML={{ __html: KOD }} />;
}

Bu skript <html data-tema="qorongi"> ni qo'yadi — CSS darhol to'g'ri ranglarni oladi, chaqnash yo'q. React hydration paytida <html> da kutilmagan atributni ko'radi — shuning uchun root layout'da <html suppressHydrationWarning>. Bu ogohlantirishni faqat <html> ning o'z atributlari uchun o'chiradi, ichkarisiga ta'sir qilmaydi.

TemaProvider — client komponent, Context + useSyncExternalStore (N-12 da qurilgan). Asosiy qatori:

tsx
const tema = useSyncExternalStore(obuna, oqi, () => "tizim" as const);

Uchinchi argument — getServerSnapshot: serverda va hydration paytida doim "tizim", keyin brauzer qiymati. React bu holatda mismatch xatosi bermaydi — hydration'dan keyin qayta chizadi.

Kanon o'lchovi (holat 13 dan beri, har holatda): hydration ogohlantirishi 0, localStorage.tema = "qorongi" bilan ochilganda sahifa darhol qorong'i.

6.3 Natija oynasida: tema modeli

Natija oynasi sandbox ichida — u yerda localStorage ga kirish taqiqlangan (xato beradi). Kanondagi oqi() buni try/catch bilan ushlaydi va doim "tizim" qaytaradi — demak tanlov saqlanmaydi. Shuning uchun quyidagi o'quv modelida localStorage o'rniga oddiy o'zgaruvchi (xotira) ishlatiladi. Qolgani — kanondagidek: Context, use(), useSyncExternalStore va hodisa:

tsx
import {
  createContext,
  use,
  useCallback,
  useSyncExternalStore,
  type ReactNode,
} from "react";

type Tema = "tizim" | "yorug" | "qorongi";
let xotira: Tema = "tizim"; // localStorage o'rnida
const tinglovchilar = new Set<() => void>();

const oqi = () => xotira;
const obuna = (f: () => void) => {
  tinglovchilar.add(f);
  return () => tinglovchilar.delete(f);
};

const TemaKonteksti = createContext<{
  tema: Tema;
  temaniQoy: (t: Tema) => void;
} | null>(null);

function TemaProvider({ children }: { children: ReactNode }) {
  const server = (): Tema => "tizim";
  const tema = useSyncExternalStore(obuna, oqi, server);
  const temaniQoy = useCallback((t: Tema) => {
    xotira = t;
    console.log(`data-tema: ${t}`);
    for (const f of tinglovchilar) f();
  }, []);
  const qiymat = { tema, temaniQoy };
  return <TemaKonteksti value={qiymat}>{children}</TemaKonteksti>;
}

function useTema() {
  const q = use(TemaKonteksti);
  if (!q) throw new Error("useTema faqat <TemaProvider> ichida");
  return q;
}

const VARIANTLAR: { qiymat: Tema; nomi: string }[] = [
  { qiymat: "tizim", nomi: "Tizim" },
  { qiymat: "yorug", nomi: "Yorug'" },
  { qiymat: "qorongi", nomi: "Qorong'i" },
];

function ThemePicker() {
  const { tema, temaniQoy } = useTema();
  return (
    <fieldset>
      <legend>Mavzu</legend>
      {VARIANTLAR.map((v) => (
        <label key={v.qiymat}>
          <input
            type="radio"
            name="tema"
            checked={tema === v.qiymat}
            onChange={() => temaniQoy(v.qiymat)}
          />{" "}
          {v.nomi}
        </label>
      ))}
      <p>Joriy: {tema}</p>
    </fieldset>
  );
}

export default function App() {
  return (
    <TemaProvider>
      <ThemePicker />
    </TemaProvider>
  );
}

Konsolda:

text
data-tema: qorongi

Ekranda:

text
Mavzu
Tizim Yorug' Qorong'i
Joriy: qorongi

«Qorong'i» bosilganda temaniQoy xotirani o'zgartirdi va tinglovchilarga xabar berdi — useSyncExternalStore komponentni qayta chizdi. Kanonda xuddi shu joyda localStorage.setItem, document.documentElement.dataset.tema = t va window.dispatchEvent(new Event("tema:ozgardi")) turadi; boshqa tabdagi o'zgarishni storage hodisasi olib keladi.

6.4 next-themes nega kirmadi

next-themes — Next uchun mashhur tema kutubxonasi. U aynan shu naqshni qiladi: <head> skripti, localStorage, suppressHydrationWarning talabi. Kanon qarori: kirmadi — portfolio da bu naqsh allaqachon bor (0 bog'liqlik, ~40 qator), paket faqat qo'shimcha bog'liqlik bo'lardi. Katta loyihada, ko'p tema va tizim sozlamalari bilan, next-themes vaqtni tejaydi — g'oyasi endi sizga tanish.

7. shadcn/ui Next'da

shadcn/ui — kutubxona emas, komponentlar kodini loyihangizga ko'chiradigan vosita (npx shadcn add button). Komponentlar Radix + Tailwind asosida, components/ui/ papkasiga tushadi va sizniki bo'ladi. 20-qismda vazifalar da ishlatgansiz (shadcn/ui I).

Next'da ikki farq: interaktiv komponentlar (Dialog, DropdownMenu) fayl boshida "use client" bilan keladi; oddiy komponentlar (Card, Badge) esa Server Component'da ham ishlaydi. shadcn Tailwind talab qiladi — portfolio da Tailwind yo'q, shuning uchun bu yerda ishlatilmaydi.

8. Portfolio qadami: CSS Module va commit

8.1 O'zgarishlar (holat 33)

Fayl O'zgarish
loyihalar/_komponentlar/LoyihaKartasi.module.css yangi — .karta (@layer komponentlar)
loyihalar/_komponentlar/LoyihaKartasi.tsx import stil …, className={stil.karta}
app/globals.css .loyihalar > li > article va .loyihalar h2/h3 qoidalari olib tashlandi

8.2 Tekshiruv

bash
npm run lint
npm run tip
npm run build
npm run start

/loyihalar ni telefon va desktop o'lchamida, yorug' va qorong'i rejimda oching: kartalar avvalgidek, ichida bo'sh qatorlar yo'q, gorizontal skroll yo'q. Kanon o'lchovi: JS o'zgarmadi (146.5 KB), CSS 2.4 → 2.7 KB (modul bo'lagi qo'shildi), axe 0, hydration 0.

8.3 Commit

bash
git add -A
git commit

Commit (kanon): Stil: loyiha kartasi CSS Module'ga (komponentlar qatlami).

9. Ko'p uchraydigan xatolar

Belgi Sabab Davosi
Stil dev'da to'g'ri, build'da boshqacha CSS import tartibi Global stil — root'da; @layer bilan tartib
Modulda body {…} — build xatosi CSS Module'da faqat lokal selektor Global qoida — globals.css ga
styled-components Server Component'da ishlamaydi Runtime CSS-in-JS Context talab qiladi "use client" + registry yoki zero-runtime yechim
Qorong'i rejimda oq "chaqnash" Mavzu faqat React'da qo'llanadi <head> dagi inline skript
<html> da hydration ogohlantirishi Skript data-tema qo'shdi <html suppressHydrationWarning>
Hamma sahifa dinamik bo'ldi Mavzu cookie'dan o'qilmoqda localStorage + skript
Klass nomlari to'qnashdi Global CSS'da bir xil nom CSS Module

10. Mashqlar

Mashqlar kurs/mashqlar/23/33-stil-tema/ da. Jonli yechimlarni «Ishga tushir» bilan sinang.

1-mashq (oson): qayerga yozasiz?

  • Saytning rang tokenlari (--rang-asosiy) —
  • Faqat blog kartasining stili —
  • Server Component'da stil, runtime JS'siz — yoki CSS
  • styled-components bilan yozilgan tugma —
Yechim
  • globals.css — tokenlar butun saytga, :root da.
  • CSS Module — BlogKartasi.module.css: nomlar to'qnashmaydi.
  • Tailwind (yoki global CSS / CSS Module) — build vaqtida yasaladi.
  • Client Component — runtime CSS-in-JS faqat client'da, registry bilan.

2-mashq (o'rta): tizim mavzusi

«tema modeli» blokini kengaytiring: «Tizim» tanlanganda Joriy: qatorida haqiqiy rang ham ko'rinsin — Joriy: tizim (yorug'). Tizim mavzusini matchMedia("(prefers-color-scheme: dark)").matches bilan aniqlang (matchMedia). Natija oynasi brauzeri yorug' rejimda deb hisoblang.

Yechim
tsx
import { useSyncExternalStore } from "react";

type Tema = "tizim" | "yorug" | "qorongi";
let xotira: Tema = "qorongi";
const tinglovchilar = new Set<() => void>();
const oqi = () => xotira;
const obuna = (f: () => void) => {
  tinglovchilar.add(f);
  return () => tinglovchilar.delete(f);
};
function temaniQoy(t: Tema) {
  xotira = t;
  for (const f of tinglovchilar) f();
}

function tizimRangi(): string {
  const qorongi = matchMedia("(prefers-color-scheme: dark)").matches;
  return qorongi ? "qorong'i" : "yorug'";
}

function ThemePicker() {
  const tema = useSyncExternalStore(obuna, oqi, () => "tizim");
  const korinish =
    tema === "tizim" ? `tizim (${tizimRangi()})` : tema;
  return (
    <fieldset>
      <legend>Mavzu</legend>
      <button onClick={() => temaniQoy("tizim")}>Tizim</button>{" "}
      <button onClick={() => temaniQoy("yorug")}>Yorug'</button>{" "}
      <button onClick={() => temaniQoy("qorongi")}>Qorong'i</button>
      <p>Joriy: {korinish}</p>
    </fieldset>
  );
}

export default function App() {
  return <ThemePicker />;
}

Ekranda:

text
Mavzu
Tizim Yorug' Qorong'i
Joriy: tizim (yorug')

matchMedia faqat brauzerda bor — shuning uchun bu funksiya client komponentda, render paytida chaqiriladi. Haqiqiy Next'da serverda matchMedia yo'q: u yerda getServerSnapshot "tizim" qaytaradi, aniq rangni esa CSS (@media (prefers-color-scheme: dark)) hal qiladi — JS'siz.

3-mashq (qiyin): CSS Module modeli

CSS Module klass nomini qanday yasashini modellashtiring: modulNomi(fayl, klass) — fayl nomidan qisqa xesh yasab ([...fayl] belgilar kodlari yig'indisini 36 lik sanoq tizimida, oxirgi 6 belgi), xesh_klass qaytarsin. Ikki fayldagi bir xil .karta turli nom olishini ko'rsating. Belgi kodi — codePointAt(0), 36 lik — toString(36) (sanoq tizimlari).

Yechim
js
function xesh(matn) {
  let h = 0;
  for (const b of matn) h = (h * 31 + b.codePointAt(0)) >>> 0;
  return h.toString(36).slice(-6);
}

function modulNomi(fayl, klass) {
  return `${xesh(fayl)}_${klass}`;
}

const a = modulNomi("loyihalar/LoyihaKartasi.module.css", "karta");
const b = modulNomi("blog/PostKartasi.module.css", "karta");
console.log(a);
console.log(b);
console.log(a === b);
const yana = modulNomi("loyihalar/LoyihaKartasi.module.css", "karta");
console.log(a === yana);

Konsolda:

text
a7o2re_karta
32ihy5_karta
false
true

Bir xil karta, turli fayl — turli nom (to'qnashuv yo'q). Bir xil fayl — har build'da bir xil nom (barqaror, kesh buzilmaydi). Next'ning haqiqiy algoritmi boshqa (Lightning CSS), lekin ikki xususiyat aynan shu: noyob va barqaror. Kanondagi .k4BiaG_karta ham shunday yasalgan.

4-mashq: Portfolio qadami

Loyiha kartasini CSS Module'ga o'tkazing («Portfolio qadami» jadvali). Build'dan keyin .next/static/chunks/ da _karta bor CSS faylni toping va hajmini ko'ring. 4 ta holatda (mobil/desktop × yorug'/qorong'i) /loyihalar ni tekshirib, commit qiling.

Yechim

Kutilgan: alohida, bir necha yuz baytli CSS fayl, ichida .xxxxxx_karta (prefiks sizda boshqa). Agar kartalarda ichki bo'sh qatorlar ko'rinsa — .karta > * { margin: 0 } va align-content: start qo'shilmagan. Qorong'i rejimni tez sinash: DevTools → Rendering → "Emulate CSS prefers-color-scheme: dark", yoki mavzu tanlovidan «Qorong'i».

11. Real ishda

  • Yangi Next loyihalarining ko'pi Tailwind + shadcn/ui bilan boshlanadi — create-next-app sukuti ham shunday. Mavjud dizayn tizimi bo'lsa — CSS Modules yoki zero-runtime yechimlar.
  • MUI, Chakra kabi katta UI kutubxonalari App Router uchun alohida qo'llanma beradi (registry, "use client"). Kompaniyalar ba'zan aynan shu sababdan zero-runtime yechimlarga ko'chmoqda.
  • Qorong'i rejim — deyarli har zamonaviy saytda; "chaqnash" — eng ko'p uchraydigan sifat xatosi.
  • Intervyu savoli: "Nega styled-components Server Component'da ishlamaydi?", "CSS Modules qanday izolyatsiya qiladi?", "Qorong'i rejimda chaqnashni qanday yo'qotasiz?"

Xulosa

  • Global CSS root layout'da; tartib import tartibiga bog'liq, @layer uni barqaror qiladi.
  • CSS Module (*.module.css) klasslarni noyob qiladi (.k4BiaG_karta), tokenlar va qatlamlar ishlayveradi.
  • Tailwind create-next-app da sukut (Turbopack loader orqali); kanon uni olib tashladi — 18 MB, 20 paket va qayta yozish narxi.
  • Runtime CSS-in-JS — faqat Client Component'da, registry bilan; build vaqtidagi yechimlar Server Component'lar bilan to'qnashmaydi.
  • Qorong'i rejim: <head> skripti + suppressHydrationWarning + getServerSnapshot — chaqnashsiz, hydration xatosiz, sahifalar statik.

Keyingi dars: i18n Next.js'da: next-intl — portfolio ga ingliz tilini qo'shamiz: [locale] segmenti, proxy, tarjima xabarlari va hreflang.

Manbalar

  • Next.js hujjati (16.4.0, node_modules/next/dist/docs/): "CSS" (Tailwind, CSS Modules, Global CSS, Ordering and Merging), "CSS-in-JS", "Preventing flash before hydration" — nextjs.org/docs/app/getting-started/css (2026-10-21 da o'qildi)
  • Kanon natijalari: natijalar/tajriba/33-tailwind.txt, natijalar/tekshiruv-33.txt, natijalar/surat/33-*; holat 33 va holat 13 (TemaProvider, TemaSkripti)
  • CSS Module chiqishi — biz ishga tushirdik: portfolio holat 32 nusxasi + holat 33 o'zgarishlari, next build, next 16.4.0, 2026-10-21
  • shadcn/ui — ui.shadcn.com/docs/installation/next; next-themes — github.com/pacocoursey/next-themes
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
Next.js'da stil va tema: global CSS, CSS Modules, Tailwind va qorong'i rejim — IlmHamroh