CSS ve stil
Bu makalede, Shadow DOM ile yapabileceğiniz diğer muhteşem şeyler ele alınmaktadır. Shadow DOM 101'de ele alınan kavramları temel alır. Giriş niteliğinde bir bilgi arıyorsanız bu makaleyi inceleyin.
Giriş
Kabul edelim. Stilsiz işaretlemenin çekici bir yanı yoktur. Neyse ki Web Bileşenleri'nin arkasındaki dahi ekip bunu öngördü ve bizi yarı yolda bırakmadı. CSS Kapsam Modülü, gölge ağacındaki içeriği stillendirmek için birçok seçenek tanımlar.
Stil kapsülleme
Gölge DOM'un temel özelliklerinden biri gölge sınırıdır. Birçok iyi özelliği vardır ancak en iyilerinden biri, stil kapsüllemeyi ücretsiz olarak sunmasıdır. Başka bir deyişle:
<div><h3>Light DOM</h3></div>
<script>
var root = document.querySelector('div').createShadowRoot();
root.innerHTML = `
<style>
h3 {
color: red;
}
</style>
<h3>Shadow DOM</h3>
`;
</script>
Bu demoyla ilgili iki ilginç gözlem var:
- Bu sayfada başka h3'ler de var ancak h3 seçiciyle eşleşen ve bu nedenle kırmızı renkte olan tek h3, ShadowRoot'taki h3'tür. Yine, varsayılan olarak kapsamlı stiller kullanılır.
- Bu sayfada tanımlanan ve h3'leri hedefleyen diğer stil kuralları içeriğime sızmaz. Bunun nedeni, seçicilerin gölge sınırını aşmamasıdır.
Bu hikayeden çıkarılacak ders nedir? Dış dünyadan stil kapsüllememiz var. Teşekkürler Gölge DOM!
Ana makine öğesini biçimlendirme
:host, gölge ağacı barındıran öğeyi seçmenize ve stillendirmenize olanak tanır:
<button class="red">My Button</button>
<script>
var button = document.querySelector('button');
var root = button.createShadowRoot();
root.innerHTML = `
<style>
:host {
text-transform: uppercase;
}
</style>
<content></content>
`;
</script>
Üst sayfadaki kuralların, öğede tanımlanan :host kurallarından daha yüksek özgüllüğe sahip olduğunu ancak ana makine öğesinde tanımlanan style özelliğinden daha düşük özgüllüğe sahip olduğunu unutmayın. Bu sayede kullanıcılar, stilinizi dışarıdan geçersiz kılabilir.
:host, yalnızca ShadowRoot bağlamında çalıştığından Shadow DOM dışında kullanılamaz.
:host(<selector>) işlevsel biçimi, bir <selector> ile eşleşirse ana makine öğesini hedeflemenize olanak tanır.
Örnek: Yalnızca öğenin kendisi .different sınıfına sahipse eşleştir (ör. <x-foo class="different"></x-foo>):
:host(.different) {
...
}
Kullanıcı durumlarına tepki verme
:host için yaygın bir kullanım alanı, özel öğe oluştururken farklı kullanıcı durumlarına (:hover, :focus, :active vb.) tepki vermek istediğiniz durumlardır.
<style>
:host {
opacity: 0.4;
transition: opacity 420ms ease-in-out;
}
:host(:hover) {
opacity: 1;
}
:host(:active) {
position: relative;
top: 3px;
left: 3px;
}
</style>
Öğeye tema uygulama
:host-context(<selector>) sözde sınıfı, kendisi veya üst öğelerinden herhangi biri <selector> ile eşleşirse ana makine öğesiyle eşleşir.
:host-context(), genellikle bir öğeyi çevresine göre temalandırmak için kullanılır. Örneğin, birçok kişi <html> veya <body> öğesine bir sınıf uygulayarak tema oluşturur:
<body class="different">
<x-foo></x-foo>
</body>
.different sınıfına sahip bir öğenin alt öğesi olduğunda <x-foo> öğesini biçimlendirmek için :host-context(.different) kullanabilirsiniz:
:host-context(.different) {
color: red;
}
Bu sayede, stil kurallarını bir öğenin Shadow DOM'unda kapsülleyerek bağlamına göre benzersiz bir şekilde stil oluşturabilirsiniz.
Tek bir gölge kökünden birden fazla ana makine türünü destekleme
:host için başka bir kullanım alanı da bir tema kitaplığı oluşturuyorsanız ve aynı Shadow DOM içinden birçok türde ana makine öğesinin stilini desteklemek istiyorsanız geçerlidir.
:host(x-foo) {
/* Applies if the host is a <x-foo> element.*/
}
:host(x-foo:host) {
/* Same as above. Applies if the host is a <x-foo> element. */
}
:host(div) {
/* Applies if the host element is a <div>. */
}
Gölge DOM dahili öğelerini dışarıdan stillendirme
::shadow sözde öğesi ve /deep/ birleştiricisi, CSS yetkisinin Vorpal kılıcına sahip olmak gibidir.
Gölge ağaçlarındaki öğeleri biçimlendirmek için gölge DOM'un sınırını aşmanıza olanak tanır.
::shadow sözde öğesi
Bir öğenin en az bir gölge ağacı varsa ::shadow sözde öğesi, gölge kökün kendisiyle eşleşir.
Bir öğenin gölge DOM'undaki düğümleri biçimlendiren seçiciler yazmanıza olanak tanır.
Örneğin, bir öğe gölge kök barındırıyorsa gölge ağacındaki tüm span'leri biçimlendirmek için #host::shadow span {} yazabilirsiniz.
<style>
#host::shadow span {
color: red;
}
</style>
<div id="host">
<span>Light DOM</span>
</div>
<script>
var host = document.querySelector('div');
var root = host.createShadowRoot();
root.innerHTML = `
<span>Shadow DOM</span>
<content></content>
`;
</script>
Örnek (özel öğeler): <x-tabs>, gölge DOM'unda <x-panel> alt öğeye sahip. Her panel, h2 başlıklarını içeren kendi gölge ağacını barındırır. Ana sayfadaki bu başlıkları biçimlendirmek için şöyle yazabilirsiniz:
x-tabs::shadow x-panel::shadow h2 {
...
}
/deep/ birleştiricisi
/deep/ birleştiricisi ::shadow birleştiricisine benzer ancak daha güçlüdür. Tüm gölge sınırlarını tamamen yok sayar ve dilediği sayıda gölge ağacına geçer. Basitçe ifade etmek gerekirse /deep/, bir öğenin ayrıntılarına inmenize ve herhangi bir düğümü hedeflemenize olanak tanır.
/deep/ birleştiricisi, özellikle birden fazla Gölge DOM düzeyinin yaygın olduğu Özel Öğeler dünyasında kullanışlıdır. Bunun en iyi örnekleri, bir dizi özel öğeyi iç içe yerleştirmek (her biri kendi gölge ağacını barındırır) veya <shadow> kullanarak başka bir öğeden devralınan bir öğe oluşturmaktır.
Örnek (özel öğeler): Ağacın herhangi bir yerinde <x-tabs> öğesinin alt öğesi olan tüm <x-panel> öğelerini seçin:
x-tabs /deep/ x-panel {
...
}
Örnek: Gölge ağacının herhangi bir yerinde .library-theme sınıfına sahip tüm öğeleri stillendirin:
body /deep/ .library-theme {
...
}
querySelector() ile çalışma
.shadowRoot, gölge ağaçları DOM geçişine açtığı gibi birleştiriciler de gölge ağaçları seçici geçişine açar.
İç içe geçmiş karmaşık bir zincir yazmak yerine tek bir ifade yazabilirsiniz:
// No fun.
document.querySelector('x-tabs').shadowRoot
.querySelector('x-panel').shadowRoot
.querySelector('#foo');
// Fun.
document.querySelector('x-tabs::shadow x-panel::shadow #foo');
Doğal öğeleri biçimlendirme
Yerel HTML kontrollerini biçimlendirmek zordur. Birçok kişi pes edip
kendi çözümünü geliştiriyor. Ancak ::shadow ve /deep/ ile web platformunda Gölge DOM kullanan tüm öğeler stillendirilebilir. <input> türleri ve <video> buna iyi birer örnektir:
video /deep/ input[type="range"] {
background: hotpink;
}
Stil kancaları oluşturma
Özelleştirme iyidir. Bazı durumlarda, gölgenizin stil kalkanında delikler açmak ve başkalarının stil oluşturması için kancalar oluşturmak isteyebilirsiniz.
::shadow ve /deep/ kullanma
/deep/ çok güçlü bir araçtır. Bu sayede bileşen yazarları, tek tek öğeleri stil verilebilir veya bir dizi öğeyi temalandırılabilir olarak belirleyebilir.
Örnek: Tüm gölge ağaçları yoksayarak .library-theme sınıfına sahip tüm öğeleri stillendirin:
body /deep/ .library-theme {
...
}
Özel sözde öğeleri kullanma
Hem WebKit hem de Firefox, yerel tarayıcı öğelerinin dahili parçalarını stillendirmek için sözde öğeler tanımlar. Buna iyi bir örnek, input[type=range]. ::-webkit-slider-thumb öğesini hedefleyerek kaydırma çubuğu tutma yerini <span style="color:blue">blue</span> biçimlendirebilirsiniz:
input[type=range].custom::-webkit-slider-thumb {
-webkit-appearance: none;
background-color: blue;
width: 10px;
height: 40px;
}
Tarayıcıların bazı dahili öğelere stil kancaları sağlamasına benzer şekilde, gölge DOM içeriğinin yazarları da belirli öğeleri dışarıdan stil verilebilir olarak belirleyebilir. Bu işlem, özel sözde öğeler aracılığıyla yapılır.
pseudo özelliğini kullanarak bir öğeyi özel sözde öğe olarak belirleyebilirsiniz.
Değerinin veya adının "x-" ile başlaması gerekir. Bu şekilde, gölge ağacındaki bu öğeyle bir ilişki oluşturulur ve dışarıdakilere gölge sınırını geçmek için belirlenmiş bir yol sağlanır.
Aşağıda, özel bir kaydırma çubuğu widget'ı oluşturma ve bir kullanıcının kaydırma çubuğu tutamacını mavi renkte biçimlendirmesine izin verme örneği verilmiştir:
<style>
#host::x-slider-thumb {
background-color: blue;
}
</style>
<div id="host"></div>
<script>
var root = document.querySelector('#host').createShadowRoot();
root.innerHTML = `
<div>
<div pseudo="x-slider-thumb"></div>' +
</div>
`;
</script>
CSS değişkenlerini kullanma
Tema kancaları oluşturmanın etkili bir yolu CSS değişkenleri kullanmaktır. Diğer kullanıcıların doldurması için "stil yer tutucuları" oluşturun.
Gölge DOM'unda değişken yer tutucuları işaretleyen bir özel öğe yazarı düşünün. Biri dahili bir düğmenin yazı tipini, diğeri ise rengini biçimlendirmek için:
button {
color: var(--button-text-color, pink); /* default color will be pink */
font-family: var(--button-font);
}
Ardından, öğeyi yerleştiren kişi bu değerleri istediği gibi tanımlar. Belki de kendi sayfalarının süper havalı Comic Sans temasına uyması için:
#host {
--button-text-color: green;
--button-font: "Comic Sans MS", "Comic Sans", cursive;
}
CSS değişkenlerinin devralma şekli nedeniyle her şey yolunda ve bu yöntem çok iyi çalışıyor. Resmin tamamı şu şekildedir:
<style>
#host {
--button-text-color: green;
--button-font: "Comic Sans MS", "Comic Sans", cursive;
}
</style>
<div id="host">Host node</div>
<script>
var root = document.querySelector('#host').createShadowRoot();
root.innerHTML = `
<style>
button {
color: var(--button-text-color, pink);
font-family: var(--button-font);
}
</style>
<content></content>
`;
</script>
Stiller sıfırlanıyor
Yazı tipleri, renkler ve satır yükseklikleri gibi devralınabilir stiller, Shadow DOM'daki öğeleri etkilemeye devam eder. Ancak Shadow DOM, maksimum esneklik için gölge sınırında ne olacağını kontrol etmemizi sağlayan resetStyleInheritance özelliğini sunar.
Bunu, yeni bir bileşen oluştururken temiz bir başlangıç yapmanın yolu olarak düşünebilirsiniz.
resetStyleInheritance
false: Varsayılan değerdir. Devralınabilir CSS özellikleri devralınmaya devam eder.true: Sınırda devralınabilir özellikleriinitialolarak sıfırlar.
Aşağıda, gölge ağacın resetStyleInheritance değiştirilmesinden nasıl etkilendiğini gösteren bir demo verilmiştir:
<div>
<h3>Light DOM</h3>
</div>
<script>
var root = document.querySelector('div').createShadowRoot();
root.resetStyleInheritance = <span id="code-resetStyleInheritance">false</span>;
root.innerHTML = `
<style>
h3 {
color: red;
}
</style>
<h3>Shadow DOM</h3>
<content select="h3"></content>
`;
</script>
<div class="demoarea" style="width:225px;">
<div id="style-ex-inheritance"><h3 class="border">Light DOM</div>
</div>
<div id="inherit-buttons">
<button id="demo-resetStyleInheritance">resetStyleInheritance=false</button>
</div>
<script>
var container = document.querySelector('#style-ex-inheritance');
var root = container.createShadowRoot();
//root.resetStyleInheritance = false;
root.innerHTML = '<style>h3{ color: red; }</style><h3>Shadow DOM<content select="h3"></content>';
document.querySelector('#demo-resetStyleInheritance').addEventListener('click', function(e) {
root.resetStyleInheritance = !root.resetStyleInheritance;
e.target.textContent = 'resetStyleInheritance=' + root.resetStyleInheritance;
document.querySelector('#code-resetStyleInheritance').textContent = root.resetStyleInheritance;
});
</script>
.resetStyleInheritance değerini anlamak biraz daha zordur. Bunun temel nedeni, yalnızca devralınabilir CSS özelliklerini etkilemesidir. Bu, devralınacak bir özellik ararken sayfa ile ShadowRoot arasındaki sınırda, ana makineden değerleri devralmak yerine initial değerini kullanın (CSS spesifikasyonuna göre).
CSS'de hangi özelliklerin devralındığından emin değilseniz bu kullanışlı listeye göz atın veya Öğe panelindeki "Devralınanları göster" onay kutusunu işaretleyin.
Dağıtılmış düğümleri stillendirme
Dağıtılmış düğümler, bir ekleme noktasında (<content> öğesi) oluşturulan öğelerdir. <content> öğesi, Light DOM'dan düğümler seçmenize ve bunları Shadow DOM'unuzda önceden tanımlanmış konumlarda oluşturmanıza olanak tanır. Mantıksal olarak gölge DOM'da değillerdir; hâlâ ana makine öğesinin alt öğeleridir. Ekleme noktaları yalnızca oluşturma ile ilgilidir.
Dağıtılan düğümler, ana dokümandaki stilleri korur. Yani ana sayfadaki stil kuralları, bir ekleme noktasında oluşturulduklarında bile öğelere uygulanmaya devam eder. Dağıtılmış düğümler mantıksal olarak hâlâ light DOM'dadır ve taşınmaz. Sadece başka bir yerde oluşturulurlar. Ancak düğümler gölge DOM'a dağıtıldığında gölge ağacında tanımlanan ek stiller alabilirler.
::content sözde öğesi
Dağıtılmış düğümler, ana makine öğesinin alt öğeleridir. Bu nedenle, bunları Shadow DOM'un içinden nasıl hedefleyebiliriz? Doğru yanıt, CSS ::content sözde öğesidir.
Bir ekleme noktasından geçen Light DOM düğümlerini hedeflemenin bir yoludur. Örneğin:
::content > h3, bir ekleme noktasından geçen tüm h3 etiketlerini biçimlendirir.
Bir örneğe göz atalım:
<div>
<h3>Light DOM</h3>
<section>
<div>I'm not underlined</div>
<p>I'm underlined in Shadow DOM!</p>
</section>
</div>
<script>
var div = document.querySelector('div');
var root = div.createShadowRoot();
root.innerHTML = `
<style>
h3 { color: red; }
content[select="h3"]::content > h3 {
color: green;
}
::content section p {
text-decoration: underline;
}
</style>
<h3>Shadow DOM</h3>
<content select="h3"></content>
<content select="section"></content>
`;
</script>
Ekleme noktalarındaki stiller sıfırlanıyor
ShadowRoot oluştururken devralınan stilleri sıfırlama seçeneğiniz vardır.
<content> ve <shadow> ekleme noktalarında da bu seçenek bulunur. Bu öğeleri kullanırken JS'de .resetStyleInheritance değerini ayarlayın veya öğenin kendisinde boole reset-style-inheritance özelliğini kullanın.
ShadowRoot veya
<shadow>ekleme noktaları için:reset-style-inheritance, devralınabilir CSS özelliklerinin gölge içeriğinize ulaşmadan önce ana makinedeinitialolarak ayarlandığı anlamına gelir. Bu konuma üst sınır denir.<content>ekleme noktaları için:reset-style-inheritance, devralınabilir CSS özelliklerinin, ana makinenin alt öğeleri ekleme noktasında dağıtılmadan önceinitialolarak ayarlandığı anlamına gelir. Bu konuma alt sınır denir.
Sonuç
Özel öğelerin yazarları olarak, içeriğimizin görünümünü ve tarzını kontrol etmek için birçok seçeneğimiz vardır. Gölge DOM, bu cesur yeni dünyanın temelini oluşturur.
Gölge DOM, kapsamlı stil kapsülleme ve dış dünyayı istediğimiz kadar (veya az) içeri almamızı sağlayan bir yöntem sunar. Yazarlar, özel sözde öğeler tanımlayarak veya CSS değişkeni yer tutucuları ekleyerek üçüncü taraflara içeriklerini daha da özelleştirmeleri için kullanışlı stil kancaları sağlayabilir. Özetle, web yazarları içeriklerinin nasıl temsil edildiği konusunda tam kontrole sahiptir.