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

Tasarım sistemlerinde ve bileşen kitaplıklarında özel özellikleri 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şenleri oluşturmayı da içeren Nord tasarım sistemimizin tasarımı ve geliştirilmesi üzerinde çalışıyorum. CSS Özel Mülkleri'ni kullanarak Web Bileşenleri'nin stiliyle ilgili sorunları nasıl çözdüğümüzü ve tasarım sistemleri ile bileşen kitaplıklarında Özel Mülkler'in sağladığı diğer bazı avantajları paylaşmak istedim.

Web bileşenlerini nasıl oluşturuyoruz?

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şenleri'nin en cazip özelliği, neredeyse tüm mevcut JavaScript çerçeveleriyle ve hatta hiç çerçeve olmadan çalışabilmesidir. Ana JavaScript paketine sayfadan referans verildikten sonra web bileşeni kullanmak, yerel bir HTML öğesi kullanmakla neredeyse aynıdır. Yerleşik bir HTML öğesi olmadığının tek gerçek göstergesi, etiketler içindeki tutarlı kısa çizgidir. Bu, tarayıcıya bunun bir web bileşeni olduğunu belirtmek için kullanılan standart bir işarettir.


// TODO: DevSite - Code sample removed as it used inline event handlers
Yukarıdaki web bileşenini bir sayfada kullanma.

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 bir web bileşeni için yazılan CSS, web bileşeninize sızamaz.

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üne veya barındırıcı seçiciye uygulanan bazı bileşen şablon 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ından dolayı daha fazla kontrasta ihtiyaç duyan bir metin satırı veya daha kalın bir kenarlığa ihtiyaç duyan bir öğe olabilir mi? 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, bu kelimelerin önüne iki kısa çizgi koymanızdır. Ö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çevemizdeki bir tasarım jetonunun özel mülk olarak gösterildiği ve yardımcı sınıfta kullanıldığı örnek.

Devralmaya gelince, tüm özel özellikler devralınır ve 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şlevi kullanılarak özel özellikleri devralma özelliği, web bileşenlerimizin Gölge DOM'unu delmemize ve geliştiricilerin bileşenlerimize stil verirken daha ayrıntılı kontrol sahibi olmasına olanak tanır.

Nord Web Bileşeninde Özel Özellikler

Tasarım sistemimiz için bir bileşen geliştirirken CSS'sine dikkatli bir yaklaşım benimseriz. Basit ancak çok sürdürülebilir kodlar oluşturmayı hedefleriz. 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 mülküne uygularız. Diğer durumlarda ise yeni bir bağlamsal özel mülk tanımlar ve değeri bu özel mülke 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);
  /* ... */
}
Özellikler, bileşenin gölge kökünde tanımlanır ve ardından bileşen stillerinde kullanılır. Tasarım jetonları listesinden özel mülkler de kullanılıyor.

Ayrıca, bileşene özgü ancak jetonlarımızda bulunmayan bazı değerleri soyutlar ve bağlama 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 temiz hale getirir. Örneğin, fareyle üzerine gelme veya etkin durum ya da bu durumda bir varyasyona stil uygularken 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);
}
Sekme bileşeninin, dolgunun birden fazla güncelleme yerine tek bir özel mülk güncellemesi kullanılarak değiştirildiği 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'ye ilgili bileşenin kullanıcısı tarafından erişilebilir.


<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 kullanarak ve dolgu özel mülkünü daha büyük bir boyuta güncelleyerek.

Ö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 stilleri engelleme imkanı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, yalnızca tasarım sistemi bileşenlerimizin yaratıcıları olarak bizim için değil, aynı zamanda bu bileşenleri ürünlerimizde kullanan geliştirme ekibimiz için de son derece güçlü olduğunu düşünüyoruz.

Özel özellikleri daha da ileri taşıma

Bu makalenin yazıldığı sırada bu bağlama dayalı özel özellikleri dokümanlarımızda açıklamadık. Ancak daha geniş kapsamlı geliştirme ekibimizin bu özellikleri anlayıp kullanabilmesi için bunu yapmayı planlıyoruz. Bileşenlerimiz, npm'de bileşenler hakkında bilinmesi gereken her şeyi içeren bir manifest dosyasıyla 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 bağlamsal özel mülkleri bu manifest veri dosyasına eklemeyi planlıyoruz.

İyileştirmek istediğimiz bir diğer alan da bu bağlamsal özel mülklerin değerleri nasıl devraldığıdır. Ö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>
İki farklı renk işlemi gerektiren bölücü bileşenimizin iki örneği. Biri, daha spesifik 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şende ayarlamanız gerekir. Bunun nedeni, bileşen ana makinesi seçici 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 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ülk olarak 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);
  /* ... */
}
İç CSS'nin yedek bir herkese açık özel mülkle ayarlanmış özel bir özel mülke dayandırılması için ayarlanmış bağlamsal özel mülklerle bölücü web bileşeni CSS'si.

Bağlamsal özel mülklerimizi bu şekilde tanımlamak, daha önce yaptığımız tüm işlemleri (ör. genel jeton değerlerini devralma ve değerleri bileşen kodumuzda yeniden kullanma) yapmaya devam edebileceğimiz anlamına gelir. Ancak bileşen, bu mülkün yeni tanımlarını kendisinde veya herhangi bir üst öğede de 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>
Yine iki bölücü var ancak bu sefer bölücü, bölüm seçiciye bölücünün bağlamsal özel özelliği eklenerek yeniden renklendirilebilir. Bölme işlevi bu değeri devralır ve daha temiz ve daha 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.

Web bileşenlerini CSS özel mülkleriyle nasıl kullandığımızla ilgili bu bilgileri yararlı bulmuşsunuzdur. Düşüncelerinizi bizimle paylaşın. Bu yöntemlerden herhangi birini kendi çalışmanızda kullanmaya karar verirseniz beni Twitter'da @DavidDarnes olarak bulabilirsiniz. Nordhealth'i @NordhealthHQ Twitter hesabından da 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 oluşturulan hero resim