Tarayıcılar Nasıl Çalışıyor 2/2

Hana Kamer
Hana Kamer
Published in
6 min readApr 30, 2016

--

Bu serinin ilk bölümünde HTML parsing ve Render Tree’nin nasıl oluştuğunu, render tree ve dom arasındakı farkları anlatmıştım. Bu seride önce, ilk seride yer alması gereken CSS parsing’den bahsedeceğim ve daha sonra kaldığım yerden devam edeceğim.

CSS parsing

CSS, HTML’den farklı olarak ‘context-free’ bir dildir. Webkit, Flex ve Bison parser yaratıcılarını kullanarak CSS gramer dosyalarından otomatik olarak parser oluşturur. Bison, aşağıdan yukarı yani shift reduce parser oluşturur.

Shift reduce parser: Bu parsing işleminde parse tree (parçalama ağacı) dallardan başlayıp köke doğru ilerlerleyerek oluşturulmaya başlanır.

Firefox el ile yazılmış, yukarıdan aşağı çalışma mantığına sahip bir parser kullanır. Sonuç olarak parçalama işlemi sonucunda bir stylesheet objesi oluşturur.

Scriptlerin ve Stylesheetlerin işlenme sırası

Web, senkron bir şekilde çalışır. Parser <script> tagına vardığında, parse etme işlemi script çalıştırılana kadar duraksar. Scriptin uzak bir kaynaktan gelecek olması durumunda yine script temin edilene kadar parse işlemi duraksar. Ancak ‘defer’ özelliği ile bu duraksama engellenebilir. Bu durumda dosyanın tamamı parse edilmeden script çalıştırılmaz.

Diğer taraftan stylesheetler, DOM ağacını değiştirmediklerinden parse işlemi sırasında hataya sebep olur. Bu tür hataları önlemek adına Firefox ortada parse edilecek stylesheetler varken scriptleri engeller. Webkit ise sadece stillere ulaşmaya çalışan scriptleri engeller.

Stillerin Hesaplanması

Render Tree’nin oluşturulması için her render objesinin görsel özellikleri hesaplanmalı. Bu da stil özellikleri hesaplanarak yapılır.

Stylesheet parse edildikten sonra kurallar, seçicilere bağlı olarak birkaç farklı hash map’e eklenir. Mapler id, class adı, tag adı ve bunların hiç birine giremeyen genel bir map olmak üzere kategorilenir. Örneğin, seçici id ise kural, id map’e eklenir.

Stylesheet (stil şablonları): kurallar bütünü.
Kural: selector ve declaration block.
Declaration block: deklarasyon grubu.
Declaration: özellik ve değer

Seçici, dosyadaki elemanlarla eşleşir. Buna ‘match’ denir.

Kurallar, eşleşen elemanlar için geçerli.

Style rules için birden fazla kaynak olabilir:

  • CSS kuralları (external olarak veya style elemanları içinde)
  • Inline style özellikleri
  • HTML görsel özellikleri

Son iki durumda eleman ve stil eşleştiği için match edilmesi kolay olur.

Sayfadaki stillerin farklı kaynakları vardır. Bunları şöyle sıralayabiliriz:

  • Sayfa kaynağı
  • Kullanıcı
  • Tarayıcıların varsayılan stylesheetleri

# Örnek olarak Chrome ve Firefox’un varsayılan stylesheetlerine buradan ulaşabilirsiniz: Chrome default style sheet, Firefox default style sheet. Bütün tarayıcıların varsayılan stylesheetlerinin listesine şuradan bakabilirsiniz.

Bu noktada reset-css’den bahsetmek istiyorum. Tarayıcıların varsayılan cssleri developerın oluşturduğu sayfanın farklı tarayıcılarda farklı görünmesine sebep olur. Bunun üstesinden gelmek için reset-css kullanılabilir. Reset-css, HTML’in bütün “type selector”lerini içerir ve bunların değerlerinin tarayıcılar arasında sabitlenmesini sağlar. (type selector: HTML düğümlerini seçebilen seçicilerdir.)

normalize.css (bütün seçicilerin özellikleri belli bir değer alır)

reset.css (bütün seçicilerin özellikleri sıfırlanır)

Firefox’da rule tree (kural ağacı) ve stil context yapısı var.

Stil context, hesaplanan son değerleri içeren yapı; rule tree ise eşleşen kurallardan oluşturulan ağaçtır.

Belli bir eleman için stil contexti hesaplanırken o elemanın kural ağacındaki yeri belirlenir, yoksa da ağaca eklenir. Daha sonra bu yapıdaki kurallar uygulanmaya başlanır. Ağacın en altındaki düğümden ağacın üst kısımlarına doğru ilerlenir. En altta yer alan düğümlerin seçicilikleri en yüksektir. Eşleştirmek istenilen path tam olarak karşılığı bulunana kadar ağaç yukarı doğru taranır.

Bir özellik ve elemanın son değerleri hesaplanırken geçilen aşamaları şöyle sıralayabiliriz:

  1. Hiç bir kuralın eşleşmemesi durumunda özelliğin inherited veya reset özelliği olup olmamasına bakılır. Inherited ise üst elemanın (parent) değerini alır; reset ise varsayılan (default) değerini alır.
    inherited:
    . ‘font-size’, ‘color’ vs
    reset:
    . ‘border’, ‘background’ vs.
  2. Bir kuralın eşleşmesi durumunda, o kuralın değeri kullanılır.
  3. Birden fazla kuralın eşleşmesi durumunda ‘cascade’ neyin kullanılacağına karar verir.

cascade: Kuralların uygulanma sırası.

Cascade sırasında kurallar belli önceliklere göre sınıflandırılır.

Bu öncelik sıralaması şöyle:

  • kaynak
  • seçicinin seçiciliği
  • sıra

Kaynak

Kaynağa bağlı uygulanma önceliği:

  1. tarayıcı
  2. kullanıcı
  3. yazar normal
  4. yazar important
  5. kullanıcı important

Bu sıralamaya göre tarayıcı deklarasyonları en önemsiz olanıdır.

Seçicilik

Kaynak önceliği seviyesinin aynı olması durumunda seçiciliğe ve sonrasında seçildikleri sıraya bakılır. HTML görsel özellikleri, denk geldikleri css deklarayonlarına çevrilirler ve yazarın düşük öncelikli kuralları kadar önceliğe sahip olurlar.

Bir seçicinin spesifikliği CSS2 dokumantasyonuna göre şöyle hesaplanır:

Seçicilerin a, b, c, d değerlerinin birleştirilmesi ile elde edilen spesifiklik değeri dikkate alınır.

a = deklarasyon, seçici olan bir kural değil de, <style></style> tagları arasında tanımlanmış ise 1; değil ise 0 değerini alır.

b = seçicide yer alan id özelliklerinin sayısı

c = seçicide yer alan diğer özelliklerin ve pseudo-classların sayısı

d = seçicide yer alan eleman adlarının ve pseudo elemanların sayısı

Spesifiklik hesabını daha iyi anlamak için şuradaki görselleştirme çalışmasına göz atabilirsiniz.

Sıra

Kaynak ve seçiciliğin son değerin hesaplanmasında yetersiz kaldığı durumda değerlerin atanma sırasına bakılır. Bu durumda en son verilen değer dikkate alınır.

Webkit’de kural ağacı yoktur. Eşeleşen kurallar 4 defa taranır. Önce non-important ve seçiciliği yüksek özellikler uygulanır, daha sonra important ve seçiciliği yüksek olan özellikler , daha sonra normal öncelikte ve non-importan özellikler ve son olarak normal öncelikte ve important olan özellikler uygulanır. Birden fazla defa tanımlanmış özellik olduğunda, cascade sırasına göre, son uygulanan kalıcı olur.

LAYOUT

Renderer (render tree’ yi oluşturan elemanlar, Firefox ‘frame’ olarak da tanımlar) oluştulup ağaca eklendiği zaman bir pozisyon ve büyüklüğe sahip olmaz. Bu değerlerin hesaplandığı aşamaya layout ve reflow denir.

HTML akışa dayalı bir layout modeli kullanır. Yani tek seferde geometrinin hesaplanması mümkün olur. Akışın sonraki aşamalarında yer alan elemanlar genelde, akışın öncesinde yer alan elemanları etkilemez. Bu yüzden akış; yukarıdan aşağıya veya sağdan sola ilerleyebilir. Bazen istisnalardan bahsedilebilir. Örneğin tablolar birden fazla geçişe gerek duyabilir.

Koordinat sistemi root frame’i (kökteki renderer) referans alır. Üst ve sol koordinatlar kullanılır.

Layout yenilenen bir işleyişe sahip. Rendererin kökünden (root) başlar (HTML dosyasında <html> elemanı). Düzenleme hiyerarşik olarak yenilenerek devam eder ve ilerler.

Kökteki renderer’in (root frame) pozisyonu 0,0'dır ve boyutları tarayıcı penceresinin görünen kısmı kadardır (viewport).

resim kaynağı için link

Bütün rendererlerin layout veya reflow metodu vardır. Her renderer düzenlenmeyi gerektiren çocuklarının layout metodunu çağırır.

DIRTY BIT SISTEMI

Küçük bir değişiklikte düzenlenmenin baştan sona tetiklenmemesi için tarayıcılar ‘dirty bit’ olarak bilinen bir sistem kullanır. Değişikliğe uğrayan veya sonradan eklenen renderer kendini ve çocuklarını ‘dirty’ olarak işaretler. Bu, düzenleme gerektirdiği anlamına gelir.

İki çeşit etiket var: ‘dirty’ ve ‘children are dirty’ (rendererin kendisi değişim gerektirmese de çocuklarından en az bir tanesi düzen gerektirdiği anlamına gelir.)

GLOBAL ve KADEMELİ DÜZENLEME

Düzenleme render treenin tamamını baştan düzenlemek üzere ‘global’ olarak tetiklenebilir. Bu,

  1. Bütün rendererları etkileyen global bir stil değişimi sonucu (font size)
  2. ekranın boyutunun değişimi sonucu tetiklenebilir.

Kademeli düzenleme durumunda sadece ‘dirty’ olarak işaretlenmiş olan rendererlar düzenlenir. Kademeli düzenleme asenkron olarak yapılırken global düzenleme senkron olarak yapılır.

Düzenleme süreci genellikle şöyle ilerler:

  1. Parent (ata) renderer kendi genişliğini belirler
  2. Children (oğul) rendererlere doğru ilerler
    1. child renderer i yerleştirir (x ve y koordinatlarını belirler)
    2. Gerekiyorsa childın düzenlenmesini tetikler (global veya dirty durumunda)
  3. Parent, çocukların margin, padding ve yüksekliklerini toplayarak kendi yüksekliğini belirler.
  4. Dirty bit’i ‘false’ olarak değiştirir

Layout sürecinin sonunda ortaya net olarak pozisyonu ve boyutu olan ‘box model’ çıkar. Bütün göreceli değerlerin kesin büyüklükleri hesaplanır.

box model: Bu model görsel özellikleri tanımlanmış dikdörtgenleri tanımlar. Her kutunun içerik alanı (yazı, resim vs) ve opsiyonel olan padding, border ve margin alanları vardır.

Her elemanın display özelliği vardır ve bu özellik ne çeşit bir kutunun oluşturulacağını belirler. Varsayılan display özelliği ‘inline’dır fakat bu tarayıcının varsayılan style sheetine göre değişiklik gösterebilir.

Renderer’in genişliği kendisini içeren container blockunun genişliği, rendererin style özelliği, marginler ve borderlar kullanılarak hesaplanır.

PAINTING

Render tree adım adım geçilerek renderer’in “paint()” methodu çağrılarak içeriğin ekranda gösterilmesi sağlanır. Painting kullanıcı arayüz altyapı komponentini kullanır (UI infrastructure).

GLOBAL ve KADEMELİ PAINTING

Düzenleme gibi renklendirme işlemi de global veya kademeli bir şekilde yapılabilir.

Renklendirme sırası:

  1. Background color
  2. Backgorund image
  3. Border
  4. Children
  5. Outline
  • Firefox’da görüntüleme listesi vardır. Doğru renklendirme sırasına göre dizilmiş rendererları içerir.

--

--