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

Alex Rudenko
Alex Rudenko

Bu makalede, Chrome 85'ten itibaren kullanıma sunulan Geliştirici Araçları'nda CSS-in-JS desteği, genel olarak CSS-in-JS ile ne kastettiğimiz ve Geliştirici Araçları tarafından uzun süredir desteklenen normal CSS'den farkı açıklanmaktadı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 son CSS çıkışı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 yerleştirilir ve statik bir kaynağa (ör. DOM düğümü veya ağ kaynağı) sahiptir. Buna karşılık, JS'de CSS genellikle statik bir kaynağa sahip değildir. Buradaki özel bir durum, <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.

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

Şimdi de CSS-in-JS kitaplıklarının yaptıklarına benzer şekilde CSSOM API'yi kullanarak stil sayfasını nasıl yerleştirebileceğinize dair bazı örneklere bakalı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; }');

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 temel hedefimiz, Stiller bölmesini kullanarak CSS-in-JS kurallarının düzenlenmesine izin vermekti. Bazen, Web API'leri kullanılarak oluşturulduklarını belirtmek için CSS-in-JS stillerini "structured" olarak da adlandırırız.

Geliştirici Araçları'nda stil düzenleme işleminin ayrıntılarına 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ı ö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 dezavantajla ele alır.

Daha sonra CSS.getMatchedStylesForNode uygulaması, tarayıcının stil motorundan belirtilen öğ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, Geliştirici Araçları'nın 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ı yürütürken 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, Geliştirici Araçları ön ucu, yeni güncellenen metin parçasının güncellenmiş konumlarını geri alır.

Bu, Geliştirici Araçları'nda CSS-in-JS'yi düzenlemenin neden anında gerçekleştirilemediğini açıklar: CSS-in-JS'nin hiçbir yerde gerçek bir kaynağı yoktur ve CSS kuralları, CSSOM veri yapılarında tarayıcının belleğinde yer alır.

CSS-in-JS için desteği nasıl ekledik?

Dolayısıyla, JS'de CSS kurallarının düzenlenmesini desteklemek için, en iyi çözümün, oluşturulmuş stil sayfaları için yukarıda açıklanan mevcut mekanizma kullanılarak düzenlenebilecek 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 açıklandığı gibi JavaScript'ten örnekleri oluşturabileceğiniz sınıftır. Kaynak metni oluşturmak için gereken 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 bunlardan 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 sarmalar ve Geliştirici Araçları'nın ihtiyaç duyduğu ek meta verileri ayıklar:

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, dahili olarak CollectStyleSheetRules çağrısı yapan CSSOMStyleSheetText adını 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 zaten new CSSStyleSheet() oluşturucusu kullanılarak oluşturulan stil sayfalarının temel düzenlenmesine 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 metinde 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 şu 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 yönü de sayfa tarafından dilediğiniz zaman değiştirilebilmesidir. Gerçek CSSOM kuralları metin sürümüyle senkronize edilmezse 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ının normal kaynak metni olmasını sağlayarak mevcut işlevlerden yararlanmamız oldu. Böylece, Geliştirici Araçları'nda stil düzenlemenin tamamen yeniden tasarlanması gerekmiyor.

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

Chrome Canary, Yeni geliştirilenler veya Beta'yı varsayılan geliştirme tarayıcınız olarak 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.