Nordhealth'in Web Bileşenlerinde Özel Mülkleri Nasıl Kullandığı

Tasarım sistemlerinde ve bileşen kitaplıklarında özel özellikler kullanmanın avantajları.

David Darnes
David Darnes

Ben Dave ve Nordhealth'te Kıdemli Kullanıcı Arayüzü Geliştiricisi olarak çalışıyorum. Nord tasarım sistemimizin tasarım ve geliştirme çalışmalarını yürütüyorum. Bu kapsamda, bileşen kitaplığımız için web bileşenleri oluşturuyorum. CSS özel mülklerini kullanarak web bileşenlerini stillendirmeyle ilgili sorunları nasıl çözdüğümüzü ve tasarım sistemlerinde ve bileşen kitaplıklarında özel mülkleri kullanmanın diğer bazı avantajlarını paylaşmak istedim.

Web bileşenlerini nasıl oluştururuz?

Web bileşenlerimizi oluşturmak için Lit'i kullanırız. Bu kitaplık; durum, kapsamlı stiller ve şablon oluşturma gibi birçok standart kod sağlar. Lit yalnızca hafif olmakla kalmaz, aynı zamanda yerel JavaScript API'leri üzerine kuruludur. Bu sayede, tarayıcının halihazırda sahip olduğu özelliklerden yararlanan, yalın bir kod paketi sunabiliriz.


import {html, css, LitElement} from 'lit';

export class SimpleGreeting extends LitElement {
  static styles = css`:host { color: blue; font-family: sans-serif; }`;

  static properties = {
    name: {type: String},
  };

  constructor() {
    super();
    this.name = 'there';
  }

  render() {
    return html`

Hey ${this.name}, welcome to Web Components!

`
; } } customElements.define('simple-greeting', SimpleGreeting);
Lit ile yazılmış bir web bileşeni.

Ancak web bileşenlerinin en çekici özelliği, neredeyse tüm mevcut JavaScript çerçeveleriyle veya hatta hiç çerçeve olmadan çalışabilmeleridir. Ana JavaScript paketi sayfada referans alındıktan sonra, bir web bileşenini kullanmak yerel bir HTML öğesini kullanmaya çok benzer. Bunun yerel bir HTML öğesi olmadığını gösteren tek gerçek işaret, etiketlerdeki tutarlı tire işaretidir. Bu, tarayıcıya bunun bir web bileşeni olduğunu belirtmek için kullanılan bir standarttır.

Gölge DOM stil kapsülleme

Yerel HTML öğelerinin Gölge DOM'u olduğu gibi, Web Bileşenleri'nin de Gölge DOM'u vardır. Gölge DOM, bir öğenin içindeki gizli bir düğüm ağacıdır. Bunu görselleştirmenin en iyi yolu, web denetleyicinizi açıp "Gölge DOM ağacını göster" seçeneğini etkinleştirmektir. Bu işlemi yaptıktan sonra denetleyicide yerel bir giriş öğesine bakmayı deneyin. Artık bu girişi açıp içindeki tüm öğeleri görme seçeneğiniz olacak. Hatta bunu web bileşenlerimizden biriyle de deneyebilirsiniz. Gölge DOM'unu görmek için özel giriş bileşenimizi incelemeyi deneyin.

Geliştirici Araçları'nda incelenen gölge DOM.
Normal bir metin girişi öğesinde ve Nord girişi web bileşenimizde gölge DOM örneği.

Gölge DOM'un avantajlarından (veya bakış açınıza bağlı olarak dezavantajlarından) biri stil kapsüllemedir. Web bileşeninizde CSS yazarsanız bu stiller dışarı sızıp ana sayfayı veya diğer öğeleri etkileyemez. Stiller tamamen bileşenin içinde yer alır. Ayrıca, ana sayfa veya üst web bileşeni için yazılan CSS, web bileşeninizde sızıntıya neden olamaz.

Stillerin bu şekilde kapsüllenmesi, bileşen kitaplığımız için avantajlıdır. Bu sayede, bir kullanıcı bileşenlerimizden birini kullandığında, üst sayfaya uygulanan stillerden bağımsız olarak bileşenlerin istediğimiz gibi görünmesini daha iyi garanti edebiliriz. Ayrıca, tüm web bileşenlerimizin köküne veya "ana makinesine" all: unset; ekleyerek bu durumu daha da güvence altına alırız.


:host {
  all: unset;
  display: block;
  box-sizing: border-box;
  text-align: start;
  /* ... */
}
Bazı bileşenler için standart kod, gölge köküne veya ana makine seçicisine uygulanıyor.

Ancak, web bileşeninizi kullanan birinin belirli stilleri değiştirmek için geçerli bir nedeni varsa ne olur? Belki de bağlamı nedeniyle daha fazla kontrasta ihtiyaç duyan bir metin satırı veya daha kalın olması gereken bir kenarlık vardır. Bileşeninizde stil kullanılamıyorsa bu stil seçeneklerini nasıl etkinleştirebilirsiniz?

CSS özel özellikleri bu noktada devreye girer.

CSS Özel Özellikleri

Özel özellikler, adlarını tamamen kendinizin verebileceği ve gereken değeri uygulayabileceğiniz CSS özellikleri olduğundan adlarını hak eder. Tek koşul, bu parametrelerin önüne iki kısa çizgi eklemenizdir. Özel özelliğinizi tanımladıktan sonra değeri var() işlevini kullanarak CSS'nizde kullanabilirsiniz.


:root {
  --n-color-accent: rgb(53, 89, 199);
  /* ... */
}

.n-color-accent-text {
  color: var(--n-color-accent);
}
CSS çerçevemizdeki bir tasarım jetonunun özel mülk olarak kullanılması ve yardımcı sınıfta kullanılmasıyla ilgili örnek.

Devralma söz konusu olduğunda, tüm özel özellikler devralınır. Bu, normal CSS özellikleri ve değerlerinin tipik davranışına uygundur. Bir üst öğeye veya öğenin kendisine uygulanan tüm özel özellikler, diğer özelliklerde değer olarak kullanılabilir. CSS çerçevemiz aracılığıyla kök öğeye uygulayarak tasarım jetonlarımız için özel özelliklerden yoğun bir şekilde yararlanırız. Bu, sayfadaki tüm öğelerin (web bileşeni, CSS yardımcı sınıfı veya jeton listemizden bir değer almak isteyen bir geliştirici) bu jeton değerlerini kullanabileceği anlamına gelir.

var() işlevi kullanılarak Özel Özelliklerin devralınabilmesi, Web Bileşenlerimizin Shadow DOM'una nüfuz etmemizi ve geliştiricilerin bileşenlerimizi stilize ederken daha ayrıntılı kontrol sahibi olmasını sağlar.

Nord web bileşenindeki özel özellikler

Tasarım sistemimiz için bir bileşen geliştirirken CSS'ye özenli bir yaklaşımla yaklaşırız. Amacımız, yalın ancak bakımı kolay kodlar oluşturmaktır. Sahip olduğumuz tasarım jetonları, kök öğedeki ana CSS çerçevemizde özel özellikler olarak tanımlanır.


:root {
  --n-space-m: 16px;
  --n-space-l: 24px;
  /* ... */
  --n-color-background: rgb(255, 255, 255);
  --n-color-border: rgb(216, 222, 228);
  /* ... */
}
Kök seçicide tanımlanan CSS özel özellikleri.

Bu jeton değerleri daha sonra bileşenlerimizde referans olarak kullanılır. Bazı durumlarda değeri doğrudan CSS özelliğine uygularız ancak diğer durumlarda yeni bir bağlamsal özel özellik tanımlar ve değeri buna uygularız.


:host {
  --n-tab-group-padding: 0;
  --n-tab-list-background: var(--n-color-background);
  --n-tab-list-border: inset 0 -1px 0 0 var(--n-color-border);
  /* ... */
}

.n-tab-group-list {
  box-shadow: var(--n-tab-list-border);
  background-color: var(--n-tab-list-background);
  gap: var(--n-space-s);
  /* ... */
}
Bileşenin gölge kökünde tanımlanan ve ardından bileşen stillerinde kullanılan özel özellikler. Tasarım jetonları listesindeki özel özellikler de kullanılıyor.

Ayrıca, bileşene özgü olup jetonlarımızda bulunmayan bazı değerleri soyutlayıp bağlamsal bir özel mülke dönüştüreceğiz. Bileşenle ilgili bağlamsal olan özel özellikler bize iki önemli avantaj sağlar. İlk olarak, bu değer bileşenin içindeki birden fazla özelliğe uygulanabildiğinden CSS'mizle daha "kuru" olabiliriz.


.n-tab-group-list::before {
  /* ... */
  padding-inline-start: var(--n-tab-group-padding);
}

.n-tab-group-list::after {
  /* ... */
  padding-inline-end: var(--n-tab-group-padding);
}
Sekme grubu dolgusu bağlamsal özel özelliği, bileşen kodunda birden fazla yerde kullanılıyor.

İkincisi ise bileşen durumu ve varyasyon değişikliklerini gerçekten temiz hale getirir. Örneğin, bir fareyle üzerine gelme veya etkin durumu ya da bu örnekte olduğu gibi bir varyasyonu stilize ederken tüm bu özellikleri güncellemek için yalnızca özel özelliğin değiştirilmesi gerekir.


:host([padding="l"]) {
  --n-tab-group-padding: var(--n-space-l);
}
Dolgunun birden fazla güncelleme yerine tek bir özel özellik güncellemesi kullanılarak değiştirildiği sekme bileşeninin bir varyasyonu.

Ancak en güçlü avantaj, bu bağlamsal özel özellikleri bir bileşende tanımladığımızda her bir bileşenimiz için bir tür özel CSS API'si oluşturmamızdır. Bu API, söz konusu bileşenin kullanıcısı tarafından kullanılabilir.


<nord-tab-group label="T>itl<e"
  >!<-- ... --
/nord>-t<ab-gr>oup

style
  nord-tab-group {
    --n-tab-group-padding: var(--n-space<-xl);
>  }
/style
Sayfada sekme grubu bileşenini kullanma ve dolgu özel özelliğini daha büyük bir boyuta güncelleme.

Önceki örnekte, seçici aracılığıyla bağlamsal bir özel özelliği değiştirilmiş olan web bileşenlerimizden biri gösterilmektedir. Bu yaklaşımın sonucu, kullanıcılara yeterli stil esnekliği sağlarken gerçek stillerin çoğunu kontrol altında tutan bir bileşendir. Ayrıca, bileşen geliştiriciler olarak kullanıcı tarafından uygulanan bu stilleri yakalama olanağına da sahibiz. Bu özelliklerden birini ayarlamak veya genişletmek istersek kullanıcının kodunda herhangi bir değişiklik yapmasına gerek kalmadan bunu yapabiliriz.

Bu yaklaşımın, tasarım sistemi bileşenlerimizin yaratıcıları olarak bizim için olduğu kadar, bu bileşenleri ürünlerimizde kullanan geliştirme ekibimiz için de son derece etkili olduğunu düşünüyoruz.

Özel özelliklerin kapsamını genişletme

Bu belge yazılırken bu bağlamsal özel özellikler belgelerimizde açıklanmamıştır. Ancak daha geniş geliştirme ekibimizin bu özellikleri anlayıp kullanabilmesi için bu özellikleri açıklamayı planlıyoruz. Bileşenlerimiz, npm'de manifest dosyasıyla paketlenir. Bu dosya, bileşenler hakkında bilinmesi gereken her şeyi içerir. Ardından, dokümantasyon sitemiz dağıtıldığında bildirim dosyasını veri olarak kullanırız. Bu işlem, Eleventy ve Global Data özelliği kullanılarak yapılır. Bu bağlamsal Özel Özellikleri bu manifest veri dosyasına eklemeyi planlıyoruz.

İyileştirmek istediğimiz bir diğer alan ise bu bağlamsal özel özelliklerin değerleri nasıl devraldığıdır. Örneğin, şu anda iki ayırıcı bileşenin rengini ayarlamak istiyorsanız bu bileşenlerin her ikisini de seçicilerle özel olarak hedeflemeniz veya özel özelliği doğrudan stil özelliğine sahip öğeye uygulamanız gerekir. Bu durum sorunsuz gibi görünse de geliştiricinin bu stilleri kapsayan bir öğede veya kök düzeyinde tanımlayabilmesi daha faydalı olur.


<nord-divider></nord-divider>

<section>
  <nord-divider></nord-divider>
   <!-- ... -->
</section>

<style>
  nord-divider {
    --n-divider-color: var(--n-color-status-danger);
  }

  section {
    padding: var(--n-space-s);
    background: var(--n-color-surface-raised);
  }
  
  section nord-divider {
    --n-divider-color: var(--n-color-status-success);
  }
</style>
İki farklı renk işlemi gerektiren iki ayırıcı bileşen örneği. Biri, daha spesifik bir seçici için kullanabileceğimiz bir bölümün içine yerleştirilmiştir ancak bölücüyü özellikle hedeflememiz gerekir.

Özel özellik değerini doğrudan bileşende ayarlamanızın nedeni, bu değerleri bileşen ana makine seçicisi aracılığıyla aynı öğede tanımlamamızdır. Doğrudan bileşende kullandığımız genel tasarım jetonları, bu sorundan etkilenmeden doğrudan iletilir ve hatta üst öğelerde bile yakalanabilir. İki platformun da en iyi özelliklerinden nasıl yararlanabiliriz?

Gizli ve herkese açık özel özellikler

Özel özel özellikler, Lea Verou tarafından oluşturulan bir özelliktir. Bu özellik, bileşenin kendisinde bağlamsal bir "özel" özel özellik olsa da geri dönüşü olan bir "herkese açık" özel özellik olarak ayarlanır.



:host {
  --_n-divider-color: var(--n-divider-color, var(--n-color-border));
  --_n-divider-size: var(--n-divider-size, 1px);
}

.n-divider {
  border-block-start: solid var(--_n-divider-size) var(--_n-divider-color);
  /* ... */
}
Dahili CSS'nin, geri dönüşlü herkese açık bir özel özellik olarak ayarlanmış olan özel bir özelliğe dayanması için bağlamsal özel özelliklerin ayarlandığı ayırıcı web bileşeni CSS'si.

Bağlamsal özel özelliklerimizi bu şekilde tanımladığımızda, daha önce yaptığımız her şeyi yapmaya devam edebiliriz. Örneğin, genel jeton değerlerini devralabilir ve değerleri bileşen kodumuzda yeniden kullanabiliriz. Ancak bileşen, bu özelliğin yeni tanımlarını kendisinde veya herhangi bir üst öğede sorunsuz bir şekilde devralır.


<nord-divider></nord-divider>

<section>
  <nord-divider></nord-divider>
   <!-- ... -->
</section>

<style>
  nord-divider {
    --n-divider-color: var(--n-color-status-danger);
  }

  section {
    padding: var(--n-space-s);
    background: var(--n-color-surface-raised);
    --n-divider-color: var(--n-color-status-success);
  }
</style>
İki ayırıcı tekrar kullanılıyor ancak bu kez ayırıcının bağlamsal özel özelliği bölüm seçiciye eklenerek ayırıcının rengi değiştirilebiliyor. Bölücü, bu değeri devralarak daha temiz ve esnek bir kod parçası oluşturur.

Bu yöntemin gerçekten "gizli" olmadığı iddia edilebilir ancak yine de endişelendiğimiz bir soruna oldukça zarif bir çözüm olduğunu düşünüyoruz. Fırsat bulduğumuzda bu konuyu bileşenlerimizde ele alacağız. Böylece geliştirme ekibimiz, bileşen kullanımını daha iyi kontrol ederken mevcut koruma önlemlerinden yararlanmaya devam edebilecek.

Web bileşenlerini CSS özel özellikleriyle nasıl kullandığımıza dair bu bilgiyi yararlı bulduğunuzu umuyoruz. Düşüncelerinizi bizimle paylaşın. Bu yöntemlerden herhangi birini kendi çalışmalarınızda kullanmaya karar verirseniz Twitter'da @DavidDarnes hesabından bana ulaşabilirsiniz. Nordhealth'i Twitter'da @NordhealthHQ adresinden takip edebilirsiniz. Ayrıca, bu tasarım sistemini bir araya getirmek ve bu makalede bahsedilen özellikleri uygulamak için çok çalışan ekibimin diğer üyelerini de takip edebilirsiniz: @Viljamis, @WickyNilliams ve @eric_habich.

Dan Cristian Pădureț tarafından çekilen lokomotif resim