Markdown'da Shadow DOM ile Model Kitaplıkları Oluşturma

Yayınlanan: 2022-03-10
Kısa özet ↬ Bazı insanlar belge yazmaktan nefret eder, bazıları ise sadece yazmaktan nefret eder. Ben yazmayı seviyorum; aksi takdirde, bunu okumazdın. Yazmayı sevmeme yardımcı oluyor çünkü profesyonel rehberlik sunan bir tasarım danışmanı olarak yazmak, yaptığım işin büyük bir parçası. Ama kelime işlemcilerden nefret ediyorum, nefret ediyorum. Teknik web belgeleri yazarken (okuyun: kalıp kitaplıkları), kelime işlemciler sadece itaatsiz değil, aynı zamanda uygunsuzdur. İdeal olarak, satır içinde belgelediğim bileşenleri eklememe izin veren bir yazma modu istiyorum ve bu, belgelerin kendisi HTML, CSS ve JavaScript'ten yapılmadığı sürece mümkün değil. Bu yazıda, kısa kodlar ve gölge DOM kapsülleme yardımı ile Markdown'a kod demolarını kolayca dahil etmek için bir yöntem paylaşacağım.

Bir masaüstü kelime işlemcisi kullanan tipik iş akışım şuna benzer:

  1. Belgenin başka bir bölümüne kopyalamak istediğim metni seçin.
  2. Uygulamanın söylediğimden biraz daha fazlasını veya daha azını seçtiğini unutmayın.
  3. Tekrar deneyin.
  4. Vazgeçin ve daha sonra yapmak istediğim seçimin eksik kısmını eklemeye (veya fazla kısmı kaldırmaya) karar verin.
  5. Seçimi kopyalayıp yapıştırın.
  6. Yapıştırılan metnin biçimlendirmesinin orijinalinden bir şekilde farklı olduğunu unutmayın.
  7. Orijinal metinle eşleşen stil ön ayarını bulmaya çalışın.
  8. Ön ayarı uygulamayı deneyin.
  9. Yazı tipi ailesini ve boyutunu manuel olarak bırakın ve uygulayın.
  10. Yapıştırılan metnin üzerinde çok fazla boşluk olduğuna dikkat edin ve boşluğu kapatmak için “Geri Al”a basın.
  11. Söz konusu metnin aynı anda birkaç satır yükseldiğini, üstündeki başlık metnine katıldığını ve stilini benimsediğini unutmayın.
  12. Ölümlülüğümü düşün.

Teknik web belgeleri yazarken (okuyun: kalıp kitaplıkları), kelime işlemciler sadece itaatsiz değil, aynı zamanda uygunsuzdur. İdeal olarak, satır içinde belgelediğim bileşenleri eklememe izin veren bir yazma modu istiyorum ve bu, belgelerin kendisi HTML, CSS ve JavaScript'ten yapılmadığı sürece mümkün değil. Bu yazıda, kısa kodlar ve gölge DOM kapsülleme yardımı ile Markdown'a kod demolarını kolayca dahil etmek için bir yöntem paylaşacağım.

Bir M, bir aşağı ok artı Markdown ve Shadown Dom'u simgeleyen karanlıkta gizlenmiş bir dedektif
Atlamadan sonra daha fazlası! Aşağıdan okumaya devam edin ↓

CSS ve İşaretleme

CSS hakkında ne söyleyeceğinizi söyleyin, ancak kesinlikle piyasadaki herhangi bir WYSIWYG düzenleyicisinden veya kelime işlemcisinden daha tutarlı ve güvenilir bir dizgi aracıdır. Niye ya? Çünkü hangi stilleri gerçekten nereye götürmeyi planladığınızı ikinci kez tahmin etmeye çalışan üst düzey bir kara kutu algoritması yok. Bunun yerine, çok açıktır: Hangi öğelerin hangi koşullarda hangi stilleri alacağını tanımlarsınız ve bu kurallara uyar.

CSS ile ilgili tek sorun, onun muadili olan HTML'yi yazmanızı gerektirmesidir. Büyük HTML sevenler bile, yalnızca düzyazı içerik üretmek istediğinizde, onu manuel olarak yazmanın zor olduğunu kabul ederler. İşte burada Markdown devreye giriyor. Kısa ve öz söz dizimi ve azaltılmış özellik seti ile öğrenmesi kolay ama yine de - program aracılığıyla HTML'ye dönüştürüldüğünde - CSS'nin güçlü ve öngörülebilir dizgi özelliklerinden yararlanabilen bir yazma modu sunar. Statik web sitesi oluşturucuları ve Ghost gibi modern blog platformları için fiili format haline gelmesinin bir nedeni var.

Daha karmaşık, ısmarlama işaretlemenin gerekli olduğu durumlarda, çoğu Markdown ayrıştırıcısı girdide ham HTML'yi kabul eder. Bununla birlikte, kişi karmaşık biçimlendirmeye ne kadar çok güvenirse, kişinin yazma sistemi daha az teknik olanlar veya zamanı ve sabrı kısıtlı olanlar için o kadar az erişilebilir olur. Kısa kodların devreye girdiği yer burasıdır.

Hugo'da Kısa Kodlar

Hugo, Google'da geliştirilmiş çok amaçlı, derlenmiş bir dil olan Go ile yazılmış statik bir site oluşturucudur. Eşzamanlılık (ve şüphesiz, tam olarak anlayamadığım diğer düşük seviyeli dil özellikleri) nedeniyle Go, Hugo'yu ışık hızında bir statik web içeriği oluşturucusu yapar. Smashing Magazine'in yeni versiyonu için Hugo'nun seçilmesinin birçok nedeninden biri de budur.

Performans bir yana, zaten aşina olabileceğiniz Ruby ve Node.js tabanlı oluşturuculara benzer şekilde çalışır: Şablonlar aracılığıyla işlenen Markdown artı meta veriler (YAML veya TOML). Sara Soueidan, Hugo'nun temel işlevleri hakkında mükemmel bir başlangıç ​​kitabı yazdı.

Benim için Hugo'nun öldürücü özelliği, kısa kodların uygulanmasıdır. WordPress'ten gelenler, konsepte zaten aşina olabilir: öncelikle üçüncü taraf hizmetlerin karmaşık yerleştirme kodlarını dahil etmek için kullanılan kısaltılmış bir sözdizimi. Örneğin, WordPress, yalnızca söz konusu Vimeo videosunun kimliğini alan bir Vimeo kısa kodu içerir.

 [vimeo 44633289]

Köşeli parantezler, içeriklerinin bir kısa kod olarak işlenmesi ve içerik ayrıştırıldığında tam HTML yerleştirme işaretlemesine genişletilmesi gerektiğini belirtir.

Go şablon işlevlerini kullanan Hugo, özel kısa kodlar oluşturmak için son derece basit bir API sağlar. Örneğin, Markdown içeriğime dahil etmek için basit bir Codepen kısa kodu oluşturdum:

 Some Markdown content before the shortcode. Aliquam sodales rhoncus dui, sed congue velit semper ut. Class aptent taciti sociosqu ad litora torquent. {{<codePen VpVNKW>}} Some Markdown content after the shortcode. Nulla vel magna sit amet dui lobortis commodo vitae vel nulla sit amet ante hendrerit tempus.

Hugo, derleme sırasında kısa kodu ayrıştırmak için otomatik olarak kısa shortcodes alt klasöründe codePen.html adlı bir şablon arar. Uygulamam şöyle görünüyor:

 {{ if .Site.Params.codePenUser }} <iframe height='300' scrolling='no' title="code demonstration with codePen" src='//codepen.io/{{ .Site.Params.codepenUser | lower }}/embed/{{ .Get 0 }}/?height=265&theme-id=dark&default-tab=result,result&embed-version=2' frameborder='no' allowtransparency='true' allowfullscreen='true'> <div> <a href="//codepen.io/{{ .Site.Params.codePenUser | lower }}/pen/{{ .Get 0 }}">See the demo on codePen</a> </div> </iframe> {{ else }} <p class="site-error"><strong>Site error:</strong> The <code>codePenUser</code> param has not been set in <code>config.toml</code></p> {{ end }}

Go şablon paketinin nasıl çalıştığı hakkında daha iyi bir fikir edinmek için Hugo'nun “Go Template Primer”ına başvurmak isteyeceksiniz. Bu arada, sadece aşağıdakilere dikkat edin:

  • Oldukça çirkin ama yine de güçlü.
  • {{ .Get 0 }} kısmı, sağlanan ilk (ve bu durumda, yalnızca) bağımsız değişkeni - Codepen Kimliğini almak içindir. Hugo, HTML öznitelikleri gibi sağlanan adlandırılmış bağımsız değişkenleri de destekler.
  • . sözdizimi geçerli bağlamı ifade eder. Yani, .Get 0 , "Geçerli kısa kod için sağlanan ilk bağımsız değişkeni al" anlamına gelir.

Her durumda, kısa kodların kurabiyeden bu yana en iyi şey olduğunu düşünüyorum ve Hugo'nun özel kısa kodlar yazmak için uygulaması etkileyici. Araştırmamdan, Jekyll içeriklerini benzer etki için kullanmanın mümkün olduğunu belirtmeliyim, ancak onları daha az esnek ve güçlü buluyorum.

Üçüncü Taraflar Olmadan Kod Demoları

Codepen (ve mevcut diğer kod oyun alanları) için çok zamanım var, ancak bu tür içeriği bir model kitaplığına dahil etmenin doğal sorunları var:

  • Bir API kullanır, bu nedenle çevrimdışı çalışmak için kolayca veya verimli bir şekilde yapılamaz.
  • Yalnızca deseni veya bileşeni temsil etmez; kendi markasıyla sarılmış kendi karmaşık arayüzüdür. Bu, odağın bileşen üzerinde olması gerektiğinde gereksiz gürültü ve dikkat dağınıklığı yaratır.

Bir süredir, kendi iframe'lerimi kullanarak bileşen demolarını yerleştirmeye çalıştım. İframe'i, demoyu kendi web sayfası olarak içeren yerel bir dosyaya yönlendiririm. iframe'leri kullanarak, üçüncü bir tarafa güvenmeden stil ve davranışı kapsüllemeyi başardım.

Ne yazık ki, iframe'ler oldukça hantaldır ve dinamik olarak yeniden boyutlandırılması zordur. Yazma karmaşıklığı açısından, ayrı dosyaların tutulmasını ve bunlara bağlantı verilmesini de gerektirir. Bileşenlerimi, yalnızca onları çalıştırmak için gereken kod da dahil olmak üzere yerinde yazmayı tercih ederim. Belgelerini yazarken demolar yazabilmek istiyorum.

demo Kısa Kodu

Neyse ki Hugo, kısa kod etiketlerini açma ve kapama arasında içerik içeren kısa kodlar oluşturmanıza olanak tanır. İçerik, {{ .Inner }} kullanılarak kısa kod dosyasında bulunur. Öyleyse, şöyle bir demo kısa kodu kullanacağımı varsayalım:

 {{<demo>}} This is the content! {{</demo>}}

“İçerik bu!” onu ayrıştıran demo.html şablonunda {{ .Inner }} olarak mevcut olacaktır. Bu, satır içi kod demolarını desteklemek için iyi bir başlangıç ​​noktasıdır, ancak kapsüllemeyi ele almam gerekiyor.

Stil Kapsülleme

Kapsülleme stilleri söz konusu olduğunda, endişelenecek üç şey vardır:

  • üst sayfadan bileşen tarafından devralınan stiller,
  • bileşenden stilleri devralan üst sayfa,
  • stiller, bileşenler arasında istemeden paylaşılıyor.

Çözümlerden biri, CSS seçicilerini, bileşenler arasında ve bileşenler ile sayfa arasında çakışma olmayacak şekilde dikkatli bir şekilde yönetmektir. Bu, bileşen başına ezoterik seçiciler kullanmak anlamına gelir ve bu, kısa ve okunabilir kod yazarken düşünmek zorunda kalacağım bir şey değildir. İç çerçevelerin avantajlarından biri, stillerin varsayılan olarak kapsüllenmiş olmasıdır, bu nedenle button { background: blue } yazabilir ve bunun yalnızca iframe içinde uygulanacağından emin olabilirim.

Bileşenlerin sayfadan stil devralmasını engellemenin daha az yoğun bir yolu, seçilen bir üst öğe üzerinde initial ​​değeriyle all özelliğini kullanmaktır. Bu öğeyi demo.html dosyasında ayarlayabilirim:

 <div class="demo"> {{ .Inner }} </div>

Ardından, all: initial öğesinin her örneğin çocuklarına yayılan örneklerine uygulamam gerekiyor.

 .demo { all: initial }

initial davranışı oldukça… kendine özgüdür. Pratikte, etkilenen öğelerin tümü yalnızca kendi kullanıcı aracısı stillerini benimsemeye geri döner (örneğin, <h2> öğeleri için display: block ). Ancak, uygulandığı öğenin — class=“demo” — belirli kullanıcı aracısı stillerinin açıkça eski haline getirilmesi gerekir. Bizim durumumuzda, bu sadece display: block , çünkü class=“demo” bir <div> .

 .demo { all: initial; display: block; }

Not: Şimdiye kadar all Microsoft Edge'de desteklenmemektedir, ancak değerlendirme aşamasındadır. Destek, aksi takdirde, güven verici derecede geniştir. Bizim amaçlarımız için, revert alma değeri daha sağlam ve güvenilir olurdu, ancak henüz hiçbir yerde desteklenmemektedir.

Gölge DOM'u Kısa Kodu Yapıyor

all: initial kullanmak, satır içi bileşenlerimizi dış etkilere karşı tamamen bağışık hale getirmez (özgünlük hala geçerlidir), ancak ayrılmış demo sınıfı adıyla uğraştığımız için stillerin ayarlanmadığından emin olabiliriz. Çoğunlukla html ve body gibi düşük özgüllükteki seçicilerden devralınan stiller elenecektir.

Bununla birlikte, bu yalnızca üst öğeden bileşenlere gelen stiller ile ilgilidir. Bileşenler için yazılan stillerin sayfanın diğer bölümlerini etkilemesini önlemek için, kapsüllenmiş bir alt ağaç oluşturmak için gölge DOM kullanmamız gerekecek.

Bir stil <button> öğesini belgelemek istediğimi hayal edin. button öğesi seçicinin kalıp kitaplığının kendisindeki <button> öğelerine veya aynı kitaplık sayfasındaki diğer bileşenlere uygulanacağından korkmadan aşağıdakine benzer bir şey yazabilmek istiyorum.

 {{<demo>}} <button>My button</button> <style> button { background: blue; padding: 0.5rem 1rem; text-transform: uppercase; } </style> {{</demo>}}

İşin püf noktası, kısa kod şablonunun {{ .Inner }} bölümünü almak ve onu yeni bir ShadowRoot innerHTML olarak eklemektir. Bunu şöyle uygulayabilirim:

 {{ $uniq := .Inner | htmlEscape | base64Encode | truncate 15 "" }} <div class="demo"></div> <script> (function() { var root = document.getElementById('demo-{{ $uniq }}'); root.attachShadow({mode: 'open'}); root.innerHTML = '{{ .Inner }}'; })(); </script>
  • $uniq , bileşen kapsayıcısını tanımlamak için bir değişken olarak ayarlanır. Benzersiz bir dize oluşturmak için bazı Go şablon işlevlerinde borular kullanır… umarım(!) — bu kurşun geçirmez bir yöntem değildir; sadece örnekleme amaçlıdır.
  • root.attachShadow , bileşen kapsayıcısını bir gölge DOM ana bilgisayarı yapar.
  • ShadowRoot innerHTML , artık kapsüllenmiş CSS'yi içeren {{ .Inner }} kullanarak dolduruyorum.

JavaScript Davranışına İzin Verme

Bileşenlerime JavaScript davranışını da dahil etmek istiyorum. İlk başta, bunun kolay olacağını düşündüm; ne yazık ki innerHTML aracılığıyla eklenen JavaScript ayrıştırılmaz veya yürütülmez. Bu, bir <template> öğesinin içeriğinden içe aktarılarak çözülebilir. Uygulamamı buna göre değiştirdim.

 {{ $uniq := .Inner | htmlEscape | base64Encode | truncate 15 "" }} <div class="demo"></div> <template> {{ .Inner }} </template> <script> (function() { var root = document.getElementById('demo-{{ $uniq }}'); root.attachShadow({mode: 'open'}); var template = document.getElementById('template-{{ $uniq }}'); root.shadowRoot.appendChild(document.importNode(template.content, true)); })(); </script>

Şimdi, örneğin çalışan bir geçiş düğmesinin satır içi demosunu ekleyebiliyorum:

 {{<demo>}} <button>My button</button> <style> button { background: blue; padding: 0.5rem 1rem; text-transform: uppercase; } [aria-pressed="true"] { box-shadow: inset 0 0 5px #000; } </style> <script> var toggle = document.querySelector('[aria-pressed]'); toggle.addEventListener('click', (e) => { let pressed = e.target.getAttribute('aria-pressed') === 'true'; e.target.setAttribute('aria-pressed', !pressed); }); </script> {{</demo>}}

Not: Geçiş düğmeleri ve Inclusive Components için erişilebilirlik hakkında derinlemesine yazdım.

JavaScript Kapsülleme

Şaşırtıcı bir şekilde JavaScript, CSS'nin gölge DOM'da olması gibi otomatik olarak kapsüllenmez. Diğer bir deyişle, bu bileşenin örneğinden önce ana sayfada başka bir [aria-pressed] düğmesi varsa, bunun yerine document.querySelector bunu hedeflerdi.

İhtiyacım olan şey, yalnızca demonun alt ağacı için document eşdeğerdir. Bu oldukça ayrıntılı olsa da tanımlanabilir:

 document.getElementById('demo-{{ $uniq }}').shadowRoot;

Demo kapsayıcıların içindeki öğeleri hedeflemem gerektiğinde bu ifadeyi yazmak zorunda kalmak istemedim. Böylece, ifadeyi yerel bir demo değişkenine atadığım ve bu atamayla kısa kod aracılığıyla sağlanan ön ekli komut dosyalarına atadığım bir hack buldum:

 if (script) { script.textContent = `(function() { var demo = document.getElementById(\'demo-{{ $uniq }}\').shadowRoot; ${script.textContent} })()` } root.shadowRoot.appendChild(document.importNode(template.content, true));

Bu, yerinde olduğunda, demo , herhangi bir bileşen alt ağacı için document eşdeğeri olur ve geçiş düğmemi kolayca hedeflemek için demo.querySelector kullanabilirim.

 var toggle = demo.querySelector('[aria-pressed]');

demo değişkeninin - ve bileşen için kullanılan tüm devam eden değişkenlerin - global kapsamda olmaması için, demonun komut dosyası içeriğini hemen çağrılan bir işlev ifadesine (IIFE) eklediğimi unutmayın. Bu şekilde, demo herhangi bir kısa kodun komut dosyasında kullanılabilir, ancak yalnızca eldeki kısa koda atıfta bulunur.

ECMAScript6'nın kullanılabildiği yerlerde, yalnızca let veya const deyimlerini içeren parantezler ile "blok kapsamı" kullanarak yerelleştirme elde etmek mümkündür. Bununla birlikte, blok içindeki diğer tüm tanımların da let veya const ( var eschewing) kullanması gerekir.

 { let demo = document.getElementById(\'demo-{{ $uniq }}\').shadowRoot; // Author script injected here }

Gölge DOM Desteği

Tabii ki, yukarıdakilerin tümü yalnızca gölge DOM sürüm 1'in desteklendiği durumlarda mümkündür. Chrome, Safari, Opera ve Android oldukça iyi görünüyor, ancak Firefox ve Microsoft tarayıcıları sorunlu. attachShadow kullanılamadığı durumlarda desteği özellik algılamak ve bir hata mesajı sağlamak mümkündür:

 if (document.head.attachShadow) { // Do shadow DOM stuff here } else { root.innerHTML = 'Shadow DOM is needed to display encapsulated demos. The browser does not have an issue with the demo code itself'; }

Veya biraz büyük bir bağımlılık (60 KB+) ve farklı bir API anlamına gelen Shady DOM ve Shady CSS uzantısını dahil edebilirsiniz. Rob Dodson, başlamanıza yardımcı olmak için paylaşmaktan mutluluk duyacağım basit bir demo sağlama nezaketini gösterdi.

Bileşenler İçin Başlıklar

Temel satır içi demo işlevi yerindeyken, çalışma demolarını belgeleriyle birlikte hızlı bir şekilde satır içi yazmak çok kolay. Bu bize, "Demoyu etiketlemek için bir başlık sağlamak istersem?" gibi sorular sorabilme lüksünü veriyor. Bu, daha önce belirtildiği gibi, Markdown ham HTML'yi desteklediğinden zaten mümkündür.

 <figure role="group" aria-labelledby="caption-button"> {{<demo>}} <button>My button</button> <style> button { background: blue; padding: 0.5rem 1rem; text-transform: uppercase; } </style> {{</demo>}} <figcaption>A standard button</figcaption> </figure>

Bununla birlikte, bu değiştirilmiş yapının tek yeni kısmı, başlığın kendisinin ifadesidir. Çıktıya sağlamak için basit bir arayüz sağlamak, gelecekteki benliğimi - ve kısa kodu kullanan diğer herkesi - zamandan ve emekten tasarruf etmek ve kodlama yazım hataları riskini azaltmak için daha iyi. Bu, kısa koda adlandırılmış bir parametre sağlayarak mümkündür - bu durumda, basitçe adlandırılmış caption :

 {{<demo caption="A standard button">}} ... demo contents here... {{</demo>}}

Adlandırılmış parametrelere şablonda erişilebilir, yeterince basit olan {{ .Get "caption" }} gibi. Altyazının ve bu nedenle çevreleyen <figure> ve <figcaption> isteğe bağlı olmasını istiyorum. if cümleciklerini kullanarak, ilgili içeriği yalnızca kısa kodun bir başlık argümanı sağladığı durumlarda sağlayabilirim:

 {{ if .Get "caption" }} <figcaption>{{ .Get "caption" }}</figcaption> {{ end }}

İşte tam demo.html şablonu şimdi nasıl görünüyor (kuşkusuz, biraz karışık, ama hile yapıyor):

 {{ $uniq := .Inner | htmlEscape | base64Encode | truncate 15 "" }} {{ if .Get "caption" }} <figure role="group" aria-labelledby="caption-{{ $uniq }}"> {{ end }} <div class="demo"></div> {{ if .Get "caption" }} <figcaption>{{ .Get "caption" }}</figcaption> {{ end }} {{ if .Get "caption" }} </figure> {{ end }} <template> {{ .Inner }} </template> <script> (function() { var root = document.getElementById('demo-{{ $uniq }}'); root.attachShadow({mode: 'open'}); var template = document.getElementById('template-{{ $uniq }}'); var script = template.content.querySelector('script'); if (script) { script.textContent = `(function() { var demo = document.getElementById(\'demo-{{ $uniq }}\').shadowRoot; ${script.textContent} })()` } root.shadowRoot.appendChild(document.importNode(template.content, true)); })(); </script>

Son bir not: Altyazı değerinde markdown sözdizimini desteklemek istersem, bunu Hugo'nun markdownify işlevi aracılığıyla iletebilirim. Bu şekilde, yazar işaretleme (ve HTML) sağlayabilir, ancak her ikisini de yapmak zorunda değildir.

 {{ .Get "caption" | markdownify }}

Çözüm

Performansı ve birçok mükemmel özelliği nedeniyle Hugo, statik site oluşturma söz konusu olduğunda şu anda benim için rahat bir seçim. Ancak kısa kodların dahil edilmesi en çekici bulduğum şey. Bu durumda, bir süredir çözmeye çalıştığım bir belgeleme sorunu için basit bir arayüz oluşturabildim.

Web bileşenlerinde olduğu gibi, çok sayıda biçimlendirme karmaşıklığı (bazen erişilebilirlik için ayarlanarak daha da kötüleşir) kısa kodların arkasına gizlenebilir. Bu durumda, <figure> daha iyi desteklenen bir "grup etiketi" sağlayan role="group" ve aria-labelledby ilişkisini dahil ettiğimden bahsediyorum - özellikle de herkesin kodlamaktan bir kereden fazla zevk aldığı şeylerden değil benzersiz öznitelik değerlerinin her durumda dikkate alınması gerektiği durumlarda.

Kısa kodların, HTML ve işlevsellik için web bileşenlerinin ne olduğunu Markdown ve içerik için olduğuna inanıyorum: yazarlığı daha kolay, daha güvenilir ve daha tutarlı hale getirmenin bir yolu. Web'in bu meraklı küçük alanında daha fazla gelişmeyi dört gözle bekliyorum.

Kaynaklar

  • Hugo belgeleri
  • "Paket Şablonu", Go Programlama Dili
  • “Kısa kodlar,” Hugo
  • "tümü" (CSS steno özelliği), Mozilla Developer Network
  • “ilk (CSS anahtar sözcüğü), Mozilla Developer Network
  • “Shadow DOM v1: Bağımsız Web Bileşenleri,” Eric Bidelman, Web Temelleri, Google Developers
  • "Şablon Öğelerine Giriş", Eiji Kitamura, WebComponents.org
  • "İçerir," Jekyll