suliskh

Mengenal Si Dia (CSS)

Ada hal penting yang mendasar tetapi sering aku salah pahami dari dia. Aku akan bercerita tentang apa hal penting itu dan bagaimana aku mengenal dan memahami dia dengan lebih baik lagi.

26 September 2021 ■ 15 menit baca

Dia itu selalu memikirkan tentang penampilan dan sering bertindak tidak seperti apa yang aku mau. Aku sering kesal padanya ( ` ω ´ ). Tetapi akhirnya aku sadar, ternyata dia hanya bertindak apa adanya. Dia hanya menjadi dirinya sendiri, dan akulah yang salah dalam memahaminya. Oh iya, aku tidak sedang membicarakan pasanganku, ya, Teman-teman. Tetapi aku sedang membicarakan CSS. Ada hal penting yang mendasar tetapi aku salah pahami dari CSS. Aku akan bercerita tentang apa hal penting itu dan bagaimana aku mengenal dan memahaminya dengan lebih baik lagi.

Aku akan mengawali cerita ini dengan cuitan kuis dari Mas Max Stoiber yang kurang lebih seperti ini isinya:

/* css */
.red {
  color: red;
}

.blue {
  color: blue;
}
<!-- html -->
<p class="red blue"> A </p>
<p class="blue red"/> B </p>

Menurut teman-teman, apakah warna dari kedua elemen p tersebut di atas?

  • A merah, B biru.
  • A biru, B merah.
  • Keduanya biru.
  • Keduanya merah.

Waktu itu aku memilih jawaban ke dua (A biru, B merah), dan itu bukanlah jawaban yang tepat. Aku juga mencoba melempar kuis ini ke teman-temanku melalui sebuah cuitan di Twitter. Dan ternyata aku tidak sendirian, banyak juga teman-teman yang masih salah paham dengan CSS. Jawaban yang benar adalah jawaban ketiga (keduanya biru). Kenapa bisa seperti itu? Markilas, mari kita ulas! ヽ(・∀・)ノ

IstilahLink

Untuk menyamakan pemahaman, mari kita bahas beberapa istilah dalam CSS terlebih dahulu. Diketahui potongan kode berikut.

p,
.text {
  color: aqua;
  font-size: 16px;
}

Dari potongan kode tersebut di atas, ada beberapa hal yang bisa kita perhatikan.

Selector
Selector digunakan untuk mendefinisikan elemen-elemen yang akan kita atur tampilannya. Pada potongan kode di atas, p dan .text adalah selector-nya.
Declaration
Sebuah CSS declaration terdiri dari pasangan nama properti dan nilainya. color dan font-size adalah nama propertinya, sedangan aqua dan 16px adalah nilai dari masing-masing properti tersebut secara berturut-turut.
Rule
Potongan kode CSS di atas kita sebut sebagai CSS rule yang terdiri dari selector dan beberapa CSS declaration.
Style Sheet
Kumpulan dari beberapa CSS rule yang ditempatkan pada suatu file tertentu dan digunakan untuk mengatur tampilan dokumen HTML kita sebut sebagai style sheet.

Sifat Cascade dari CSSLink

Sebuah elemen bisa ditarget oleh beberapa CSS rule sekaligus yang mungkin memiliki beberapa declaration yang sama. Setiap CSS rule tersebut bisa berasal dari berbagai macam sumber dan cara penulisan. Sifat cascade dari CSS mengharuskan rendering engine pada peramban untuk menggabungkan semua CSS rule tersebut dan menentukan nilai akhir dari suatu properti yang akan diterapkan ke suatu elemen. Cascade merupakan sifat utama dari CSS yang bahkan diamplifikasi dan disematkan sebagai bagian dari namanya, Cascading Style Sheet. Untuk bisa menulis CSS dengan lebih baik, kita harus bisa memahami sifat cascade tersebut.

Terdapat tiga kriteria yang digunakan dalam cascading : order and origin, specificity, dan penggunaan !important.

Order and OriginLink

Kriteria pertama yang digunakan dalam proses cascading adalah urutan penulisannya. Secara sederhana, jika terdapat lebih dari satu declaration untuk suatu elemen, maka declaration yang ditulis paling akhir akan lebih diprioritaskan. Mari kita lihat potongan kode berikut.

p {
  font-weight: 400;
}
p {
  font-size: 3rem;
  font-weight: 600;
}
p {
  font-size: 2rem;
}

Maka untuk properti font-size pada elemen p, nilai 2rem akan diterapkan. Sedangkan properti font-weight akan bernilai 600.

Selain itu, kita juga harus ingat bahwa style sheet yang ikut dalam proses cascading tidak hanya bersumber dari yang kita tulis sendiri. Setidaknya terdapat tiga jenis origin dari suatu style sheet : user-agent origin, user origin, dan author origin.

User-Agent Origin
Ini adalah style sheet yang berasal dari peramban dan ditargetkan ke elemen-elemen dasar HTML. Setiap peramban bisa memiliki user-agent style sheet yang berbeda dengan peramban lainnya. Biasanya kita memanfaatkan pustaka seperti reset.css atau normalize.css untuk menyeragamkannya. Style sheet yang berasal dari peramban ini memiliki prioritas paling kecil.
User Origin
Setiap pengguna bisa melakukan kustomisasi pada peramban yang mereka gunakan, misalnya pengaturan ukuran huruf (font-size), jenis huruf (font-family), dan juga warna huruf (font-color). Style sheet ini punya prioritas lebih tinggi dari user-agent origin.
Author Origin
Ini adalah style sheet yang punya prioritas paling tinggi di antara kedua jenis origin lainnya. Style sheet ini berasal dari kode CSS yang kita, para pengembang web, tulis. Pustaka pihak ketiga yang kita gunakan juga termasuk dalam author origin.

Terdapat 2 jenis origin tambahan, yaitu animation origin dan transition origin. Keduanya berasal dari rule "virtual" yang merepresentasikan efek pada saat properti transition dan animation berjalan. Transition origin punya prioritas lebih tinggi dari animation origin. Dan keduanya punya prioritas lebih tinggi dari ketiga jenis origin di atas.

SpecificityLink

Dari aturan order dan origin yang sudah kita bahas sebelumnya, kita tahu bahwa apabila suatu elemen memiliki beberapa declaration untuk sebuah properti yang sama, maka declaration yang paling akhir ditulis yang akan diterapkan. Namun, ternyata kita juga bisa menemukan kondisi dimana declaration yang ditulis lebih awal justru yang diterapkan. Kondisi ini terjadi karena declaration tersebut memiliki specificity lebih tinggi dari yang lainnya. Specificity adalah bobot yang diberikan kepada setiap CSS declaration. Semakin tinggi bobotnya, maka akan semakin diprioritaskan.

Penentuan specificity adalah dengan melakukan kalkulasi bobot pada selector dari rule di mana CSS declaration itu dituliskan. Untuk mempermudah, kita bisa memberi bobot tertentu sesuai dengan jenis selector-nya.

  • ID selector berbobot 100, misalnya #login-form dan #main.

  • Class selector berbobot 10, misalnya .blue, .red, dan .header.

  • Attribute selector berbobot 10. misalnya [type=checkbox] dan [href*="suliskh.com"].

  • Pseudo-selector berbobot 10, misalnya :hover, :first-child, dan :nth-child(n).

  • Type selector berbobot 1, misalnya h1, p, dan form.

  • Pseudo-element berbobot 1, misalnya ::after, ::before, dan ::first-letter.

  • Universal selector (*) berbobot 0.

  • Combinator berbobot 0, terdiri dari +, >, dan ~.

  • Negation (:not()) berbobot 0, tetapi selector di dalamnya tetap memiliki bobot.

Apabila suatu CSS declaration dituliskan di dalam rule yang memiliki lebih dari satu selector, maka bobotnya kita akumulasikan. Agar lebih jelas, kita coba lihat contohnya, Yuk!

/* `*` = 0. total = 0 */
* {
  ...;
}

/* `form` = 1, `#login` = 100, total = 101 */
form #login {
  ...;
}

/* `ul`= 1, `>` = 0, `li`= 1, `:first-child` = 10, total = 12 */
ul > li:first-child {
  ...;
}

/* `a` = 1, `[href="#"]` = 10, `.underline` = 10, total = 21 */
a[href="#"].underline {
  ...;
}

Beberapa situs seperti specifishity.com dan cssspecificity.com memiliki contoh dan ilustrasi yang cukup lengkap mengenai specificity.

(・ω・)☞

Dalam cascade, CSS declaration yang ditulis secara inline melalui atribut style (misalnya <p style="color: blue;" />) akan dianggap sebagai author origin dan memiliki specificity lebih tinggi dibandingkan dengan selector apapun. Kita bisa memberi bobot specificity 1.000 pada CSS declaration yang ditulis secara inline.

Penggunaan !importantLink

Terkadang aku menggunakan !important yang disematkan di akhir sebuah CSS declaration untuk memastikan nilainya berhasil diterapkan. Aku biasa menggunakan teknik ini untuk meng-override styling dari pustaka pihak ketiga.

Penggunaan !important juga akan mempengaruhi aturan order and origin yang sudah kita bahas sebelumnya. Berikut adalah pengaruh urutan dari prioritas terkecil hingga terbesar.

  1. User-Agent origin.
  2. User origin.
  3. Author origin.
  4. Animation origin.
  5. Author origin dengan !important.
  6. User origin dengan !important.
  7. User-Agent dengan !important.
  8. Transition origin.

Kita harus menggunaan !important dengan penuh kesadaran akan implikasinya terhadap cascade, karena bisa jadi justru akan mempersulit proses debugging dan overriding di masa depan. Sebisa mungkin manfaatkan sifat cascade untuk mengatur prioritas kode CSS yang kita tulis.

(・ω・)☞

Kita bisa memberi bobot specificity 10.000 pada CSS declaration yang menggunakan !important.

InheritanceLink

Selain cascade, satu sifat penting lainnya adalah inheritance. Jika suatu properti CSS pada elemen tidak mempunyai declaration yang secara eksplisit ditargetkan padanya, maka properti tersebut akan memiliki nilai yang disesuaikan dengan initial value-nya, misalnya properti line-height yang memiliki initial value normal. Namun, ada beberapa properti yang secara bawaan akan memiliki nilai yang disesuaikan dengan induknya. Properti itu disebut sebagai inherited property. Jika teman-teman melihat bagian "Formal Definition" pada dokumentasi CSS di MDN, maka teman-teman akan menemukan keterangan "inherited" yang bernilai "yes" atau "no". Misalnya saja pada dokumentasi properti color, diketahui kolom "inherited" bernilai "yes". Artinya, properti color merupakan sebuah inherited property.

Selanjutnya, mari kita lihat potongan kode berikut.

<header>
  <h1>Halo-halo Bandung</h1>
  <p>Lagu ciptaan Ismail Marzuki</p>
</header>
header {
  border: 1px solid black;
  color: green;
}

Jika kita coba jalankan potongan kode tersebut di peramban, maka teks "Halo-halo Bandung" di dalam h1 dan teks "Lagu ciptaan Ismail Marzuki" di dalam p akan berwarna green, walaupun kita tidak menambahkan CSS declaration untuk properti color pada kedua elemen tersebut. Hal ini terjadi karena properti color merupakan inherited property yang memiliki nilai bawaan dari induknya, dalam hal ini bernilai green yang didapat dari header. Namun, apa yang terjadi apabila header tidak punya declaration untuk properti color? Hal yang akan terjadi adalah rendering engine pada peramban akan mencari declaration untuk properti color ke induk di atasnya lagi hingga menemukannya.

Kita juga mengetahui bahwa properti border hanya akan diterapkan pada header, tetapi tidak pada elemen-elemen di dalamnya karena properti border bukan merupakan inherited property. Namun, kita juga bisa memaksa suatu properti agar menyesuaikan induknya dengan menggunakan inherit sebagai nilainya.

p {
  border: inherit;
}

Oke, Teman-teman. Kita sudah membahas sifat-sifat dasar dari CSS, yaitu cascade dan inheritance. Kriteria yang mempengaruhi cascade adalah order and origin, specificity, dan penggunaan !important. Nah, selanjutnya mari kita bahas mengapa kasus di awal tadi berakhir dengan keduanya berwarna biru.

  • Kedua declaration sama-sama berasal dari author origin. Namun, color: blue memiliki prioritas lebih tinggi daripada .color:red karena ditulis paling akhir.
  • Kedua declaration memiliki bobot specificity yang sama yaitu 10, karena masing-masing memiliki sebuah class selector (.red dan .blue). Jadi specificity-nya tidak mempengaruhi prioritas.
  • Kedua declaration tidak menggunakan !important.
  • Sifat inheritance tidak berlaku karena nilai dari properti color ditulis secara eksplisit.
  • Urutan penulisan pada atribut class di elemen HTML tidak mempengaruhi prioritas.

Jadi, properti color dari kedua elemen p pada kasus itu akan bernilai blue.


Begitulah ceritaku dalam mengenal CSS. Ternyata ada sifat-sifat penting dan mendasar yang belum aku pahami sebelumnya. Namun, sifat-sifat tersebut dibuat bukan untuk menyulitkan kita sebagai penggunanya. Menurutku, itu adalah hal-hal esensial yang diperlukan agar kita bisa menulis CSS dengan terstuktur dan lebih baik lagi.

Oh iya, teman-teman juga bisa membaca spesifikasi lengkap CSS Cascade and Inheritance dari W3C di sini. Dan sebagai bahan bacaan lanjutan, ada beberapa pola desain CSS yang menurutku sangat mempertimbangkan sifat cascade dan inheritance seperti: BEM, ITCSS, SMACSS, dan CUBE.

Demikian, terima kasih telah mampir ke tulisanku ini. Semoga bermanfaat, Ya!

(^0^)ノ