14 Ocak 2016 Perşembe

CSS3 Gradients(renk geçişleri)

      CSS3 renk geçişleri oluşturabilmek için iki fonksiyon tanımlamıştır.

  • linear-gradient
  • radial-gradient

      İsimlerinden de anlaşılacağı üzere biri doğrusal(linear), diğeri dairesel(radial) geçişler olurturuyor. Bu özellik ancak, özellik olarak resim atayabildiğimiz elementlerde kullanılabilir. Mesela background-image, border-image, list-style-image gibi elementler. Biz daha çok background-image üzerinden gideceğiz ve filmin sonunda border-image durumuna bir göz atacağız. Şöyle bir elementimiz olsun:

<div class="boxx">Lorem ipsum</div>

      CSS:

.boxx { background-image: linear-gradient(yellow, green); }
Lorem ipsum

       Fonksiyonun en basit ve sade kullanımı yukarıdaki kullanımdır. Fonksiyona yazdığımız birinci renkten ikinci renge doğru bir geçiş olmakta. Ve bu şekilde başka bir değer belirtmezsek işlem, yukarıdan aşağı doğru gerçekleşmekte. Bu yönü değiştirmek için derece kullanabildiğimiz gibi anahtar kelimeler de kullanabiliyoruz. Mesela:

      to left

.boxx { background-image:linear-gradient(to left, yellow, green) }
Lorem ipsum

      to right

.boxx { background-image:linear-gradient(to right, yellow, green) }
Lorem ipsum

      to left top

.boxx { background-image:linear-gradient(to left top, yellow, green) }
Lorem ipsum

      to right bottom

.boxx { background-image:linear-gradient(to right bottom, yellow, green) }
Lorem ipsum

      10deg

.boxx { background-image:linear-gradient( 10deg, yellow, green) }
Lorem ipsum

      20deg

.boxx { background-image:linear-gradient( 20deg, yellow, green) }
Lorem ipsum

      30deg

.boxx { background-image:linear-gradient( 30deg, yellow, green) }
Lorem ipsum

      40deg

.boxx { background-image:linear-gradient( 40deg, yellow, green) }
Lorem ipsum

      50deg

.boxx { background-image:linear-gradient( 50deg, yellow, green) }
Lorem ipsum

      60deg

.boxx { background-image:linear-gradient( 60deg, yellow, green) }
Lorem ipsum

      70deg

.boxx { background-image:linear-gradient( 70deg, yellow, green) }
Lorem ipsum

      80deg

.boxx { background-image:linear-gradient( 80deg, yellow, green) }
Lorem ipsum

      90deg

.boxx { background-image:linear-gradient( 90deg, yellow, green) }
Lorem ipsum

      120deg

.boxx { background-image:linear-gradient( 120deg, yellow, green) }
Lorem ipsum

      Derece değerlerinin hangi yönde ilerlediğini anladığını umuyorum. Sıfır derecede aşağıdan yukarıya işlem yapıyor. Derede arttıkça açı saat yönünde ilerliyor. 90 derece soldan sağa, 180 derece yukarıdan aşağıya doğru işlem yapıyor. Yön belitmediğimiz zaman da yukarıdan aşağıya doğru işlem yapıyordu değil mi, demekki varsayılan değer 180deg imiş.
W3Schools bu fonksiyonu şöyle bildiriyor bize:

linear-gradient(direction, color-stop1, color-stop2, ...)

Bu tanım en az iki renk bildirmek zorunda olduğumuzu gösteriyor. Sondaki üç nokta ise (en az iki renk belirledikten sonra) istediğimiz kadar renk belirtebileceğimizi gösteriyor. Bakalım gerçekten öylemi?

.boxx { background-image:linear-gradient( 90deg, yellow, green, blue, red, darkcyan, darkorange, fuchsia, lavender, lightcoral, powderblue, springgreen, saddlebrown, slateblue) }
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

      Evet çingene bohçası gibi bir elementimiz oldu. Belirlediğimiz renkler varsayılan olarak eşit bir şekilde alanı paylaşıyorlar. Kimin ne kadar alana yayılacağını biz de belirleyebiliriz. Tabi bu kadar çok renk üzerinde değil, biz yine iki renge dönelim. İki rengi, başka bir bilgi belirtmeden direk kullandığımız zaman birinci rengin değeri 0%, ikinci rengin değeri 100% olmuş oluyor. Yani geçiş, elementin tepesinden başlıyor alt sınırda bitiyor. Yani elementin görünen tüm alanı geçiş alanı olmuş oluyor. Nasıl oluyor? Tanıma tekrar bakalım.

linear-gradient(direction, color-stop1, color-stop2, ...)

      Bu tanımda direction'ın ne olduğu belli. Adamların color-stop dediği şeye ise biz kısaca renk durma noktası diyeceğiz. Evet çok da kısa değil ama mânâyı kaybetmemek için daha fazla kısaltmıyorum. Renk durma noktası işin tam tanımını yapıyor aslında. Zaten o yüzden bu adı vermişler buna. Yoksa niye versinler, manyak mı bu adamlar? Yapılan işlem durma noktası belirlemek renge.

.boxx { background-image: linear-gradient( yellow, green }
Lorem ipsum

      Bu durumda birinci rengin durma noktası 0%'dır. Buna direk 0 da diyebiliriz. Yani elementin üst sınır çizgisi. İkinci rengin durma noktası 100%'dür. Yani elementin alt sınır çizgisi. Arada kalan alan ise geçiş alanı. Bu iki durma noktası birbirinden ne kadar uzak olursa renklerin birbirine karışması da o kadar belli belirsiz olur. Bu durma noktalarına negatif değerler de verilebiliyor.

.boxx { background-image: linear-gradient( yellow -100%, red 200%) }
Lorem ipsum

      Dediğimiz gibi çok hafif bir geçiş oldu. Ve bunun tersi olarak, durma noktalarının arasındaki mesafeyi yakın tutarsak eğer daha düz bir geçiş elde ederiz.

.boxx { background-image: linear-gradient( yellow 40%, red 60%) }
Lorem ipsum

Peki aradaki mesafeyi sıfıra indirirsek ne olur?
Tabiki geçiş olmaz. Yani iki düz renk elde ederiz.

.boxx { background-image: linear-gradient( yellow 40%, red 40%) }
Lorem ipsum

      İki rengin de durma noktası aynı ama üçüncü bir renk olmadığı için elementin 40%'tan sonraki kısmını kırmızı renk kaplıyor. Üçüncü bir renk olsaydı o renk kaplayacaktı kalan alanı. Durma noktalarına aynı değerleri vererek şeritli arkaplanlar yapabiliriz. Bunun için sadece background-size özelliğine istediğimiz genişliğini vermemiz yeterli. background-size özelliği iki değer alır. Bu değerler sırasıyla x ve y ekseninde arkaplanın genişliğini belirlememizi sağlar. Arkaplan varsayılan olarak x ve y ekseninde elementi kaplayana kadar tekrar ettiği için sonuç şeritli bir arkaplan olur.

.boxx { background-image: linear-gradient( yellow 40%, red 40%); background-size:10px 30px }
Lorem ipsum

      Aslında burada 10x30'luk bir parça yaptık sadece. Eğer arkaplan tekrar etmesin dersek bu parçayı görebiliriz.

.boxx { background-image: linear-gradient( yellow 40%, red 40%); background-size:10px 30px; background-repeat: no-repeat }

      Ayrıca ikinci değere 0 verseydik yine önceki rengin değeri verilmiş kabul edilirdi. Bu şekilde rengin genişliğini değiştirmek istediğimiz zaman iki değil bir değeri değiştirmemiz yeterli olacak. O yüzden şerit yaparken bu şekilde yapacağız.

.boxx { background-image: linear-gradient( midnightblue 33%, saddlebrown 0, saddlebrown 66%, blueviolet 0, blueviolet 99%); background-size:10px 30px }

      0 değeri verdiğimiz renkler, bir önceki rengin durma noktasıyla aynı durma noktasına sahip olduğu anlamına geliyor. Renkleri birbiri ardınca nasıl uzattığımıza dikket et. Bu şekilde dilediğin kadar şerit oluşturabilirsin. Fakat bunun biraz daha kolay bir yolunu da bulabiliriz.

repeating-linear-gradient()

.boxx { background-image: repeating-linear-gradient(yellow 0, yellow 20px, blue 0, blue 40px) }

      background-size belirtmedik. Ayrıca ilk rengin sıfır değerini belirttik. Eğer renklere hiç bir değer belirtmeseydik önceki fonksiyon gibi işlem yapacaktı.

boxx { background-image: repeating-linear-gradient(yellow, blue) }

      repeating olayında renklere değer verirken, bir önceki rengin değerinden daha büyük değer vermemiz gerekiyor ki işlemi görebilelim.

.boxx { background-image: repeating-linear-gradient(yellow 0px, blue 40px) }

      Renklere verdiğimiz değerler ile belirttiğimiz alan kadar bir gradient oluşturuyor ve elementin geri kalan kısmında da bunu tekrar ediyor. İki renk değerinin farkı gradient'in yüksekliğidir. Yukardaki her bir gradient 40px yüksekliğinde. Eğer gradient soldan sağa olsaydı genişliği 40px olacaktı.

      Şerit olayına dönecek olursak, kullanımı yukarda görmüş olduğun gibi normal fonksiyon ile aynı. Fakat her iki fonksiyonda da renk sayısını arttırınca sıkıntı başlıyor. Mesela 4 renkli bir şerit yapmak istersek şöyle:

.boxx { background-image: repeating-linear-gradient(45deg, goldenrod 0, goldenrod 20px, yellow 0px, yellow 40px,  violet 0, violet 60px, chartreuse 0, chartreuse 80px) }

      Eğer şeritli arkaplanları seviyorsan ve sürekli kullanacaksan, her seferinde bunu böyle sıfırdan başlayıp yazmak bir süre sonra iyice sıkıcı olmaya başlar. Bu yazım tarzını biraz daha makul hale getirmek css önişlemci uygulamalarıyla mümkün. Sass, Less veya (benim favorim) Stylus bu konuda sana çok yardımcı olacaktır. Ben stylus kullanıyorum. Pek fazla stylus bilgim yok ama biraz uğraşarak bg-stripe fonksiyonunu yazdım. Gerçi css profesörleri buna fonksiyon değil mixin diyorlar ama şimdiye kadar programlama dilleriyle uğraştığım için ağız alışkanlığından dolayı fonksiyon diyorum ben. Sen istersen kamyon lastiği diyebilirsin.

See the Pen bg-stripe (with stylus) by hsyn (@hsyn12) on CodePen.

      Bu fonksiyona göre sadece renkleri bildirerek kullanabiliyoruz. Bu şekilde şerit kalınlığı ile yön değeri varsayılan olarak .7em ve 45deg.

.boxx
  bg-stripe(red, green, blue)

      Varsayılan değerleri değiştirmek istersek şöyle yazıyoruz:

.boxx
  bg-stripe(red, green, blue, size:2em)

      Veya:

.boxx
  bg-stripe(red, green, blue, size:1em, direction:135deg)

radial-gradient()

      Bu fonksiyon da yukarıdaki fomksiyonlardan çok farklı değil. En yalın hali şöyle:

.boxx { background-image:radial-gradient(red, yellow) }

      Yazının başında bu fonksiyon için dairesel dedik ama gördüğün gibi tam olarak dairesel değil. Tam olarak dairesel yapmak için:

.boxx { background-image:radial-gradient(circle, red, yellow) }

      Hâlâ net bir şekilde dairesel olup olmadığı tam ortaya çıkmadı ama birazdan çıkacak. Önce w3schools fonksiyonu nasıl tanıtıyor ona bakalım.

radial-gradient(shape size at position, start-color, ..., last-color)

      Bu arada, biz sürekli background-image özelliğini kullanıyoruz ama background özelliğine de yazabiliriz bu gradient'leri. Çünkü gradientler tamamen resim özelliğinde ve resim gibi işlem görüyor. Arkaplana nasıl direk resim atayabiliyorsak gradient de atayabiliriz.

Fonksiyondaki shape parametresi şekil oluyor ve buraya iki şekilden biri girilebiliyor.

  1. ellipse
  2. circle

      Tahmin edebildiğin gibi varsayılan değer ellipse. size parametresinin ise alabileceği dört değer var.

  1. closest-side
  2. farthest-side
  3. closest-corner
  4. farthest-corner

      Tahmin edemeyeceğin üzere varsayılan değer farthest-corner. Tabi bunların ne anlama geldiğini anlamak için bir bakış atmamız gerekiyor. Son olarak at position parametresi olayın nerede patlak vereceğini belirlemek için. Varsayılan değer center. Anlaşıldığı üzere yön belirten anahtar kelimeler kullanılabiliyor, bunun yanında tabiki herhangi bir ölçü birimi de kullanılabilir.

div:nth-child(1) { background: radial-gradient(circle closest-side at 60% 40%, #f00, #ff0)}
div:nth-child(2) { background: radial-gradient(circle farthest-side at 60% 40%, #f00, #ff0)}
div:nth-child(3) { background: radial-gradient(circle closest-corner at 60% 40%, #f00, #ff0)}
div:nth-child(4) { background: radial-gradient(circle farthest-corner at 60% 40%, #f00, #ff0)}
closest-side
farthest-side
closest-corner
farthest-corner

      closest-side değerinde gradient tamamen elementin sınırları içinde kalıyor. Türkçe karşılığı ise en yakın kenar anlamında. Elemente bakınca anlaşılıyor değil mi? Gradient kendine en yakın kenarı baz alıyor ve onun dışına çıkmıyor. Böylece renk geçişi elementin içinde kalıyor. Fakat farthest-side değerinde renk geçişi elementin biraz dışına çıkıyor. Çünkü anlamı en uzak kenar. Bu yüzden renk geçişi biraz daha fazla alana yayılıyor ve elementin dışına çıkabiliyor. Fakat baz aldığı kenarı kesinlikle aşmıyor. Zaten kendini o kenara göre yayıyor. closest-corner ise tabiki en yakın köşe anlamına geliyor ve şekle bakınca da anlaşılıyor derdi. Renk geçişi en yakın köşeyi aşmayacak şekilde yayılıyor. farthest-corner ise en uzak köşe demek ve gördüğün gibi en uzak köşeyi kendine sınır yapıyor ve ona göre yayılıyor renk geçişi.

      Birden fazla gradient de belirtebiliriz haberin olsun. Fakat birden fazla gradient olunca hepsi üstüste bineceği için sadece bir tanesi görünecek. Mantîken son belirtilen gradient'in görünmesi gerekirken ilginç bir şekilde ilk belirtilen gradient görünüyor. Sorun değil. Sorun, renkleri transparan olarak belirtmek zorunda olduğumuz. Renklerin opacity değelerini uygun düzeye indirip kullanmak gerekiyor. Ama hiç bununla uğraşmadan background-blend-mode özelliğine multiply değeri vererek bu işi css'e ihâle edebiliriz.

.boxx {
        background: radial-gradient(at 10% 50%, aqua, burlywood, chartreuse),
                    radial-gradient(at 50% 50%, ghostwhite, palegreen, yellow),
                    radial-gradient(at 90% 50%, lightsteelblue, blueviolet, orangered);
        height: 400px;
        background-blend-mode: multiply;
}

      Ama bunu circle değeri ile yaparsak biraz daha anlamlı olabilir.

.boxx {
    background: radial-gradient(circle at 10% 50%, aqua, burlywood, chartreuse),
                radial-gradient(circle at 50% 50%, ghostwhite, palegreen, yellow),
                radial-gradient(circle at 90% 50%, lightsteelblue, blueviolet, orangered);
    height: 400px;
    background-blend-mode: multiply;
}

Fakat renklere değer verirsek neler olduğunu biraz daha iyi anlayabiliriz.

.boxx {
    background: radial-gradient(circle at 10% 50%, aqua 40px, burlywood 80px, chartreuse 120px),
                radial-gradient(circle at 50% 50%, ghostwhite 40px, palegreen 80px, yellow 120px),
                radial-gradient(circle at 90% 50%, lightsteelblue 40px, blueviolet 80px, orangered 120px);
    height: 400px;
    background-blend-mode: multiply;
}

      Bu şekilde yapacaksak renkleri mümkün olduğunca açık seçmemiz gerek, çünkü renkler birbirine girdikçe koyulaşıyor. Ama bu da ilginç bir durum. Çünkü beyaz diye tâbir ettiğimiz renk tüm renklerin karışımıdır değil mi? Ama burada renkler karıştıkça koyulaşıyor ve arkaplan kararıyor.

.boxx {
    background: radial-gradient(circle at 10% 50%, mediumblue 40px, mediumslateblue 80px, tomato 120px),
                radial-gradient(circle at 50% 50%, maroon 40px, teal 80px, darkgreen 120px),
                radial-gradient(circle at 90% 50%, purple 40px, darkcyan 80px, orangered 120px);
    height: 400px;
    background-blend-mode: multiply;
}

      Olay bu. Tabi böyle tek tek renk belirleyip uğraşacak değiliz. Şuradan kafamıza göre ayrlayıp kullanabiliriz.

      Şimdi gelelim şeritli radial mevzusuna. Yine linear olayında olduğu gibi aynı taktikle dairesel şeritler yapabiliriz. Taktik neydi? Renklere aynı durma noktaları tanımlıyorduk değil mi? Ve bunu yaparken de önceki rengi biraz sonraki renge sündürüyorduk.

.boxx { background: radial-gradient(circle, darkorange 0, darkorange 30px,
                                             red 0, red 60px,
                                             navy 0, navy 90px);
}

      İstediğimiz sonuç tabiki bu değil. Ama neye ihtiyacımız olduğunu tahmin edebildiğini tahmin edebiliyorum.

repeating-radial-gradient()

.boxx { background: repeating-radial-gradient(circle, darkorange 0, darkorange 30px,
                                                      red 0, red 60px,
                                                      navy 0, navy 90px);
}

      Yine tahmin edebileceğin gibi bunu da otomatiğe bağlayabiliriz.

See the Pen radial stripe with stylus by hsyn (@hsyn12) on CodePen.

      Yukarılarda biryerlerdeki linear olayından hiç bir farkı yok. Zaten kodları da ordan kopyalayıp yapıştırdım ve koordinat ile radial kısmını, bir de size değerini değiştirdim hepsi bu. Bu fonksiyona göre, sadece renkleri belirterek elementin ortasından başlayan dairesel şeritler yapabiliyoruz.

.boxx {
      radGrad(red, green, blue);
  }

      Koordinat veya ölçü değiştirmek için ise şöyle:

.boxx {
    radGrad(red, green, blue, coordinate:90% 30%, size:10px);
}

      Ayrıca bu gradient'lerin responsive olduğuna da dikkatini çekmek isterim. Yani ekran küçüldüğünde gradient de küçülüyor. Fakat maalesef gradient'ler animasyonlar ile kullanılamıyor. Yani animatable özelliği taşımıyorlar. Aslında kullanılabiliyor, ama gradient üzerindeki değişimi görebilmek için sayfanın yenilenmesi gerekiyor. Tabi o zaman da animasyonun bir anlamı kalmıyor çünkü olay yine başa dönüyor. Fakat bazı arkadaşlar animasyon etkisi verebilmek için akıllıca bir iş yapmışlar. background-position değerini animasyon ile değiştirerek sanki gradient değişiyormuş gibi bir hava yaratmışlar. Bu aleti de buradan kurcalayabilirsin.

border gradient

      Sıra geldi gradient'leri border olarak kullanmaya. Aslında bunun için border-image özelliği yapmışlar ama biz şu kitabın 71. sayfasındaki yöntemi kullanacağız. Bunun için bazı ön bilgilere ihtiyacımız var. Mesela background-clip ve background-origin özelliği. Bu özellik(background-clip), elementin arkaplan renginin nereden başlayacağını belirtiyor. Varsayılan değeri border-box. Yani elementin arkaplan rengi border çizgileri de dahil olamak üzere boyanıyor. background-origin ise arkaplan resminin nereden başlayacağını belirtiyor. Varsayılan değeri padding-box. Yani arkaplan resmi elementin border çizgileri hariç, padding boşluğu dahil olmak üzere elemente yerleşiyor. Bu iki özelliğin alabileceği değerler aynı.

  • border-box (background-clip varsayılan)
  • padding-box (background-origin varsayılan)
  • content-box

      Aradaki fark, background-clip arkaplan boyama alanını, background-origin arkaplan resim alanını kastediyor. Bu bilgiler ışığında olayımız, arkaplana bir gradient atayıp, background-origin özelliğini padding-box'tan border-box'a geçirerek bir alicengiz oyunu yapmak. Tabi ambiyansa uygun border ve padding değerleri de vereceğiz. İki tane gradient'imiz olacak, biri arkaplan renginde ve origin değeri padding-box olacak. Diğeri ise şeritli olacak ve border-box değerinde. En iyisi görelim şunu.

.boxx {
        background: #333;
        height: 15em;
        padding: 1em;
        border: 1.5em solid transparent;
        box-sizing: border-box;
        background: linear-gradient(#333, #333) padding-box,
                    repeating-linear-gradient(45deg,
                                                red 0, red .5em,
                                                #333 0, #333 1em,
                                                green 0, green 1.5em,
                                                #333 0, #333 2em) border-box;
}
Nibh maecenas! Culpa! Natoque. Lorem, amet, blandit eaque minima! Rerum do, integer praesent, dis non? Dis integer aliquip, perferendis facilis, illo, egestas, cupiditate atque voluptas sodales pellentesque, hic turpis tristique pharetra ipsa nullam porttitor neque, hac gravida modi! Beatae harum diam aliquip? Voluptate cursus, mattis! Vel, magnam dignissimos consectetuer nemo? Facilisi, iaculis montes nobis, magnam laboris quia amet reprehenderit dignissimos voluptates orci nihil provident, tempor suspendisse! Asperiores sequi? Corporis incididunt pariatur molestias iusto pariatur nec. Molestias maxime tempora nullam repellat! Maiores incididunt eleifend augue dis dolore ad dolor, curae doloribus! Tempora ab! Repellendus voluptas natus at pariatur sagittis ad nonummy.

      Kitaptakinden biraz farklı yaptık, çünkü kitabı yazan ablamız arkaplan rengini tam hesap etmemiş. Border olarak yaptığımız ikinci gradient'te renkler arasında boşluk oluşturmak için arkaplan rengini kullanmak gerekiyor. Yazar ise transparent değeri kullanmış. transparent değeri yanlızca beyaz arkaplanda çalışır, değişik renkteki arkaplanlarda cırt olur. Aslında bu noktada background özelliğinin de tam olarak nasıl tanımlandığına bir bakmak gerek.

background: color image position/size repeat origin clip attachment

      Biz buradaki image ve origin değerlerini kullandık. Bu durumda anlaşılması pek de zor olmayan bir işlem gerçekleştirmiş olduğumuz da ortaya çıkıyor. Resmin birini border'a, diğerini padding'e dayıyoruz, dolayısıyla birinin kenarı border'da gözüküyor, diğeri ise daha içerde kalıyor. Çünkü 1.5em border, ve 1em de padding verdik. Ve border transparent olduğu için görünmez durumda. Haliyle altındaki gradient origin olarak border-box kullanınca o gradient görünüyor. Normalde bu origin'in padding-box olduğunu yukarda belirtmiştik değil mi?

      İstersen son olarak bunu da otomatikleştirelim.

See the Pen bbox (border gradient with stylus) by hsyn (@hsyn12) on CodePen.

      bbox fonksiyonu yukarıda yazdığımız fonksiyonlardan biraz daha gevşek bir fonksiyon. Çünkü bu olayda değiştirilebilecek çok fazla özellik var. O yüzden fonksiyonu daha fazla çorba etmemek için bazı özellikleri direk elemente vermemiz gerekiyor. Mesela border ve padding değerini. Fonksiyon daha çok gradient üzerine yoğunlaşmış durumda. İstediğin kadar renk belirtebilirsin, fonksiyon hepsinin arasına bir boşluk bırakarak sıraya diziyor. Daha doğrusu aralara arkaplan rengini yerleştiriyor. Böylece sanki boşluk varmış gibi gözüküyor.

Sanırım bir birlikteliğin sdaha sonuna gelmiş bulunmaktayız. Yayında ve yapımda emeği geçen tüm arkadaşlarım adına esenlikler dilerim. Hoşçakalın, esenkalın, kaybolun..