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

Tasarım sistemlerinde ve bileşen kitaplıklarında Özel Mülkler kullanmanın avantajları.

David Darnes
David Darnes

Adım Dave, Nordhealth'ta Kıdemli Kullanıcı Arayüzü Geliştiricisi olarak çalışıyorum. Bileşen kitaplığımız için Web Bileşenlerinin oluşturulmasını içeren Nord tasarım sistemimizin tasarımı ve geliştirilmesi üzerinde çalışıyorum. CSS Özel Mülkleri'ni kullanarak Web Bileşenleri'nin stil özelliklerini ayarlamayla ilgili sorunları nasıl çözdüğümüzü ve tasarım sistemlerinde ve bileşen kitaplıklarında Özel Mülkleri kullanmanın diğer avantajlarından bazılarını sizinle paylaşmak istiyorum.

Web bileşenlerimizi oluşturmak için Lit'i kullanırız. Lit, durum, kapsamlı stiller, şablon oluşturma ve daha fazlası gibi birçok standart kod sağlayan bir kitaplıktır. Lit yalnızca hafif değil, aynı zamanda yerel JavaScript API'leri üzerine kuruludur. Bu sayede, tarayıcının halihazırda sahip olduğu özelliklerden yararlanan basit 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 yanı, neredeyse mevcut JavaScript çerçeveleriyle çalışmaları, hatta hiçbir çerçeveyle çalışmamalarıdır. Sayfada ana JavaScript paketine başvurulduktan sonra, bir Web Bileşeni kullanmak yerel HTML öğesi kullanmaya çok benzer. Bunun yerel bir HTML öğesi olmadığını gösteren tek gerçek işaret, etiketlerin içindeki tutarlı kısa çizgidir. Bu, tarayıcıya bunun bir Web Bileşeni olduğunu belirten bir standarttır.


// TODO: DevSite - Code sample removed as it used inline event handlers
Bir sayfada yukarıda oluşturulan Web Bileşeni'ni kullanarak.

Gölge DOM stili 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 öğe içindeki gizli bir düğüm ağacıdır. Bunu görselleştirmenin en iyi yolu, web denetçinizi açıp "Gölge DOM ağacını göster" seçeneğini etkinleştirmektir. Bunu 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. Bunu web bileşenlerimizden biriyle de deneyebilirsiniz. Gölge DOM'unu görmek için özel giriş bileşenimizi denetlemeyi deneyin.

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

Gölge DOM'un avantajlarından (veya bakış açınıza bağlı olarak dezavantajlarından) biri stil kapsayıcılığıdır. Web bileşeninizde CSS yazarsanız bu stiller dışarı sızamaz ve ana sayfayı veya diğer öğeleri etkileyemez. Bu stiller tamamen bileşen içindedir. Ayrıca, ana sayfa veya üst Web Bileşeni için yazılmış CSS, Web Bileşeninize sızdıramaz.

Bileşen kitaplığımızdaki stillerin bu şekilde kapsüllenmesi bir avantajdır. Bu, kullanıcılar bileşenlerimizden birini kullandığında, ana sayfaya uygulanan stillerden bağımsız olarak bileşenin istediğimiz gibi görüneceği konusunda bize daha fazla güvence verir. Daha da emin olmak için tüm web bileşenlerimizin köküne veya "ana makinesine" all: unset; ekleriz.


:host {
  all: unset;
  display: block;
  box-sizing: border-box;
  text-align: start;
  /* ... */
}
Gölge kökü veya ana makine seçiciye uygulanan bazı bileşenlerin ortak metni kodu.

Ancak web bileşeninizi kullanan bir kullanıcının belirli stilleri değiştirmek için geçerli bir nedeni varsa ne olur? Bağlam nedeniyle daha fazla kontrast gerektiren bir metin satırı olabilir veya kenarlığın daha kalın olması gerekiyordur. Bileşeninize stil uygulanamıyorsa bu stil seçeneklerinden nasıl yararlanabilirsiniz?

İşte bu noktada CSS özel mülkleri devreye girer.

CSS Özel Özellikleri

Özel Özellikler, adları çok uygun olan CSS özellikleridir. Bu özellikleri tamamen kendiniz adlandırabilir ve istediğiniz değeri uygulayabilirsiniz. Tek şart, bunların önüne iki kısa çizgi eklemenizdir. Özel özelliğinizi beyan ettikten sonra değer, var() işlevi kullanılarak CSS'nizde kullanılabilir.


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

.n-color-accent-text {
  color: var(--n-color-accent);
}
CSS Çerçevemizde, Özel Mülk olarak bir tasarım jetonunun ve yardımcı sınıfta kullanılan bir tasarım jetonu örneği.

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

var() işlevini kullanarak Özel Özellikleri devralmamız, Web Bileşenleri'nin Gölge DOM'sini delmemizi ve geliştiricilerin, bileşenlerimizin stilini belirlerken daha hassas bir kontrole sahip olmalarını sağlar.

Kuzey Web Bileşeni'ndeki Özel Mülkler

Tasarım sistemimiz için bir bileşen geliştirdiğimizde, CSS'si konusunda dikkatli bir yaklaşım benimsiyoruz. Yalın ancak son derece sürdürülebilir bir kod hedeflemeyi hedeflemekteyiz. Sahip olduğumuz tasarım jetonları, kök öğedeki ana CSS Çerçevemizde yer alan Ö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 mülküne uygularız. Bazı durumlarda ise, aslında yeni bir içeriğe dayalı Özel Mülk tanımlayıp 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ü olan ancak jetonlarımızda bulunmayan bazı değerleri soyutlayarak içeriğe dayalı bir Özel Mülke dönüştürürüz. Bileşenle alakalı özel özellikler bize iki önemli avantaj sağlar. Öncelikle, bu değer bileşen içindeki birden fazla özelliğe uygulanabileceğinden CSS'mizde 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);
}
Bileşen kodunda birden fazla yerde kullanılan sekme grubu dolgu bağlamsal özel mülkü.

İkincisi, bileşen durumu ve varyasyon değişikliklerini gerçekten düzenli hale getirir. Söz gelimi, bir fareyle üzerine gelme veya etkin durumun ya da bu durumda bir varyasyonun stilini belirlerken bu özelliklerin tümünü 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 Mülk güncellemesi kullanılarak değiştirildiği sekme bileşeninin bir varyasyonu.

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


<nord-tab-group label="Title">
  <!-- ... -->
</nord-tab-group>

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

Önceki örnekte, bir seçici aracılığıyla değiştirilen bağlamsal özel mülkü olan web bileşenlerimizden biri gösterilmektedir. Bu yaklaşımın sonucu, gerçek stillerin çoğunu kontrol altında tutarken kullanıcıya yeterli stil esnekliği sağlayan bir bileşendir. Ayrıca, bileşen geliştiricileri olarak kullanıcı tarafından uygulanan bu stillere müdahale edebiliyoruz. Bu özelliklerden birini düzenlemek veya genişletmek istersek, kullanıcının kodlarını değiştirmesine gerek kalmadan bunu yapabiliriz.

Bu yaklaşımı, yalnızca tasarım sistemi bileşenlerimizi oluşturanlar olarak değil, ürünlerimizde bu bileşenleri kullanan geliştirme ekibimiz için de son derece güçlü buluyoruz.

Özel Mülkleri bir adım ileriye taşıma

Bu içeriği yazarken, dokümanlarımızda aslında bu içeriğe dayalı Özel Mülkleri açıklamıyoruz ancak, daha geniş çaptaki geliştirme ekibimizin bu özellikleri anlayabilmesi ve yararlanabilmesi için bu özellikleri sunmayı planlıyoruz. Bileşenlerimiz, kendileri hakkında bilmeniz gereken her şeyi içeren bir manifest dosyası ile npm'de paketlenir. Ardından, doküman sitemiz dağıtıldığında manifest dosyasını veri olarak kullanırız. Bu işlem, Eleventy ve Global Data özelliği kullanılarak yapılır. Bu içeriğe dayalı Özel Mülkleri, bu manifest veri dosyasına eklemeyi planlıyoruz.

Geliştirmek istediğimiz bir başka alan da bu içeriğe dayalı Özel Mülklerin değerleri devralma şeklidir. Örneğin, şu anda iki bölücü bileşenin rengini ayarlamak istiyorsanız bu bileşenlerin her ikisini de özel olarak seçicilerle hedeflemeniz veya özel özelliği doğrudan stil özelliğiyle öğeye uygulamanız gerekir. Bu iyi görünebilir ancak geliştiricinin bu stilleri kapsayıcı bir öğede veya hatta kök düzeyinde tanımlayabilmesi daha yararlı 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>
Ayırıcı bileşenimizin, iki farklı renk değerine ihtiyacı olan iki örneği. Biri, daha belirli bir seçici için kullanabileceğimiz bir bölümün içine yerleştirilmiştir ancak ayırıcıyı özel olarak hedeflememiz gerekir.

Özel Mülk değerini doğrudan bileşen üzerinde 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ı doğrudan geçer, bu sorundan etkilenmez ve hatta üst öğelerde müdahale edilebilir. İki platformun da en iyi özelliklerinden nasıl yararlanabiliriz?

Gizli ve herkese açık özel özellikler

Özel özel mülkler, Lea Verou tarafından oluşturulmuştur. Bileşenin kendisinde bağlamsal bir "özel" özel mülktür ancak yedek bir "herkese açık" özel mülke ayarlanmıştı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);
  /* ... */
}
İçeriğe dayalı Özel Özellikler içeren ayırıcı Web Bileşeni CSS'si, dahili CSS'nin yedek içeren herkese açık bir Özel Mülk olarak ayarlanmış özel bir Özel Mülke dayalı olmasını sağlayacak şekilde ayarlanmıştır.

İçeriğe dayalı Özel Mülklerimizi bu şekilde tanımlamamız, genel jeton değerlerini devralma ve değerleri bileşen kodumuzda yeniden kullanma gibi önceden yaptığımız tüm işlemleri yapmaya devam edebileceğimiz anlamına gelir. Ancak bileşen, bu özelliğin yeni tanımlarını da kendisinde veya herhangi bir üst öğede incelikle devralacaktı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>
Yine iki ayırıcı var ancak bu sefer ayırıcının bağlama dayalı özel özelliği bölüm seçiciye eklenerek ayırıcının rengi değiştirilebilir. Ayırıcı, bu kodu devralarak daha net ve esnek bir kod parçası oluşturur.

Bu yöntemin gerçekten "gizli" olmadığı söylenebilir ancak endişelendiğimiz bir soruna oldukça şık bir çözüm sunduğunu düşünüyoruz. Fırsatımız olduğunda bu sorunu bileşenlerimizde ele alacağız. Böylece geliştirme ekibimiz, mevcut güvenlik önlemlerimizden yararlanırken bileşen kullanımı üzerinde daha fazla kontrole sahip olacak.

CSS Özel Mülkleri ile Web Bileşenleri'ni nasıl kullandığımıza ilişkin bu bilgiyi yararlı bulmuşsunuzdur. Düşüncelerinizi bizimle paylaşın. Kendi işinizde bu yöntemlerden herhangi birini kullanmaya karar verirseniz beni Twitter'da (@DavidDarnes) bulabilirsiniz. Nordhealth @NordhealthHQ hesabını Twitter'da da bulabilirsiniz. Ayrıca, bu tasarım sistemini bir araya getirmek ve bu makalede bahsedilen özellikleri uygulamak için çalışan ekibimin geri kalanı da var: @Viljamis, @WickyNilliams ve @eric_habich.

Dan Cristian Pădureț tarafından oluşturulan hero resim