Modern web tarayıcılarının perde arkası
Önsöz
WebKit ve Gecko'nun şirket içi işlemleriyle ilgili bu kapsamlı rehber Bu, İsrailli geliştirici Tali Garsiel tarafından yapılan çok sayıda araştırmanın sonucudur. Birkaçından fazla yıl içinde, tarayıcılarla ilgili yayınlanan tüm verileri inceledi ve tarayıcı kaynak kodunu okumaya zaman ayırıyoruz. Yazdı:
Bir web geliştiricisi olarak, tarayıcı işlemlerinin iç dünyası hakkında bilgi edinin daha iyi kararlar almanıza ve gelişimin ardındaki gerekçeleri öğrenmenize yardımcı olur en iyi uygulamalara göz atın. Bu oldukça uzun bir belge olsa da, ayrıntılı bir inceleme sunmalısınız. Pişman olmazsınız.
Paul Ireland, Chrome Geliştirici İlişkileri
Giriş
Web tarayıcıları, en yaygın kullanılan yazılımlardır. Bu kılavuzda, Çevik yaklaşımın
perde arkasında çalışıyorlar. google.com
yazdığınızda ne olacağını göreceğiz.
basılı tutun.
Bahseteceğimiz tarayıcılar
Günümüzde masaüstünde kullanılan başlıca beş tarayıcı vardır: Chrome, Internet Explorer, Firefox, Safari ve Opera. Mobilde, ana tarayıcılar Android Tarayıcı, iPhone, Opera Mini ve Opera Mobile, UC Tarayıcı, Nokia S40/S60 tarayıcıları ve Chrome'dur. Opera tarayıcıları dışında, tümü WebKit tabanlıdır. Açık kaynak tarayıcılar olan Firefox, Chrome ve Safari'den (kısmen açık kaynak) örnekler vereceğim. StatCounter istatistiklerine göre (Haziran 2013 itibarıyla) Chrome, Firefox ve Safari, küresel masaüstü tarayıcı kullanımının yaklaşık% 71'ini oluşturur. 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 belgesidir, ancak PDF, resim veya başka tür bir içerik de olabilir. Kaynağın konumu, kullanıcı tarafından URI (Tekdüzen Kaynak Tanımlayıcısı) kullanılarak belirlenir.
Tarayıcının HTML dosyalarını yorumlama ve görüntüleme yöntemi, HTML ve CSS özelliklerinde belirtilmiştir. Bu spesifikasyonlar, web'in standartlar organizasyonu olan W3C (World Wide Web Consortium) kuruluşu tarafından korunmaktadır. Tarayıcılar yıllarca spesifikasyonların yalnızca bir kısmını karşıladı ve kendi uzantılarını geliştirdi. Bu da web yazarları için ciddi uyumluluk sorunlarına neden oluyordu. Bugün, tarayıcıların çoğu spesifikasyonlara hemen uymaktadır.
Tarayıcı kullanıcı arayüzlerinin birbirleriyle birçok ortak noktası vardır. Yaygın kullanıcı arayüzü öğeleri arasında şunlar bulunur:
- URI eklemek için adres çubuğu
- Geri ve ileri düğmeleri
- Yer işareti ekleme seçenekleri
- Geçerli dokümanları yenilemek veya yüklemeyi durdurmak için yenile ve durdur düğmeleri
- Sizi ana sayfanıza yönlendiren ana sayfa düğmesi
Tuhaf bir biçimde, tarayıcının kullanıcı arayüzü herhangi bir resmi spesifikasyonda belirtilmemiş; yalnızca, yıllara dayanan deneyimle şekillendirilen iyi uygulamalardan ve birbirlerini taklit eden tarayıcıların kullanıcı arayüzüyle ilgili olarak belirtiliyor. HTML5 spesifikasyonu bir tarayıcıda bulunması gereken kullanıcı arayüzü öğelerini tanımlamaz, ancak bazı ortak öğeleri listeler. Bunların arasında adres çubuğu, durum çubuğu ve araç çubuğu bulunur. Elbette, Firefox'un indirme yöneticisi gibi belirli bir tarayıcıya özel özellikler de vardır.
Üst düzey altyapı
Tarayıcının ana bileşenleri şunlardır:
- Kullanıcı arayüzü: Buna adres çubuğu, geri/ileri düğmesi, yer işareti ekleme menüsü vb. dahildir. İstenen sayfayı gördüğünüz pencere hariç, tarayıcının her bölümü görüntülenir.
- Tarayıcı motoru: Kullanıcı arayüzü ile oluşturma motoru arasındaki işlemleri sıralar.
- Oluşturma motoru: İstenen içeriğin görüntülenmesinden 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.
- Ağ iletişimi: Platformdan bağımsız bir arayüz arkasındaki farklı platformlarda farklı uygulamalar kullanarak HTTP istekleri gibi ağ çağrıları için.
- Kullanıcı arayüzü arka ucu: Birleşik kutular ve pencereler gibi temel widget'ları çizmek için kullanılır. Bu arka uç, platforma özgü olmayan genel bir arayüz sunar. Altında ise işletim sistemi kullanıcı arayüzü yöntemleri kullanılır.
- JavaScript çevirmeni. JavaScript kodunu ayrıştırmak ve yürütmek için kullanılır.
- Veri depolama. Bu bir kalıcılık katmanıdır. Tarayıcının, çerezler gibi her türlü veriyi yerel olarak kaydetmesi gerekebilir. Tarayıcılar localStorage, IndexedDB, WebSQL ve FileSystem gibi depolama mekanizmalarını da destekler.
![Tarayıcı bileşenleri](https://web.dev/static/articles/howbrowserswork/image/browser-components-9cd8ff834cc9c.png?authuser=5&hl=tr)
Chrome gibi tarayıcıların, her sekme için bir tane olmak üzere oluşturma motorunun birden çok örneğini çalıştırdığını unutmamak önemlidir. Her sekme ayrı bir işlemde çalışır.
Oluşturma motorları
Oluşturma motorunun sorumluluğu... Oluşturma, istenen içeriğin tarayıcı ekranında görüntülenmesidir.
Varsayılan olarak, oluşturma motoru HTML ve XML dokümanları ile resimlerini görüntüleyebilir. Eklentiler veya uzantılar aracılığıyla diğer veri türlerini gösterebilir; örneğin, bir PDF görüntüleyici eklentisi kullanarak PDF dokümanlarını görüntüleme. Ancak bu bölümde ana kullanım alanına odaklanacağız: HTML'yi ve CSS kullanılarak biçimlendirilmiş resimleri görüntüleme.
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 ortaya çıkmış ve Apple tarafından Mac ve Windows'u destekleyecek şekilde değiştirilmiş açık kaynaklı bir oluşturma motorudur.
Ana akış
Oluşturma motoru, istenen dokümanın içeriğini almaya başlar ağ katmanından değiştirilebilir. 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ışı](https://web.dev/static/articles/howbrowserswork/image/rendering-engine-basic-fl-2fba02b24e871.png?authuser=5&hl=tr)
Oluşturma motoru, HTML dokümanını ayrıştırmaya başlar ve "içerik ağacı" adı verilen bir ağaçta öğeleri DOM düğümlerine dönüştürür. Motor, hem harici CSS dosyalarındaki hem de stil öğelerindeki stil verilerini ayrıştırır. HTML'deki görsel talimatlarla birlikte bilgilerin stil özelliklerini ayarlama, başka bir ağaç oluşturmak için kullanılacaktır: oluşturma ağacı.
Oluşturma ağacı, renk ve boyutlar gibi görsel özelliklere sahip dikdörtgenler içerir. Dikdörtgenler ekranda görüntülenecek doğru sırada olmalıdır.
Oluşturma ağacı oluşturulduktan sonra bir "düzen" geçer bahsedeceğim. Bu, her bir düğüme ekranda görünmesi gereken yerin tam koordinatlarını vermek anlamına gelir. Sonraki aşama boyalama: Oluşturma ağacı geçilecek ve her düğüm, kullanıcı arayüzü arka uç katmanı kullanılarak boyanacaktır.
Bunun kademeli bir süreç olduğunu bilmeniz önemlidir. Oluşturma motoru, daha iyi bir kullanıcı deneyimi sağlamak için içerikleri mümkün olan 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ını beklemez. İçeriğin bazı bölümleri ayrıştırılıp görüntülenir. Süreç, ağdan gelmeyen içerikle devam eder.
Ana akış örnekleri
![WebKit ana akışı.](https://web.dev/static/articles/howbrowserswork/image/webkit-main-flow-b779d50c0cf28.png?authuser=5&hl=tr)
![Mozilla'nın Gecko oluşturma motoru ana akışı.](https://web.dev/static/articles/howbrowserswork/image/mozillas-gecko-rendering-b18e445544965.jpg?authuser=5&hl=tr)
Şekil 3 ve 4'ten, WebKit ve Gecko biraz farklı terminoloji kullansa da, akışın temelde aynı olduğunu görebilirsiniz.
Geko, görsel olarak biçimlendirilmiş öğeler ağacına "Çerçeve ağacı" adını verir. Her öğe bir çerçevedir. WebKit, "Oluşturma Ağacı" terimini kullanıyor ve "Oluşturma Nesneleri"nden oluşur. WebKit, "düzen" terimini kullanıyor için kullanılan bir dönüşüm yöntemidir. Gecko ise bunu "Yeniden Düzenleme" olarak adlandırır. "Ek" WebKit'in oluşturma ağacı oluşturmak için DOM düğümleri ile görsel bilgileri birbirine bağlama terimidir. Anlamsal olmayan küçük bir fark, Gecko'nun HTML ve DOM ağacı arasında fazladan bir katmana sahip olmasıdır. Buna "içerik havuzu" denir. DOM öğelerini üreten bir fabrikadır. Akışın her bir bölümü hakkında konuşacağız:
Ayrıştırma - genel
Ayrıştırma, oluşturma motoru içinde çok önemli bir işlem olduğundan, biraz daha ayrıntıya gireceğiz. Ayrıştırma hakkında küçük bir girişle başlayalım.
Bir belgenin ayrıştırılması, kodun kullanabileceği bir yapıya çevrilmesi 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ğacı düğümü.](https://web.dev/static/articles/howbrowserswork/image/mathematical-expression-t-6681a2511ead2.png?authuser=5&hl=tr)
Dilbilgisi
Ayrıştırma, dokümanın uyduğu söz dizimi kurallarına, yani yazıldığı dil veya biçime dayanır. Ayrıştırabileceğiniz her biçimin, kelime bilgisi ve söz dizimi kurallarından oluşan deterministik dil bilgisi olması gerekir. Buna bağlamsız dil bilgisi. İnsan dilleri bu tür diller 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özcüksel analiz ve söz dizimi analizi.
Sözcüksel analiz, girdiyi jetonlara ayırma işlemidir. Jetonlar dil sözlüğüdür, yani geçerli yapı taşlarının koleksiyonudur. İnsan dilinde ise bu dil için sözlükte geçen tüm kelimelerden oluşur.
Söz dizimi analizi, dil söz dizimi kurallarının uygulanmasıdır.
Ayrıştırıcılar genellikle işi iki bileşene böler: girişi geçerli jetonlara ayırmaktan sorumlu lexer (bazen jeton oluşturucu 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 ayırıcı.
Lexer, boşluklar ve satır sonları gibi alakasız karakterleri nasıl çıkaracağını biliyor.
![Kaynak dokümandan ağaçları ayrıştırmaya](https://web.dev/static/articles/howbrowserswork/image/from-source-document-par-c9c8c59da1ef2.png?authuser=5&hl=tr)
Ayrıştırma işlemi yinelemeli bir işlemdir. Ayrıştırıcı genellikle yeni bir jeton ister ve jetonu söz dizimi kurallarından biriyle eşleştirmeye çalışır. Bir kural eşleşirse 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 tüm 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 durum, 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: Girdi dokümanı başka bir biçime dönüştürülür. Buna örnek olarak derleme verilebilir. Kaynak kodu makine koduna derleyen derleyici, kodu önce bir ayrıştırma ağacına ayrıştırır ve ardından ağacı bir makine kodu belgesine çevirir.
![Derleme akışı](https://web.dev/static/articles/howbrowserswork/image/compilation-flow-57cfc3aa68a53.png?authuser=5&hl=tr)
Ayrıştırma örneği
Şekil 5'te, matematiksel bir ifadeden bir ayrıştırma ağacı oluşturduk. Basit bir matematiksel dil tanımlamayı deneyelim ve ayrıştırma işlemini görelim.
Söz dizimi:
- Dil söz dizimi yapı taşları ifadeler, terimler ve işlemlerdir.
- Dilimiz birçok ifade içerebilir.
- İfade, bir "terim" olarak tanımlanır ardından bir "operasyon" gelir. ve ardından başka bir terim
- İşlem, bir artı veya eksi jetonudur
- Terim, bir tam sayı jetonu veya ifadedir
2 + 3 - 1
girişini analiz edelim.
Bir kuralla eşleşen ilk alt dize 2
: 5. kurala göre bu bir terimdir.
İkinci eşleşme 2 + 3
değeridir: Bu, üçüncü kuralla eşleşir: bir terim ve ardından bir işlem ve ardından başka bir terim.
Bir sonraki eşleşme, yalnızca girişin sonunda isabet alır.
2 + 3
zaten bir terim olduğu için 2 + 3 - 1
bir ifadedir. Dolayısıyla, elimizde bir terimin ardından bir işlem gelen başka bir terim vardır.
2 + +
hiçbir kuralla eşleşmediği için geçersiz bir giriş.
Sözlük ve söz dizimi için resmi tanımlar
Kelime hazinesi 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 adı verilen bir biçimde tanımlanır. Dilimiz şu şekilde tanımlanacaktır:
expression := term operation term
operation := PLUS | MINUS
term := INTEGER | expression
Bir dilin, dil bilgisi bağlamsız dilbilgisi ise normal ayrıştırıcılar tarafından ayrıştırılabileceğini söyledik. Bağlamsız dil bilgisinin sezgisel tanımı, tamamen BNF'de ifade edilebilen bir dilbilgisidir. Resmi tanım için bkz. Bağlamsız dil bilgisi ile ilgili Wikipedia makalesi
Ayrıştırıcı türleri
İki tür ayrıştırıcı vardır: yukarıdan aşağıya ayrıştırıcılar ve aşağıdan yukarı ayrıştırıcılar. Anlaşılması kolay bir açıklama ise yukarıdan aşağıya ayrıştırıcıların söz diziminin üst düzey yapısını incelemesi ve 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 kademeli olarak söz dizimi kurallarına dönüştürür.
İki tür ayrıştırıcının örneğimizi nasıl ayrıştıracağına bakalım.
Yukarıdan aşağıya ayrıştırıcı daha üst düzey kuraldan başlar: 2 + 3
öğesini bir ifade olarak tanımlar. Daha sonra 2 + 3 - 1
, bir ifade olarak tanımlanır (İfadeyi tanımlama süreci gelişerek diğer kurallarla eşleşir, ancak başlangıç noktası en üst düzey kuraldır).
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 işlem, girişin sonuna kadar devam eder. Kısmen eşleşen ifade, ayrıştırıcının yığınına yerleştirilir.
Bu tür aşağıdan yukarı ayrıştırıcıya, giriş sağa kaydırıldığından (bir işaretçinin ilk olarak girişin başlangıcını işaret ettiğini ve sağa gittiğini düşünün) ve kademeli olarak söz dizimi kurallarına indirgenmiş olması nedeniyle, kaydırma azaltma ayrıştırıcısı bu tür bir ayrıştırıcı olarak adlandırılır.
Ayrıştırıcılar otomatik olarak oluşturuluyor
Ayrıştırıcı oluşturabilen araçlar vardır. Onlara dilinizin dil bilgisini (kelime hazinesini ve söz dizimi kurallarını) sağlarsınız ve çalışan bir ayrıştırıcı oluştururlar. Ayrıştırıcı oluşturmak, ayrıştırma konusunda derinlemesine bilgi gerektirir ve elle optimize edilmiş bir ayrıştırıcı oluşturmak kolay değildir. Bu nedenle, ayrıştırıcı oluşturucular çok yararlı olabilir.
WebKit, iyi bilinen iki ayrıştırıcı oluşturucu kullanır: Lexer oluşturmak için Flex, ayrıştırıcı oluşturmak için Bison (Lex ve Yacc adlı adlarla karşılaşabilirsiniz). Esnek giriş, jetonların normal ifade tanımlarını içeren bir dosyadır. Bizon'un girişi, BNF biçimindeki dil söz dizimi kurallarıdır.
HTML Ayrıştırıcı
HTML ayrıştırıcının işi, HTML işaretlemesini ayrıştırma ağacına dönüştürmektir.
HTML dil bilgisi
HTML sözlüğü ve söz dizimi, W3C kuruluşu tarafından oluşturulan spesifikasyonlarda tanımlanmıştır.
Ayrıştırma girişinde gördüğümüz gibi, dil bilgisi söz dizimi, BNF gibi biçimler kullanılarak resmi olarak tanımlanabilir.
Maalesef tüm geleneksel ayrıştırıcı konuları HTML için geçerli değildir (bunları yalnızca eğlence için açmadım; CSS ve JavaScript'i ayrıştırmada kullanılacaklar). HTML, ayrıştırıcıların ihtiyaç duyduğu bağlamsız dilbilgisiyle kolayca tanımlanamaz.
HTML - DTD (Belge Türü Tanımı) kavramını tanımlamak için resmi bir biçim vardır. Ancak bu, bağlamsız bir dil bilgisi değildir.
Bu ilk bakışta tuhaf görünüyor; HTML, XML'e oldukça yakındır. Çok sayıda XML ayrıştırıcısı vardır. HTML - XHTML'nin XML varyasyonu vardır. Peki aralarındaki büyük fark nedir?
Aralarındaki fark, HTML yaklaşımının daha "rahatlayıcı" olmasıdır: Belirli etiketleri atlamanıza (daha sonra dolaylı olarak eklenir) veya bazen başlangıç ya da bitiş etiketlerini atlamanıza olanak tanır ve bu böyle devam eder. Genel olarak "yumuşak" bir söz dizimini kullanmanız gerekir.
Bu görünüşte küçük bir ayrıntı, çok büyük bir fark yaratıyor. Bir yandan, HTML'nin bu kadar popüler olmasının en önemli 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. Özetle, dilbilgisi bağlamdan bağımsız olmadığı için 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çim, izin verilen tüm öğelerin tanımlarını, özelliklerini ve hiyerarşilerini içerir. Daha önce gördüğümüz gibi, HTML DTD bağlamsız bir dilbilgisi 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şaretleme için destek içerir. Amaç eski içeriklerle geriye dönük uyumluluk sağlamaktır. Geçerli katı DTD burada: www.w3.org/TR/html4/strict.dtd
DOM
Çıktı ağacı ("ayrıştırma ağacı"), DOM öğesi ve özellik düğümlerinden oluşan bir ağaçtır. DOM, Belge Nesne Modeli'nin kısaltmasıdır. HTML belgesinin nesne sunumu ve HTML öğelerinin dış dünyaya (JavaScript gibi) arayüzüdür.
Ağacın kökü "Doküman"dır nesnesini tanımlayın.
DOM'nin işaretleme ile neredeyse bire bir ilişkisi vardır. Ö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 dönüştürülür:
![Örnek işaretlemenin DOM ağacı](https://web.dev/static/articles/howbrowserswork/image/dom-tree-the-example-mar-70be67fe14c9a.png?authuser=5&hl=tr)
HTML gibi, DOM de W3C kuruluşu tarafından belirlenir. www.w3.org/DOM/DOMTR sayfasına göz atın. Dokümanların değiştirilmesine ilişkin genel bir spesifikasyondur. Belirli bir modülde HTML'ye özgü öğeler açıklanmaktadır. HTML tanımları şurada bulunabilir: 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, ağacın DOM arayüzlerinden birini uygulayan öğelerden oluştuğunu kastediyorum. Tarayıcılar, tarayıcı tarafından dahili olarak kullanılan diğer ö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.
Nedenler şunlardır:
- Dilin affedici doğası.
- Tarayıcıların, iyi bilinen geçersiz HTML durumlarını desteklemek için geleneksel hata toleransına sahip olması.
- Ayrıştırma işlemi yeniden 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ılamaz, tarayıcılar HTML'yi ayrıştırmak için özel ayrıştırıcılar oluşturur.
Ayrıştırma algoritması, HTML5 spesifikasyonunda ayrıntılı olarak açıklanmaktadır. Algoritma iki aşamadan oluşur: tokenizasyon ve ağaç inşası.
Tokenizasyon, girdiyi jetonlara ayrıştıran sözlüksel analizdir. 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, bir sonraki jetonu tanımak için sonraki karakteri tüketir ve girişin sonuna kadar bu şekilde devam eder.
![HTML ayrıştırma akışı (HTML5 spesifikasyonundan alınmıştır)](https://web.dev/static/articles/howbrowserswork/image/html-parsing-flow-taken-6118c51b92b56.png?authuser=5&hl=tr)
Tokenleştirme algoritması
Algoritmanın sonucu 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 tokenizasyon durumundan ve ağaç yapısından etkilenir. Bu, kullanılan aynı karakterin, mevcut duruma bağlı olarak doğru bir sonraki durum için farklı sonuçlar vereceği anlamına gelir. Algoritma, tam olarak açıklanamayacak kadar karmaşık olduğu için ilkeyi anlamamıza yardımcı olacak basit bir örneğe göz atalım.
Temel örnek - aşağıdaki HTML'yi tokenleştirme:
<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.
Bir a-z
karakterinin kullanılması "Başlangıç etiketi jetonu" oluşturulmasına neden olur ve 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, mevcut jeton yayınlanır ve durum tekrar "Veri durumu" olarak değişir.
<body>
etiketi aynı adımlarla ele alınacaktır.
Şimdiye kadar html
ve body
etiketleri yayınlandı. Şimdi "Veri durumuna" geri döndük.
Hello world
öğesinin H
karakterinin kullanılması, karakter jetonunun oluşturulmasına ve yayılmasına neden olur. Bu işlem, </body>
öğesinin <
değerine ulaşılana kadar devam eder. Hello world
öğesinin her karakteri için bir karakter jetonu yayınlayacağız.
Şimdi "Etiket açık durumuna" geri döndük.
Bir sonraki /
girdisinin kullanılması, end tag token
oluşturulmasına ve "Etiket adı durumu"na geçilmesine neden olur. >
değerine ulaşana 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ı gibi ele alınır.
![Örnek girişi şifrelendirme](https://web.dev/static/articles/howbrowserswork/image/tokenizing-example-input-9d0cc36689681.png?authuser=5&hl=tr)
Ağaç yapım algoritması
Ayrıştırıcı oluşturulduğunda Doküman nesnesi oluşturulur. Ağaç oluşturma aşamasında, kökünde Doküman bulunan DOM ağacı değiştirilir ve öğeler eklenir. Jeton oluşturucu tarafından yayınlanan her düğüm, ağaç oluşturucu tarafından işlenir. Spesifikasyon, her jeton için hangi DOM öğesinin ilgili olduğunu tanımlar ve bu jeton için oluşturulur. Öğe, DOM ağacına ve ayrıca açık öğeler 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 durum makinesi olarak da tanımlanır. Bu durumlar "ekleme modları" olarak adlandırılır.
Örnek giriş için ağaç oluşturma sürecine göz atalım:
<html>
<body>
Hello world
</body>
</html>
Ağaç oluşturma aşamasında verilen giriş, tokenizasyon aşamasından alınan bir jeton dizisidir. İlk mod "başlangıç modu"dur. "html"yi alma jeton "before html" moduna taşınır ve bu modda jetonun yeniden işlenmesine neden olur. Bu işlem, kök Doküman nesnesine eklenecek HTMLHTMLElement öğesinin oluşturulmasına neden olur.
Durum, "beforehead" olarak değiştirilir. "Gövde" kodu alınır. "head" öğesi olmasa da, örtülü olarak bir HTMLHeadElement oluşturulur ve ağaca eklenir.
Şimdi "head" (head) moduna ve ardından "ardından" moduna geçiyoruz. Gövde jetonu yeniden işlenir, bir HTMLBodyElement oluşturulup eklenir ve mod, "in body" değerine aktarılır.
"Hello world" ifadesinin karakter simgeleri dizenin alındığına dikkat edin. İlki, bir "Metin" oluşturulmasına ve eklenmesine neden olur ve diğer karakterler bu düğüme eklenir.
Gövde uç jetonunun alınması, aktarımın " after body" moduna geçmesine neden olur. Şimdi bizi " after body" moduna taşıyacak html bitiş etiketini alacağız. Dosya jetonunun sonunu almak, ayrıştırmayı sonlandırır.
![Örnek HTML'nin ağaç yapısı.](https://web.dev/static/articles/howbrowserswork/image/tree-construction-exampl-4e9757a851f96.gif?authuser=5&hl=tr)
Ayrıştırma sona erdiğinde gerçekleştirilecek işlemler
Bu aşamada, tarayıcı dokümanı etkileşimli olarak işaretler ve "ertelenmiş" durumundaki komut dosyalarını ayrıştırmaya başlar. mode: Doküman ayrıştırıldıktan sonra yürütülmesi gereken dosyalar. Bu işlemin ardından dokümanın durumu "tamamlandı" olarak ayarlanır. ve bir "yükleme" tetiklenecek.
Jetonlara ayırma ve ağaç oluşturma için tüm algoritmaları HTML5 spesifikasyonunda bulabilirsiniz.
Tarayıcılar hata toleransı
Hiçbir zaman "Geçersiz Söz Dizimi" almazsınız hatası verir. Tarayıcılar geçersiz içeriği düzeltir ve bu şekilde 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 etmem gerekir ("mytag" standart bir etiket değildir, "p" ve "div" öğelerinin yanlış iç içe yerleştirilmiş olması vb.) ancak tarayıcı bunu düzgün şekilde gösteriyor ve şikayet etmiyor. Ayrıştırıcı kodunun büyük bir kısmı HTML yazarı hatalarını düzeltmektedir.
Hata işleme tarayıcılarda oldukça tutarlıdır, ancak işin en güzel yanı, bu hatanın HTML spesifikasyonları arasında yer almamasıdır. Yer işareti ekleme ve geri-ileri düğmeleri gibi, bu da yıllar içinde tarayıcılarda gelişen bir şeydir. Birçok sitede tekrarlanan geçersiz HTML yapıları olduğu bilinmektedir 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ımlamaktadır. (WebKit, HTML ayrıştırıcı sınıfının başındaki yorumda bunu güzel bir şekilde özetler.)
Ayrıştırıcı, token atanmış girişleri belgeye ayrıştırarak belge ağacını oluşturur. Belge iyi bir şekilde biçimlendirilmişse ayrıştırılması kolay olur.
Maalesef düzgün biçimlendirilmemiş birçok HTML dokümanını işlemek zorundayız, bu nedenle ayrıştırıcının hatalar konusunda toleranslı olması gerekir.
En azından aşağıdaki hata durumlarıyla ilgili işlem yapmamız gerekir:
- Eklenen öğe bazı dış etiketlerin içinde açıkça yasaklanmıştır. Bu durumda, öğeyi yasaklayan etikete kadar olan tüm etiketleri kapatmalı ve daha sonra eklemeliyiz.
- Öğeyi doğrudan eklememize izin verilmez. Belgeyi yazan kişinin aradaki etiketleri unutmuş olması (veya aradaki etiketin isteğe bağlı olması) mümkün olabilir. Bu durum, şu etiketlerde geçerli olabilir: HTML HEAD BODY TBODY TR TD LI (bunu unutmadım mı?).
- Bir satır içi öğenin içine blok öğesi eklemek istiyoruz. Bir sonraki yüksek blok öğesine kadar tüm satır içi öğeleri kapatın.
- Bu işe yaramazsa, öğeyi eklememize izin verilene kadar öğeleri kapatın veya etiketi yoksayın.
Şimdi bazı WebKit hata toleransı örneklerine göz atalım:
<br>
yerine </br>
Bazı siteler <br>
yerine </br>
kullanıyor. WebKit, IE ve Firefox ile uyumlu olması için bunu <br>
gibi işler.
Kod:
if (t->isCloseTag(brTag) && m_document->inCompatMode()) {
reportError(MalformedBRError);
t->beginTag = true;
}
Hata işlemenin dahili olduğunu unutmayın: kullanıcıya gösterilmez.
Başıboş bir tablo
Tipik tablo, başka bir tablonun içinde bulunan ancak tablo hücresinin içinde bulunmayan 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ının dışına çıkarır. Tablolar artık kardeş olacak.
İç içe form öğeleri
Kullanıcının başka bir formun içine form koyması 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 ifade ediyor.
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
Bu durumda, yorum kendini gösterir.
if (t->tagName == htmlTag || t->tagName == bodyTag )
return;
Bu nedenle, web yazarları (WebKit hata toleransı kod snippet'inde örnek olarak görünmek istemiyorsanız) iyi oluşturulmuş HTML'ler yazın.
CSS ayrıştırma
Girişteki ayrıştırma kavramlarını hatırlıyor musunuz? HTML'nin aksine CSS, bağlamsız bir dil bilgisidir 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'nin sözlük ve söz dizimi dil bilgisini tanımlar.
Bazı örneklere göz atalım:
Sözlüksel dil bilgisi (sözlükler), her bir belirteç 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 (ör. sınıf adı) kısaltmasıdır. "ad" bir öğe kimliğidir ("#" ile belirtilir)
Söz dizimi dil bilgisi BNF'de açıklanmaktadı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çicidir. Küme ayraçlarının içindeki kısım, bu kural grubu tarafından uygulanan kuralları içerir.
Bu yapı, bu tanımda resmi olarak tanımlanmıştır:
ruleset
: selector [ ',' S* selector ]*
'{' S* declaration [ ';' S* declaration ]* '}' S*
;
Bu, kural kümesinin bir seçici veya isteğe bağlı olarak virgülle ve boşlukla ayrılmış bir dizi seçici olduğu (S, boşluk anlamına gelir) anlamına gelir. Kural kümesi, süslü ayraçlar ve bunların içinde noktalı virgülle ayrılmış bir bildirim veya isteğe bağlı olarak bir dizi bildirim içerir. "beyan" ve "selector" aşağıdaki BNF tanımlarıyla tanımlanacaktır.
WebKit CSS ayrıştırıcı
WebKit, CSS dil bilgisi 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ı girişinden hatırlayacağınız gibi, Bison aşağıdan yukarıya kaydırma-azaltma ayrıştırıcısı oluşturur. Firefox, manuel olarak yazılan yukarıdan aşağıya bir ayrıştırıcı kullanır. Her iki durumda da her CSS dosyası bir StyleSheet nesnesine 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.](https://web.dev/static/articles/howbrowserswork/image/parsing-css-4531ebee58764.png?authuser=5&hl=tr)
Komut dosyaları ve stil sayfaları için işleme sırası
Komut Dosyaları
Web modeli eşzamanlıdır. Yazarlar, ayrıştırıcı bir <script>
etiketine ulaştığında komut dosyalarının ayrıştırılmasını ve yürütülmesini bekler.
Dokümanın ayrıştırılması, komut dosyası yürütülene kadar durdurulur.
Komut dosyası harici ise kaynağın öncelikle ağdan getirilmesi gerekir. Bu da eşzamanlı olarak yapılır ve kaynak getirilene kadar ayrıştırma işlemleri durdurulur.
Bu model yıllardır kullanıldı ve HTML4 ve 5 spesifikasyonlarında da belirtildi.
Yazarlar "ertele"yi ekleyebilir özelliğini bir komut dosyasına yükleyebilirsiniz. Bu durumda, doküman ayrıştırmayı durdurmaz ve doküman ayrıştırıldıktan sonra yürütülür. HTML5, komut dosyasını farklı bir iş parçacığı tarafından ayrıştırılıp yürütülmesi için eşzamansız olarak işaretlemek üzere bir seçenek 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ığı belgenin geri kalanını ayrıştırır ve ağdan başka hangi kaynakların yüklenmesi gerektiğini bulup bunları yükler. Bu şekilde, kaynaklar paralel bağlantılara yüklenebilir ve genel hız iyileştirilir. 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ının farklı bir modeli vardır. Kavramsal olarak, stil sayfaları DOM ağacını değiştirmediği için bunları beklemek ve belge ayrıştırmasını durdurmak için bir neden yoktur. Bununla birlikte, belge ayrıştırma aşamasında stil bilgilerini isteyen komut dosyalarıyla ilgili bir sorun vardır. Stil henüz yüklenmemiş ve ayrıştırılmamışsa, komut dosyası yanlış yanıtlar alacaktır ve bu durum pek çok soruna yol açmış olabilir. Uç bir durum gibi görünse de oldukça yaygın bir durumdur. Firefox, yüklenmeye ve ayrıştırılmaya devam eden 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.
Ağaç yapımı oluşturma
DOM ağacı oluşturulurken tarayıcı başka bir ağaç olan oluşturma ağacını da oluşturur. Bu ağaç, görsel öğelerin gösterileceği sıraya göre sıralanmıştır. Belgenin görsel temsilidir. Bu ağacın amacı, içerikleri doğru sırada boyamayı sağlamaktır.
Firefox, oluşturma ağacındaki öğeleri "çerçeveler" olarak çağırır. WebKit, oluşturucu veya oluşturma nesnesi terimini kullanır.
Oluşturucu, kendini ve alt öğelerini yerleştirmeyi ve boyamayı iyi biliyor.
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 bir düğümün CSS kutusuna karşılık gelen dikdörtgen bir alanı temsil eder. Genişlik, yükseklik ve konum gibi geometrik bilgileri içerir.
Kutu türü "görüntülü reklam" sütunundan etkilenir. değeri (stil hesaplama bölümüne bakın). Görüntü özelliğine göre bir DOM düğümü için ne tür oluşturucunun oluşturulması gerektiğine karar vermeye yönelik WebKit kodunu aşağıda bulabilirsiniz:
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 denetimlerinde ve tablolarında özel çerçeveler 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. Örneğin, "head" öğesine dokunun. Ayrıca, görüntü değeri "none" değerine atanan öğeler de ağaçta görünmez (görünürlüğü "gizli" olan öğeler ağaçta görünür).
Çeşitli görsel nesnelere 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 ve diğeri düğme için. Ayrıca metin, genişlik bir satır için yeterli olmadığından birden çok satıra ayrıldığında, yeni satırlar ekstra oluşturucular olarak eklenir.
Birden fazla oluşturucuya başka bir örnek de bozuk HTML'dir. CSS spesifikasyonuna göre bir satır içi öğe yalnızca blok öğeleri veya yalnızca satır içi öğeleri içermelidir. Karma 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. Kayan öğeler ve kesinlikle konumlandırılmış öğeler akış dışındadır, ağacın farklı bir bölümüne yerleştirilmiş ve gerçek çerçeveyle eşlenmiştir. Yer tutucu çerçevenin olması gereken yer burasıdır.
![Oluşturma ağacı ve ilgili DOM ağacı.](https://web.dev/static/articles/howbrowserswork/image/the-render-tree-the-corr-f699894ef4c75.png?authuser=5&hl=tr)
Ağacı oluşturma akışı
Firefox'ta sunu, DOM güncellemeleri için işleyici olarak kaydedilir.
Sunum, çerçeve oluşturma yetkisini FrameConstructor
öğesine verir ve oluşturucu stili çözer (bkz. stil hesaplama) ve bir çerçeve oluşturur.
WebKit'te stili çözümleme ve oluşturucu oluşturma işlemine "ek" adı verilir. Her DOM düğümünün bir "attach" öğesi vardır yöntemidir. Ek eşzamanlı. DOM ağacına düğüm ekleme, yeni düğümü "attach" olarak çağırır yöntemidir.
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ığı nesneye (diğer tüm blokları içeren en üstteki blok) karşılık gelir. Boyutları görüntü alanıdır, yani tarayıcı penceresi görüntüleme alanı boyutlarıdır.
Firefox'ta ViewPortFrame
, WebKit'te ise RenderView
olarak adlandırılır.
Bu, dokümanın işaret ettiği oluşturma nesnesidir.
Ağacın geri kalanı, DOM düğümlerinin eklenmesi olarak oluşturulur.
İşleme modeliyle ilgili CSS2 spesifikasyonuna bakın.
Stil hesaplaması
Oluşturma ağacını oluşturmak, her oluşturma nesnesinin görsel özelliklerinin hesaplanmasını gerektirir. Bu, her bir öğenin stil özellikleri hesaplanarak yapılır.
Stil, HTML'de çeşitli kaynaklı stil sayfaları, satır içi stil öğeleri ve görsel özellikler ("bgcolor" özelliği gibi) içerir. Daha sonra, eşleşen CSS stili özelliklerine dönüştürülür.
Stil sayfalarının kaynağı; tarayıcının varsayılan stil sayfaları, sayfanın yazarı tarafından sağlanan 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, favori stillerinizi tanımlamanıza olanak sağlar). Örneğin Firefox'ta bu işlem, "Firefox Profili" bölümüne bir stil sayfası yerleştirerek yapılır. klasörü) açın.
Stil hesaplaması birkaç zorluğu da beraberinde getirir:
- Stil verileri, çok sayıda stil özelliğini barındıran çok büyük bir yapıdır ve bu durum hafıza sorunlarına neden olabilir.
Her öğenin eşleşme kurallarını bulmak, optimize edilmeyen öğeler için performans sorunlarına neden olabilir. Eşleşmeleri bulmak için her bir öğeye ait kural listesinin tamamını taşımak ciddi bir iştir. Seçicilerin yapısı karmaşık olabilir. Bu durum, eşleştirme sürecinin işe yaramadığı kanıtlanmış, gelecek vaat eden bir süreçle başlamasına neden olabilir. Bunun için başka bir yolun denenmesi gerekir.
Ö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 yol seçersiniz. Yalnızca iki div öğesinin olduğunu ve kuralın geçerli olmadığını öğrenmek için düğüm ağacını en üst düzeye taşımanız gerekebilir. Daha sonra ağaçtaki diğer yolları denemeniz gerekir.Kuralların uygulanması, kuralların hiyerarşisini tanımlayan oldukça karmaşık basamak kuralları içerir.
Tarayıcıların bu sorunlarla nasıl karşılaştığına bakalım:
Stil verisi paylaşılıyor
WebKit düğümleri, stil nesnelerine (RenderStyle) başvuruyor. Bu nesneler, bazı koşullarda düğümler tarafından paylaşılabilir. Düğümler kardeş veya kuzentir ve:
- Öğeler aynı fare durumunda olmalıdır (ör. bir tanesi :hover içinde olamazken diğeri olamaz)
- Hiçbir öğenin kimliği olmamalıdır
- Etiket adları eşleşmelidir
- Sınıf özellikleri eşleşmelidir
- Eşlenen özellik grubu aynı olmalıdır
- Bağlantı durumları eşleşmelidir
- Odak durumları eşleşmelidir
- Hiçbir öğe özellik seçiciden etkilenmeyecektir. Bu durumdan etkilenenler, seçici içindeki herhangi bir konumda özellik seçici kullanan bir seçici eşleşmesi bulunması olarak tanımlanır.
- Öğelerde satır içi stil özelliği olmamalıdır
- Kullanılan eşdüzey seçici bulunmamalıdır. WebCore, herhangi bir eşdüzey seçici ile karşılaşıldığında genel bir anahtarla karşılaşır ve mevcut olduğunda tüm belge için stil paylaşımını devre dışı bırakır. Buna, + seçici ile :first-child ve :last-child gibi seçiciler dahildir.
Firefox kural ağacı
Firefox'ta stil hesaplamasını kolaylaştırmak için fazladan iki ağaç bulunur: kural ağacı ve stil bağlam ağacı. WebKit'te de stil nesneleri bulunur. Ancak bunlar stil bağlamı ağacı gibi bir ağaçta depolanmaz. Yalnızca DOM düğümü ilgili stile işaret eder.
![Firefox stili bağlam ağacı.](https://web.dev/static/articles/howbrowserswork/image/firefox-style-context-tre-f578b75b74df7.png?authuser=5&hl=tr)
Stil bağlamları bitiş değerleri içerir. Değerler, tüm eşleşen kuralları doğru sırayla uygulayıp ve bunları mantıksal değerlerden somut değerlere dönüştüren işlemler gerçekleştirerek hesaplanır. Örneğin, mantıksal değer ekranın bir yüzdesiyse hesaplanır ve mutlak birimlere dönüştürülür. Kural ağacı fikri çok zekice. Tekrar hesaplamayı önlemek için bu değerlerin düğümler arasında paylaşılmasını sağlar. Bu sayede alandan da tasarruf etmiş olursunuz.
Eşleşen tüm kurallar bir ağaçta depolanır. Bir yoldaki en alt düğümler daha yüksek önceliğe sahiptir. Ağaç, bulunan kural eşleşmelerine ilişkin tüm yolları içerir. Kuralların depolanması geç gerçekleştirilir. Ağaç, her düğümün başında hesaplanmaz, ancak bir düğüm stilinin hesaplanması gerektiğinde, hesaplanan yollar ağa eklenir.
Ana fikir, ağaç yollarını bir sözlükte kelimeler olarak görmektir. Bu kural ağacını daha önce hesapladığımızı varsayalım:
![Hesaplanmış kural ağacı](https://web.dev/static/articles/howbrowserswork/image/computed-rule-tree-f874f412bbaf.png?authuser=5&hl=tr)
İçerik ağacındaki başka bir öğeye ilişkin kuralları eşleştirmemiz gerektiğini ve eşleşen kuralların (doğru sırada) B-E-I olduğunu bulun. Bu yol, ağaçta zaten mevcut çünkü A-B-E-I-L yolunu hesaplamıştık. Artık daha az işimiz olacak.
Ağacın çalışmamızı nasıl kurtardığını görelim.
struct'lara bölme
Stil bağlamları struct'a ayrılır. Bu struct'lar, kenarlık veya renk gibi belirli bir kategoriye ilişkin stil bilgilerini içerir. Bir struct'daki 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çta tüm struct'ları (hesaplanan son değerleri içeren) önbelleğe alarak bize yardımcı olur. Buradaki fikir, alt düğüm struct için bir 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 öğenin stil bağlamını hesaplarken, önce kural ağacındaki bir yolu hesaplarız veya mevcut bir yolu kullanırız. Daha sonra, yeni stil bağlamımızda struct'ları doldurmak için yoldaki kuralları uygulamaya başlarız. Yolun en alt düğümünden başlarız. Düğüm en yüksek önceliğe (genellikle en spesifik seçici) sahip olan düğümden başlar ve yapısı dolana kadar ağacın bir kısmını çekeriz. Bu kural düğümünde struct için bir spesifikasyon yoksa büyük ölçüde optimizasyon yapabiliriz. Ağacı tam olarak belirten ve işaret eden bir düğüm bulana kadar ağaçta yukarı doğru ilerleriz. Bu, en iyi optimizasyondur. struct'ın tamamı paylaşılır. Bu, bitiş değerlerin hesaplanması ve bellekten tasarruf edilmesini sağlar.
Kısmi tanımlar bulursak struct doldurulana kadar ağaçta yukarı çıkarız.
struct'ımızın tanımını bulamazsak, struct'ın "devralınan" bir struct olması durumunda bağlam ağacında üst öğemizin struct'ını işaret ederiz. Bu örnekte, struct'ları da başarıyla paylaştık. Sıfırlanmış bir struct ise varsayılan değerler kullanılır.
En belirgin düğüm değer eklediyse onu gerçek değerlere dönüştürmek için bazı ek hesaplamalar yapmamız gerekir. Daha sonra, sonucu çocuklar tarafından kullanılabilmesi için ağaç düğümünde önbelleğe alırız.
Bir öğenin aynı ağaç düğümüne işaret eden kardeşi veya erkek kardeşi olması durumunda, stil bağlamının tamamı bunlar arasında paylaşılabilir.
Bir örnek verelim: Bu HTML kodunu
<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>
Ayrıca aşağıdaki kurallar da geçerlidir:
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'ı doldurmamız gerektiğini varsayalım: color struct ve margin struct. struct rengi yalnızca tek bir üye içerir: renk Kenar boşluğu struct'ı dört tarafı içerir.
Sonuçta ortaya çıkan kural ağacı aşağıdaki gibi görünecektir (düğümler şu düğüm adıyla işaretlenmiştir: kuralın işaret ettiği kuralın numarası):
![Kural ağacı](https://web.dev/static/articles/howbrowserswork/image/the-rule-tree-23f05b0dac33f.png?authuser=5&hl=tr)
Bağlam ağacı şöyle görünecektir (düğüm adı: işaret ettikleri kural düğümü):
![Bağlam ağacı.](https://web.dev/static/articles/howbrowserswork/image/the-context-tree-771124b7cb80d.png?authuser=5&hl=tr)
HTML'yi ayrıştırdığımızı ve ikinci <div>
etiketine ulaştığımızı varsayalım. Bu düğüm için bir stil bağlamı oluşturmamız ve stil yapılarını doldurmamız gerekiyor.
Kuralları eşleştirecek ve <div>
için eşleşme kurallarının 1, 2 ve 6 olduğunu belirleyeceğiz.
Bu, ağaçta zaten öğemizin kullanabileceği bir yol olduğu ve kural 6 için (kural ağacındaki F düğümü) yalnızca bir düğüm daha eklememiz gerektiği anlamına gelir.
Stil bağlamı oluşturup bağlam ağacına ekleyeceğiz. Yeni stil bağlamı, kural ağacındaki F düğümüne işaret eder.
Şimdi stil struct'larını doldurmamız gerekiyor. Kenar boşluğunu doldurarak başlayacağız. Son kural düğümü (F), kenar boşluğuna ekleme yapmadığından, önceki düğüm eklemesinde hesaplanan önbelleğe alınmış bir struct'ı bulup kullanana kadar ağaçta yukarı çıkabiliriz. Bu bilgiyi, kenar boşluğu kurallarını belirten en üstteki düğüm olan B düğümünde buluruz.
color struct'ın bir tanımımız olduğundan önbelleğe alınmış bir struct'ı kullanamayız. Rengin bir özelliği olduğundan diğer özellikleri doldurmak için ağacın yukarısına çıkmamız gerekmez. Son değeri hesaplayıp (dizeyi RGB'ye dönüştürün vb.) ve bu düğümde hesaplanan struct'ı önbelleğe alacağız.
İkinci <span>
öğesi üzerinde çalışmak daha da kolaydır. Kurallara uyulacak ve önceki kaplumbağa gibi G kuralına işaret ettiği sonucuna varacağız.
Aynı düğüme işaret eden kardeşlerimiz olduğu için stil bağlamının tamamını paylaşabilir ve sadece önceki kapsamın bağlamına işaret edebiliriz.
Üst öğeden devralınan kuralları içeren struct'larda, önbelleğe alma işlemi içerik ağacında yapılır (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 eklediğimizde:
p {font-family: Verdana; font size: 10px; font-weight: bold}
Bu durumda, bağlam ağacında div öğesinin alt öğesi olan paragraf öğesi, üst öğesiyle aynı yazı tipini paylaşmış olabilir. Bu durum, paragraf için yazı tipi kuralı belirtilmediyse geçerlidir.
Kural ağacı olmayan WebKit'te, eşleşen bildirimler dört kez geçilir. İlk olarak, önemli olmayan yüksek öncelikli özellikler uygulanır (öncelikleri görüntüleme gibi diğerleri bağımlı olduğu için ilk olarak uygulanması gereken özellikler), ardından yüksek öncelikli önemli olanlar, normal öncelikli önemsiz özellikler ve normal öncelikli önemli kurallar uygulanır. Bu, birden çok kez görünen özelliklerin doğru basamak sırasına göre çözümleneceği anlamına gelir. Son kazanan kazanır.
Özetlemek gerekirse: Stil nesnelerini (tamamen veya bunların içindeki struct'ların 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 bir eşleşme için kuralları manipüle etme
Stil kuralları için birkaç kaynak vardır:
- Harici stil sayfalarında veya stil öğelerinde CSS kuralları.
css p {color: blue}
. - Şunlar gibi satır içi stil özellikleri:
html <p style="color: blue" />
. - HTML görsel özellikleri (alakalı stil kurallarıyla eşlenir)
html <p bgcolor="blue" />
. Son ikisi stil özelliklerine sahip olduğundan öğeyle kolayca eşleştirilebilir ve HTML özellikleri anahtar olarak öğe kullanılarak eşlenebilir.
Daha önce 2. sorunda belirtildiği gibi, CSS kuralı eşleştirmesi daha karmaşık olabilir. Zorluğu çözmek için kurallar daha kolay erişim sağlayacak şekilde değiştirilir.
Stil sayfası ayrıştırıldıktan sonra kurallar, seçiciye göre çeşitli karma eşlemelerinden birine eklenir. Kimlik, sınıf adı ve etiket adına göre haritalar ve bu kategorilere uymayan her şey için genel bir harita bulunur. Seçici bir kimlik ise kural kimlik eşlemesine, bir sınıfsa sınıf haritasına da eklenir.
Bu değiştirme, kuralları eşleştirmeyi çok daha kolay hale getirir. Her beyana bakmanız gerekmez: Haritalardan bir öğeyle ilgili kuralları çıkarabiliriz. Bu optimizasyon kuralların% 95'inden fazlasını ortadan kaldırır, böylece eşleştirme sürecinde(4.1) bu kuralların dikkate alınması bile gerekmez.
Ö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şlemesine, üçüncüsü de etiket eşlemesine eklenir.
Aşağıdaki HTML parçası için;
<p class="error">an error occurred</p>
<div id=" messageDiv">this is a message</div>
Önce p öğesine ilişkin kuralları bulmaya çalışacağız. Sınıf haritası bir "hata" içerecek "p.error" kuralının altında bulunur. Div öğesinin, kimlik eşlemesinde (anahtar kimliktir) ve etiket eşlemesinde ilgili kuralları olur. Dolayısıyla geriye kalan tek iş, anahtarlar tarafından ayıklanan kurallardan hangilerinin gerçekten eşleştiğini bulmaktır.
Örneğin, div kuralı şuysa:
table div {margin: 5px}
Anahtar en sağdaki seçici olduğu için yine de etiket haritasından çıkarılır. Ancak, tablo üst öğesi olmayan div öğemizle eşleşmez.
Bu değiştirme işlemini 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 genel). Özellik, eşleşen kurallardan herhangi biri tarafından tanımlanmamışsa bazı mülkler ü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 basamak sırası gelir.
Stil özelliğinin bildirimi birkaç stil sayfasında ve bir stil sayfasında birkaç kez görünebilir. Bu, kuralların uygulanma sırasının çok önemli olduğu anlamına gelir. Buna "basamak" adı verilir sipariş. CSS2 spesifikasyonuna göre basamak sırası (düşükten yükseğe):
- Tarayıcı bildirimleri
- Kullanıcı normal bildirimleri
- Yazar normal bildirimleri
- Yazarla ilgili önemli beyanlar
- Kullanıcılarla ilgili önemli beyanlar
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 değerlendirilir.
Belirginlik
Seçici netliği CSS2 spesifikasyonu tarafından şu şekilde tanımlanır:
- ait olduğu bildirim bir "style" ise sayı 1 özelliği, aksi takdirde 0 (= a) olmalıdır
- seçicideki kimlik özelliklerinin sayısını say (= b)
- seçicideki diğer özelliklerin ve sözde sınıfların sayısını say (= c)
- seçicideki öğe adlarının ve sözde öğelerin sayısını say (= d)
Dört sayıyı a-b-c-d (büyük bir tabana sahip bir sayı sisteminde) birleştirmek belirliliği elde etmenizi sağlar.
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 kullanabilirsiniz. Çok düşük bir ihtimal olarak a=17 ise 17 haneli bir sayı tabanlı sayı girmeniz gerekir. Daha sonra durum, aşağıdaki gibi bir seçici kullanıldığında ortaya çıkabilir: html body div div p... (seçicinizde 17 etiket olması 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 baloncuk sıralama, büyük listelerde ise birleştirme sıralama özelliğini kullanır.
WebKit, kurallar için >
operatörünü geçersiz kılarak sıralama 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ğini gösteren bir işaret kullanır. Stil, ekleme sırasında tam olarak yüklenmediyse yer tutucular kullanılır ve dokümanda işaretlenir. Bu durumda, stil sayfaları yüklendikten sonra yer tutucular yeniden hesaplanır.
Düzen
Oluşturucu oluşturulup ağaca eklendiğinde bir konumu ve boyutu olmaz. Bu değerlerin hesaplanmasına düzen veya yeniden düzenleme adı verilir.
HTML, akış tabanlı bir düzen modeli kullanır. Böylece, çoğu zaman geometrinin tek bir geçişte hesaplanması mümkündür. Daha sonra "akışta" olan öğeler genellikle "akışta" daha önceki öğelerin geometrisini etkilemez. Bu nedenle düzen, dokümanda soldan sağa, yukarıdan aşağıya ilerleyebilir. İstisnalar vardır: Örneğin, HTML tabloları için birden fazla geçiş gerekli olabilir.
Koordinat sistemi kök çerçeveye bağlıdır. Üst ve sol koordinatlar kullanılır.
Düzen, yinelemeli bir işlemdir. 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 gereken her oluşturucu için geometrik bilgileri hesaplar.
Kök oluşturucunun konumu 0,0 ve boyutları görüntü alanıdır (tarayıcı penceresinin görünür bölümü).
Tüm oluşturucuların bir "düzeni" vardır veya "yeniden düzenle" yönteminde 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 kurmamak için tarayıcılar, bahsedeceğim. Değiştirilen veya eklenen bir oluşturucu, kendisini ve alt öğelerini "kirli" olarak işaretler: düzen gerekiyor.
İki işaret vardır: "kirli" ve "çocuklar kirli" Bu, oluşturucunun kendisi iyi olsa bile, düzene ihtiyacı olan en az bir alt öğeye sahip olduğu anlamına gelir.
Genel ve artımlı düzen
Düzen, oluşturma ağacının tamamında tetiklenebilir - bu "genel"dir kullanır. Bunun nedeni şunlar olabilir:
- Yazı tipi boyutu değişikliği gibi tüm oluşturucuları etkileyen genel bir stil değişikliği.
- Bir ekranın yeniden boyutlandırılması nedeniyle
Düzen artımlı olabilir, yalnızca kirli oluşturucular yerleştirilir (bu durum ek düzen gerektirecek bazı hasarlara neden olabilir).
Oluşturucular kirli olduğunda artımlı düzen (eşzamansız olarak) tetiklenir. Örneğin, ağdan ekstra içerik geldikten ve DOM ağacına eklendikten sonra oluşturma ağacına yeni oluşturucular eklendiğinde.
![Artımlı düzen.](https://web.dev/static/articles/howbrowserswork/image/incremental-layout-da3da0a148135.png?authuser=5&hl=tr)
Eşzamansız ve Eşzamanlı düzen
Artımlı düzen eşzamansız olarak yapılır. Firefox "yeniden düzenleme komutlarını" sıraya alıyor bir planlayıcı bu komutların toplu yürütülmesini tetikler. WebKit'te, artımlı düzeni yürüten bir zamanlayıcı da vardır. Ağaç geçilir ve "kirli"dir oluşturucularının düzeni bozuldu.
"offsetHeight" gibi stil bilgileri isteyen komut dosyaları artımlı düzeni eşzamanlı olarak tetikleyebilir.
Genel düzen genellikle eşzamanlı olarak tetiklenir.
Düzen, bazen kaydırma konumu gibi bazı özelliklerin değişmesi nedeniyle bir ilk düzenden sonra geri çağırma olarak tetiklenir.
Optimizasyonlar
Bir düzen "yeniden boyutlandırma" ile tetiklendiğinde veya oluşturucu konumundaki(boyutta değil) bir değişiklik olursa, oluşturulan 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 metin alanlarına eklenen metinler gibi çevresini etkilemediği durumlarda gerçekleşebilir (aksi takdirde, her tuş vuruşu kökten başlayan bir düzeni tetikler).
Düzen süreci
Düzen genellikle aşağıdaki kalıbı kullanır:
- Üst oluşturucu kendi genişliğini belirler.
- Ebeveyn, alt öğeleri gözden geçirir ve:
- Alt oluşturucuyu yerleştirin (x ve y değerlerini ayarlar).
- Gerekirse alt düzeni çağırırlar (kirli olanlar, genel bir düzendeyiz veya başka bir nedenle, alt öğenin boyunu hesaplayan bir alt öğe düzeni).
- Üst öğe, kendi yüksekliğini ayarlamak için alt öğelerin birikimli yüksekliklerini, kenar boşlukları ve dolgu yüksekliklerini kullanır. Bu, üst oluşturucunun üst öğesi tarafından kullanılır.
- Kirli bitini false (yanlış) olarak ayarlar.
Firefox bir "durum" kullanır nesnesini(nsHTMLReflowState) döndürür ("yeniden düzenleme" olarak adlandırılır). Diğerlerinin yanı sıra eyalet, üst öğe genişliğini de içerir.
Firefox düzeninin çıktısı "metrics" şeklindedir. (nsHTMLReflowMetrics) şeklindedir. Oluşturucu hesaplanan yüksekliğini içerir.
Genişlik hesaplaması
Oluşturucunun genişliği, kapsayıcı bloğunun genişliği, oluşturucunun stili "width" (genişlik) kullanılarak hesaplanır kenar boşlukları ve kenarlıklar vardır.
Örneğin, aşağıdaki div öğesinin genişliği:
<div style="width: 30%"/>
WebKit tarafından şu şekilde hesaplanır(calcWidth sınıfı RenderBox yöntemi):
- Kapsayıcı genişliği, mevcut kapsayıcıların maksimum genişliği ve 0'dır. Bu örnekte kullanılabilirGenişlik değeri, şu şekilde hesaplanan contentWidthtir:
clientWidth() - paddingLeft() - paddingRight()
clientwidth ve clientHeight, bir nesnenin iç kısmını gösterir (kenarlık ve kaydırma çubuğu hariç).
Öğelerin genişliği "width"dir stil özelliğini gönderin. Kapsayıcı genişliğinin yüzdesi hesaplanarak mutlak bir değer olarak hesaplanır.
Yatay kenarlıklar ve dolgular eklenmiştir.
Şimdiye kadar bu "tercih edilen genişlik" hesaplaması yapılıyordu. Artık 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ünemez birim) küçükse minimum genişlik kullanılır.
Bir düzen gerektiğinde değerler önbelleğe alınır, ancak genişlik değişmez.
Satır Sonu
Bir düzenin ortasındaki oluşturucu, bozulması gerektiğine karar verdiğinde durur ve düzenin bozulması gereken üst öğesine yayılır. Üst öğe, onlarda ek oluşturucuları ve çağrı düzenini oluşturur.
Resim
Boyama aşamasında, oluşturma ağacı geçilir ve oluşturucunun "paint()" işlevi yöntemi çağrılır. Boyama, kullanıcı arayüzü altyapı bileşenini kullanır.
Küresel ve artımlı
Düzen gibi boyama da küresel (ağaçın tamamı boyanmış) veya 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örtgeni geçersiz kılar. Bu durum, işletim sisteminin bunu "kirli bölge" olarak görmesine neden olur. ve bir "boya" oluşturmak unutmayın. İşletim sistemi bunu akıllıca yapar ve birkaç bölgeyi tek bir bölge altında birleştirir. 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. Sunum bu etkinlikleri dinler ve mesajı, oluşturma köküne aktarır. İlgili oluşturucuya ulaşılana kadar ağaçtan geçilir. Kendini (ve genellikle çocuklarını) yeniden boyayacak.
Boyama sırası
CSS2, boyama işleminin sırasını tanımlar. Bu, öğelerin yığma bağlamlarında yığılma sırasıdır. Bazlar sırttan öne doğru boyandığı için bu sıra boyamayı etkiler. Blok oluşturucunun yığın sıralaması aşağıdaki gibidir:
- arka plan rengi
- arka plan resmi
- border
- çocuklar
- 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 ilgili oluşturucuları doğru tablo sıralamasında (oluşturucuların arka planları, kenarlıklar vb.) içerir.
Böylece, ağaç bir kez yeniden boyamak için birkaç kez değil, yalnızca bir kez geçilmesi gerekir. Tüm arka planlar, resimler, sonra tüm kenarlıklar boyanır.
Firefox, diğer opak öğelerin tamamen altındaki öğeler gibi, gizli olacak öğeleri 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 karşılık olarak mümkün olan en az düzeyde işlem yapmaya çalışır. Bu nedenle bir öğenin renginde yapılan değişiklikler, yalnızca yeniden boyanmasına neden olur. Öğe konumunda yapılan değişiklikler, öğenin, alt öğelerinin ve muhtemelen kardeşlerin düzenine ve yeniden boyanmasına neden olur. DOM düğümü eklemek, düğümün düzenine ve yeniden boyanmasına neden olur. "html"nin yazı tipi boyutunu artırmak gibi büyük değişiklikler öğesi, önbelleklerin geçersiz kılınmasına, tüm ağacın yeniden düzenlenmesine ve yeniden boyanmasına neden olur.
Oluşturma motorunun iş parçacıkları
Oluşturma motoru, tek iş parçacıklıdır. 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 iş parçacığıdır. Chrome'da bu, sekme işlemi ana iş parçacığıdır.
Ağ işlemleri, birkaç paralel iş parçacığı kullanılarak gerçekleştirilebilir. Paralel bağlantıların sayısı sınırlıdır (genellikle 2-6 bağlantı).
Etkinlik döngüsü
Tarayıcının 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ü için Firefox kodudur:
while (!mExiting)
NS_ProcessNextEvent(thread);
CSS2 görsel modeli
Tuval
CSS2 spesifikasyonuna göre, tuval terimi, tarayıcının içeriği boyadığı "biçimlendirme yapısının oluşturulduğu alanı" tanımlar.
Zemin, alanın her boyutu için sınırsızdır 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 adresine göre, tuval başka bir yerdeyse şeffaf, değilse tarayıcı tarafından tanımlanmış bir renk verilir.
CSS Box modeli
CSS kutu modeli, belge ağacındaki öğeler için oluşturulan ve görsel biçimlendirme modeline göre hazırlanan dikdörtgen kutuları açıklar.
Her kutunun bir içerik alanı (ör. metin, resim vb.) ve isteğe bağlı olarak çevresindeki dolgu, kenarlık ve kenar boşluğu alanları vardır.
![CSS2 kutu modeli](https://web.dev/static/articles/howbrowserswork/image/css2-box-model-9c2ab852d1fb4.jpg?authuser=5&hl=tr)
Her düğüm bu tür 0...n kutu oluşturur.
Tüm öğelerde "display" bulunuyor özelliği ile birlikte oluşturulacak kutu türünü belirler.
Örnekler:
block: generates a block box.
inline: generates one or more inline boxes.
none: no box is generated.
Varsayılan, satır içidir ancak tarayıcı stil sayfası başka varsayılanlar ayarlayabilir. Örneğin: "div" için varsayılan ekran öğesi bloktur.
Varsayılan stil sayfası örneğini şu adreste bulabilirsiniz: www.w3.org/TR/CSS2/sample.html.
Konumlandırma şeması
Üç şema vardır:
- Normal: Nesne dokümandaki konumuna göre konumlandırılır. Bu, onun oluşturma ağacındaki yerinin DOM ağacındaki yeri gibi olduğu ve kutu türüne ve boyutlarına göre düzenlendiği anlamına gelir
- Bolluk: Nesne önce normal akış gibi yerleştirilmiştir, ardından mümkün olduğunca sola veya sağa hareket ettirilir
- Mutlak: Nesne, oluşturma ağacında DOM ağacından farklı bir yere yerleştirilmiştir
Konumlandırma şeması "konum" ile belirlenir. özelliği ve "kayan" özelliğini gönderin.
- statik ve göreceli olması normal akışa neden olur
- mutlak ve sabit neden mutlak konumlandırma
Statik konumlandırmada herhangi 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 aşağıdakilere göre belirlenir:
- Kutu türü
- Kutu boyutları
- Konumlandırma şeması
- Resim boyutu ve ekran boyutu gibi harici bilgiler
Kutu türleri
Blok kutusu: bir blok oluşturur, tarayıcı penceresinde kendi dikdörtgeni bulunur.
![Engelle kutusu.](https://web.dev/static/articles/howbrowserswork/image/block-box-b5c0bff4a44d2.png?authuser=5&hl=tr)
Satır içi kutu: Kendi bloğu yoktur ancak içeren bir blokun içindedir.
![Satır içi kutular.](https://web.dev/static/articles/howbrowserswork/image/inline-boxes-a9ff03002e7e2.png?authuser=5&hl=tr)
Bloklar art arda dikey olarak biçimlendirilir. Satır içi satırlar yatay olarak biçimlendirilir.
![Engelle ve satır içi biçimlendirme.](https://web.dev/static/articles/howbrowserswork/image/block-inline-formatting-a8450c63cf457.png?authuser=5&hl=tr)
Satır içi kutular, satırların veya "satır kutularının" içine yerleştirilir. Çizgiler en az en uzun kutu kadar uzundur, ancak kutular "referans çizgisi" ile hizalandığında daha uzun olabilir - bir öğenin alt kısmının, alttan sonra başka bir kutunun bir noktasına hizalandığı anlamına gelir. Kapsayıcı genişliği yeterli değilse satır içi öğeler birkaç satıra yerleştirilir. Bu genellikle bir paragrafta gerçekleşir.
![Çizgiler.](https://web.dev/static/articles/howbrowserswork/image/lines-68c55a378a7ff.png?authuser=5&hl=tr)
Konumlandırma
Akraba
Göreli konumlandırma: Her zamanki gibi konumlandırılır ve daha sonra, gerekli delta kadar taşınır.
![Göreli konumlandırma.](https://web.dev/static/articles/howbrowserswork/image/relative-positioning-fceed0670b8c5.png?authuser=5&hl=tr)
Kayanlar
Kayan kutu, bir çizginin soluna veya sağına kaydırılır. İşin ilginç yanı, diğer kutuların etrafından akıyor olması. 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.](https://web.dev/static/articles/howbrowserswork/image/float-dd9b790210284.png?authuser=5&hl=tr)
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ıya bağlıdır. Sabit modda kapsayıcı, görüntü alanıdır.
![Sabit konumlandırma.](https://web.dev/static/articles/howbrowserswork/image/fixed-positioning-881933fcb1a2f.png?authuser=5&hl=tr)
Katmanlı temsil
Bu, Z-endeksi CSS mülkü tarafından belirtilir. Kutunun üçüncü boyutunu, yani "z ekseni" boyunca konumunu gösterir.
Kutular, yığınlara ayrılır (yığma bağlamları olarak adlandırılır). Her yığında önce arkadaki öğeler, kullanıcıya daha yakın olacak şekilde en üstte olan ileri öğeler boyanır. Örtüşme olması durumunda en üstteki öğe, önceki öğeyi gizler.
Yığınlar, z-endeksi özelliğine göre sıralanır. "Z-endeksi" içeren kutular yerel bir grup oluşturur. Görüntü alanında dış grup bulunur.
Ö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.](https://web.dev/static/articles/howbrowserswork/image/fixed-positioning-84a46b366dc9a.png?authuser=5&hl=tr)
Kırmızı div, işaretlemede yeşil div'den önce gelmesine ve daha önce normal akışta boyanmasına rağmen, z-endeksi özelliği daha yüksek olduğundan, kök kutunun tuttuğu yığında daha ileri düzeydedir.
Kaynaklar
Tarayıcı mimarisi
- Grosskurth, Ahmet. Web Tarayıcıları için Referans Mimari (pdf)
- Gupta, Vineet. Tarayıcılar Nasıl Çalışır? - Bölüm 1 - Mimari
Ayrıştırma
- Aho, Sethi, Ullman, Derleyiciler: İlkeler, Teknikler ve Araçlar (diğer adıyla "Ejderha kitabı"), Addison-Wesley, 1986
- Rick Jelliffe. Cesur ve Güzel: HTML 5 için iki yeni taslak.
Firefox
- L. David Baron, Daha hızlı HTML ve CSS: Web Geliştiricileri için Layout Engine Dahilileri.
- L. David Baron, Fast HTML and CSS: Layout Engine Internals for Web Developers (Google teknik konuşma videosu)
- L. David Baron, Mozilla Layout Engine
- L. David Baron, Mozilla Style System Belgeleri
- Chris Waterson, Notes on HTML Reflow
- Chris Waterson, Gecko Overview (Gecko'ya Genel Bakış)
- Alexander Larsson, The Life of an HTML HTTP request (Bir HTML HTTP isteğinin ömrü)
WebKit
- David Hyatt, CSS'yi Uygulama(1. bölüm)
- David Hyatt, An Overview of WebCore
- David Hyatt, WebCore Oluşturma
- David Hyatt, The FOUC Problem
W3C Özellikleri
Tarayıcı oluşturma talimatları
- Firefox ile bağlantı kurun. https://developer.mozilla.org/Build_Documentation
- WebKit'e gidin. http://webkit.org/building/build.html
Çeviriler
Bu sayfa iki kez Japoncaya çevrildi:
- Tarayıcılar Nasıl Çalışır? - Modern Web Tarayıcılarının Perde Arkası (ja) Sahibi: @kosei
- ブラウザってどうやって動いてるの?(モダンWEBブラウザシーンの裏側 Hazırlayan: @ikeike443 ve @kiyoto01 ile iletişime geçebilirsiniz.
Harici olarak barındırılan çevirileri görüntüleyebilirsiniz: Korece ve Türkçe.
Hepinize teşekkür ederiz.