Geliştirici Araçları'nda JS içinde CSS desteği

Alex Rudenko
Alex Rudenko

Bu makalede, Chrome 85'ten beri DevTools'ta sunulan JS'de CSS desteği ve genel olarak JS'de CSS'den ne anladığımız ve DevTools tarafından uzun süredir desteklenen normal CSS'den nasıl farklı olduğu ele alınmaktadır.

JS'de CSS nedir?

JS'de CSS'nin tanımı oldukça belirsiz. Geniş anlamda, JavaScript kullanarak CSS kodunu yönetmeye yönelik bir yaklaşımdır. Örneğin, CSS içeriğinin JavaScript kullanılarak tanımlandığı ve nihai CSS çıktısının uygulama tarafından anında oluşturulduğu anlamına gelebilir.

DevTools bağlamında, JS'de CSS, CSS içeriğinin CSSOM API'leri kullanılarak sayfaya yerleştirilmesi anlamına gelir. Normal CSS, <style> veya <link> öğeleri kullanılarak enjekte edilir ve statik bir kaynağı (ör. DOM düğümü veya ağ kaynağı) vardır. Buna karşılık, JS'de CSS genellikle statik bir kaynağa sahip değildir. Buradaki özel durum, bir <style> öğesinin içeriğinin CSSOM API kullanılarak güncellenebilmesidir. Bu durum, kaynağın gerçek CSS stil sayfasıyla senkronize olmamasına neden olur.

JS'de CSS kitaplığı (ör. styled-component, Emotion, JSS) kullanıyorsanız kitaplık, geliştirme moduna ve tarayıcıya bağlı olarak CSSOM API'lerini kullanarak arka planda stiller enjekte edebilir.

CSSOM API'yi kullanarak CSS-in-JS kitaplıklarının yaptığına benzer şekilde bir stil sayfası eklemeyle ilgili bazı örneklere göz atalım.

// Insert new rule to an existing CSS stylesheet
const element = document.querySelector('style');
const stylesheet = element.sheet;
stylesheet.replaceSync('.some { color: blue; }');
stylesheet.insertRule('.some { color: green; }');

Ayrıca tamamen yeni bir stil sayfası da oluşturabilirsiniz:

// Create a completely new stylesheet
const stylesheet = new CSSStyleSheet();
stylesheet.replaceSync('.some { color: blue; }');
stylesheet.insertRule('.some { color: green; }');

// Apply constructed stylesheet to the document
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];

Geliştirici Araçları'nda CSS desteği

DevTools'ta CSS ile çalışırken en sık kullanılan özellik Stiller bölmesidir. Stiller bölmesinde, belirli bir öğe için hangi kuralların geçerli olduğunu görüntüleyebilir, kuralları düzenleyebilir ve sayfadaki değişiklikleri anında görebilirsiniz.

Geçen yıldan önce, CSSOM API'leri kullanılarak değiştirilen CSS kuralları için destek oldukça sınırlıydı: Uygulanan kuralları yalnızca görebilir ancak düzenleyemezdiniz. Geçen yılki ana hedefimiz, Stiller bölmesi kullanılarak JS'de CSS kurallarının düzenlenmesine izin vermekti. Bazen, JS'de CSS stillerini Web API'leri kullanılarak oluşturulduklarını belirtmek için "oluşturulan" olarak da adlandırırız.

Geliştirici Araçları'nda stil düzenlemenin işleyiş şekliyle ilgili ayrıntılara göz atalım.

Geliştirici Araçları'ndaki stil düzenleme mekanizması

Geliştirici Araçları&#39;ndaki stil düzenleme mekanizması

DevTools'ta bir öğe seçtiğinizde Stiller bölmesi gösterilir. Stiller bölmesi, öğe için geçerli CSS kurallarını almak üzere CSS.getMatchedStylesForNode adlı bir CDP komutu gönderir. CDP, Chrome DevTools Protokolü'nün kısaltmasıdır ve DevTools ön ucunun, incelenen sayfa hakkında ek bilgi almasına olanak tanıyan bir API'dir.

Çağrıldığında CSS.getMatchedStylesForNode, belgedeki tüm stil sayfalarını tanımlar ve tarayıcının CSS ayrıştırıcısını kullanarak bunları ayrıştırır. Ardından, her CSS kuralını stil sayfası kaynağındaki bir konumla ilişkilendiren bir dizin oluşturur.

CSS'nin neden tekrar ayrıştırılması gerekiyor? diye sorabilirsiniz. Buradaki sorun, tarayıcının performans nedeniyle CSS kurallarının kaynak konumlarıyla ilgilenmemesi ve bu nedenle bunları saklamamasıdır. Ancak DevTools'un CSS düzenlemeyi desteklemesi için kaynak konumlarına ihtiyacı vardır. Normal Chrome kullanıcılarının performans cezasını ödemesini istemeyiz ancak DevTools kullanıcılarının kaynak konumlara erişmesini isteriz. Bu yeniden ayrıştırma yaklaşımı, her iki kullanım alanını da minimum olumsuz etkiyle ele alır.

Ardından CSS.getMatchedStylesForNode uygulaması, tarayıcının stil motorundan belirli öğeyle eşleşen CSS kuralları sağlamasını ister. Son olarak yöntem, stil motoru tarafından döndürülen kuralları kaynak kodla ilişkilendirir ve CSS kurallarıyla ilgili yapılandırılmış bir yanıt sağlar. Böylece DevTools, kuralın hangi kısmının seçici veya özellikler olduğunu bilir. Bu, DevTools'un seçiciyi ve özellikleri bağımsız olarak düzenlemesine olanak tanır.

Şimdi düzenlemeye bakalım. CSS.getMatchedStylesForNode işlevinin her kural için kaynak konumlarını döndürdüğünü hatırlıyor musunuz? Bu, düzenleme için çok önemlidir. Bir kuralı değiştirdiğinizde DevTools, sayfayı gerçekten güncelleyen başka bir CDP komutu gönderir. Komut, güncellenen kural parçasının orijinal konumunu ve parçanın güncellenmesi gereken yeni metnini içerir.

Geliştirici Araçları, arka uçta düzenleme çağrısını işlerken hedef stil sayfasını günceller. Ayrıca, yönettiği stil sayfası kaynağının kopyasını ve güncellenen kuralın kaynak konumlarını da günceller. Düzenleme çağrısına yanıt olarak DevTools ön ucu, yeni güncellenen metin parçasının güncellenmiş konumlarını alır.

Bu, DevTools'ta JS'de CSS düzenlemenin neden hazır olarak çalışmadığını açıklar: JS'de CSS'nin herhangi bir yerde depolanmış gerçek bir kaynağı yoktur ve CSS kuralları, CSSOM veri yapılarında tarayıcının belleğinde bulunur.

JS'de CSS desteğini nasıl ekledik?

Bu nedenle, JS'de CSS kurallarının düzenlenmesini desteklemek için en iyi çözümün, yukarıda açıklanan mevcut mekanizma kullanılarak düzenlenebilecek oluşturulmuş stil sayfaları için bir kaynak oluşturmak olduğuna karar verdik.

İlk adım, kaynak metni oluşturmaktır. Tarayıcının stil motoru, CSS kurallarını CSSStyleSheet sınıfında depolar. Bu sınıf, daha önce de belirtildiği gibi JavaScript'den örnek oluşturabileceğiniz sınıftır. Kaynak metni oluşturmak için kullanılacak kod aşağıdaki gibidir:

String InspectorStyleSheet::CollectStyleSheetRules() {
  StringBuilder builder;
  for (unsigned i = 0; i < page_style_sheet_->length(); i++) {
    builder.Append(page_style_sheet_->item(i)->cssText());
    builder.Append('\n');
  }
  return builder.ToString();
}

CSSStyleSheet örneğinde bulunan kuralları iterasyonla tarar ve tek bir dize oluşturur. Bu yöntem, InspectorStyleSheet sınıfının bir örneği oluşturulduğunda çağrılır. InspectorStyleSheet sınıfı bir CSSStyleSheet örneğini sarar ve DevTools tarafından gerekli olan ek meta verileri ayıklayıp çıkarır:

void InspectorStyleSheet::UpdateText() {
  String text;
  bool success = InspectorStyleSheetText(&text);
  if (!success)
    success = InlineStyleSheetText(&text);
  if (!success)
    success = ResourceStyleSheetText(&text);
  if (!success)
    success = CSSOMStyleSheetText(&text);
  if (success)
    InnerSetText(text, false);
}

Bu snippet'te, CollectStyleSheetRules işlevini dahili olarak çağıran CSSOMStyleSheetText işlevini görüyoruz. Stil sayfası satır içi veya kaynak stil sayfası değilse CSSOMStyleSheetText çağrılır. Temel olarak bu iki snippet, new CSSStyleSheet() kurucu kullanılarak oluşturulan stil sayfalarının temel düzeyde düzenlenmesine zaten olanak tanır.

CSSOM API kullanılarak mutasyona uğratılmış <style> etiketiyle ilişkili stil sayfaları özel bir durumdur. Bu durumda stil sayfası, kaynak metni ve kaynakta bulunmayan ek kuralları içerir. Bu durumu ele almak için bu ek kuralları kaynak metne birleştiren bir yöntem sunuyoruz. CSS kuralları orijinal kaynak metnin ortasına eklenebilir. Bu nedenle, burada sıra önemlidir. Örneğin, orijinal <style> öğesinin aşağıdaki metni içerdiğini varsayalım:

/* comment */
.rule1 {}
.rule3 {}

Ardından sayfa, JS API'yi kullanarak aşağıdaki kural sırasını oluşturan bazı yeni kurallar ekledi: .rule0, .rule1, .rule2, .rule3, .rule4. Birleştirme işleminden sonra ortaya çıkan kaynak metin şöyle olmalıdır:

.rule0 {}
/* comment */
.rule1 {}
.rule2 {}
.rule3 {}
.rule4 {}

Kuralların kaynak metin konumlarının tam olması gerektiğinden, orijinal yorumların ve girintilerin korunması düzenleme işlemi için önemlidir.

JS'de CSS stil sayfalarının özel bir başka yönü de sayfa tarafından dilediğiniz zaman değiştirilebilmeleridir. Gerçek CSSOM kuralları metin sürümüyle senkronize olmazsa düzenleme çalışmaz. Bunun için, bir stil sayfası değiştirilirken tarayıcının DevTools'un arka uç kısmını bilgilendirmesine olanak tanıyan bir prob özelliğini kullanıma sunduk. Mutasyona uğramış stil sayfaları, CSS.getMatchedStylesForNode işlevinin bir sonraki çağrısı sırasında senkronize edilir.

Tüm bu parçalar mevcut olduğunda JS'de CSS düzenleme zaten çalışır ancak kullanıcı arayüzünü, bir stil sayfasının oluşturulup oluşturulmadığını belirtecek şekilde iyileştirmek istedik. CDP'nin CSS.CSSStyleSheetHeader özelliğine, ön uçta CSS kuralının kaynağını düzgün şekilde görüntülemek için kullanılan isConstructed adlı yeni bir özellik ekledik:

Oluşturulabilir stil sayfası

Sonuçlar

Buradaki hikayemizi özetlemek gerekirse, DevTools'un desteklemediği JS'de CSS ile ilgili ilgili kullanım alanlarını inceledik ve bu kullanım alanlarını destekleyen çözümü adım adım açıkladık. Bu uygulamanın ilginç yanı, CSSOM CSS kurallarına normal bir kaynak metin ekleyerek mevcut işlevlerden yararlanabilmemiz ve DevTools'ta stil düzenlemenin tamamen yeniden tasarlanması ihtiyacını ortadan kaldırabilmemizdir.

Daha fazla bilgi için tasarım önerimizi veya ilgili tüm yamalar için referans veren Chromium takip hatasına göz atın.

Önizleme kanallarını indirme

Varsayılan geliştirme tarayıcınız olarak Chrome Canary, Yeni Geliştirilenler veya Beta sürümünü kullanabilirsiniz. Bu önizleme kanalları, en son DevTools özelliklerine erişmenizi sağlar, en yeni web platformu API'lerini test etmenize olanak tanır ve sitenizdeki sorunları kullanıcılarınızdan önce bulmanıza yardımcı olur.

Chrome Geliştirici Araçları Ekibi ile iletişime geçme

Yeni özellikler, güncellemeler veya Geliştirici Araçları ile ilgili başka herhangi bir konu hakkında konuşmak için aşağıdaki seçenekleri kullanın.