Kenapa ini penting
Kamu sekarang menguasai alatnya. Pertanyaan berikutnya adalah pertanyaan yang biasa muncul di code review atau wawancara kerja: "Bagaimana kamu mengorganisasi stylesheet untuk proyek besar?" dan "Di tahun ini, masih perlu Sass atau cukup CSS native?" Jawaban yang matang tidak berupa "selalu pakai X", melainkan pertimbangan untung-rugi berdasarkan konteks. Modul ini membahas pola arsitektur 7-1, perbandingan jujur Sass dengan fitur CSS native (nesting dan custom properties), lalu studi kasus refactor dari stylesheet monolit menjadi struktur modular.
Konsep inti
Pola 7-1
Pola 7-1 (dipopulerkan oleh panduan Sass Guidelines karya Kitty Giraudel) berarti 7 folder partial dan 1 file utama yang menyatukannya:
| Folder | Isi | Contoh file |
|---|---|---|
abstracts/ |
Hal yang tidak menghasilkan CSS sendiri: variabel, function, mixin, placeholder | _tokens.scss, _mixins.scss, _functions.scss |
vendors/ |
CSS pihak ketiga | _swiper.scss |
base/ |
Reset, tipografi dasar, gaya elemen HTML | _reset.scss, _typography.scss |
layout/ |
Kerangka besar halaman | _header.scss, _footer.scss, _grid.scss |
components/ |
Komponen kecil yang dipakai ulang | _tombol.scss, _kartu.scss, _modal.scss |
pages/ |
Gaya khusus satu halaman | _beranda.scss, _checkout.scss |
themes/ |
Variasi tema | _gelap.scss |
File main.scss hanya berisi @use ke tiap folder, tanpa aturan gaya. Dengan sistem modul modern, setiap folder biasanya punya _index.scss yang meneruskan isinya dengan @forward (untuk abstracts) atau memuat file-filenya dengan @use (untuk folder yang menghasilkan CSS).
Satu hal penting: dengan @use, setiap file yang butuh variabel atau mixin harus memuat abstracts sendiri. Ini berbeda dengan era @import di mana variabel "kebetulan" tersedia karena sudah diimpor lebih dulu. Awalnya terasa repot, tetapi justru membuat ketergantungan setiap file terlihat jelas.
7-1 bukan aturan wajib. Proyek kecil cukup memakai 3 sampai 4 folder (abstracts, base, layout, components). Di aplikasi React atau Vue, gaya komponen sering diletakkan di samping komponennya (misalnya Tombol.module.scss), sementara abstracts dan base tetap terpusat.
Sass vs CSS native: diskusi yang jujur
CSS terus berkembang dan sekarang punya banyak fitur yang dulu hanya ada di Sass:
| Kebutuhan | CSS native | Sass |
|---|---|---|
| Variabel | Custom properties, hidup di runtime, ikut cascade, bisa diubah JS | $variabel, hanya saat compile |
| Nesting | Didukung browser modern sejak 2023 | Sudah lama ada, plus penggabungan string seperti &__judul |
| Kalkulasi | calc(), clamp(), min(), max() |
Matematika saat compile, math.div, unit conversion |
| Modul / pemisahan file | @import CSS (memicu request berantai tanpa bundler) |
@use/@forward, digabung jadi satu file saat compile |
| Loop dan logika | Tidak ada | @each, @for, @if, @function |
| Mixin | Belum tersedia secara luas | @mixin dengan argumen dan @content |
| Manipulasi warna | color-mix(), relative color syntax di browser modern |
sass:color |
| Responsif berbasis wadah | Container query | Tidak relevan (Sass hanya menulis CSS) |
Ada satu perbedaan nesting yang sering menjebak: Sass bisa menggabungkan string selector seperti &__judul menjadi .kartu__judul. CSS native tidak bisa; di CSS native, &__judul tidak menghasilkan selector BEM. Jadi kalau proyekmu sangat bergantung pada pola BEM dengan &__, Sass masih unggul.
Panduan keputusan:
- Pakai CSS native saja kalau proyek kecil sampai menengah, sudah memakai bundler seperti Vite (yang bisa menggabungkan file CSS), butuh theming runtime, dan tidak memerlukan loop atau mixin.
- Pakai Sass kalau kamu punya design system dengan banyak varian yang dihasilkan dari data (map plus loop), butuh mixin breakpoint dan function, bekerja di codebase yang sudah memakai Sass, atau tim bergantung pada nesting BEM.
- Paling umum di proyek modern: keduanya. Sass untuk struktur, loop, dan mixin saat build. Custom properties untuk nilai yang berubah saat runtime seperti tema.
Yang perlu diingat: Sass menambah langkah build dan satu dependency. Itu biaya kecil, tetapi tetap biaya. Keputusan "pakai Sass atau tidak" sebaiknya diambil karena kebutuhan nyata, bukan karena kebiasaan.
Checklist review stylesheet
Saat me-review kode SCSS orang lain, periksa:
- Semua pemuatan memakai
@use/@forward, tidak ada@importSass. - Nesting maksimal tiga level.
- Tidak ada nilai ajaib berulang; warna dan spacing berasal dari token.
- Media query lewat mixin breakpoint, bukan angka acak.
- Tidak ada
@extendyang menyeberang ke dalam media query atau antar komponen. - Loop hanya menghasilkan utility yang benar-benar dipakai.
- CSS hasil compile tidak di-commit sebagai sumber yang diedit manual.
Contoh kode
Studi kasus: kamu mewarisi style.scss satu file 400 baris dari proyek lama. Potongannya:
// SEBELUM: style.scss (gaya lama, campur aduk)
@import "variables";
$blue: #2563eb;
body { margin: 0; font-family: Arial; }
.header {
background: $blue;
.nav {
ul {
li {
a { color: white; &:hover { color: #ddd; } }
}
}
}
}
.card { padding: 20px; border: 1px solid #ddd; }
.card .title { color: $blue; font-size: 20px; }
@media (min-width: 768px) { .card { padding: 30px; } }
@media (min-width: 768px) { .header .nav ul { display: flex; } }
.btn { background: $blue; color: white; padding: 10px 20px; }
.btn-red { @extend .btn; background: red; }
Masalah yang ditemukan saat review: @import usang, nesting lima level (.header .nav ul li a), warna diulang, breakpoint 768px ditulis manual berkali-kali, nama campuran (.card .title bukan BEM), @extend pada class nyata.
Hasil refactor ke struktur 7-1 yang disederhanakan:
src/scss/
├── abstracts/
│ ├── _index.scss # @forward tokens, mixins
│ ├── _tokens.scss
│ └── _mixins.scss
├── base/
│ ├── _index.scss # @use reset, typography
│ ├── _reset.scss
│ └── _typography.scss
├── layout/
│ ├── _index.scss
│ └── _header.scss
├── components/
│ ├── _index.scss
│ ├── _kartu.scss
│ └── _tombol.scss
└── main.scss
abstracts/_tokens.scss:
$warna: (
"utama": #2563eb,
"bahaya": #dc2626,
"garis": #ddd,
"teks-terang": #fff,
) !default;
$breakpoints: ("md": 48rem, "lg": 64rem) !default;
$font-dasar: system-ui, Arial, sans-serif !default;
abstracts/_mixins.scss:
@use "sass:map";
@use "tokens";
@mixin naik($nama) {
@if not map.has-key(tokens.$breakpoints, $nama) {
@error "Breakpoint '#{$nama}' tidak dikenal.";
}
@media (min-width: map.get(tokens.$breakpoints, $nama)) {
@content;
}
}
abstracts/_index.scss:
@forward "tokens";
@forward "mixins";
base/_typography.scss (dimuat oleh base/_index.scss bersama _reset.scss):
@use "../abstracts" as a;
body {
margin: 0;
font-family: a.$font-dasar;
}
layout/_header.scss:
@use "sass:map";
@use "../abstracts" as a;
.header {
background: map.get(a.$warna, "utama");
&__daftar { // dulu: .header .nav ul
margin: 0;
padding: 0;
list-style: none;
@include a.naik(md) { display: flex; gap: 1rem; }
}
&__link { // dulu: .header .nav ul li a
color: map.get(a.$warna, "teks-terang");
&:hover { opacity: 0.8; }
}
}
components/_tombol.scss:
@use "sass:map";
@use "../abstracts" as a;
// Mixin menggantikan @extend .btn
@mixin -dasar-tombol($latar) {
padding: 0.625rem 1.25rem;
color: white;
background: $latar;
border: none;
}
.tombol {
@include -dasar-tombol(map.get(a.$warna, "utama"));
&--bahaya { background: map.get(a.$warna, "bahaya"); } // dulu: .btn-red
}
components/_kartu.scss:
@use "sass:map";
@use "../abstracts" as a;
.kartu {
padding: 1.25rem;
border: 1px solid map.get(a.$warna, "garis");
@include a.naik(md) { padding: 1.875rem; }
&__judul {
font-size: 1.25rem;
color: map.get(a.$warna, "utama");
}
}
components/_index.scss dan main.scss:
// components/_index.scss
@use "tombol";
@use "kartu";
// main.scss: hanya merangkai, tanpa aturan gaya
@use "base";
@use "layout";
@use "components";
npx sass src/scss/main.scss dist/css/main.css --style=compressed --no-source-map
# → Satu file CSS, tanpa peringatan deprecation.
# Selector terdalam kini satu class (contoh .header__link) dibanding sebelumnya .header .nav ul li a.
Langkah refactor yang aman di dunia nyata:
- Compile versi lama, simpan hasilnya sebagai
before.cssdan ambil screenshot halaman-halaman penting. - Pindahkan token dulu (warna, breakpoint), tanpa mengubah selector.
- Pecah file per komponen, ganti
@importdengan@use. Sass menyediakan alat migrasi resmi:npx sass-migrator module --migrate-deps src/scss/main.scss. - Baru kemudian ratakan nesting dan ganti nama ke BEM, sambil memperbarui HTML.
- Bandingkan screenshot sebelum dan sesudah. Perbedaan visual berarti ada yang terlewat.
Kesalahan umum
- Mengira variabel dari
main.scssotomatis tersedia di partial lain. Dengan@use, tidak. Cara benar: setiap partial memuatabstractsyang dibutuhkannya sendiri. - Menyalin pola
&__juduldari Sass ke CSS native nesting. Di CSS native itu tidak menghasilkan.kartu__judul. Cara benar: tulis selector BEM lengkap di CSS native, atau tetap pakai Sass. - Menerapkan 7-1 penuh untuk landing page satu halaman. Folder kosong hanya menambah kebingungan. Cara benar: mulai dari 3 sampai 4 folder, tambah sesuai kebutuhan.
- Refactor besar sekaligus tanpa pembanding. Cara benar: lakukan bertahap, simpan hasil compile dan screenshot sebelum mulai.
- Menghapus custom properties karena "sudah pakai Sass". Kamu kehilangan theming runtime. Cara benar: Sass menghasilkan custom properties dari map, keduanya bekerja sama.
Latihan
- Mudah, Gambarkan struktur folder 7-1 untuk toko online kecil, lalu tentukan di folder mana file berikut diletakkan:
_navbar.scss,_tombol.scss,_halaman-produk.scss,_tokens.scss,_reset.scss. - Sedang, Tulis ulang kode SCSS berikut menjadi CSS native dengan nesting dan custom properties, tanpa Sass:
$utama: #2563eb; .kartu { padding: 1rem; .judul { color: $utama; } &:hover { box-shadow: 0 2px 8px #0002; } }. - Menantang, Buat file
_tema.scssyang memakai@eachuntuk mengubah map Sass$warnamenjadi custom properties di:root(misalnya--warna-utama), sehingga warna bisa ditimpa saat runtime oleh[data-theme="dark"].
Lihat solusi
# Soal 1
scss/
├── abstracts/ _tokens.scss, _mixins.scss
├── vendors/ (kosong, isi kalau pakai library)
├── base/ _reset.scss, _typography.scss
├── layout/ _navbar.scss, _footer.scss
├── components/ _tombol.scss, _kartu-produk.scss
├── pages/ _halaman-produk.scss
├── themes/ _gelap.scss
└── main.scss
/* Soal 2: CSS native, tanpa compile */
:root { --utama: #2563eb; }
.kartu {
padding: 1rem;
.judul { color: var(--utama); } /* → .kartu .judul */
&:hover { box-shadow: 0 2px 8px #0002; } /* → .kartu:hover */
}
// Soal 3: _tema.scss
$warna: (
"utama": #2563eb,
"latar": #ffffff,
"teks": #0f172a,
);
:root {
@each $nama, $nilai in $warna {
--warna-#{$nama}: #{$nilai};
}
}
[data-theme="dark"] {
--warna-latar: #0f172a;
--warna-teks: #f1f5f9;
}
body {
color: var(--warna-teks);
background: var(--warna-latar);
}
// → :root { --warna-utama: #2563eb; --warna-latar: #ffffff; --warna-teks: #0f172a; }
// Sass menyusun daftar dari data, browser yang mengganti nilainya saat tema berubah.
Ringkasan
- Pola 7-1: abstracts, vendors, base, layout, components, pages, themes, plus satu
main.scssyang hanya merangkai. - Dengan
@use, setiap partial memuat sendiri modul yang dibutuhkannya; ketergantungan jadi eksplisit. - CSS native kini punya nesting dan custom properties, tetapi belum punya loop, mixin, dan penggabungan string
&__seperti Sass. - Pilihan paling umum: Sass untuk struktur dan generasi saat build, custom properties untuk nilai runtime.
- Refactor bertahap: simpan pembanding, pindahkan token, pecah file, migrasi ke
@use(bisa dengansass-migrator), ratakan nesting, bandingkan hasil visual.