CSS Filter funkcije
U CSS-u ostoji poseban atribut filter koji koristimo kada želimo da primenimo neki od specijalnih efekata (filtera) na neki elemenat. Filteri predstavljaju algoritamske transformacije slike. Sa njima se obično srećemo u softverskim alatima za obradu slike, poput Adobe Photoshopa. Najčešće je u pitanju manipulacija bojama, ali filteri mogu služiti i za generisanje proceduralnog grafičkog sadržaja (npr. lens flare, clouds, mosaic tiles i sl. efekti) ili manipulaciju pikselima (npr. blur, sharpen, offset, twirl...)
CSS za sada prepoznaje desetak osnovnih filtera, koji se uglavnom svode na kolor manipulaciju. U softverima za rad sa grafikom, većina ovih efekata i nisu zaista filteri, već prosto komande za obradu slike.
brightness() | Promena osvetljenosti - boje se mogu posvetliti ili zatamniti |
contrast() | Promena kontrasta - kontrast je moguće smanjiti ili povećati |
saturate() | Promena zasićenosti boja - sliku je moguće učiniti drečavom ili potpuno izbledeti boje |
hue-rotate() | Promena nijanse (hue) boje - promena nijanse boja po kolornom krugu |
invert() | Inverzija boja - efekat foto-negativa |
grayscale() | Prevođenje boja u sive tonove - efekat crno-bele slike |
sepia() | Prevođenje boja u sepia tonove - efekat "stare fotografije" |
drop-shadow() | Efekat senke - element ili slika bacaju senku |
opacity() | Providnost - elemenat ili sliku je moguće učiniti poluprovidnom |
blur() | Efekat zamućenja - elemenat ili sliku je moguće "zamagliti" |
Nabrojane CSS funkcije se zadaju preko atributa filter i odnose se na ceo elemenat (za sada je nemoguće primeniti filter samo npr. na pozadinu elementa). Takođe je moguće zadati više filter funkcija, s tim što se njihov efekat primenjuje od prve ka poslednjoj.
Još jedan atribut koji "prima" filter funkcije je backdrop-filter. Ovim atributom definišemo efekat koji će se primeniti na sve ono što se nalazi "iza" samog elementa. Ovo obično podrazumeva da element "prekriva" neke druge elemente (npr. ako je apsolutno pozicioniran) ili sliku u pozadini. Takođe, ovo ima smisla samo ako je sam element na nekim mestima providan ili bar poluprovidan (kako bi se videlo ono što je iza njega).
filter: filter-funkcija();
filter: filter-funkcija() filter-funkcija() ...;
backdrop-filter: filter-funkcija();
backdrop-filter: filter-funkcija() filter-funkcija() ...;
Inače, atributi filter i backdrop-filter mogu biti animirani. Više o ovome pogledajte na kraju teksta.
Hajde sada da vidimo ono najzanimljivije - kako ovi efekti izgledaju. Možete se odmah baciti na isprobavanje. U ovom primeru smo objedinili sve filtere.
brightness()
contrast()
saturate()
Najpre ćemo proći kroz osnovne tri CSS filterske funkcije, kojima se vrši korekcija boja.
Funkcija brightness() služi za promenu svetline boja. Kao parametar se navodi numerička vrednost ili adekvatni procenat koji predstavlja nivo osvetljenosti:
- 0..1 (0%..100%) - zatamnjenje od najtamnije nijanse do originala
- 1 (100%) - originalna slika
- 1+ (preko 100%) - posvetljavanje boja
filter: brightness(1.3);
--- JE ISTO KAO ---
filter: brightness(130%);
Ne postoji neka unepred definisana maksimalna vrednost ili vrednost na kojoj će slika postati potpuno "bela" (to suštinski zavisi i od originala).
Pomoću funkcije contrast() vršimo podešavanje kontrasta slike, odnosno elementa. Vrednost takođe može biti numerik ili procenat:
- 0..1 (0%..100%) - od potpuno sive slike (nikakav kontrast) do originala
- 1 (100%) - original, bez promene
- 1+ (preko 100%) - pojačavanje kontrasta
Najzad, podešavanje zasićenosti boja postižemo pomoću funkcije saturate(). Vrednost i ovde može biti numerik ili procenat:
- 0..1 (0%..100%) - od crno-bele slike (tj. sivih nijansi - bez ikakvih boja) do originala
- 1 (100%) - original, bez promene
- 1+ (preko 100%) - pojačavanje zasićenosti, boje postaju sve "drečavije"
Primer za osnovnu manipulaciju bojama
Ovde vidimo primere kako izgleda osnovna kolor-manipulacija. Ono što je zajedničko za ove tri CSS funkcije je što se na osnovu vrednosti parametra rezultat može kretati u dva smera. Znači slika može biti zatamnjena ili posvetljena, sa smanjenim ili pojačanim kontrastom, sa sivljim ili drečavijim bojama.
Kod sve tri funkcije se "umanjenje" postiže vrednostima između 0 i 1, a "uvećanje" vrednostima preko 1. Vrednost 1 je "neutralna", odnosno ne izaziva promenu.
Autor sličice koju smo koristili u primerima je David Revoy, a preuzeta je sa njegovog open-source strip projekta Pepper and Carrot.
<style>
div {
background-size: cover;
background-image: url("img/pic-pepper-and-carrot-stare.jpg");
}
.bright-1 { filter: brightness(0.4); }
.bright-2 { filter: brightness(1); }
.bright-3 { filter: brightness(1.8); }
.cont-1 { filter: contrast(0.3); }
.cont-2 { filter: contrast(1); }
.cont-3 { filter: contrast(2); }
.sat-1 { filter: saturate(30%); }
.sat-2 { filter: saturate(100%); }
.sat-3 { filter: saturate(200%); }
</style>
Možemo videti kako izgledaju rezultati ovih funkcija.
hue-rotate()
Kao što znamo, ceo spektar boja, odnosno nijansi može se predstaviti kolornim krugom. Dakle možemo krenuti od crvene, preko narandžaste do žute, odatle preko zelene do plave, da bismo preko ljubičaste opet stigli do crvene. To je upravo ono što vidimo na slici.
Šta je onda "rotiranje" kroz nijanse? Pogledajte ponovo sliku. Recimo da vršimo rotaciju boja za 90o:
- svaka crvena nijansa postaje žuto-zelena,
- zelena postaje cijan-plava,
- plava postaje crveno-ljubičasta, itd.
Upravo takvu kolor-rotaciju obavlja funkcija hue-rotate(). Dakle, kao parametar se zadaje ugao predstavljen u npr. stepenima (deg) ili obrtajima (turn). Pri tom je npr. ugao od 90o izražen kao 90deg (90 stepeni) ili 0.25turn (četvrtina obrta).
Ugao može biti i negativan. Na primer, ugao od -60o je isti kao 300o, ili u obrtajima, npr. -0.15turn je isto kao 0.85turn.
Ako navedemo vrednost 0deg (isto i 360deg) ili 0turn (isto kao 1turn), to je onda jednako originalnom izgledu slike.
Pomoću ove funkcije možemo neznatno promeniti nijanse na slici ili učiniti da izgleda potpuno "vanzemaljski".
Primer za promenu nijanse
Ovde imamo jedan osnovni primer gde smo izvrteli pun krug i od originala, preko nekih 5 koraka promena, stigli opet do originala.
<style>
div {
background-size: cover;
background-image: url("img/pic-pepper-and-carrot-stare.jpg");
}
.hue-1 { filter: hue-rotate(0turn); }
.hue-2 { filter: hue-rotate(0.2turn); }
.hue-3 { filter: hue-rotate(0.4turn); }
.hue-4 { filter: hue-rotate(0.6turn); }
.hue-5 { filter: hue-rotate(0.8turn); }
.hue-6 { filter: hue-rotate(1turn); }
</style>
Ovde vidimo kako ovaj efekat funkcioniše:
Colorize efekat
Ok, znamo da još nismo stigli do sepia() funkcije, ali evo primera kako kombinovanjem te funkcije sa hue-rotate() možemo da dobijemo "colorize" ili makar sličan efekat, kada se cela slika prebaci u monohromatske nijanse neke boje.
<style>
div {
background-size: cover;
background-image: url("img/pic-pepper-and-carrot-stare.jpg");
}
.hue-1 {
filter: sepia(100%) hue-rotate(-0.3turn) saturate(80%);
}
.hue-2 {
filter: sepia(100%) hue-rotate(0turn);
}
.hue-3 {
filter: sepia(100%) hue-rotate(0.3turn) saturate(80%);
}
</style>
Za ovo nam je upravo i trebao sepia() filter, pošto on ne uklanja boje već ih upravo svodi na monohromatske nijanse. Posle toga ostaje samo da "izvrtimo" boje kako bismo postigli drugu nijansu. Za ovo nam ne bi značio grayscale(1) ili saturate(0), pošto tada nema boja koje bismo mogli da "vrtimo".
invert()
grayscale()
sepia()
Sad ćemo objasniti tri funkcije koje služe za primenu određenog kolornog efekta. Za sve tri funkcije, kao parmetar se navodi numerička vrednost od 0..1 ili procenat (0% do 100%). Vrednost 0 označava situaciju kada nema efekta, odnosno sliku koja je jednaka originalu. Vrednost 1 (ili 100%) predstavlja maksimalnu primenu efekta. Svaka druga vrednost predstavlja neku "međufazu".
Šta rade ove funkcije? Funkcija invert() "obrće" boje na slici, odnosno praktično kreira negativ slike. Svaka međufaza predstavlja neki od prelaza od originalne do "negativne" slike. Tako, sticajem okolnosti, srednja vrednost od 0.5 generiše "ravnu" sivu sliku.
Funkcija grayscale() stvara crno-belu verziju slike, odnosno sliku sastavljenu samo od sivih nijansi. Praktično isti efekat dobijamo kompletnom desaturizacijom, odnosno korišćenjem filtera saturate(0). Svaka međufaza vrednosti od 0..1 predstavlja sve "sivlju" sliku, dok se boje potpuno ne izgube.
Treća funkcija, sepia() stvara efekat "stare fotografije" tako što svodi sliku na žućkaste monohromatske nijanse. Slično kao kod funkcije grayscale(), međufaze između 0..1 polako umanjuju boje i idu ka monohromatskoj slici.
Primer za efekat promene boje
U ovom primeru isprobavamo manipulaciju bojama slike koristeći specijalne efekte. Sve tri funkcije imaju vrednost od 0..1, gde 0 predstavlja originalnu sliku (efekat se ne primenjuje) a 1 predstavlja maksimalnu primenu efekta.
<style>
div {
background-size: cover;
background-image: url("img/pic-pepper-and-carrot-stare.jpg");
}
.inv-1 { filter: invert(0); }
.inv-2 { filter: invert(0.6); }
.inv-3 { filter: invert(1); }
.sep-1 { filter: sepia(0); }
.sep-2 { filter: sepia(0.5); }
.sep-3 { filter: sepia(1); }
.gray-1 { filter: grayscale(0); }
.gray-2 { filter: grayscale(0.5); }
.gray-3 { filter: grayscale(1); }
</style>
Rezultat je sledeći:
drop-shadow()
opacity()
blur()
Konačno dolazimo do pravih specijalnih efekata. Za razliku od svih do sada opisanih filter funkcija, ove funkcije se ne bave običnim podešavanjima boje, već zaista izvode neki efekat nad elementom.
Funkcija drop-shadow() kreira senku elementa. Na prvi pogled, deluje potpuno isto kao CSS atribut box-shadow. Čak su i parametri isti:
- X offset (metrika) - izmeštanje senke po horizontali
- Y offset (metrika) - izmeštanje senke po vertikali
- blur (metrika) - zamućenost senke
- boja (kolorna vrednost) - boja senke
Međutim, filter kreira senku po mnogo kompleksnijem algoritmu. Dok box-shadow iscrtava senku samo na osnovu dimenzija i zaobljenosti objekta, filter drop-shadow() uzima u obzir i providnost elementa, kao i sve podelemente koji utiču na "siluetu" objekta.
Na sličan način bismo mogli da poistovetimo i filter funkciju opacity() sa CSS atributom opacity. Ova funkcija, kao i pomenuti atribut, kontroliše providnost elementa. Paramater funkcije je istovetan vrednosti atributa - u pitanju je numerička vrednost između 0..1 (funkciji se može zadati i procenat od 0% do 100% sa istim značenjem). Vrednost 0 označava potpuno providan objekat dok vrednost 1 označava objekat koji je potpuno vidljiv (nema transparencije). Sve međuvrednosti označavaju neki nivo poluprovidnosti.
Generalno, zavisno od web čitača, trebalo bi da se filter CSS funkcije iscrtavaju brže od adekvatnih CSS atributa, pošto bi (bar u teoriji) crtanje trebalo da se usmerava direktno na grafičku kartu.
Zaista, na prvi pogled nećemo uočiti razliku, sve dok ne uvežemo opacity() funkciju u "lanac" filtera. Tada ćemo primetiti da se ovako zadata providnost uzima u obzir za efekte koji su kasnije navedeni u filter atributu. Ovo se najbolje vidi ako posle poziva opacity() funkcije pozovemo drop-shadow(). Primetićemo da je senka uzela u obzir i poluprovidnost elementa.
Najzad imamo i funkciju blur() koja vrši zamućenje objekta. Za poznavaoce aplikacija za obradu slike, dovoljno je reći da ovom funkcijom primenjujemo Gaussian blur efekat. Kao parametar se zadaje metrika koja označava veličinu zamućenja, odnosno koliko piksela se "stapa". Što je ova vrednost veća, to je slika mutnija. Ako pokušamo da umesto metrike zadamo procenat, funkcija neće raditi.
Primer za specijalne efekte
Funkcija drop-shadow()
Hajde najpre da vidimo kako se ponaša filter drop-shadow() i kako se razlikuje u odnosu na CSS atribut box-shadow.
<style>
aside {
position: relative;
width: 250px;
height: 80px;
background-color: #ffb;
border: 2px solid black;
box-sizing: border-box;
}
div {
position: absolute;
width: 100px;
height: 20px;
top: 15px;
right: -30px;
background-color: #fff;
color: red;
border: 2px solid red;
font-size: 8pt;
}
.mod {
background-color: transparent;
border: 10px solid white;
}
.senka {
box-shadow: 4px 4px 6px #000;
}
.senka-filter {
filter: drop-shadow(4px 4px 6px #000);
}
</style>
<aside class="senka">
box-shadow
<div>Mali okvir</div>
</aside>
<aside class="senka-filter">
filter: drop-shadow()
<div>Mali okvir</div>
</aside>
<aside class="mod senka">
box-shadow
<div>Mali okvir</div>
</aside>
<aside class="mod senka-filter">
filter: drop-shadow()
<div>Mali okvir</div>
</aside>
<br />
<aside>
<img src="/graf/prof-sandy-left.png" class="senka" width="150" >
</aside>
<aside>
<img src="/graf/prof-sandy-left.png" class="senka-filter" width="150" >
</aside>
Kapo što vidimo u primeru, senka se odnosi na veliki aside element. E, sad, obratite pažnju na senku kod div bloka, koji izviruje iz aside elementa. CSS atribut box-shadow kreira senku isključivo oblika elementa za koji je zadat, dok filter funkcija drop-shadow() uzima u obzir realan oblik, i na osnovu njegovih podelemenata - tako će senka biti nacrtana i za div blok.
U drugom primeru vidimo da funkcija drop-shadow() uzima u obzir i providne delove elementa, tako da suštinski može zameniti i text-shadow atribut.
Najzad, vidimo da drop-shadow() uzima u obzir i providnost slike.
Funkcija opacity()
Pogledajmo sada kako funkcioniše filter opacity().
<style>
aside {
position: relative;
width: 250px;
height: 70px;
background-color: #ffb;
border: 2px solid black;
box-sizing: border-box;
}
div {
position: absolute;
width: 100px;
height: 20px;
top: 25px;
right: -30px;
background-color: #fff;
color: red;
border: 2px solid red;
}
.atr-shadow {
box-shadow: 4px 4px 6px #000;
}
.atr-opacity {
opacity: 0.4;
}
.fun-shadow {
filter: drop-shadow(4px 4px 6px #000);
}
.fun-opacity {
filter: opacity(0.4);
}
.fun-shadow-opacity {
filter: drop-shadow(4px 4px 6px #000) opacity(0.4);
}
.fun-opacity-shadow {
filter: opacity(0.4) drop-shadow(4px 4px 6px #000);
}
</style>
<aside class="atr-opacity fun-opacity">
opacity<br />filter: opacity()
<div>DIV</div>
</aside>
<aside class="atr-shadow atr-opacity">
box-shadow<br />opacity
<div>DIV</div>
</aside>
<br />
<aside class="atr-shadow fun-opacity">
box-shadow<br />filter: opacity()
<div>DIV</div>
</aside>
<aside class="atr-opacity fun-shadow">
opacity<br />filter: drop-shadow()
<div>DIV</div>
</aside>
<br />
<aside class="fun-shadow-opacity">
filter: drop-shadow() opacity()
<div>DIV</div>
</aside>
<aside class="fun-opacity-shadow">
filter: opacity() drop-shadow()
<div>DIV</div>
</aside>
<br />
<aside class="atr-opacity">
opacity
<div class="atr-opacity">opacity</div>
</aside>
<aside class="fun-opacity">
filter: opacity()
<div class="fun-opacity">filter: opacity()</div>
</aside>
Ovde se vidi da je CSS funkcija opacity() veoma slična atributu opacity. Međutim, možemo primetiti dva efekta koji predstavljaju specifičnost korišćenja funkcije. Najpre, u prvom primeru primećujemo da ako na element primenimo i atribut opacity i filter opacity(), dobijamo pojačanu providnost elementa. To znači da jednu ili drugu stvar možemo koristiti kao "korekciju" ranije zadate providnosti, bez menjanja "originala".
Druga značajna stvar se primećuje kada "ulančavamo" funkciju opacity() sa drugim funkcijama u atributu filter. Najočiglednije je kada je to funkcija drop-shadow(). Vidimo da je jedini slučaj kada je poluprovidnost uzeta u obzir pri iscrtavanju senke (koja se onda providi kroz element) onaj u kome je prvo zadata funkcija opacity() a posle nje funkcija drop-shadow().
Funkcija blur()
Konačno dolazimo do potpuno originalne CSS filter funkicje - blur(), koja nema svoj pandan među CSS atributima.
<style>
.blur-0 { filter: blur(0); }
.blur-1 { filter: blur(1px); }
.blur-2 { filter: blur(3px); }
.blur-3 { filter: blur(5px); }
.blur-4 { filter: blur(7px); }
.blur-5 { filter: blur(10px); }
</style>
Kao što se vidi, parametar je metrika i označava veličinu zamućenja. Što je ova vrednost veća, slika je mutnija. Pošto blur() zamućuje sve što se nalazi unutar elementa na koji se primenjuje, morali smo malo više da se potrudimo da bi se tekst iznad slika uopšte video. Koristili smo kontejner i dva apsolutno pozicionirana elementa unutar njega - jedan sa zamućenjem i jedan sa tekstom.
Animacija i kombinacija filtera
Ostali smo vam dužni još objašnjenje vezano za animaciju filtera. Već smo rekli da atributi filter i backdrop-filter mogu biti animirani. To znači da možemo zadati kontinuiranu promenu tokom nekog vremena od jednog do drugog "stanja".
Međutim, postoji jedno ograničenje. Animacija će raditi samo ako smo i početni i završni izgled definisali na potpuno isti način - dakle, koristeći iste CSS funkcije, zadate istim redosledom. Jedino što sme da se menja su parametri funkcija.
Dakle, ovo bi moglo:
filter: brightness(50%) blur(5px);
--- PRELAZI U ---
filter: brightness(120%) blur(0);
Ali ovo ne bi prošlo:
filter: brightness(50%) blur(5px);
--- NEĆE PREĆI U ---
filter: brightness(120%); <-- NEDOSTAJE BLUR()!
filter: brightness(50%) blur(5px);
--- NEĆE PREĆI U ---
filter: blur(0) brightness(120%); <-- DRUGAČIJI REDOSLED!
Primer - Animacija filtera
Ovde smo zadali tri jednostavna primera. Pređite mišem preko svakog elementa kako biste videli animirani efekat.
<style>
.primer-1 {
filter: grayscale(100%) brightness(60%);
transition-duration: 0.5s;
transition-property: filter;
}
.primer-1:hover {
filter: grayscale(0%) brightness(120%);
}
.primer-2 {
filter: brightness(160%) blur(5px);
transition-duration: 0.5s;
transition-property: filter;
}
.primer-2:hover {
filter: brightness(1) blur(0);
}
.primer-3 {
filter: hue-rotate(180deg) contrast(1.7);
transition-duration: 0.5s;
transition-property: filter;
}
.primer-3:hover {
filter: hue-rotate(0deg) contrast(1);
}
</style>
- Mozilla Developer Network, Filter
- Quackit, CSS Functions
- S. Greig (2013): CSS3 Pushing the Limits, Wiley, Chichester