Tarayıcılar nasıl çalışır?

Modern web tarayıcılarının perde arkası

Paul Irish
Tali Garsiel
Tali Garsiel

Önsöz

WebKit ve Gecko'nun şirket içi operasyonları hakkındaki bu kapsamlı yardım, İsrailli geliştirici Tali Garsiel'in yaptığı birçok araştırmanın sonucudur. Birkaç yıl boyunca tarayıcı dahili bileşenleriyle ilgili yayınlanan tüm verileri inceledi ve web tarayıcısı kaynak kodunu okumak için çok zaman harcadı. Şöyle yazdı:

Web geliştiricisi olarak tarayıcı operasyonlarının ayrıntılarını öğrenmek, daha iyi kararlar almanıza ve geliştirmeyle ilgili en iyi uygulamaların arkasındaki gerekçeleri öğrenmenize yardımcı olur. Bu belge oldukça uzun olsa da ayrıntılara biraz zaman ayırmanızı öneririz. Pişman olmazsınız.

Paul Ireland, Chrome Developer Relations

Giriş

En çok kullanılan yazılım web tarayıcılarıdır. Bu rehberde, bunların perde arkasında nasıl çalıştığını açıklayacağım. Adres çubuğuna google.com yazdığınızda, tarayıcı ekranında Google sayfasını görene kadar ne olduğunu göreceğiz.

Bahsedeceğimiz tarayıcılar

Bugün masaüstünde kullanılan başlıca beş tarayıcı vardır: Chrome, Internet Explorer, Firefox, Safari ve Opera. Mobil cihazlarda ana tarayıcılar Android Tarayıcı, iPhone, Opera Mini ve Opera Mobile, UC Tarayıcısı, Nokia S40/S60 tarayıcıları ve Chrome'dur. Opera tarayıcıları dışında tümü WebKit'e dayanır. Açık kaynak tarayıcılar olan Firefox ve Chrome ve Safari'den (kısmen açık kaynak) örnekler vereceğim. StatCounter istatistiklerine göre (Haziran 2013 itibarıyla) Chrome, Firefox ve Safari, dünya genelinde masaüstü tarayıcı kullanımının yaklaşık% 71'ini oluşturmaktadır. Mobil cihazlarda, Android Tarayıcı, iPhone ve Chrome kullanımın yaklaşık% 54'ünü oluşturur.

Tarayıcının ana işlevi

Bir tarayıcının ana işlevi, seçtiğiniz web kaynağını sunucudan isteyerek ve tarayıcı penceresinde görüntüleyerek sunmaktır. Kaynak genellikle bir HTML dokümanıdır, ancak PDF, resim veya başka türde bir içerik de olabilir. Kaynağın konumu, kullanıcı tarafından URI (Tekdüzen Kaynak Tanımlayıcı) kullanılarak belirlenir.

Tarayıcının HTML dosyalarını yorumlama ve görüntüleme biçimi, HTML ve CSS spesifikasyonlarında belirtilir. Bu özellikler, web için standart organizasyon olan W3C (World Wide Web Consortium) kuruluşu tarafından korunmaktadır. Tarayıcılar yıllar boyunca spesifikasyonların yalnızca bir kısmını uyarak kendi uzantılarını geliştirdi. Bu durum, web yazarları için ciddi uyumluluk sorunlarına yol açmıştı. Günümüzde tarayıcıların çoğu bu özelliklere aşağı yukarı uyuyor.

Tarayıcı kullanıcı arayüzleri birbirleriyle birçok ortaktır. Yaygın kullanıcı arayüzü öğeleri arasında şunlar yer alır:

  1. URI eklemek için adres çubuğu
  2. Geri ve ileri düğmeleri
  3. Yer işareti ekleme seçenekleri
  4. Geçerli dokümanların yüklenmesini yenilemek veya durdurmak için yenile ve durdur düğmeleri
  5. Sizi ana sayfanıza yönlendiren ana sayfa düğmesi

İşin ilginç yanı, tarayıcının kullanıcı arayüzü herhangi bir resmi tanımlamada belirtilmemiştir, yalnızca yıllara dayanan deneyime dayanan iyi uygulamalardan ve tarayıcıların birbirini taklit etmesinden gelir. HTML5 spesifikasyonu, bir tarayıcının sahip olması gereken kullanıcı arayüzü öğelerini tanımlamaz, ancak bazı ortak öğeleri listeler. Adres çubuğu, durum çubuğu ve araç çubuğu bunlardan bazılarıdır. Elbette, Firefox'un indirme yöneticisi gibi belirli bir tarayıcıya özgü özellikler vardır.

Üst düzey altyapı

Tarayıcının ana bileşenleri şunlardır:

  1. Kullanıcı arayüzü: Adres çubuğu, geri-ileri düğmesi, yer işareti menüsü vb. öğeleri içerir. İstenen sayfayı gördüğünüz pencere hariç, tarayıcının her bölümü görüntülenir.
  2. Tarayıcı motoru: Kullanıcı arayüzü ile oluşturma motoru arasındaki işlemleri kontrol eder.
  3. Oluşturma motoru: İstenen içeriği görüntülemekten sorumludur. Örneğin, istenen içerik HTML ise oluşturma motoru HTML ve CSS'yi ayrıştırır ve ayrıştırılan içeriği ekranda görüntüler.
  4. Ağ iletişimi: HTTP istekleri gibi ağ çağrıları için, platformdan bağımsız bir arayüz kullanarak farklı platformlar için farklı uygulamalar kullanılır.
  5. Kullanıcı arayüzü arka ucu: Karma kutu ve pencereler gibi temel widget'ları çizmek için kullanılır. Bu arka uç, platforma özgü olmayan genel bir arayüzü gösterir. Alt kısımda ise işletim sistemi kullanıcı arayüzü yöntemleri kullanılır.
  6. JavaScript yorumlayıcısı. JavaScript kodunu ayrıştırmak ve yürütmek için kullanılır.
  7. Veri depolama. Bu bir kalıcılık katmanıdır. Tarayıcının çerezler gibi her tür veriyi yerel olarak kaydetmesi gerekebilir. Tarayıcılar, localStorage, IndexedDB, WebSQL ve FileSystem gibi depolama mekanizmalarını da destekler.
Tarayıcı bileşenleri
Şekil 1: Tarayıcı bileşenleri

Chrome gibi tarayıcıların, oluşturma motorunun her sekme için bir tane olmak üzere birden fazla örneğini çalıştırdığını unutmamak önemlidir. Her sekme ayrı bir işlemde çalışır.

Oluşturma motorları

Oluşturma motorunun sorumluluğu gayet iyi... Oluşturma, istenen içeriğin tarayıcı ekranında görüntülenmesidir.

Oluşturma motoru, varsayılan olarak HTML ve XML dokümanlarını ve resimlerini görüntüleyebilir. Eklentiler veya uzantılar aracılığıyla diğer veri türlerini görüntüleyebilir (örneğin, bir PDF görüntüleyici eklentisi kullanarak PDF dokümanları görüntülemek). Ancak bu bölümde asıl kullanım örneğine odaklanacağız: CSS kullanılarak biçimlendirilen HTML ve resimlerin görüntülenmesi.

Farklı tarayıcılar farklı oluşturma motorları kullanır: Internet Explorer Trident, Firefox Gecko, Safari, WebKit kullanır. Chrome ve Opera (15 sürümünden itibaren), WebKit'in bir çatal olan Blink'i kullanır.

WebKit, Linux platformu için bir motor olarak başlatılmış, Mac ve Windows'u desteklemek üzere Apple tarafından değiştirilmiş açık kaynaklı bir oluşturma motorudur.

Ana akış

Oluşturma motoru, istenen belgenin içeriğini ağ katmanından almaya başlar. Bu işlem genellikle 8 KB'lık parçalar halinde yapılır.

Bundan sonra, oluşturma motorunun temel akışı şu şekildedir:

Oluşturma motoru temel akışı
Şekil 2: Oluşturma motoru temel akışı

Oluşturma motoru, HTML dokümanını ayrıştırmaya başlar ve öğeleri "içerik ağacı" adı verilen bir ağaçtaki DOM düğümlerine dönüştürür. Motor, hem harici CSS dosyalarında hem de stil öğelerinde stil verilerini ayrıştırır. HTML'deki görsel talimatlarla birlikte stil bilgileri başka bir ağaç olan oluşturma ağacı oluşturmak için kullanılacaktır.

Oluşturma ağacı, renk ve boyut gibi görsel özelliklere sahip dikdörtgenler içerir. Dikdörtgenler ekranda görüntülenmek için doğru sıradadır.

Oluşturma ağacının oluşturulmasından sonra ağaç bir "düzen" sürecinden geçer. Bu, her bir düğüme, ekranda görünmesi gereken yerde tam koordinatların verilmesi anlamına gelir. Bir sonraki aşama boyama aşamasıdır. Oluşturma ağacından bir geçiş yapılır ve her düğüm, kullanıcı arayüzü arka uç katmanı kullanılarak boyanır.

Bunun kademeli bir süreç olduğunun anlaşılması önemlidir. Oluşturma motoru, daha iyi kullanıcı deneyimi için içerikleri en kısa sürede ekranda görüntülemeye çalışır. Oluşturma ağacını oluşturmaya ve düzenlemeye başlamadan önce tüm HTML'nin ayrıştırılması beklemez. Süreç, ağdan gelmeye devam eden içeriklerin geri kalanıyla devam ederken içeriğin bazı bölümleri ayrıştırılır ve görüntülenir.

Ana akış örnekleri

WebKit ana akışı.
Şekil 3: WebKit ana akışı
Mozilla'nın Gecko oluşturma motoru ana akışı.
Şekil 4: Mozilla Gecko oluşturma motoru ana akışı

Şekil 3 ve 4'ten, WebKit ve Gecko biraz farklı terminoloji kullanmasına rağmen akışın temelde aynı olduğunu görebilirsiniz.

Geko, görsel olarak biçimlendirilmiş öğeler ağacını "Çerçeve ağacı" olarak adlandırır. Her öğe bir çerçevedir. WebKit, "Oluşturma Ağacı" terimini kullanır ve "Oluşturma Nesneleri"nden oluşur. WebKit, öğelerin yerleştirilmesi için "düzen" terimini kullanırken, Gecko buna "Yeniden düzenleme" adını verir. "Ek", oluşturma ağacını oluşturmak için DOM düğümlerini ve görsel bilgileri bağlamak için kullanılan WebKit terimidir. Anlamsal olmayan küçük bir fark da Gecko'nun HTML ve DOM ağacı arasında fazladan bir katman olmasıdır. "İçerik havuzu" olarak adlandırılan bu sistem, DOM öğelerini oluşturmak için kullanılan bir fabrikadır. Akışın her bir bölümünden bahsedeceğiz:

Ayrıştırma - genel

Ayrıştırma, oluşturma motorunda çok önemli bir işlem olduğundan, biraz daha ayrıntılı bir şekilde ele alacağız. Ayrıştırma hakkında küçük bir girişle başlayalım.

Bir dokümanı ayrıştırmak, onu kodun kullanabileceği bir yapıya çevirmek anlamına gelir. Ayrıştırmanın sonucu genellikle belgenin yapısını temsil eden bir düğüm ağacıdır. Buna, ayrıştırma ağacı veya söz dizimi ağacı denir.

Örneğin, 2 + 3 - 1 ifadesinin ayrıştırılması şu ağacı döndürebilir:

Matematiksel ifade ağaç düğümü.
Şekil 5: matematiksel ifade ağaç düğümü

Dilbilgisi

Ayrıştırma, dokümanın uyması gereken söz dizimi kurallarına, yani yazıldığı dil veya biçim temel alınarak yapılır. Ayrıştırabileceğiniz her biçim, kelime ve söz dizimi kurallarından oluşan belirleyici dil bilgisine sahip olmalıdır. Buna bağımsız dil bilgisi denir. İnsan dilleri böyle değildir ve bu nedenle geleneksel ayrıştırma teknikleriyle ayrıştırılamaz.

Ayrıştırıcı - Lexer kombinasyonu

Ayrıştırma iki alt sürece ayrılabilir: sözlük analizi ve söz dizimi analizi.

Sözcüksel analiz, girdileri belirteçlere ayırma işlemidir. Jetonlar dil sözlüğü, yani geçerli yapı taşları koleksiyonudur. İnsan dilinde söz konusu dil için sözlükte görünen tüm kelimeleri içerir.

Söz dizimi analizi, dil söz dizimi kurallarının uygulanmasıdır.

Ayrıştırıcılar genellikle çalışmayı iki bileşene ayırır: Girişi geçerli jetonlara bölmekten sorumlu olan lexer (bazen belirteç olarak da adlandırılır) ve belge yapısını dil söz dizimi kurallarına göre analiz ederek ayrıştırma ağacını oluşturmaktan sorumlu ayrıştırıcı.

Bilgi sahibi, boşluklar ve satır sonları gibi alakasız karakterleri nasıl kaldıracağını bilir.

Kaynak belgeden ağaçları ayrıştırma
Şekil 6: kaynak belgeden ağaçları ayrıştırmaya

Ayrıştırma işlemi yinelemeli bir işlemdir. Ayrıştırıcı genellikle lexer'dan yeni bir jeton ister ve jetonu söz dizimi kurallarından biriyle eşleştirmeye çalışır. Bir kural eşleştirilirse ayrıştırma ağacına jetona karşılık gelen bir düğüm eklenir ve ayrıştırıcı başka bir jeton ister.

Hiçbir kural eşleşmezse ayrıştırıcı, jetonu dahili olarak depolar ve dahili olarak depolanan jetonlarla eşleşen bir kural bulunana kadar jeton istemeye devam eder. Hiçbir kural bulunmazsa ayrıştırıcı bir istisna oluşturur. Bu, dokümanın geçerli olmadığı ve söz dizimi hataları içerdiği anlamına gelir.

Çeviri

Çoğu durumda, ayrıştırma ağacı nihai ürün değildir. Ayrıştırma genellikle çeviride kullanılır: Giriş dokümanını başka bir biçime dönüştürme. Buna örnek olarak derleme verilebilir. Kaynak kodu makine kodu olarak derleyen derleyici, önce onu ayrıştırma ağacına ayrıştırır, ardından ağacı makine kodu belgesine dönüştürür.

Derleme akışı
Şekil 7: derleme akışı

Ayrıştırma örneği

Şekil 5'te, matematiksel bir ifadeden bir ayrıştırma ağacı oluşturduk. Basit bir matematik dili tanımlamayı deneyelim ve ayrıştırma işlemine bakalım.

Söz dizimi:

  1. Dil söz dizimi yapı taşları ifadeler, terimler ve işlemlerdir.
  2. Dilimiz herhangi bir sayıda ifade içerebilir.
  3. Bir ifade, bir "terim" ve ardından bir "işlem" ve onu izleyen başka bir terim olarak tanımlanır.
  4. Bir işlem, bir artı jetonu veya eksi jetonudur
  5. Terim, bir tam sayı jetonu veya bir ifadedir

2 + 3 - 1 girişini analiz edelim.

Bir kuralla eşleşen ilk alt dize 2: 5. kurala göre bir terimdir. İkinci eşleşme 2 + 3'dir: Bu, üçüncü kuralla eşleşir: bir terimin ardından bir işlem ve başka bir terim gelir. Bir sonraki eşleşme yalnızca girişin sonunda isabet alır. 2 + 3 ifadesinin bir terim olduğunu zaten bildiğimiz için 2 + 3 - 1 bir ifadedir. Dolayısıyla bir terimin ardından başka bir terimin geldiği bir işlem bulunur. 2 + + hiçbir kuralla eşleşmediğinden geçersiz bir giriştir.

Sözlük ve söz dizimi için resmi tanımlar

Kelimeler genellikle normal ifadelerle ifade edilir.

Örneğin, dilimiz şu şekilde tanımlanır:

INTEGER: 0|[1-9][0-9]*
PLUS: +
MINUS: -

Gördüğünüz gibi, tam sayılar normal ifadeyle tanımlanır.

Söz dizimi genellikle BNF adlı bir biçimde tanımlanır. Dilimiz şu şekilde tanımlanacaktır:

expression :=  term  operation  term
operation :=  PLUS | MINUS
term := INTEGER | expression

Bir dilin, bağlamdan bağımsız gramer olması halinde normal ayrıştırıcılar tarafından ayrıştırılabileceğini söyledik. Bağlamsız dilbilgisinin sezgisel tanımı, tamamen BNF'de ifade edilebilen bir dilbilgisidir. Resmi tanım için Bağlamsız dil bilgisi ile ilgili Wikipedia makalesine bakın

Ayrıştırıcı türleri

İki tür ayrıştırıcı vardır: yukarıdan aşağı ayrıştırıcılar ve aşağıdan yukarıya ayrıştırıcılar. Bunun anlaşılır bir açıklaması, yukarıdan aşağıya ayrıştırıcıların söz diziminin üst düzey yapısını inceleyerek bir kural eşleşmesi bulmaya çalışmasıdır. Aşağıdan yukarıya ayrıştırıcılar, girişle başlar ve alt düzey kurallardan üst düzey kurallar karşılanana kadar bunu kademeli olarak söz dizimi kurallarına dönüştürür.

İki ayrıştırıcı türünün örneğimizi nasıl ayrıştıracağına bakalım.

Yukarıdan aşağı ayrıştırıcı, üst düzey kuraldan başlar: 2 + 3 ifadesini bir ifade olarak tanımlar. Ardından, 2 + 3 - 1 bir ifade olarak tanımlanır (ifadeyi tanımlama süreci gelişir, diğer kurallarla eşleşir ancak başlangıç noktası en üst düzey kural olur).

Aşağıdan yukarıya ayrıştırıcı, bir kural eşleşene kadar girişi tarar. Ardından, eşleşen girişi kuralla değiştirir. Bu, girişin sonuna kadar devam eder. Kısmen eşleşen ifade, ayrıştırıcının yığınına yerleştirilir.

Yığınla Giriş
2 + 3 - 1
term + 3 - 1
dönemsel işlem 3 - 1
ifade - 1
ifade işlemi 1
ifade -

Bu tür bir yukarıdan yukarı ayrıştırıcı, kayma düşürücü ayrıştırıcı olarak adlandırılır, çünkü giriş sağa doğru kaydırılır (bir işaretçinin ilk olarak girişin başlangıcında olduğunu ve sağa doğru ilerlediğini düşünün) ve kademeli olarak söz dizimi kurallarına indirgenir.

Ayrıştırıcıları otomatik olarak oluşturma

Ayrıştırıcı oluşturabilen araçlar vardır. Onlara dilinizin dil bilgisini, yani kelime dağarcığını ve söz dizimi kurallarını beslersiniz ve çalışan bir ayrıştırıcı oluştururlar. Ayrıştırıcı oluşturmak, ayrıştırmayı derinlemesine anlamayı gerektirir ve optimize edilmiş bir ayrıştırıcıyı elle oluşturmak kolay değildir. Bu nedenle, ayrıştırıcı oluşturucular çok kullanışlı olabilir.

WebKit, iyi bilinen iki ayrıştırıcı oluşturucu kullanır: lexer oluşturmak için Flex ve ayrıştırıcı oluşturmak için Bison (Bu araçlarla Lex ve Yacc adlarıyla karşılaşabilirsiniz). Flex girişi, jetonların normal ifade tanımlarını içeren bir dosyadır. Bison'ın girişi, BNF biçimindeki dil söz dizimi kurallarıdır.

HTML Ayrıştırıcı

HTML ayrıştırıcısının işi, HTML işaretlemesini bir ayrıştırma ağacında ayrıştırmaktır.

HTML dil bilgisi

HTML sözlüğü ve söz dizimi, W3C kuruluşu tarafından oluşturulan spesifikasyonlarda tanımlanmıştır.

Ayrıştırmaya giriş bölümünde gördüğümüz gibi, dil bilgisi söz dizimi BNF gibi biçimler kullanılarak resmi bir şekilde tanımlanabilir.

Maalesef geleneksel ayrıştırıcı konularının tümü HTML için geçerli değil (bunları eğlenmek için açmadım - CSS ve JavaScript'i ayrıştırmada kullanılacak). HTML, ayrıştırıcıların ihtiyaç duyduğu bağlam serbest dilbilgisiyle kolayca tanımlanamaz.

HTML - DTD (Doküman Türü Tanımı) tanımlamak için resmî bir biçim vardır ancak bu, bağlamdan bağımsız bir dil bilgisi değildir.

Bu ilk bakışta tuhaf görünebilir; HTML, XML'e oldukça yakındır. Kullanabileceğiniz çok sayıda XML ayrıştırıcı vardır. HTML'nin bir XML varyasyonu (XHTML) vardır, dolayısıyla büyük fark nedir?

Aralarındaki fark, HTML yaklaşımının daha "bağışlayıcı" olmasıdır: Belirli etiketleri (daha sonra dolaylı bir şekilde eklenir) veya bazen başlangıç ya da bitiş etiketlerini ve benzeri öğeleri hariç tutmanıza olanak tanır. Bu, XML'in sert ve zorlu söz diziminin aksine "yumuşak" bir söz dizimidir.

Bu küçük gibi görünen ayrıntı büyük bir fark yaratıyor. Bir yandan HTML'nin bu kadar sevilmesinin ana nedeni budur: Hatalarınızı affeder ve web yazarının hayatını kolaylaştırır. Diğer yandan, resmi dil bilgisi yazmayı zorlaştırır. Özetlemek gerekirse, dil bilgisi bağlamdan bağımsız olmadığından HTML geleneksel ayrıştırıcılar tarafından kolayca ayrıştırılamaz. HTML, XML ayrıştırıcılar tarafından ayrıştırılamaz.

HTML DTD

HTML tanımı DTD biçimindedir. Bu biçim, SGML ailesinin dillerini tanımlamak için kullanılır. Bu biçimde, izin verilen tüm öğeler, bunların özellikleri ve hiyerarşileri için tanımlar bulunur. Daha önce gördüğümüz gibi, HTML DTD bağlam serbest dil bilgisi oluşturmaz.

DTD'nin birkaç varyasyonu vardır. Yüksek düzey modu yalnızca spesifikasyonlara uygundur ancak diğer modlar, geçmişte tarayıcılar tarafından kullanılan işaretlemeyi destekler. Amaç, eski içeriklerle geriye dönük uyumluluktır. Geçerli katı DTD şu adrestedir: www.w3.org/TR/html4/strict.dtd

DOM

Çıktı ağacı ("ayrıştırma ağacı") DOM öğesi ve özellik düğümlerini içeren bir ağaçtır. DOM, Belge Nesne Modeli'nin kısaltmasıdır. Bu, HTML belgesinin nesne sunumudur ve HTML öğelerinin JavaScript'te olduğu gibi dış dünyaya arayüzü sunar.

Ağacın kökü "Document" nesnesidir.

DOM, işaretleme ile neredeyse bire bir ilişkiye sahiptir. Örneğin:

<html>
  <body>
    <p>
      Hello World
    </p>
    <div> <img src="example.png"/></div>
  </body>
</html>

Bu işaretleme aşağıdaki DOM ağacına çevrilir:

Örnek işaretlemenin DOM ağacı
Şekil 8: Örnek işaretlemenin DOM ağacı

DOM, HTML gibi W3C kuruluşu tarafından belirtilir. www.w3.org/DOM/DOMTR sayfasına göz atın. Dokümanlarda değişiklik yapmaya yönelik genel bir spesifikasyondur. Belirli bir modül, HTML'ye özgü öğeleri açıklar. HTML tanımlarını şu adreste bulabilirsiniz: www.w3.org/TR/2003/REC-DOM-Level-2-HTML-20030109/idl-definitions.html.

Ağacın DOM düğümleri içerdiğini söylediğimde, bunun ağaç DOM arayüzlerinden birini uygulayan öğelerden oluştuğu anlamına gelir. Tarayıcılar, tarayıcı tarafından dahili olarak kullanılan başka özelliklere sahip somut uygulamalar kullanır.

Ayrıştırma algoritması

Önceki bölümlerde gördüğümüz gibi, HTML normal yukarıdan aşağı veya aşağıdan yukarı ayrıştırıcılar kullanılarak ayrıştırılamaz.

Bunun nedenleri şunlardır:

  1. Dilin hoşgörülü yapısı.
  2. Tarayıcıların, iyi bilinen geçersiz HTML durumlarını desteklemek için geleneksel hata toleransına sahip olması.
  3. Ayrıştırma işlemi tekrar giriliyor. Diğer dillerde kaynak, ayrıştırma sırasında değişmez ancak HTML'de dinamik kod (document.write() çağrılarını içeren komut dosyası öğeleri gibi) fazladan jetonlar ekleyebilir. Böylece, ayrıştırma işlemi aslında girişi değiştirir.

Normal ayrıştırma teknikleri kullanılamıyor, tarayıcılar HTML ayrıştırmak için özel ayrıştırıcılar oluşturur.

Ayrıştırma algoritması, HTML5 spesifikasyonunda ayrıntılı olarak açıklanmıştır. Algoritma iki aşamadan oluşur: jetonlara ayırma ve ağaç yapısı.

Tokenizasyon, girişlerin belirteçlere ayrıldığı sözlük analizidir. HTML jetonları arasında başlangıç etiketleri, bitiş etiketleri, özellik adları ve özellik değerleri bulunur.

Jeton oluşturucu, jetonu tanır, ağaç oluşturucuya verir ve bir sonraki jetonu tanımak için sonraki karakteri kullanır ve girişin sonuna kadar bu şekilde devam eder.

HTML ayrıştırma akışı (HTML5 spesifikasyonundan alınmıştır)
Şekil 9: HTML ayrıştırma akışı (HTML5 spesifikasyonundan alınmıştır)

Jetonlara ayırma algoritması

Algoritmanın çıkışı bir HTML jetonudur. Algoritma, durum makinesi olarak ifade edilir. Her durum, giriş akışının bir veya daha fazla karakterini kullanır ve bu karakterlere göre sonraki durumu günceller. Karar, mevcut belirtkeleme durumundan ve ağaç yapısından etkilenir. Bu, kullanılan aynı karakterin geçerli duruma bağlı olarak bir sonraki doğru durum için farklı sonuçlar vereceği anlamına gelir. Algoritma tam olarak açıklanamayacak kadar karmaşık. Bu nedenle ilkeyi anlamamıza yardımcı olacak basit bir örnek inceleyelim.

Temel örnek: Aşağıdaki HTML'nin jetonlara uygun hale getirilmesi:

<html>
  <body>
    Hello world
  </body>
</html>

Başlangıç durumu "Veri durumu"dur. < karakteriyle karşılaşıldığında durum "Etiket açık durumu" olarak değiştirilir. a-z karakterinin kullanılması, "Başlangıç etiketi jetonu" oluşturulmasına neden olur. Durum, "Etiket adı durumu" olarak değiştirilir. > karakteri tüketilene kadar bu durumda kalırız. Her karakter yeni jeton adına eklenir. Örneğimizde, oluşturulan jeton bir html jetonudur.

> etiketine ulaşıldığında geçerli jeton yayınlanır ve durum tekrar "Veri durumu" olarak değişir. <body> etiketi, aynı adımlarla ele alınacaktır. Şu ana kadar html ve body etiketleri yayınlandı. Şu anda "Veri durumu"na geri dönmüş bulunuyoruz. Hello world öğesinin H karakterinin kullanılması, karakter jetonu oluşturulmasına ve yayınlanmasına neden olur. Bu durum, </body> öğesinin < değerine ulaşılana kadar devam eder. Hello world öğesinin her karakteri için bir karakter jetonu yayınlarız.

Şu anda "Etiket açık durumu"na geri döndük. Bir sonraki (/) girişin kullanılması, end tag token oluşturulmasına ve "Etiket adı durumu"na taşınmasına neden olur. > olana kadar yine bu durumda kalırız.Ardından yeni etiket jetonu yayınlanır ve "Veri durumu"na geri döneriz. </html> girişi, önceki destek kaydında olduğu gibi ele alınır.

Örnek girişi şifrelendirme
Şekil 10: Örnek girişi şifrelendirme

Ağaç yapım algoritması

Ayrıştırıcı oluşturulduğunda Belge nesnesi oluşturulur. Ağaç oluşturma aşamasında, kökünde Dokümanın yer aldığı DOM ağacı değiştirilir ve ağaç ağa öğeler eklenir. Belirteç oluşturucu tarafından yayınlanan her düğüm, ağaç kurucusu tarafından işlenir. Spesifikasyon, her jeton için hangi DOM öğesinin kendisiyle alakalı olduğunu tanımlar ve bu jeton için oluşturulur. Öğe, DOM ağacına ve açık öğe yığınına eklenir. Bu yığın, iç içe yerleştirme uyuşmazlıklarını ve kapatılmamış etiketleri düzeltmek için kullanılır. Algoritma aynı zamanda bir durum makinesi olarak da tanımlanır. Bu durumlara "ekleme modları" denir.

Örnek girişteki ağaç yapım sürecini inceleyelim:

<html>
  <body>
    Hello world
  </body>
</html>

Ağaç oluşturma aşamasında giriş, tokenizasyon aşamasındaki bir dizi jetondur. İlk mod, "başlangıç modu"dur. "html" jetonunun alınması "html öncesi" moduna geçilmesine ve jetonun bu modda yeniden işlenmesine neden olur. Bu, kök Belge nesnesine eklenecek olan HTMLhtmlElement öğesinin oluşturulmasına neden olur.

Durum, "before" olarak değiştirilir. Daha sonra "body" jetonu alınır. "head" jetonumuz olmasa da HTMLHeadElement dolaylı olarak oluşturulur ve ağaca eklenir.

Şimdi "in head" moduna ve ardından "after" moduna geçiyoruz. Gövde jetonu yeniden işlenir, bir HTMLBodyElement oluşturulup eklenir ve mod "in body" (gövdede) bölümüne aktarılır.

"Merhaba dünya" dizesinin karakter jetonları artık alınmıştır. Birincisi, bir "Metin" düğümünün oluşturulup eklenmesini sağlar ve diğer karakterler bu düğüme eklenir.

Gövde bitiş jetonunun alınması, "body sonrası" moduna aktarım yapılmasına neden olur. Şimdi, bizi "gövdeden sonra" moduna taşıyacak HTML bitiş etiketini alacağız. Dosya sonu jetonunun alınması ayrıştırma işlemini sonlandırır.

Örnek HTML&#39;nin ağaç yapısı.
Şekil 11: Örnek html'nin ağaç yapısı

Ayrıştırma işlemi tamamlandığında gerçekleştirilen işlemler

Bu aşamada tarayıcı dokümanı etkileşimli olarak işaretler ve "ertelenmiş" moddaki, yani doküman ayrıştırıldıktan sonra yürütülmesi gereken komut dosyalarını ayrıştırmaya başlar. Ardından, doküman durumu "complete" olarak ayarlanır ve bir "load" etkinliği tetiklenir.

Jetonlara ayırma ve ağaç oluşturma algoritmalarının tamamını HTML5 spesifikasyonunda bulabilirsiniz.

Tarayıcıların hata toleransı

Bir HTML sayfasında hiçbir zaman "Geçersiz Söz Dizimi" hatası almazsınız. Tarayıcılar geçersiz içeriği düzeltir ve devam eder.

Örneğin şu HTML'yi ele alalım:

<html>
  <mytag>
  </mytag>
  <div>
  <p>
  </div>
    Really lousy HTML
  </p>
</html>

Yaklaşık bir milyon kuralı ihlal etmiş olmalıyım ("mytag" standart bir etiket değildir, "p" ve "div" öğelerinin yanlış iç içe yerleştirilmesi ve daha fazlası) ancak tarayıcı bunu yine de doğru bir şekilde gösteriyor ve şikayet etmiyor. Ayrıştırıcı kodunun önemli bir bölümü HTML yazar hatalarını düzeltmeye yöneliktir.

Hata işleme, tarayıcılarda oldukça tutarlıdır ancak ne kadar şaşırtıcıdır ki HTML özelliklerinin bir parçası değildir. Yer işaretleri ve geri/ileri düğmeleri gibi, bu özellik de tarayıcılar tarafından yıllar içinde geliştirilmiş bir özelliktir. Birçok sitede tekrarlanan bilinen geçersiz HTML yapıları vardır ve tarayıcılar bunları diğer tarayıcılarla uyumlu bir şekilde düzeltmeye çalışır.

HTML5 spesifikasyonu bu gereksinimlerden bazılarını tanımlar. (WebKit, HTML ayrıştırıcı sınıfının başındaki açıklamada bunu güzel bir şekilde özetlemiştir.)

Ayrıştırıcı, token atanmış girişleri dokümana ayrıştırır ve belge ağacını oluşturur. Doküman iyi biçimlendirilmişse ayrıştırması kolaydır.

Ne yazık ki, düzgün biçimlendirilmemiş birçok HTML dokümanını işlemek zorundayız. Bu nedenle, ayrıştırıcının hatalara karşı toleranslı olması gerekir.

En azından aşağıdaki hata koşullarıyla ilgilenmemiz gerekir:

  1. Eklenen öğe, dış etiketler içinde açıkça yasaklanmıştır. Bu durumda, öğeyi yasaklayan etikete kadar tüm etiketleri kapatmalı ve daha sonra eklemeliyiz.
  2. Öğeyi doğrudan eklememize izin verilmiyor. Dokümanı yazan kişi arada bir etiketleri unutmuş (veya arada kalan etiketin isteğe bağlı olduğunu) unutmuş olabilir. Bu, şu etiketler için geçerli olabilir: HTML HEAD BODY TBODY TR TD LI (unuttum mu?).
  3. Bir satır içi öğenin içine blok öğesi eklemek istiyoruz. Bir sonraki üst blok öğesine kadar tüm satır içi öğeleri kapatın.
  4. Bu işe yaramazsa, öğeyi eklememize izin verilene kadar öğeleri kapatın veya etiketi yoksayın.

Bazı WebKit hata toleransı örneklerine göz atalım:

<br> yerine </br>

Bazı siteler <br> yerine </br> kullanıyor. IE ve Firefox ile uyumlu olması için, WebKit bunu <br> gibi kullanır.

Kod:

if (t->isCloseTag(brTag) && m_document->inCompatMode()) {
     reportError(MalformedBRError);
     t->beginTag = true;
}

Hata işlemenin dahili olduğunu unutmayın: Kullanıcıya sunulmaz.

Sokakta kalmış bir tablo

Yol dışı tablo, başka bir tablonun içinde yer alan ancak tablo hücresinin içinde yer almayan tablodur.

Örneğin:

<table>
  <table>
    <tr><td>inner table</td></tr>
  </table>
  <tr><td>outer table</td></tr>
</table>

WebKit, hiyerarşiyi iki kardeş tablo olarak değiştirir:

<table>
  <tr><td>outer table</td></tr>
</table>
<table>
  <tr><td>inner table</td></tr>
</table>

Kod:

if (m_inStrayTableContent && localName == tableTag)
        popBlock(tableTag);

WebKit, geçerli öğe içerikleri için bir yığın kullanır: İç tabloyu dış tablo yığınından çıkarır. Tablolar artık kardeş olur.

İç içe form öğeleri

Kullanıcının başka bir formun içine form yerleştirmesi durumunda ikinci form yoksayılır.

Kod:

if (!m_currentFormElement) {
        m_currentFormElement = new HTMLFormElement(formTag,    m_document);
}

Çok derin bir etiket hiyerarşisi

Yorum kendini söylüyor.

bool HTMLParser::allowNestedRedundantTag(const AtomicString& tagName)
{

unsigned i = 0;
for (HTMLStackElem* curr = m_blockStack;
         i < cMaxRedundantTagDepth && curr && curr->tagName == tagName;
     curr = curr->next, i++) { }
return i != cMaxRedundantTagDepth;
}

Yanlış yerleştirilmiş html veya gövde bitiş etiketleri

Yorum da çok önemli.

if (t->tagName == htmlTag || t->tagName == bodyTag )
        return;

Bu nedenle web yazarları, WebKit hata toleransı kod snippet'inde örnek olarak görünmek istemediğiniz sürece, iyi biçimlendirilmiş HTML yazmanız gerekir.

CSS ayrıştırma

Girişteki ayrıştırma kavramlarını hatırlıyor musunuz? HTML'den farklı olarak CSS bağlam içermeyen bir dilbilgisidir ve giriş bölümünde açıklanan ayrıştırıcı türleri kullanılarak ayrıştırılabilir. Aslında CSS spesifikasyonu, CSS sözcüksel ve söz dizimi dilbilgisini tanımlar.

Bazı örneklere göz atalım:

Sözcüksel dilbilgisi (vocabulary), her jeton için normal ifadelerle tanımlanır:

comment   \/\*[^*]*\*+([^/*][^*]*\*+)*\/
num       [0-9]+|[0-9]*"."[0-9]+
nonascii  [\200-\377]
nmstart   [_a-z]|{nonascii}|{escape}
nmchar    [_a-z0-9-]|{nonascii}|{escape}
name      {nmchar}+
ident     {nmstart}{nmchar}*

"ident", tanımlayıcının kısaltmasıdır (ör. sınıf adı). "name", bir öğe kimliğidir ("#" ile belirtilir)

Söz dizimi dil bilgisi, BNF'de açıklanmıştır.

ruleset
  : selector [ ',' S* selector ]*
    '{' S* declaration [ ';' S* declaration ]* '}' S*
  ;
selector
  : simple_selector [ combinator selector | S+ [ combinator? selector ]? ]?
  ;
simple_selector
  : element_name [ HASH | class | attrib | pseudo ]*
  | [ HASH | class | attrib | pseudo ]+
  ;
class
  : '.' IDENT
  ;
element_name
  : IDENT | '*'
  ;
attrib
  : '[' S* IDENT S* [ [ '=' | INCLUDES | DASHMATCH ] S*
    [ IDENT | STRING ] S* ] ']'
  ;
pseudo
  : ':' [ IDENT | FUNCTION S* [IDENT S*] ')' ]
  ;

Açıklama:

Kural kümesi şu yapıdır:

div.error, a.error {
  color:red;
  font-weight:bold;
}

div.error ve a.error seçicilerdir. Küme parantezlerinin içindeki bölüm, bu kural grubu tarafından uygulanan kuralları içerir. Bu yapı, resmi olarak bu tanımda tanımlanmıştır:

ruleset
  : selector [ ',' S* selector ]*
    '{' S* declaration [ ';' S* declaration ]* '}' S*
  ;

Bu, bir kural kümesinin virgülle ve boşlukla (S, beyaz boşluk anlamına gelir) ayrılmış bir seçici veya isteğe bağlı olarak bir dizi seçici olduğu anlamına gelir. Kural kümesi, süslü ayraçlar ve bunların içinde bir bildirim veya isteğe bağlı olarak noktalı virgülle ayrılmış çeşitli bildirimler içerir. "beyan" ve "seçici", aşağıdaki BNF tanımlarında tanımlanır.

WebKit CSS ayrıştırıcı

WebKit, CSS dilbilgisi dosyalarından otomatik olarak ayrıştırıcılar oluşturmak için Flex ve Bison ayrıştırıcı oluşturma araçlarını kullanır. Ayrıştırıcının tanıtımından hatırlayacağınız gibi, Bison, "alttan yukarıya doğru kaydırıcı" tarzında bir ayrıştırıcı oluşturur. Firefox, manuel olarak yazılmış bir yukarıdan aşağı ayrıştırıcı kullanır. Her iki durumda da her CSS dosyası bir StyleSheet nesnesi olarak ayrıştırılır. Her nesne CSS kuralları içerir. CSS kuralı nesneleri, seçici ve bildirim nesnelerinin yanı sıra CSS dil bilgisine karşılık gelen diğer nesneleri içerir.

CSS ayrıştırılıyor.
Şekil 12: CSS'yi ayrıştırma

Komut dosyaları ve stil sayfaları için işleme sırası

Komut Dosyaları

Web'in modeli eşzamanlıdır. Yazarlar, ayrıştırıcı bir <script> etiketine ulaştığında komut dosyalarının hemen ayrıştırılmasını ve yürütülmesini bekler. Dokümanın ayrıştırılması, komut dosyası çalıştırılana kadar durdurulur. Komut dosyası harici ise kaynağın önce ağdan alınması gerekir. Bu da eşzamanlı olarak gerçekleştirilir ve kaynak alınana kadar durdurmaların ayrıştırılması gerçekleştirilir. Bu model uzun yıllardır bu modeldi ve HTML4 ve 5 spesifikasyonlarında da belirtilmiş. Yazarlar bir komut dosyasına "defer" özelliğini ekleyebilir. Bu durumda, doküman ayrıştırma durdurulur ve doküman ayrıştırıldıktan sonra yürütülür. HTML5, farklı bir iş parçacığı tarafından ayrıştırılıp yürütülmesi için komut dosyasını eşzamansız olarak işaretleme seçeneği ekler.

Tahmine dayalı ayrıştırma

Bu optimizasyonu hem WebKit hem de Firefox yapar. Komut dosyalarını yürütürken başka bir iş parçacığı, dokümanın geri kalanını ayrıştırır ve ağdan başka hangi kaynakların yüklenmesi gerektiğini öğrenip yükler. Bu şekilde, kaynaklar paralel bağlantılara yüklenebilir ve genel hız artırılabilir. Not: Tahmine dayalı ayrıştırıcı yalnızca harici komut dosyaları, stil sayfaları ve resimler gibi harici kaynaklara yapılan referansları ayrıştırır. Ana ayrıştırıcıya bırakılan DOM ağacında değişiklik yapmaz.

Stil sayfaları

Stil sayfaları ise farklı bir modele sahiptir. Kavramsal olarak, stil sayfaları DOM ağacını değiştirmediğinden, bunları beklemek ve doküman ayrıştırmayı durdurmak için bir neden yoktur. Ancak doküman ayrıştırma aşamasında stil bilgileri isteyen komut dosyalarıyla ilgili bir sorun var. Stil henüz yüklenip ayrıştırılmamışsa komut dosyası yanlış yanıtlar alır ve görünüşe göre bu durum çok fazla soruna yol açar. Sıra dışı bir durum gibi görünse de oldukça yaygındır. Firefox hâlâ yüklenme ve ayrıştırılmakta olan bir stil sayfası olduğunda tüm komut dosyalarını engeller. WebKit, komut dosyalarını yalnızca yüklenmemiş stil sayfalarından etkilenebilecek belirli stil özelliklerine erişmeye çalıştıklarında engeller.

Oluşturulan ağaç yapımı

DOM ağacı oluşturulurken tarayıcı, oluşturma ağacı olan başka bir ağaç oluşturur. Bu ağaçta, görüntülenecekleri sırayla görsel öğeler bulunur. Belgenin görsel temsilidir. Bu ağacın amacı, içeriklerin doğru sırada boyanmasını sağlamaktır.

Firefox, oluşturma ağacındaki öğeleri "çerçeveler" olarak adlandırır. WebKit, oluşturucu veya oluşturma nesnesi terimini kullanır.

Oluşturucu, kendisini ve alt öğelerini nasıl yerleştirip boyayacağını bilir.

Oluşturucuların temel sınıfı olan WebKit'in RenderObject sınıfı aşağıdaki tanıma sahiptir:

class RenderObject{
  virtual void layout();
  virtual void paint(PaintInfo);
  virtual void rect repaintRect();
  Node* node;  //the DOM node
  RenderStyle* style;  // the computed style
  RenderLayer* containgLayer; //the containing z-index layer
}

Her oluşturucu, CSS2 spesifikasyonunda açıklandığı gibi genellikle düğümün CSS kutusuna karşılık gelen dikdörtgen bir alanı temsil eder. Genişlik, yükseklik ve konum gibi geometrik bilgiler içerir.

Kutu türü, düğümle ilgili stil özelliğinin "display" değerinden etkilenir (stil hesaplaması bölümüne bakın). Burada, display özelliğine göre, DOM düğümü için ne tür bir oluşturucunun oluşturulması gerektiğine karar vermek için kullanılan WebKit kodu verilmiştir:

RenderObject* RenderObject::createObject(Node* node, RenderStyle* style)
{
    Document* doc = node->document();
    RenderArena* arena = doc->renderArena();
    ...
    RenderObject* o = 0;

    switch (style->display()) {
        case NONE:
            break;
        case INLINE:
            o = new (arena) RenderInline(node);
            break;
        case BLOCK:
            o = new (arena) RenderBlock(node);
            break;
        case INLINE_BLOCK:
            o = new (arena) RenderBlock(node);
            break;
        case LIST_ITEM:
            o = new (arena) RenderListItem(node);
            break;
       ...
    }

    return o;
}

Öğe türü de dikkate alınır: Örneğin, form kontrolleri ve tabloların özel çerçeveleri vardır.

WebKit'te, bir öğe özel oluşturucu oluşturmak isterse createRenderer() yöntemini geçersiz kılar. Oluşturucular, geometrik olmayan bilgiler içeren stil nesnelerine işaret eder.

Oluşturma ağacının DOM ağacıyla ilişkisi

Oluşturucular DOM öğelerine karşılık gelir, ancak ilişki bire bir değildir. Görsel olmayan DOM öğeleri, oluşturma ağacına eklenmez. "head" öğesi buna örnek olarak gösterilebilir. Ayrıca, görüntüleme değeri "none" (hiçbiri) olarak atanan öğeler ağaçta görünmez (ancak "gizli" görünürlüğe sahip öğeler ağaçta görünür).

Birkaç görsel nesneye karşılık gelen DOM öğeleri vardır. Bunlar genellikle tek bir dikdörtgenle açıklanamayan karmaşık yapıya sahip öğelerdir. Örneğin, "select" öğesinin üç oluşturucusu vardır: biri görüntüleme alanı, biri açılır liste kutusu, diğeri düğme için. Ayrıca, genişlik tek bir satır için yeterli olmadığından metin birden fazla satıra bölündüğünde, yeni satırlar ekstra oluşturucular olarak eklenir.

Birden fazla oluşturucuya diğer bir örnek de bozuk HTML'dir. CSS spesifikasyonuna göre, satır içi öğeler ya sadece blok öğeleri ya da sadece satır içi öğeler içermelidir. Karışık içerik söz konusu olduğunda satır içi öğeleri sarmalamak için anonim blok oluşturucular oluşturulur.

Bazı oluşturma nesneleri bir DOM düğümüne karşılık gelir ancak ağaçta aynı yerde değildir. Şamandıralar ve kesinlikle konumlandırılmış öğeler akışın dışında kalmış, ağacın farklı bir bölümüne yerleştirilmiş ve gerçek çerçeveyle eşlenmiş. Yer tutucu çerçeve, olması gereken yerdir.

Oluşturma ağacı ve ilgili DOM ağacı.
Şekil 13: Oluşturma ağacı ve ilgili DOM ağacı. "Görüntü Alanı", başlangıçtaki kapsayıcı bloktur. WebKit'te bu, "RenderView" nesnesi olur

Ağaç oluşturma akışı

Firefox'ta sunu, DOM güncellemeleri için işleyici olarak kaydedilir. Sunu, kare oluşturma yetkisini FrameConstructor öğesine verir ve kurucu da stili çözümler (bkz. stil hesaplaması) ve bir çerçeve oluşturur.

WebKit'te stili çözümleme ve oluşturucu oluşturma sürecine "ek" adı verilir. Her DOM düğümünde bir "attach" yöntemi vardır. Ek eşzamanlıdır; DOM ağacına düğüm eklendiğinde yeni düğüm "attach" yöntemi kullanılır.

HTML ve gövde etiketlerinin işlenmesi, oluşturma ağacı kökünün oluşturulmasıyla sonuçlanır. Kök oluşturma nesnesi, CSS spesifikasyonunun kapsayıcı blok olarak adlandırdığı öğeye karşılık gelir: Diğer tüm blokları içeren en üstteki blok. Boyutları görüntü alanıdır: tarayıcı penceresinin görüntüleme alanı boyutları. Firefox'ta ViewPortFrame, WebKit ise RenderView olarak adlandırıyor. Bu, dokümanın işaret ettiği oluşturma nesnesidir. Ağacın geri kalanı, bir DOM düğümü eklemesi olarak oluşturulur.

İşleme modeliyle ilgili CSS2 spesifikasyonuna bakın.

Stil hesaplaması

Oluşturma ağacını oluşturmak için her bir oluşturma nesnesinin görsel özelliklerinin hesaplanması gerekir. Bu, her bir öğenin stil özellikleri hesaplanarak yapılır.

Stil, çeşitli kaynaklardan stil sayfaları, satır içi stil öğeleri ve HTML'deki görsel özellikleri ("bgcolor" özelliği gibi) içerir. Daha sonra, eşleşen CSS stil özelliklerine dönüştürülür.

Stil sayfalarının kaynağı, tarayıcının varsayılan stil sayfaları, sayfa yazarının sağladığı stil sayfaları ve kullanıcı stil sayfalarıdır. Bunlar, tarayıcı kullanıcısı tarafından sağlanan stil sayfalarıdır (tarayıcılar, en beğendiğiniz stilleri tanımlamanıza olanak sağlar). Örneğin Firefox’ta bu, "Firefox Profili" klasörüne bir stil sayfası yerleştirilerek yapılır).

Stil hesaplaması bazı zorlukları beraberinde getirir:

  1. Stil verileri, çok sayıda stil özelliğini barındıran çok büyük bir yapıdır ve bu da bellek sorunlarına neden olabilir.
  2. Her öğe için eşleşen kuralları bulmak, öğeler optimize edilmezse performans sorunlarına neden olabilir. Eşleşmeleri bulmak için her öğenin kural listesinin tamamını incelemek yoğun bir iştir. Seçiciler, eşleştirme sürecinin işe yaramadığı kanıtlanmış, görünüşte umut verici bir yolda başlamasına ve başka bir yolun denenmesine neden olabilecek karmaşık bir yapıya sahip olabilir.

    Örneğin, şu bileşik seçici:

    div div div div{
    ...
    }
    

    Kuralların, 3 div öğesinin alt öğesi olan bir <div> için geçerli olduğu anlamına gelir. Kuralın belirli bir <div> öğesi için geçerli olup olmadığını kontrol etmek istediğinizi varsayalım. Kontrol etmek için ağaçta belirli bir yolu seçersiniz. Yalnızca iki div öğesi olduğunu ve kuralın geçerli olmadığını öğrenmek için düğüm ağacını yukarı çekmeniz gerekebilir. Bu durumda ağaçta diğer yolları denemeniz gerekir.

  3. Kuralların uygulanması, kuralların hiyerarşisini tanımlayan oldukça karmaşık basamaklı kurallar içerir.

Tarayıcıların bu sorunlarla nasıl karşılaştığına bakalım:

Stil verilerini paylaşma

WebKit düğümleri stil nesnelerine (RenderStyle) başvuruyor. Bu nesneler bazı koşullarda düğümler tarafından paylaşılabilir. Düğümler kardeş veya kuzendir ve:

  1. Öğeler aynı fare durumunda olmalıdır (ör. biri :hover değeri içinde olamazken diğeri olamaz)
  2. Hiçbir öğenin kimliği olmamalıdır
  3. Etiket adları eşleşmelidir
  4. Sınıf özellikleri eşleşmelidir.
  5. Eşlenen özellik grubu aynı olmalıdır
  6. Bağlantı durumları eşleşmelidir
  7. Odak durumları eşleşmelidir
  8. Öğelerin hiçbiri özellik seçicilerden etkilenmemelidir. Burada etkilenen, seçici içindeki herhangi bir konumda, özellik seçici kullanan herhangi bir seçici eşleşmesinin bulunması olarak tanımlanır
  9. Öğelerde satır içi stil özelliği olmamalıdır
  10. Kullanılmakta olan eşdüzey seçici olmamalıdır. WebCore, herhangi bir eşdüzey seçiciyle karşılaşıldığında genel bir anahtar atar ve bunlar varsa dokümanın tamamı için stil paylaşımını devre dışı bırakır. Bunlara + seçici ile :first-child ve :last-child gibi seçiciler dahildir.

Firefox kural ağacı

Stil hesaplamasının daha kolay olması için Firefox'ta iki ekstra ağaç bulunur: kural ağacı ve stil bağlam ağacı. WebKit'in stil nesneleri de vardır ancak stil bağlam ağacı gibi bir ağaçta depolanmaz; yalnızca DOM düğümü ilgili stili işaret eder.

Firefox stili bağlam ağacı.
Şekil 14: Firefox stili içerik ağacı.

Stil bağlamları bitiş değerleri içerir. Değerler, eşleşen tüm kuralların doğru sırada uygulanarak ve bunları mantıksal değerlerden somut değerlere dönüştüren değişiklikler uygulanarak hesaplanır. Örneğin, mantıksal değer ekranın belirli bir yüzdesiyse hesaplanır ve mutlak birimlere dönüştürülür. Kural ağacı fikri gerçekten çok zekice. Düğümlerin tekrar hesaplanmasını önlemek için bu değerlerin düğümler arasında paylaşılmasını sağlar. Bu şekilde alandan da tasarruf edilir.

Eşleşen tüm kurallar bir ağaçta depolanır. Bir yoldaki alt düğümler daha yüksek önceliğe sahiptir. Ağaç, bulunan kural eşleşmeleri için tüm yolları içerir. Kuralların saklanması daha geç gerçekleştirilir. Ağaç, her düğüm için başlangıçta hesaplanmaz ancak bir düğüm stilinin hesaplanması gerektiğinde hesaplanan yollar ağa eklenir.

Buradaki fikir, ağaç yollarını bir sözlükte kelimeler olarak görmektir. Şu kural ağacını zaten hesapladığımızı varsayalım:

Hesaplanan kural ağacı
Şekil 15: Hesaplanmış kural ağacı.

İçerik ağacındaki başka bir öğe için kuralları eşleştirmemiz ve eşleşen kuralların (doğru sırada) B-E-I olduğunu bulmamız gerektiğini varsayalım. A-B-E-I-L yolunu zaten hesapladığımız için bu yol ağaçta zaten mevcut. Artık yapacak daha az işimiz olacak.

Ağacın bizi nasıl işlerden kurtardığını görelim.

Yapılara ayırma

Stil bağlamları struct'lara ayrılır. Bu yapılar, kenarlık veya renk gibi belirli bir kategoriyle ilgili stil bilgilerini içerir. Bir struct içindeki tüm özellikler devralınır veya devralınmaz. Devralınan özellikler, öğe tarafından tanımlanmadığı sürece üst öğesinden devralınan özelliklerdir. Devralınmayan özellikler ("sıfırlama" özellikleri olarak adlandırılır) tanımlanmamışsa varsayılan değerleri kullanır.

Ağaç, ağaçtaki (hesaplanan son değerleri içerir) tüm struct'ları önbelleğe alarak bize yardımcı olur. Buradaki düşünce, alt düğüm bir struct için tanım sağlamadıysa üst düğümde önbelleğe alınmış bir struct'ın kullanılabileceğidir.

Kural ağacını kullanarak stil bağlamlarını hesaplama

Belirli bir öğe için stil bağlamını hesaplarken, öncelikle kural ağacında bir yol hesaplarız veya mevcut bir yolu kullanırız. Daha sonra, yeni stil bağlamımızdaki struct'ları doldurmak için yoldaki kuralları uygulamaya başlarız. Yolun en alt düğümünden, en yüksek önceliğe sahip olan düğümden (genellikle en spesifik seçici) başlar ve struct'ımız dolana kadar ağacı dolaşırız. Söz konusu kural düğümünde struct için bir belirtim yoksa büyük ölçüde optimizasyon yapabiliriz. Düğümü tam olarak belirten bir düğüm bulana kadar ağaçta yukarı çıkar ve ona işaret eden bir düğüm buluruz. Bu en iyi optimizasyondur. struct'ın tamamı paylaşılır. Böylece son değerler ve bellek hesaplamaları önlenir.

Kısmi tanım bulursak struct doldurulana kadar ağacın üst kısmına çıkarız.

struct'ımız için hiçbir tanım bulamadıysak struct'ın "devralınan" türde olması durumunda bağlam ağacında üst öğemizin struct'ına işaret ederiz. Bu örnekte, struct'ları da başarıyla paylaşabildik. Sıfırlanmış bir struct ise varsayılan değerler kullanılır.

En belirgin düğüm değer eklerse bunu gerçek değerlere dönüştürmek için ekstra hesaplamalar yapmamız gerekir. Ardından, çocukların kullanılabilmesi için sonucu ağaç düğümünde önbelleğe alırız.

Bir öğenin aynı ağaç düğümüne işaret eden bir kardeş veya erkek kardeş olması durumunda, stil bağlamının tamamı bu öğeler arasında paylaşılabilir.

Bir örnek verelim: Diyelim ki bu HTML'de

<html>
  <body>
    <div class="err" id="div1">
      <p>
        this is a <span class="big"> big error </span>
        this is also a
        <span class="big"> very  big  error</span> error
      </p>
    </div>
    <div class="err" id="div2">another error</div>
  </body>
</html>

Ve şu kurallar:

div {margin: 5px; color:black}
.err {color:red}
.big {margin-top:3px}
div span {margin-bottom:4px}
#div1 {color:blue}
#div2 {color:green}

İşleri basitleştirmek için yalnızca iki struct (color struct ve margin struct) doldurmamız gerektiğini varsayalım. struct rengi yalnızca bir üye içerir: renk kenar boşluğu struct dört kenarı içerir.

Elde edilen kural ağacı şöyle görünür (düğümler düğüm adıyla işaretlenir:

Kural ağacı
Şekil 16: Kural ağacı

Bağlam ağacı şöyle görünür (düğüm adı: işaret ettikleri kural düğümü):

Bağlam ağacı.
Şekil 17: Bağlam ağacı

HTML'yi ayrıştırdığımızı ve ikinci <div> etiketine ulaştığımızı varsayalım. Bu düğüm için stil bağlamı oluşturmamız ve stil yapılarını doldurmamız gerekiyor.

Kuralları eşleştireceğiz ve <div> için eşleşme kurallarının 1, 2 ve 6 olduğunu keşfedeceğiz. Bu, öğemizin ağaçta kullanabileceği bir yol olduğu ve 6. kural için (kural ağacındaki F düğümü) başka bir düğüm eklememiz gerektiği anlamına gelir.

Stil için bir bağlam oluşturup bağlam ağacına koyacağız. Yeni stil bağlamı, kural ağacındaki F düğümünü işaret eder.

Şimdi stil struct'larını doldurmamız gerekiyor. İlk olarak margin struct'ı dolduracağız. Son kural düğümü (F) margin struct'a eklenmediğinden, önceki düğüm eklemesinde hesaplanan önbelleğe alınmış bir struct'ı bulup kullanana kadar ağacın üst kısmına gidebiliriz. Kimliği, kenar boşluğu kurallarını belirten en üstteki düğüm olan B düğümünde buluruz.

struct renginin bir tanımı olduğundan önbelleğe alınmış struct'ı kullanamayız. Rengin tek bir özelliği olduğundan, diğer özellikleri doldurmak için ağacın üst kısmına gitmemiz gerekmez. Son değeri hesaplarız (dizeyi RGB'ye dönüştürün vb.) ve hesaplanan struct'ı bu düğümde önbelleğe alırız.

İkinci <span> öğesi üzerindeki iş daha da kolaydır. Kuralları eşleştirir ve önceki aralıkta olduğu gibi G kuralını işaret ettiği sonucuna varırız. Aynı düğümü gösteren kardeşlerimiz olduğu için tüm stil bağlamını paylaşıp yalnızca önceki kapsamın bağlamına işaret edebiliriz.

Üst öğeden devralınan kurallar içeren yapılar için önbelleğe alma işlemi bağlam ağacında gerçekleştirilir (renk özelliği aslında devralınır ancak Firefox bunu sıfırlanmış olarak değerlendirir ve kural ağacında önbelleğe alır).

Örneğin, bir paragraftaki yazı tipleri için kurallar eklersek:

p {font-family: Verdana; font size: 10px; font-weight: bold}

Bu durumda, bağlam ağacındaki div öğesinin alt öğesi olan paragraf öğesi, üst öğesiyle aynı yazı tipi yapısını paylaşabilir. Bunun nedeni, paragraf için yazı tipi kuralı belirtilmemişse demektir.

Kural ağacı olmayan WebKit'te, eşleşen bildirimler dört kez aktarılır. Önce önemli olmayan yüksek öncelikli özellikler (Görüntülü Reklam Ağı gibi diğerleri bağımlı olduğu için öncelikle uygulanması gereken özellikler), ardından yüksek öncelikli önemli, ardından normal öncelikli önemli olmayan, ardından normal öncelikli önemli kurallar uygulanır. Yani birden fazla kez görünen mülkler doğru basamak sırasına göre çözümlenir. Son kazanmış.

Özetlemek gerekirse, stil nesnelerini (içindeki yapıların tamamını veya bir kısmını) paylaşmak 1. ve 3. sorunları çözer. Firefox kural ağacı, özelliklerin doğru sırada uygulanmasına da yardımcı olur.

Kolay eşleşme için kuralları değiştirme

Stil kuralları için birkaç kaynak vardır:

  1. Harici stil sayfalarında veya stil öğelerinde CSS kuralları. css p {color: blue}
  2. html <p style="color: blue" /> gibi satır içi stil özellikleri
  3. HTML görsel özellikleri (ilgili stil kurallarıyla eşlenir) html <p bgcolor="blue" /> Stil özelliklerine sahip olduğu için son ikisi öğeyle kolayca eşleştirilir ve HTML özellikleri, öğe anahtar olarak kullanılarak eşlenebilir.

Daha önce sorun 2'de belirtildiği gibi, CSS kuralı eşleştirmesi daha karmaşık olabilir. Zorluğu çözmek için daha kolay erişim sağlamak üzere kurallar değiştirilir.

Stil sayfası ayrıştırıldıktan sonra, kurallar seçiciye göre çeşitli karma eşlemelerinden birine eklenir. Kimliğe, sınıf adına, etiket adına göre haritalar ve bu kategorilere uymayan her şey için bir genel harita bulunur. Seçici bir kimlik ise kural, kimlik eşlemesine, bir sınıfsa sınıf haritasına eklenir vb.

Bu değiştirme işlemi, kuralların eşleştirilmesini çok daha kolay hale getirir. Her beyana bakmanıza gerek yoktur: Haritalardan bir öğe için alakalı kuralları çıkarabiliriz. Bu optimizasyon, kuralların% 95'ten fazlasını ortadan kaldırır. Böylece, eşleştirme sürecinde(4.1) dikkate alınmalarına bile gerek kalmaz.

Örnek olarak aşağıdaki stil kurallarını inceleyelim:

p.error {color: red}
#messageDiv {height: 50px}
div {margin: 5px}

İlk kural sınıf haritasına eklenir. İkincisi kimlik eşlemede, üçüncüsü etiket eşlemededir.

Aşağıdaki HTML parçası için;

<p class="error">an error occurred</p>
<div id=" messageDiv">this is a message</div>

İlk olarak p öğesine ilişkin kuralları bulmaya çalışacağız. Sınıf haritası, altında "p.error" kuralının bulunduğu bir "error" anahtarı içerir. Div öğesi, kimlik eşlemesinde (anahtar kimliktir) ve etiket eşlemede alakalı kurallara sahiptir. Dolayısıyla, geriye kalan tek iş, anahtarlar tarafından çıkarılan kurallardan hangilerinin gerçekten eşleştiğini bulmaktır.

Örneğin, div kuralı şöyle ise:

table div {margin: 5px}

Anahtar en sağdaki seçici olduğundan yine de etiket eşlemeden ayıklanır ancak tablo üst öğesi olmayan div öğemizle eşleşmez.

Bu değişikliği hem WebKit hem de Firefox yapar.

Stil sayfası basamak sırası

Stil nesnesi, her görsel özelliğe karşılık gelen özelliklere sahiptir (tüm CSS özellikleri ancak daha geneldir). Özellik, eşleşen kuralların herhangi biri tarafından tanımlanmazsa bazı özellikler üst öğe stili nesnesi tarafından devralınabilir. Diğer özelliklerin varsayılan değerleri vardır.

Sorun birden fazla tanım olduğunda başlar. Burada sorunu çözmek için basamaklı sıralama kullanılır.

Bir stil özelliği bildirimi birkaç stil sayfasında ve bir stil sayfasında birkaç kez görüntülenebilir. Bu da kuralların uygulanma sırasının çok önemli olduğu anlamına gelir. Buna "basamakla" sırası denir. CSS2 spesifikasyonuna göre, basamak sırası (düşükten yükseğe) şu şekildedir:

  1. Tarayıcı bildirimleri
  2. Kullanıcı normal bildirimleri
  3. Yazar normal bildirimleri
  4. Yazar önemli bildirimleri
  5. Önemli kullanıcı bildirimleri

Tarayıcı bildirimleri en az öneme sahiptir ve kullanıcı yalnızca bildirim önemli olarak işaretlenmişse yazarı geçersiz kılar. Aynı sıraya sahip bildirimler spesifikliğe ve ardından belirtildikleri sıraya göre sıralanır. HTML görsel özellikleri, eşleşen CSS bildirimlerine dönüştürülür . Bunlar düşük önceliğe sahip yazar kuralları olarak kabul edilir.

Belirginlik

Seçici belirliliği, CSS2 spesifikasyonu tarafından aşağıdaki gibi tanımlanır:

  1. ait olduğu bildirim, seçicili bir kural yerine bir "style" özelliğiyse 1 sayılır, değilse 0 (= a)
  2. seçicideki kimlik özelliklerinin sayısını say (= b)
  3. seçicideki diğer özelliklerin ve sözde sınıfların sayısını say (= c)
  4. seçicideki öğe adlarının ve sözde öğelerin sayısını say (= d)

a-b-c-d arasındaki dört sayının (tabanı büyük olan bir sayı sisteminde) birleştirildiğinde belirlilik elde edilir.

Kullanmanız gereken sayı tabanı, kategorilerden birindeki en yüksek sayıya göre tanımlanır.

Örneğin, a=14 ise onaltılık taban değerini kullanabilirsiniz. Çok düşük bir ihtimal de olsa a=17 olması halinde 17 haneli bir sayı tabanı kullanmanız gerekir. Sonraki durum, şuna benzer bir seçiciyle ortaya çıkabilir: html body div div p... (seçicinizde 17 etiket olması pek olası değildir).

Bazı örnekler:

 *             {}  /* a=0 b=0 c=0 d=0 -> specificity = 0,0,0,0 */
 li            {}  /* a=0 b=0 c=0 d=1 -> specificity = 0,0,0,1 */
 li:first-line {}  /* a=0 b=0 c=0 d=2 -> specificity = 0,0,0,2 */
 ul li         {}  /* a=0 b=0 c=0 d=2 -> specificity = 0,0,0,2 */
 ul ol+li      {}  /* a=0 b=0 c=0 d=3 -> specificity = 0,0,0,3 */
 h1 + *[rel=up]{}  /* a=0 b=0 c=1 d=1 -> specificity = 0,0,1,1 */
 ul ol li.red  {}  /* a=0 b=0 c=1 d=3 -> specificity = 0,0,1,3 */
 li.red.level  {}  /* a=0 b=0 c=2 d=1 -> specificity = 0,0,2,1 */
 #x34y         {}  /* a=0 b=1 c=0 d=0 -> specificity = 0,1,0,0 */
 style=""          /* a=1 b=0 c=0 d=0 -> specificity = 1,0,0,0 */

Kuralları sıralama

Kurallar eşleştirildikten sonra, basamak kurallarına göre sıralanır. WebKit, küçük listeler için kabarcık sıralamayı, büyük listeler için birleştirme sıralamayı kullanır. WebKit, kurallar için > operatörünü geçersiz kılarak sıralamayı uygular:

static bool operator >(CSSRuleData& r1, CSSRuleData& r2)
{
    int spec1 = r1.selector()->specificity();
    int spec2 = r2.selector()->specificity();
    return (spec1 == spec2) : r1.position() > r2.position() : spec1 > spec2;
}

Kademeli süreç

WebKit, tüm üst düzey stil sayfalarının (@imports dahil) yüklendiği durumları işaretleyen bir işaret kullanır. Stil, ekleme sırasında tam olarak yüklenmediyse yer tutucular kullanılır ve dokümanda işaretlenir. Stil sayfaları yüklendiğinde bunlar yeniden hesaplanır.

Düzen

Oluşturucu oluşturulup ağaca eklendiğinde konumu ve boyutu olmaz. Bu değerlerin hesaplanmasına düzen veya yeniden düzenleme denir.

HTML'de akışa dayalı bir düzen modeli kullanılır. Diğer bir deyişle, geometri, çoğu zaman tek bir geçişte hesaplanabilir. Daha sonra "akışta" olan öğeler, genellikle "akışta" daha erken bulunan öğelerin geometrisini etkilemez. Bu nedenle düzen, dokümanda soldan sağa, yukarıdan aşağıya doğru ilerleyebilir. İstisnalar mevcuttur. Örneğin, HTML tabloları birden fazla geçiş gerektirebilir.

Koordinat sistemi kök çerçeveye göre belirlenir. Üst ve sol koordinatlar kullanılır.

Düzen, yinelemeli bir süreçtir. HTML belgesinin <html> öğesine karşılık gelen kök oluşturucuda başlar. Düzen, çerçeve hiyerarşisinin bir kısmında veya tamamında yinelemeli olarak devam eder ve bunu gerektiren her oluşturucu için geometrik bilgileri hesaplar.

Kök oluşturucunun konumu 0,0'dır ve boyutları görüntü alanı, yani tarayıcı penceresinin görünür bölümüdür.

Tüm oluşturucular bir "düzen" veya "yeniden düzenleme" yöntemine sahiptir. Her oluşturucu, düzen gerektiren alt öğelerinin düzen yöntemini çağırır.

Kirli bit sistemi

Her küçük değişiklikte tam bir düzen yapmamak için, tarayıcılar bir "kirli bit" sistemi kullanır. Değiştirilen veya eklenen bir oluşturucu, kendisini ve alt öğelerini "kirli": gereken düzen olarak işaretler.

İki bayrak vardır: "kirli" ve "çocuklar kirli"; diğer bir deyişle, oluşturucu düzgün olsa da düzene ihtiyacı olan en az bir alt öğe vardır.

Küresel ve artımlı düzen

Düzen, oluşturma ağacının tamamında tetiklenebilir. Bu, "genel" düzendir. Bunun nedeni aşağıdakilerden biri olabilir:

  1. Yazı tipi boyutu değişikliği gibi, tüm oluşturucuları etkileyen genel bir stil değişikliği.
  2. Bir ekranın yeniden boyutlandırılması sonucunda

Düzen artımlı olabilir, yalnızca hatalı oluşturucular yerleştirilecektir (bu, ekstra düzen gerektirecek bir miktar hasara neden olabilir).

Oluşturucular kirli olduğunda artımlı düzen tetiklenir (eşzamansız olarak). Örneğin, ağdan fazladan içerik gelip DOM ağacına eklendikten sonra oluşturma ağacına yeni oluşturucular eklendiğinde.

Artımlı düzen.
Şekil 18: Artımlı düzen - yalnızca kirli oluşturucular ve bunların alt öğeleri yerleştirilmiş

Eşzamansız ve Eşzamanlı düzen

Artımlı düzen eşzamansız olarak yapılır. Firefox, artımlı düzenler için "yeniden düzenleme komutlarını" sıraya alır ve bir planlayıcı bu komutların toplu olarak yürütülmesini tetikler. WebKit'te, artımlı düzen yürüten bir zamanlayıcı da vardır. Ağaca geçiş yapılır ve "kirli" oluşturucular düzensizdir.

"offsetHeight" gibi stil bilgileri isteyen komut dosyaları, eşzamanlı olarak artımlı düzeni tetikleyebilir.

Genel düzen genellikle eşzamanlı olarak tetiklenir.

Kaydırma konumu gibi bazı özelliklerin değişmesi nedeniyle, bazen düzen ilk düzenden sonra bir geri çağırma olarak tetiklenir.

Optimizasyonlar

Bir düzen, "yeniden boyutlandırma" veya oluşturucu konumundaki(boyut değil) bir değişiklik tarafından tetiklendiğinde, oluşturma boyutları önbellekten alınır ve yeniden hesaplanmaz...

Bazı durumlarda yalnızca bir alt ağaç değiştirilir ve düzen kökten başlamaz. Bu durum, değişikliğin yerel olduğu ve etrafındaki öğeleri etkilemediği (metin alanlarına eklenen metin gibi) durumlarda ortaya çıkabilir (aksi halde, her tuş vuruşu kökten başlayan bir düzeni tetikler).

Düzen süreci

Düzen genellikle aşağıdaki kalıba sahiptir:

  1. Üst oluşturucu, kendi genişliğini belirler.
  2. Ebeveyn, çocukların üzerinden geçer ve:
    1. Alt oluşturucuyu yerleştirin (x ve y'yi ayarlar).
    2. Gerekirse alt düzeni çağırır. Bunlar kirli veya genel bir düzende bulunuyoruz ya da çocuğun boyunu hesaplayan başka bir nedenden dolayı.
  3. Üst öğe, kendi yüksekliğini ayarlamak için alt öğelerin toplam yüksekliklerini, kenar boşlukları ve dolgu yüksekliklerini kullanır. Bu, üst oluşturucunun üst öğesi tarafından kullanılacaktır.
  4. Kirli bitini false olarak ayarlar.

Firefox, düzen parametresi olarak bir "state" nesnesi(nsHTMLReflowState) kullanır ("reflow" olarak adlandırılır). Diğerlerinin yanı sıra eyalet, üst öğe genişliğini de içerir.

Firefox düzeninin çıktısı bir "metrics" nesnesidir(nsHTMLReflowMetrics). Oluşturucu tarafından hesaplanan yüksekliği içerir.

Genişlik hesaplaması

Oluşturucunun genişliği, kapsayıcı bloğunun genişliği, oluşturucunun stil "width" özelliği, kenar boşlukları ve kenarlıklar kullanılarak hesaplanır.

Örneğin, aşağıdaki div öğesinin genişliği:

<div style="width: 30%"/>

WebKit tarafından şu şekilde hesaplanır(class RenderBox yöntemi calcWidth):

  • Kapsayıcı genişliği, kullanılabilir Genişlik ve 0 kapsayıcılarının maksimum genişliğidir. Bu durumda availableWidth, şu şekilde hesaplanan contentWidth'tir:
clientWidth() - paddingLeft() - paddingRight()

clientWidth ve clientHeight, bir nesnenin kenarlık ve kaydırma çubuğu hariç olmak üzere içini temsil eder.

  • Öğenin genişliği, "width" stil özelliğidir. Kapsayıcı genişliğinin yüzdesi hesaplanarak mutlak bir değer olarak hesaplanır.

  • Yatay kenarlıklar ve dolgular eklenir.

Şimdiye kadar bu, "tercih edilen genişlik" için hesaplanıyordu. Şimdi minimum ve maksimum genişlikler hesaplanacaktır.

Tercih edilen genişlik maksimum genişlikten büyükse maksimum genişlik kullanılır. Minimum genişlikten (en küçük bölünmez birim) küçükse, minimum genişlik kullanılır.

Düzene ihtiyaç duyulması halinde değerler önbelleğe alınır ancak genişlik değişmez.

Satır Kırma

Bir düzenin ortasındaki oluşturucu bozulması gerektiğine karar verdiğinde oluşturucu durur ve bozulması gereken düzen üst öğesine yayılır. Üst öğe, ekstra oluşturucular oluşturur ve bunlarda düzen çağırır.

Resim

Boyama aşamasında, oluşturma ağacına geçilir ve içeriği ekranda görüntülemek için oluşturucunun "paint()" yöntemi çağrılır. Boyama işlemi, kullanıcı arayüzü altyapı bileşenini kullanır.

Küresel ve artımlı

Düzende olduğu gibi, boyama küresel de olabilir; ağacın tamamı boyanmış olabilir ya da artımlı olabilir. Artımlı boyamada, oluşturucuların bazıları tüm ağacı etkilemeyecek şekilde değişir. Değiştirilen oluşturucu, ekrandaki dikdörtgenini geçersiz kılar. Bu, işletim sisteminin bölgeyi "kirli bölge" olarak görmesine ve "boya" etkinliği oluşturmasına neden olur. İşletim sistemi bunu akıllıca yapar ve birkaç bölgeyi tek bir bölgede bir araya getirir. Oluşturucu, ana işlemden farklı bir işlemde olduğundan Chrome'da bu daha karmaşıktır. Chrome, işletim sistemi davranışını bir ölçüde simüle eder. Sunu, bu etkinlikleri dinler ve mesaj için, oluşturma köküne yetki verir. İlgili oluşturucuya ulaşılana kadar ağaçta gezinilir. Kendisini (ve genellikle alt öğelerini) yeniden boyayacaktır.

Boyama sırası

CSS2, boyama işleminin sırasını tanımlar. Aslında bu, öğelerin yığınlama bağlamlarında yığılma sırasıdır. Yığınlar arkadan öne doğru boyandığından bu sıra resmi etkiler. Bir blok oluşturucunun yığma sırası şu şekildedir:

  1. arka plan rengi
  2. arka plan resmi
  3. border
  4. çocuklar
  5. outline

Firefox görüntüleme listesi

Firefox, oluşturma ağacının üzerinden geçer ve boyanmış dikdörtgen için bir görüntüleme listesi oluşturur. Dikdörtgenle alakalı oluşturucuları, doğru boyama sırasında (oluşturucuların arka planları, ardından kenarlıklar vb.) içerir.

Bu şekilde, yeniden boyamak için ağaçtan birkaç kez geçmek yerine yalnızca bir kez geçilmesi gerekir. Tüm arka planlar, ardından tüm resimler, ardından tüm kenarlıklar vb. boyanır.

Firefox, diğer opak öğelerin tamamen altındaki öğeler gibi gizli olacak öğeler eklemeyerek işlemi optimize eder.

WebKit dikdörtgen depolama alanı

WebKit, yeniden boyamadan önce eski dikdörtgeni bit eşlem olarak kaydeder. Daha sonra, yalnızca yeni ve eski dikdörtgenler arasındaki deltayı boyar.

Dinamik değişiklikler

Tarayıcılar, bir değişikliğe yanıt olarak mümkün olan en az işlemi gerçekleştirmeye çalışır. Bu nedenle, bir öğenin renginde yapılan değişiklikler yalnızca öğenin yeniden boyanmasına neden olur. Öğenin konumunda yapılan değişiklikler, öğenin, alt öğelerinin ve muhtemelen kardeş öğelerinin düzenine ve yeniden boyanmasına neden olur. DOM düğümü eklemek, düğümün düzenine ve yeniden boyanmasına neden olur. "html" öğesinin yazı tipi boyutunun yükseltilmesi gibi büyük değişiklikler önbelleklerin geçersiz kılınmasına, geçişin yapılmasına ve ağacın tamamının yeniden boyanmasına neden olur.

Oluşturma motorunun iş parçacıkları

Oluşturma motoru tek iş parçacığı biçimindedir. Ağ işlemleri dışında neredeyse her şey tek bir iş parçacığında gerçekleşir. Firefox ve Safari'de bu, tarayıcının ana ileti dizisidir. Chrome'da sekme işlemi ana iş parçacığıdır.

Ağ işlemleri, birkaç paralel iş parçacığı tarafından gerçekleştirilebilir. Paralel bağlantı sayısı sınırlıdır (genellikle 2 - 6 bağlantı).

Etkinlik döngüsü

Tarayıcı ana iş parçacığı bir etkinlik döngüsüdür. Sürecin devam etmesini sağlayan sonsuz bir döngüdür. Etkinlikleri (düzen ve boyama etkinlikleri gibi) bekler ve işler. Bu, ana etkinlik döngüsüne ilişkin Firefox kodudur:

while (!mExiting)
    NS_ProcessNextEvent(thread);

CSS2 görsel modeli

Tuval

CSS2 spesifikasyonuna göre, tuval terimi "biçimlendirme yapısının oluşturulduğu alanı", yani tarayıcının içeriği boyadığı alanı tanımlar.

Tuval, alanın her boyutu için sonsuzdur, ancak tarayıcılar görüntü alanının boyutlarına göre bir başlangıç genişliği seçer.

www.w3.org/TR/CSS2/zindex.html uyarınca, başka bir alanın içinde yer alması halinde tuval şeffaftır, aksi takdirde tarayıcı tarafından tanımlanan bir renk verilir.

CSS Kutusu modeli

CSS kutusu modeli, doküman ağacındaki öğeler için oluşturulan ve görsel biçimlendirme modeline göre düzenlenmiş dikdörtgen kutuları açıklar.

Her kutunun bir içerik alanı (metin, resim vb.) ve isteğe bağlı olarak çevreleyen dolgu, kenarlık ve kenar boşluğu alanları vardır.

CSS2 kutu modeli
Şekil 19: CSS2 kutu modeli

Her düğüm bu tür kutular oluşturur.

Tüm öğeler, oluşturulacak kutunun türünü belirleyen bir "display" özelliğine sahiptir.

Örnekler:

block: generates a block box.
inline: generates one or more inline boxes.
none: no box is generated.

Varsayılan ayar satır içidir, ancak tarayıcı stil sayfası başka varsayılanlar ayarlayabilir. Örneğin: "div" öğesi için varsayılan görünüm blok şeklindedir.

Varsayılan stil sayfası örneğini şu adreste bulabilirsiniz: www.w3.org/TR/CSS2/sample.html.

Konumlandırma şeması

Üç şema vardır:

  1. Normal: Nesne, dokümandaki konumuna göre konumlandırılır. Bu, oluşturma ağacındaki yerinin DOM ağacındaki yeri gibi olduğu ve kutu türü ile boyutlarına göre düzenlendiği anlamına gelir
  2. Kayan: nesne önce normal akış gibi yerleştirilir, daha sonra mümkün olduğunca sola veya sağa taşınır
  3. Mutlak: Nesne, oluşturma ağacında, DOM ağacında olduğundan farklı bir yere yerleştirilmiştir

Konumlandırma şeması, "position" özelliği ve "float" özelliği tarafından ayarlanır.

  • statik ve göreceli ise normal bir akışa neden olur
  • mutlak ve sabit neden mutlak konumlandırma

Statik konumlandırmada hiçbir konum tanımlanmaz ve varsayılan konumlandırma kullanılır. Diğer şemalarda, yazar konumu belirtir: üst, alt, sol, sağ.

Kutunun yerleştirilme şekli şu unsurlara göre belirlenir:

  • Kutu türü
  • Kutu boyutları
  • Konumlandırma şeması
  • Resim boyutu ve ekran boyutu gibi harici bilgiler

Kutu türleri

Engelleme kutusu: Bir blok oluşturur - tarayıcı penceresinde kendi dikdörtgeni vardır.

Engelle kutusu.
Şekil 20: Engelle kutusu

Satır içi kutu: Kendi bloğu yoktur, ancak kapsayıcı bir bloğun içindedir.

Satır içi kutular.
Şekil 21: Satır içi kutular

Bloklar birbiri ardına dikey olarak biçimlendirilir. Satır içi satırlar yatay olarak biçimlendirilir.

Engelleme ve satır içi biçimlendirme&#39;yi tıklayın.
Şekil 22: Engelleme ve Satır İçi biçimlendirme

Satır içi kutular, çizgilerin veya "satır kutularının" içine yerleştirilir. Çizgiler en az en uzun kutunun yüksekliğindedir, ancak kutular "referans çizgisi" olarak hizalandığında daha uzun da olabilir. Başka bir deyişle, bir öğenin alt kısmı, alttaki başka bir kutunun bir noktasına hizalanır. Kapsayıcı genişliği yeterli değilse satır içi satırlar birkaç satıra yerleştirilir. Bu durum genellikle bir paragrafta gerçekleşir.

Çizgiler.
Şekil 23: Çizgiler

Konumlandırma

Akraba

Göreli konumlandırma - Her zamanki gibi konumlandırılır ve daha sonra, gerekli delta ile taşınır.

Göreli konumlandırma.
Şekil 24: Göreli konumlandırma

Kayanlar

Kayan kutu, çizginin soluna veya sağına kaydırılır. İlginç özellik, diğer kutuların etrafından akmasıdır. HTML:

<p>
  <img style="float: right" src="images/image.gif" width="100" height="100">
  Lorem ipsum dolor sit amet, consectetuer...
</p>

Şöyle görünecek:

Kayan noktalı.
Şekil 25: Kayan noktalı

Mutlak ve sabit

Düzen, normal akıştan bağımsız olarak tam olarak tanımlanır. Öğe, normal akışa katılmaz. Boyutlar kapsayıcıyla ilişkilidir. Sabitte kapsayıcı, görüntü alanıdır.

Sabit konumlandırma.
Şekil 26: Sabit konumlandırma

Katmanlı gösterim

Bu, Z-endeksi CSS özelliği tarafından belirtilir. Kutunun üçüncü boyutunu temsil eder: Kutunun "z ekseni" boyuncaki konumu.

Kutular gruplara ayrılır (buna bağlam yığınları denir). Her yığında önce arka öğeler ve kullanıcıya daha yakın olacak şekilde en üstteki ön öğeler boyanır. Örtüşme durumunda en üstteki öğe, eski öğeyi gizler.

Yığınlar, Z-endeksi özelliğine göre sıralanır. "Z-endeksi" özelliğine sahip kutular, yerel bir yığın oluşturur. Görüntü alanının dış yığını var.

Örnek:

<style type="text/css">
  div {
    position: absolute;
    left: 2in;
    top: 2in;
  }
</style>

<p>
  <div
    style="z-index: 3;background-color:red; width: 1in; height: 1in; ">
  </div>
  <div
    style="z-index: 1;background-color:green;width: 2in; height: 2in;">
  </div>
</p>

Sonuç şöyle olur:

Sabit konumlandırma.
Şekil 27: Sabit konumlandırma

Kırmızı div, işaretlemedeki yeşil div öğesinden önce olmasına ve normal akışta daha önce boyanmış olmasına rağmen z-endeksi özelliği daha yüksek olduğundan kök kutunun tuttuğu yığında daha ileri doğrudur.

Kaynaklar

  1. Tarayıcı mimarisi

    1. Grosskurth, Ahmet. Web Tarayıcıları İçin Referans Mimari (pdf)
    2. Gupta, Vineet. Tarayıcılar Nasıl Çalışır? - 1. Bölüm - Mimari
  2. Ayrıştırılıyor

    1. Aho, Sethi, Ullman, Derleyiciler: İlkeler, Teknikler ve Araçlar (diğer adıyla "Ejderha kitabı"), Addison-Wesley, 1986
    2. Rick Jelliffe. Cesur ve Güzel: HTML 5 için iki yeni taslak.
  3. Firefox

    1. L. David Baron, Faster HTML and CSS: Layout Engine Internals for Web Developers (Daha Hızlı HTML ve CSS: Web Geliştiricileri için Layout Engine Internals).
    2. L. David Baron, Faster HTML and CSS: Layout Engine Internals for Web Developers (Google teknik konuşma videosu)
    3. L. David Baron, Mozilla'nın Düzen Motoru
    4. L. David Baron, Mozilla Stil Sistemi Belgeleri
    5. Chris Waterson, HTML Yeniden Akışı Hakkında Notlar
    6. Chris Waterson, Gecko'ya Genel Bakış
    7. Alexander Larsson, The Life of an HTML HTTP request (Bir HTML HTTP isteğinin yaşamı)
  4. WebKit

    1. David Hyatt, CSS'yi uygulama(1. bölüm)
    2. David Hyatt, WebCore'a Genel Bakış
    3. David Hyatt, WebCore Rendering
    4. David Hyatt, The FOUC Problemi
  5. W3C Teknik Özellikleri

    1. HTML 4.01 Spesifikasyonu
    2. W3C HTML5 Spesifikasyonu
    3. Basamaklı Stil Sayfaları Düzey 2 Düzeltme 1 (CSS 2.1) Spesifikasyonu
  6. Tarayıcı derleme talimatları

    1. Firefox. https://developer.mozilla.org/Build_Documentation
    2. WebKit. http://webkit.org/building/build.html

Çeviriler

Bu sayfa Japoncaya iki kez çevrildi:

Korece ve Türkçe dillerinin harici olarak barındırılan çevirilerini görüntüleyebilirsiniz.

Hepinize teşekkür ederiz.