A fejezetben azt tekintjük át, hogy milyen lehetőségek vannak a CSS által definiált stílusok kezelésére. A stílusok segítségével készíthetünk igen látványos weboldalakat, ezekre támaszkodnak az animációk is, amelyekre ugyancsak kitérünk.
A modern kliensoldali webprogramozásban a CSS szabályok ismerete elengedhetetlen szükséglet. Nem csupán a honlapszerkesztőknek kell a formázási tulajdonságokat ismernie, hanem minden JavaScript programozónak is. Ennek oka kettős. Az egyik az, hogy – ahogy azt DOM-ról szóló fejezetnél láttuk a kiválasztásról szóló részben – az elemek feldolgozásra jelölésének legrugalmasabb módját éppen a CSS szelektorok adják. Ezzel gyakorlatilag tetszőleges elemeket ki tudunk választani az oldalon mindenféle bonyolultabb fabejárás alkalmazása nélkül. Szintaktikája és szabályai egyszerűek, gyorsan tanulhatóak. Nem véletlen, hogy manapság ez a kiválasztás alapja, és szinte kivétel nélkül minden böngésző implementálta az ehhez szükséges DOM metódusokat.
A másik oka a CSS szabályok ismeretének az, hogy a JavaScript programozás egy – sokszor jelentős – része a felülettel, az elemek megjelenésével kapcsolatos. Meg kell jeleníteni, el kell tüntetni, át kell helyezni, mozgatni kell elemeket az oldalon, ezeket viszont mind a stílusszabályokon keresztül lehet megtenni.
Ebben a fejezetben a kliensoldali webprogramozás látványos részével, a stílusok programozásával foglalkozunk. Egy elem megjelenését három szinten tudjuk befolyásolni stílusbeállításokkal:
A következőkben az egyes szintek jellemzőit és az ezekkel kapcsolatos ismereteket tekintjük át. A fejezet végén pedig megnézzük, hogy hogyan lehet egyszerűen látványos animációkat létrehozni CSS és JavaScript segítségével.
Egy elem stílusbeállításait legközvetlenebbül a style attribútumon keresztül lehet elvégezni.
<elem style="css tulajdonságok"></elem>
JavaScriptben a style attribútumnak az elemnek megfelelő DOM objektum style tulajdonsága felel meg. A style egy olyan objektum (CSS2Properties), aminek egyes tulajdonságain keresztül férünk hozzá az elem stílustulajdonságaihoz. Úgy, ahogy a HTML elemek és a DOM objektumok esetén egy az egy megfelelés van, és az egyik módosítása megjelenik a neki megfelelő párban, a style objektum tulajdonságai is ugyanolyan élő módon vannak összekötve az elem megjelenésért felelős CSS tulajdonságokkal. A style objektumban az összes lehetséges CSS tulajdonság megjelenik stílustulajdonságként, ez utóbbiak az analóg módszer szerint vannak megfeleltetve a CSS tulajdonságoknak. Az átírási szabály (camel case) a következő:
Íme néhány példa az átírásra:
CSS tulajdonság | JavaScript tulajdonság |
color | color |
background | background |
margin-left | marginLeft |
font-size | fontSize |
border-bottom-width | borderBottomWidth |
Ennek megfelelően egy tetszőlegesen kiválasztott elem stílusbeállításait style objektuma tulajdonságainak megfelelő értéket adva lehet megtenni. Például egy elem alsó keretének vastagságát a következőképpen lehet beállítani:
elem.style.borderBottomWidth = '5px';
Egy elem stílusbeállításainak lekérdezésekor azonban korlátokba ütközünk, ugyanis csak azok a stílustulajdonságoknak van értéke, amelyek vagy a style attribútumban voltak megadva, vagy JavaScript kódban kaptak értéket. Minden egyéb stílustulajdonság értéke üres szöveg. Ez azt jelenti, hogy nem minden stílustulajdonság kérdezhető le a style objektummal, csak azok, amelyekről vagy a HTML-ben, vagy a JavaScript kódban nyilatkoztunk. Így például a class attribútumon keresztül érvényesített szabályok hatása sem kérdezhető le. A böngésző azonban minden elemről pontosan tudja, hogy hol helyezkedik el, és hogyan néz ki, azaz ismeri az összes elem összes stílustulajdonságát. Ezt az információt hívjuk számított stílusnak.
JavaScriptből elérhetőek azok a stílusinformációk, amelyeket a böngésző tart nyilván minden elemről. Ennek elérése egy ma már szabványos metódussal, a window.getComputedStyle(elem) segítségével tehető meg. Ennek paramétereként (elem) azt a DOM objektumot kell megadni, amelynek számított stílusára kíváncsiak vagyunk. Régebbi Internet Explorerek még nem támogatják ezt a metódust, ezekben az elem.currentStyle() függvény biztosítja ugyanezt a funkcionalitást.
A metódusok által visszaadott objektumokról annyit érdemes tudni, hogy a CSS-ben alkalmazható tulajdonság-rövidítések (pl. border vagy background) ezekben nem elérhetők, csak az elemi tulajdonságok (pl. borderBottomColor vagy backgroundPosition) használhatóak.
Példaképpen tekintsük az alábbi dokumentumot, amin egy div elemet formázunk meg stílusosztállyal és style attribútumon keresztül:
<!doctype html> <html> <head> <meta charset="utf-8"> <title></title> <style type="text/css"> .doboz { width: 100px; height: 100px; border: 2px solid orange; position: absolute; } </style> </head> <body> <div id="doboz" class="doboz" style="left: 20px"></div> </body> </html>
Az alábbi JavaScript kódban először beállítjuk az elem top tulajdonságát a style objektumán keresztül.
var d = document.getElementById('doboz'); d.style.top = '50px';
Az elem style objektumán keresztül csak a HTML-ben és a JavaScriptben beállított stílustulajdonságokat tudjuk lekérdezni:
d.style; //CSS2Properties d.style.top; //"50px" d.style.left; //"20px" d.style.width; //"" d.style.height; //""
A számított stíluson keresztül viszont tetszőleges, nem rövidített stílustulajdonsága lekérdezhető:
var s = window.getComputedStyle(d); s.top; //"50px" s.left; //"20px" s.width; //"100px" s.height; //"100px" s.border; //"" s.borderBottomWidth; //"2px" s.position; //"absolute"
A HTML elemek class attribútumát a nekik megfelelő DOM objektum className tulajdonsága alatt lehet lekérdezni és módosítani. A class attribútumban vagy egy vagy több stílusosztálynév jelenhet meg. Az utóbbi esetben az egyes osztályneveket szóközzel kell elválasztani.
<elem id="elem1" class="osztaly"></elem> <elem id="elem2" class="osztaly1 osztaly2 osztaly3"></elem>
JavaScriptben lekérdezve ugyanez az információ jelenik meg a className tulajdonságban szöveges formában.
document.getElementById('elem1').className; //osztaly document.getElementById('elem2').className; //osztaly1 osztaly2 osztaly3
Stílusosztályok kezelésénél nagyon gyakori egy-egy újabb osztály hozzáadása, törlése vagy meglétének ellenőrzése egy elemnél. E feladatok gyakorlatilag a className által visszaadott szöveg feldolgozásából áll. Hozzáadáskor egy szóközzel elválasztva kell hozzáfűzni az eddig még nem létező osztálynevet, törléskor meg kell keresni, és törölni kell, meglétének ellenőrzésekor pedig a keresés eredményét kell visszaadni. A keresést legegyszerűbb reguláris kifejezéssel megadni.
function vaneOsztaly(elem, o) { return elem.className.search(new RegExp('(^|\\s+)' + o + '(\\s+|$)')) > -1; } function hozzaadOsztaly(elem, o) { if (!vaneOsztaly(elem, o)) { elem.className += (elem.className ? ' ' : '') + o; } } function torolOsztaly(elem, o) { elem.className = elem.className .replace(new RegExp('(^|\\s+)' + o + '(\\s+|$)'), ' ') //osztálynév törlése .replace(/^\s*|\s*$/g, ''); //kétoldali felesleges szóköz eltávolítása }
Példaképpen tekintsük az alábbi egyszerű bekezdésnél a fenti függvények működését:
<p id="par1">Bekezdés</p>
var p = document.getElementById('par1'); p.className; //"" hozzaadOsztaly(p, 'piros'); p.className; //"piros" hozzaadOsztaly(p, 'idezet'); p.className; //"piros idezet" vaneOsztaly(p, 'idezet'); //true torolOsztaly(p, 'piros'); p.className; //"idezet" torolOsztaly(p, 'idezet'); p.className; //""
HTML-ben a link vagy style elemmel lehet stíluslapot elhelyezni. A style elem belső stíluslapot hoz létre, a link elem külső stíluslapot tesz elérhetővé az oldalon belül. Típus szerint háromféle stíluslapot különböztetünk meg:
Az alábbi HTML kód ezekre mutat példát. Az első link permanens, a második preferált, a harmadik alternatív, a style elemmel létrehozott pedig megint csak permanens stíluslap.
<!doctype html> <html> <head> <meta charset="utf-8"> <title></title> <link rel="stylesheet" type="text/css" href="permanens.css"> <link rel="stylesheet" type="text/css" href="preferalt.css" title="preferalt"> <link rel="alternate stylesheet" type="text/css" href="alternativ.css" title="alternativ"> <style type="text/css"> p { font-style: italic; } </style> </head> <body> <p>Valamilyen szöveg.</p> </body> </html>
Kevesen tudják, hogy az alternatív stíluslapokat a böngészők felületéről is lehet aktiválni. Ekkor a preferált stíluslap helyett a kiválasztott alternatív stíluslap kerül az oldalon érvényesítésre. Nem minden böngésző teszi ezt alapértelmezetten elérhetővé, némelyikben csak megfelelő kiegészítővel érhető el ez a funkcionalitás. Mozilla Firefoxban a Nézet/Oldalstílus menüpont szolgál erre a feladatra. Fenti példánk esetén ez így néz ki:
JavaScriptben a document.styleSheets tömbszerű gyűjteményen keresztül kérdezhetők el a dokumentumba ágyazott stíluslapok. Fenti HTML dokumentumunknál ez a következőt adja:
A document.styleSheets tömb szabvány által meghatározott, ún. StyleSheet objektumokat tartalmaz, amelyeknek a főbb tulajdonságai:
Stíluslapok dinamikus ki- és bekapcsolása a disabled tulajdonság beállításával lehetséges. Programozottan bármelyik stíluslap elérhetősége megváltoztatható függetlenül attól, hogy milyen típusba esik. Általában szerencsés dolog megtartani az elvárt viselkedést: a permanens stíluslapok mindig aktívak, a váltás csak a preferált és alternatív stíluslapokat érinti. Ha JavaScriptben szeretnénk megvalósítani ezt a kódot, akkor a stíluslaplistában csak azokat a stíluslapokat szükséges vizsgálni, amelyek title tulajdonsága nem üres. Egy lehetséges stíluslapváltó függvény a következőképpen nézhet ki:
function stilusLapValto(cim) { var s = document.styleSheets; for (var i = 0; i < s.length; i++) { if (s[i].title) { s[i].disabled = s[i].title != cim; } } }
Egy stíluslap-objektumon belül lehetőség van a benne definiált szabályok elérésére is a szabványos cssRules tömbön keresztül, és egy szabályon belül megadott stílustulajdonságok kezelésére a style gyűjteménnyel. Ezek segítségével a stíluslapokon új szabály vehető fel, meglévő törölhető vagy szabadon módosítható. Ennek tárgyalása messze túlmutat e tananyag céljain. Példaképpen álljon itt a fenti HTML dokumentumban definiált style elem első szabályának bővítése a betűméretre vonatkozóan, ami a felületen a megjelenő paragrafus méretét változtatja meg.
document.styleSheets[3].cssRules[0].style.fontSize = '40px';
Animációnak nevezzük egy elem egy vagy több stílustulajdonságának kezdő és végállapota közötti véges hosszú idő alatt lejátszódó folyamatos(nak tűnő) átmenetét. Animáció során a stílustulajdonság nem azonnal a végállapot értékét veszi fel, hanem az értékintervallumot diszkrét lépésekre bontva a stílustulajdonság ezen értékeket veszi fel egymás után időben előrehaladva. Az animációk a felhasználói felület működtetésének fontos részét képezik. A látványosságon túl nagy szerepet töltenek be az oldal használhatóságában: jól megtervezett animációk segítenek a felhasználónak az egyes felületi folyamatok megértésében és nyomon követésében azáltal, hogy két állapot között folyamatosan átmenetet képeznek, és nem villanásszerűen veszik fel módosított értékeiket.
Animációt JavaScriptben időzítők segítségével lehet létrehozni. Ezekkel tudjuk azt elérni, hogy szabályozott időközönként változtassuk meg egy elem stílustulajdonságának értékét. Időzítő használatával – mivel alapvetően egy aszinkron folyamatról van szó – a felület használható marad, és további szkriptek futása is lehetséges párhuzamosan.
Egy tipikus animációs függvény fontosabb paraméterei a következők:
A JavaScripttel történő animációnak vannak hátrányai is. Sok elem párhuzamos mozgatása nagyon lassú, illetve a böngésző részéről erőforrásigényes lehet, amit a párhuzamosan futó egyéb számítások lassíthatnak, szaggatott animációt eredményezve. A lépésszám jó megválasztása segíthet ezen a problémán, de teljes egészében nem oldja meg. Továbbá a JavaScriptes animációt nehezebb a böngészőnek optimalizálni, ami megint csak az erőforrásokat veszi nagyobb mértékben igénybe.
Példaképpen nézzük meg egy div elem szélességének megváltoztatását. Animáció nélkül ez a következőképpen néz ki:
<style type="text/css"> .doboz { width: 100px; height: 100px; border: 2px solid orange; position: absolute; top: 50px; left: 20px; } </style> <div id="doboz"></div>
var d = document.getElementById('doboz'); d.style.width = '500px';
Ugyanezt animálva az alábbi JavaScript kód biztosítja:
function idozito() { var d = document.getElementById('doboz'); var w = parseInt(window.getComputedStyle(d).width, 10); if (w < 500) { d.style.width = (w + 10) + 'px'; setTimeout(idozito, 50); } } idozito();
A CSS3 lehetőséget ad deklaratív módon meghatározni animációkat. Pontosabban a szabvány megkülönbözteti az átmeneteket és az animációkat. Átmenetek esetén egy stílustulajdonság két értéke közötti folyamatos átmenetképzést végzi el a böngésző, míg animációknál kulcskocka alapú átmenetekre, ismétlődő végrehajtásra és magasabb szintű paraméterezésre van lehetőség. A deklaratív megközelítéssel animációk készítése programozási feladat helyett paraméterezési kérdéssé egyszerűsödnek, amivel egy alkalmazás bonyolultsága csökken. Használatuk további előnye, hogy böngészőtámogatottságuk egyre nagyobb, és – ami manapság igen fontos – mobilböngészők is egyre szélesebb körben támogatják. További előnye, hogy ekkor az animálást a böngésző végzi, így jobban figyelembe tudja venni a futó folyamatokat, erőforrásainak terheltségét, és jobban képes optimalizálni az átmenetek képzését. Azok az animációk például, amelyek más fülön vannak, vagy nem látszanak az oldalon, kevesebb erőforrást kapnak, mint azok, amelyek éppen a dokumentum látható részén zajlanak.
Átmenetek létrehozása a transition stílustulajdonság beállításával lehetséges. Részeként a következő paraméterek megadása szükséges, amelyek a transition tulajdonság alatt egyszerre megadhatók:
Mivel a CSS3-as lehetőségek még viszonylag újak, ezért a legtöbb böngésző csak a saját vendor prefixe alatt teszi elérhetővé az átmeneteket. A biztonság kedvéért érdemes mindegyiket megadni a minél szélesebb támogatottság eléréséhez. Például mindegyik tulajdonság 2 másodperces lineáris animálása 1 másodperces késleltetéssel a következőképpen adható meg:
Például az ebben a részben már megismert div doboz szélességét az egérmutató fölévitelelére animálva megváltoztatni az alábbi CSS kóddal lehetséges. Ebben jelezzük a transition tulajdonságban, hogy a width paraméter értékében beállt változást folytonos átmenettel hajtsa végre. Az érték megváltozása az egérmutató fölémozgatására történik, erről a :hover pszeudo-osztállyal gondoskodunk.
.doboz { width: 100px; height: 100px; border: 2px solid orange; -webkit-transition: width 1s ease-in-out 0s; -moz-transition: width 1s ease-in-out 0s; -ms-transition: width 1s ease-in-out 0s; -o-transition: width 1s ease-in-out 0s; transition: width 1s ease-in-out 0s; } .doboz:hover { width: 500px; }
A CSS3 animációk még viszonylag újak, teljes bemutatásuk túllépi e tananyag kereteit. Példaképpen nézzük meg, hogy hogyan is kell egy ilyen animációt létrehozni:
@keyframes anim { 0% { border: 1px solid orange; } 50% { width: 200px; background-color: blue; } 100% { border: 30px solid orange; background-color: green; width: 600px; } } .doboz { width: 100px; height: 100px; border: 2px solid orange; } .doboz:hover { animation-name: anim; animation-duration: 1s; animation-iteration-count: 4; animation-direction: alternate; animation-timing-function: ease-in-out; }
CSS3 átmenetek programozásakor általában deklaratívan beállítjuk a transition tulajdonságot, majd JavaScripttel elég csak az animálandó tulajdonságot a végértékére módosítani. Ha a div doboz szélességét gombnyomásra szeretnénk átmenettel megváltoztatni, akkor elég a következő CSS és JavaScript kód:
.doboz { width: 100px; height: 100px; border: 2px solid orange; -webkit-transition: width 1s ease-in-out 0s; -moz-transition: width 1s ease-in-out 0s; -ms-transition: width 1s ease-in-out 0s; -o-transition: width 1s ease-in-out 0s; transition: width 1s ease-in-out 0s; }
var d = document.getElementById('doboz'); d.style.width = '500px';
A transition stílustulajdonság természetesen JavaScripttel is megadható vagy módosítható a style objektum transition tulajdonságán keresztül.
elem.style.transition = 'all 1s linear 0s';
Végül lehetőség van reagálni az átmenet befejeződésére a transitionend esemény kezelésével.
A CSS3 szabvány látványos újítása a transzformációk is, amelyekkel 2D vagy 3D átalakítások vihetők végbe az elemeken deklaratív módon a transform stílustulajdonságon keresztül. A 2D-s transzformációk elemei:
Példaképpen tekintsük néhány hasonló div kocka átalakítását:
#skew { transform: skew(20deg); } #scale { transform: scale(0.9,0.5); } #rotate { transform: rotate(90deg); } #translate { transform: translate(50px, 60px); }
3D transzformációknál a következő stílustulajdonságok adhatók meg:
Hasonló kockák 3D-s átalakítását az alábbi kóddal a lenti képen láthatjuk:
#alap { perspective: 800px; perspective-origin: 50% 100px; } #scale { transform: scale3d(0.9,0.5,0.1); } #translate { transform: translate3d(50px, 60px, 100px); } #rotateX { transform: rotateX(45deg); } #rotateY { transform: rotateY(45deg); } #rotateZ { transform: rotateZ(45deg); }
A transzformációk párosíthatók az átmenetekkel, így látványos módon változtathatjuk meg az elemek elrendezését. A fenti példában mindegyik tulajdonságot animálva (all) és csak az egérmutatóra beállítva a transzformációkat az alábbi animációt kapjuk:
A tananyag az ELTE - PPKE informatika tananyagfejlesztési projekt (TÁMOP-4.1.2.A/1-11/1-2011-0052) keretében valósult meg.
A tananyag elkészítéséhez az ELTESCORM keretrendszert használtuk.