CSS'nin ne kadar iş yaptığını hiç düşündünüz mü? Tek bir özelliği değiştirdiğinizde web sitenizin tamamı birden farklı bir düzende görünür. Bu bir tür sihir. Şu ana kadar, web geliştirici topluluğu olarak bu büyüye yalnızca tanık olup gözlemleyebildik. Peki kendi sihretimizi yaratmak istersek? Sihirbaz olmak isterseniz ne olur?
Houdini'yi kullanın.
Houdini görev gücü, CSS motorunun belirli bölümlerini web geliştiricilerine sunmak için birlikte çalışan Mozilla, Apple, Opera, Microsoft, HP, Intel ve Google'dan mühendislerden oluşur. Çalışma grubu, gerçek web standartları haline gelmeleri için W3C tarafından kabul edilmelerini sağlamak amacıyla taslak koleksiyonu üzerinde çalışıyor. Kendilerine birkaç üst düzey hedef belirlediler, bunları spesifikasyon taslakları haline getirdiler ve bu taslaklar da destekleyici, alt düzey spesifikasyon taslakları oluşturdu.
"Houdini"den bahsedildiğinde genellikle bu taslakların koleksiyonu kastedilir. Bu makale yazılırken taslak listesi eksikti ve taslakların bazıları yalnızca yer tutucuydu.
Teknik özellikler
Worklet'ler (spec)
Worklet'ler tek başına pek yararlı değildir. Bunlar, sonraki taslakların çoğunu mümkün kılmak için sunulan bir kavramdır. "İş parçası" ifadesini gördüğünüzde aklınıza Web İşleyiciler geldiyse haklısınız. Bu iki kavram arasında çok fazla örtüşme vardır. Peki, zaten çalışanlarımız varken neden yeni bir şeye ihtiyacımız var?
Houdini'nin amacı, web geliştiricilerin kendi kodlarını CSS motoruna ve çevre sistemlere bağlamasına olanak tanıyan yeni API'ler sunmaktır. Bu kod parçalarından bazılarının her karede çalıştırılması gerekeceğini varsaymak gerçekçi bir varsayımdır. Bazıları tanımı gereği Web İşleyici spesifikasyonundan alıntı:
Bu, web işçilerinin Houdini'nin yapmayı planladığı işlemler için uygun olmadığı anlamına gelir. Bu nedenle, iş parçacıkları icat edilmiştir. İş parçacıkları, imzaları iş parçasının türüne göre önceden tanımlanmış bir yöntem koleksiyonunu tanımlamak için ES2015 sınıflarından yararlanır. Hafif ve kısa ömürlüdür.
CSS Paint API (özellik)
Paint API, Chrome 65'te varsayılan olarak etkindir. Ayrıntılı girişi okuyun.
Birleştirici iş akışı
Burada açıklanan API kullanımdan kaldırılmıştır. Oluşturucu iş parçası yeniden tasarlandı ve artık "Animasyon İş Parçası" olarak öneriliyor. API'nin mevcut iterasyonu hakkında daha fazla bilgi edinin.
Oluşturucu iş parçası spesifikasyonu WICG'ye taşınmış ve üzerinde çalışılacak olsa da beni en çok heyecanlandıran spesifikasyon bu. Bazı işlemler CSS motoru tarafından bilgisayarınızın grafik kartına aktarılır. Bu, hem grafik kartınıza hem de genel olarak cihazınıza bağlıdır.
Tarayıcı genellikle DOM ağacını alır ve belirli ölçütlere göre bazı dallara ve alt ağaçlara kendi katmanlarını vermeye karar verir. Bu alt ağaçlar kendilerini üzerine boyar (gelecekte bir boyama iş parçası kullanılarak). Son adımda, artık boyanmış olan bu ayrı katmanların tümü, ekranınızda görünen nihai görüntüyü oluşturmak için z-dizinlerine, 3D dönüşümlere ve benzeri öğelere göre üst üste yığılır ve yerleştirilir. Bu işleme kompozisyon adı verilir ve kompozitör tarafından yürütülür.
Birleştirme işleminin avantajı, sayfa biraz kaydırılırken tüm öğelerin kendilerini yeniden boyaması gerekmemesidir. Bunun yerine, önceki karedeki katmanları yeniden kullanabilir ve kompozitörü güncellenmiş kaydırma konumuyla yeniden çalıştırabilirsiniz. Bu sayede işler hızlıca halledilir. Bu sayede 60 fps'ye ulaşabiliriz.
Adından da anlaşılacağı gibi, karıştırıcı iş parçası, karıştırıcıya bağlanmanıza ve bir öğenin önceden boyanmış katmanının diğer katmanların üzerine yerleştirilme ve katmanlandırılma şeklini etkilemenize olanak tanır.
Daha ayrıntılı olarak belirtmek gerekirse tarayıcıya belirli bir DOM düğümü için oluşturma işlemine katılmak istediğinizi söyleyebilir ve kaydırma konumu, transform
veya opacity
gibi belirli özelliklere erişim isteğinde bulunabilirsiniz. Bu, öğenin kendi katmanına yerleştirilmesini zorunlu kılar ve her karede kodunuz çağrılır. Katman dönüştürme özelliğini kullanarak katmanınızı hareket ettirebilir ve özelliklerini (opacity
gibi) değiştirebilirsiniz. Böylece 60 fps'de harika şeyler yapabilirsiniz.
Birleştirici iş parçacığı kullanılarak paralaks kaydırma için tam bir uygulama örneğini aşağıda bulabilirsiniz.
// main.js
window.compositorWorklet.import('worklet.js')
.then(function() {
var animator = new CompositorAnimator('parallax');
animator.postMessage([
new CompositorProxy($('.scroller'), ['scrollTop']),
new CompositorProxy($('.parallax'), ['transform']),
]);
});
// worklet.js
registerCompositorAnimator('parallax', class {
tick(timestamp) {
var t = self.parallax.transform;
t.m42 = -0.1 * self.scroller.scrollTop;
self.parallax.transform = t;
}
onmessage(e) {
self.scroller = e.data[0];
self.parallax = e.data[1];
};
});
Robert Flack, derleyici iş parçası için bir polyfill yazdı. Bu polyfill'i deneyebilirsiniz. Ancak performans üzerindeki etkisi çok daha yüksek olacaktır.
Düzen iş akışı (spec)
İlk gerçek özellik taslağı önerildi. Bu özelliğin kullanıma sunulması biraz zaman alacak.
Bu konudaki spesifikasyon da neredeyse boştur ancak kavram ilgi çekicidir: Kendi düzeninizi yazın. Düzenleme iş parçası, display: layout('myLayout')
yapmanıza ve bir düğümün çocuklarını düğümün kutusunda düzenlemek için JavaScript'inizi çalıştırmanıza olanak tanır.
Elbette CSS'nin flex-box
düzeninin tam JavaScript uygulaması, eşdeğer bir doğal uygulamayı çalıştırmaktan daha yavaştır. Ancak, köşeleri kesmenin performans kazancı sağlayabileceği bir senaryo hayal etmek kolaydır. Windows 10 veya tuğla stilinde bir düzen gibi yalnızca kartlardan oluşan bir web sitesi düşünün. Mutlak ve sabit konumlandırma, z-index
kullanılmaz, öğeler hiçbir zaman örtüşmez veya herhangi bir kenarlık ya da taşma olmaz. Yeniden düzende tüm bu kontrolleri atlayabilmek performans kazancı sağlayabilir.
registerLayout('random-layout', class {
static get inputProperties() {
return [];
}
static get childrenInputProperties() {
return [];
}
layout(children, constraintSpace, styleMap) {
const width = constraintSpace.width;
const height = constraintSpace.height;
for (let child of children) {
const x = Math.random()*width;
const y = Math.random()*height;
const constraintSubSpace = new ConstraintSpace();
constraintSubSpace.width = width-x;
constraintSubSpace.height = height-y;
const childFragment = child.doLayout(constraintSubSpace);
childFragment.x = x;
childFragment.y = y;
}
return {
minContent: 0,
maxContent: 0,
width: width,
height: height,
fragments: [],
unPositionedChildren: [],
breakToken: null
};
}
});
Yazılı CSSOM (spec)
Yazılı CSSOM (CSS Nesne Modeli veya Basamaklı Stil Sayfaları Nesne Modeli), muhtemelen hepimizin karşılaştığı ve kabul etmeyi öğrendiği bir sorunu ele alır. Bunu bir JavaScript satırı ile açıklamak isterim:
$('#someDiv').style.height = getRandomInt() + 'px';
Bir birim eklemek için bir sayıyı bir dizeye dönüştürerek matematik yapıyoruz. Ardından, tarayıcının bu dizeyi ayrıştırmasını ve CSS motoru için tekrar sayıya dönüştürmesini sağlıyoruz. JavaScript ile dönüşümleri değiştirdiğinizde bu durum daha da kötüye gider. Artık yok. CSS'de yazma işlemi başlayacak.
Bu taslak, daha gelişmiş taslaklardan biridir ve üzerinde bir polyfill üzerinde çalışılmaktadır. (Sorumluluk reddi beyanı: polyfill kullanmak, hesaplama yükü açısından daha da fazla artışa neden olur. Amaç, API'nin ne kadar kullanışlı olduğunu göstermektir.)
Dize yerine, her CSS özelliğinin kendi anahtarına ve karşılık gelen değer türüne sahip olduğu bir öğenin StylePropertyMap
üzerinde çalışırsınız. width
gibi özelliklerin değer türü LengthValue
'tür. LengthValue
, em
, rem
, px
, percent
vb. gibi tüm CSS birimlerinin sözlüğüdür. height: calc(5px + 5%)
ayarlandığında LengthValue{px: 5, percent: 5}
elde edilir. box-sizing
gibi bazı mülkler yalnızca belirli anahtar kelimeleri kabul eder ve bu nedenle KeywordValue
değer türüne sahiptir. Bu özelliklerin geçerliliği çalışma zamanında kontrol edilebilir.
<div style="width: 200px;" id="div1"></div>
<div style="width: 300px;" id="div2"></div>
<div id="div3"></div>
<div style="margin-left: calc(5em + 50%);" id="div4"></div>
var w1 = $('#div1').styleMap.get('width');
var w2 = $('#div2').styleMap.get('width');
$('#div3').styleMap.set('background-size',
[new SimpleLength(200, 'px'), w1.add(w2)])
$('#div4')).styleMap.get('margin-left')
// => {em: 5, percent: 50}
Özellikler ve değerler
(spec)
CSS özel özelliklerini (veya resmi olmayan takma adları olan "CSS değişkenleri"ni) biliyor musunuz? Bunlar, türleri de içeren öğelerdir. Şimdiye kadar değişkenler yalnızca dize değerlerine sahip olabiliyordu ve basit bir arama ve değiştirme yaklaşımı kullanılıyordu. Bu taslak, değişkenleriniz için yalnızca bir tür belirtmenize değil, aynı zamanda varsayılan bir değer tanımlamanıza ve JavaScript API'si kullanarak devralma davranışını etkilemenize olanak tanır. Teknik olarak bu, özel özelliklerin standart CSS geçişleri ve animasyonlarıyla canlandırılmasına da olanak tanır. Bu da üzerinde düşünülen bir konudur.
["--scale-x", "--scale-y"].forEach(function(name) {
document.registerProperty({
name: name,
syntax: "<number>",
inherits: false,
initialValue: "1"
});
});
Yazı tipi metrikleri
Yazı tipi metrikleri, adından da anlaşılacağı gibidir. X dizesini Y yazı tipiyle Z boyutunda oluşturuyorum. Sınırlayıcı kutu (veya sınırlayıcı kutular) nedir? Ruby ek açıklamalarını kullanırsam ne olur? Bu özellik çok fazla istendi ve Houdini nihayet bu istekleri yerine getirecek.
Bir saniye, hepsi bu kadar da değil!
Houdini'nin taslak listesinde daha da fazla özellik var ancak bunların geleceği oldukça belirsiz ve fikirler için yer tutucudan başka bir şey değiller. Özel taşma davranışları, CSS söz dizimi uzantısı API'si, yerel kaydırma davranışının genişletilmesi ve benzer şekilde iddialı olan ve web platformunda daha önce mümkün olmayan şeyleri mümkün kılan özellikler bu kapsamdadır.
Demolar
Demonun kodunu (polyfill kullanan canlı demo) açık kaynak olarak yayınladım.