2016. március 31.

CSS – fps módra

10 perc olvasási idő

CSS – fps módra

Hozzávalók: a kedvenc text editorod, egy tetszőleges pre-processor és egy csipet npm. Az scss, less vagy styl fájljaid darabold logikai egységekre, melyeket 10 ezredmásodperc alatt összefűzöl. Összefűzés előtt ne felejtsd el folyamatosan fordítani őket. Végül ízlés szerint csatold a projekthez. Üdvözöllek az fps konyhájában!

A Nevezzük a nevén: BEM c. blog posztom kapcsán vetődött fel, hogy az elnevezésen túl van, akinek inkább a strukturáltság és az újra felhasználhatóság okoz problémát. Az első gondolatom az volt: rendben, akkor beszéljünk a már jól ismert CSS ajánlásokról… Hmmm, inkább mégsem. Helyette megmutatom mi, hogyan csináljuk.

Mi is szembesültünk azokkal a problémákkal, melyek a fenntarthatóságot is gátolták. Az újra felhasználhatóságról meg ne is beszéljünk. Újra és újra bejárni projekt kezdetekor ugyanazokat a rutinokat. Ezért létrehoztunk egy SCSS-en alapuló induló csomagot, amely megadja a struktúrát, az általában szükséges elemeket, és még néhány extrát a kezünk alá.

Struktúra

Az SMACSS (Jonathan Snook) ajánlása is ad egyfajta struktúrát, amit már jól ismerünk: Base, Layout, Module, State, Theme. Ettől nem is tértünk el igazán, hiszen eddig sem szerettük volna feltalálni a spanyol viaszt. A következőképpen néz ki az általunk követett struktúra:

  • Base
  • reset.scss
  • base.scss
  • typo.scss
  • helper.scss
  • Components
  • form.scss
  • form.input.scss
  • form.textarea.scss
  • form.checkbox.scss
  • navigation.icon.scss
  • icons.scss
  • [...]
  • Pages
  • [...]
  • Layouts
  • grid.scss
  • layout.scss
  • Units
  • functions.scss
  • mixins.scss
  • silents.scss
  • config.scss
  • shame.scss

Nem is annyira más, igaz? A Module-ból Components lett, a Themeből Pages, a State pedig eltűnt. Alapvetően ez a kezdő csomag tartalmi weboldalakhoz készült, így nincs értelme a komponenstől elválasztani az állapotait. Viszont bekerült a Units, amely olyan SCSS-eket tartalmaz, amelyeknek nincs konkrét CSS kimenete. Függvények, mixinek és csendes osztályok segítségével kész megoldásokkal gyorsíthatod a fejlesztés folyamatát.

Csak át kell írni

Biztos sokat hallottad már ezt a kijelentést, mikor olyan színkód került a kódba, ami nem egyezik meg az ügyfél által megadott design guideline-nal és a grafikus néha elfelejti, de te jól tudod, ez a „Csak átírjuk” valójában x fájl * y sort jelent, ahol előfordul.
Ezért került be a gyökérbe egy config.scss, amelyben általános, működés és kimenetet befolyásoló változók vannak.


/**
 * Custom
 */
$responsive:        true  !default;
$use-rem-unit:      false !default;

/**
 * Paths
 */
$path--icon:    '../svg/icons';
$path--svg:     '../svg' !default;
$path--img:     '../img' !default;

/**
 * Colors
 */
 $color--a: #f58427; 
 $color--b: #0077c0;

/**
 * Breakpoints
 */
$breakpoints: (
    'palm' '(max-width: 480px)',
    'lap' '(min-width: 481px) and (max-width: 1023px)',
    'portable' '(max-width: 1023px)',
    'desk' '(min-width: 1024px)'
) !default;

Ez csak egy kis betekintés a fájlba. Ide kerülnek az alap töréspontok, amire épül a grid és néhány segédosztály, a font méretek, használt font családok és színpaletta stb. Ezzel elértük, hogy a CSS kódunk könnyen tudja követni a változásokat.

Írd meg egyszer, használd sokszor!

Vannak olyan elemek, melyeket szinte minden projekt kapcsán újra és újra megírtunk, de miért? Írjuk meg egyszer és használjuk sokszor! Erre kitűnő példa egy hamburger ikon. Szinten minden responsive tartalmi weboldalnál előforduló elem. Megjelenésében teljesen ugyanolyan, néhány tulajdonságtól eltekintve. Ezeket a tulajdonságokat változókba vezettük ki, így az egyedi designhoz csak néhány értéket kell módosítani.


/**
 * Navigation mobile icon
 */

$width:            24px !default;
$height:           20px !default;
$padding:          20px 0 20px 20px !default;
$color:            #fff !default;
$background:       false !default;

$state-color:      false !default;
$state-background: false !default;

$animate-duration: .5s   !default;

Most jogosan merül fel benned a kérdés, hogy ezek az előre megírt komponensek bekerülnek CSS kimenetbe, akkor is ha nincs rá szükségünk, és feleslegesen nagy lesz a felhasználó által letöltött adat mennyiség? A válasz: természetesen nem.
Ezeket a komponenseket feltételhez kötöttük, mely a config.scss-ben adható meg.

config.sccs


/**
* Used component
*/
$used-components: (
    navigation-icon: false,
    icons: true !default
);

navigation.icon.scss


@if map-get($used-components, navigation-icon) {
    .navigation-icon {
        [...]
    }
}

Hasonlóan leegyszerűsíthetőek a „tömeg” osztályok, például az ikonok. Az ikonokat egy tömbbe gyűjtjük és @each-el generáljuk le a megfelelő osztályokat.


$icons: (
    ( name: 'file',   
      src: 'icon-file.svg',
      height: 30px, width: 23px, 
      before: true),
      
    ( name: 'pdf',   
      src: 'icon-pdf.svg',
      height: 30px, width: 33px, 
      tag: true),
);

Amit meg kell adni az egy hivatkozási név, amely alapján lehet hivatkozni rá. Az elérési útvonalát a $path--icon változó adja, melyet a config fájlban hoztunk létre, ezért elég a fájl nevét megadni. A méreteken kívül szükséges még meghatározni, hogy az ikont HTML elemként vagy annak pseudo elemeként (before/after) szeretnénk használni, vagy sem. Utóbbi esetben egy postfixel hozza létre a kapcsolódó osztályt.

CSS


.icon--file-b:before {
    display: inline-block;

    width: 23px; 
    height: 30px;

    vertical-align: middle;

    background: url(../svg/icons/icon-file.svg) no-repeat center;
}

.icon--file-b:before {
    margin-right: 15px; 

    content: '';
}

.icon--pdf {
    display: inline-block;

    width: 33px; 
    height: 30px;

    vertical-align: middle;

    background: url(../svg/icons/icon-pdf.svg) no-repeat center;
}

HTML


<i class="icon icon--pdf"></i>


<a href="javascript:void(0);" class="icon icon--file-b">css-fps-modra.doc</a>

Az első gondolatod talán az lehet, hogy sok a redundáns tulajdonság. Ezek később a CSS minify-olása közben kerülnek összevonásra. Ami még talán érdekes lehet: a sok background-image. Ugyanis minden SVG hivatkozás egy plusz query-t jelent, ami lassítja az oldal betöltődését. Ezt egy gulp-css-base64 npm modullal oldottuk meg, mely a fájl elérési útvonalát lecseréli a fájl base64 kódjára. Természetesen így a CSS végkimeneteli fájl mérete megcsalhat, hiszen már tartalmazzák az SVG fájlokat is.

Segéd osztályok

Előfordult már veled, hogy egy-két soros szöveget kellett középre igazítani, dőltté tenni, vagy csak egyszerűen eltüntetni valamelyik töréspontnál, esetleg beszúrni egy nagyobb eltartást? Ilyenkor vakarod a fejed, hogy minek is nevezd. Kissé jellegtelen, nem tudod logikához kötni. Ilyen esetekre jók az általános segéd osztályok.

Ezekből az alapokon kívül (wrapper, clear, clear-fix…) még négy típust hoztunk létre: text, floating, display, spacer.
Ezek az osztályok módosítókon keresztül biztosítják az alap rendezési, és megjelenítési tulajdonságokat. Szintén módosítókon keresztül a grid töréspontjaihoz igazíthatóak.
Hogy néz ki használatban? Egy egyszerű példán levetítve valahogy így:


<p class="text text--center text--desk-right">text</p>

A szöveg desktop kijelzőkön jobbra rendeződik, mobil eszközökön középre.

Ami esetleg nem annyira általános az a spacer, elég rugalmas osztály, amivel két elem közötti eltartást implementálhatunk gyorsan. Akár egymás alá is törhetjük azokat, anélkül, hogy grid szerkezetébe helyeznénk.


<span>text</span>
<hr class="spacer spacer--20 spacer--desk-40 spacer--desk-horizontal" />
<span>text2</span>

A két szöveges elem között 40px eltartást biztosít. Mobile eszközökön pedig a két elemet egymás alá fogja törni, és közöttük 20px lesz az eltartás.

A spacer méreteit szintén tömbben tároljuk, hisz nem szeretnénk felesleges osztályokat létrehozni.

Természetesen a segéd osztályok CSS kimenete több ízben is feltételhez van kötve. Az első, hogy egyáltalán responsive a projekt, így figyeli a $responsive változót. Amennyiben a config fájlban false-ra van állítva, semmilyen töréspontot nem generál le. Figyeli, hogy milyen töréspontok esetén szeretnénk használni azokat $breakpoint-has-helpers: ('palm', 'lap', 'portable', 'desk') !default; és végezetül, mely segéd osztályokra van szükségünk.


/**
* Used helpers
*/
$used-helpers: (
	text:     true,
	floating: true,
	display:  true,
	spacer:   true,
);

Ezzel minimalizálva a felesleges osztályokat, hogy valóban csak azok kerüljenek a CSS-be, ami tényleg használatban is van.

Eszköztár

A pre-processorok rengeteg olyan lehetőséget biztosítanak, amelyekkel csak élnünk kell, és felgyorsíthatjuk a munkánkat. Ilyenek a funkciók, mixinek és csendes osztályok. Ezeket a units könyvtárba gyűjtöttük.

A mixinek egy részét mi írtuk, másik részét már létező mixin könyvtárakból vettünk át. Megszámolni sem tudom hány alkalommal kerestem úgynevezett „CSS triangle generator”-t és mennyivel egyszerűbb beírni: @include triangle(30px 10px, #fff, top, ':after');.

Az alap függvényeken kívül létrehozhatsz saját függvényeket is. Mi is így tettünk. A mi függvénytárunk például szerepel egy calc-rem függvény, ami pixel mértékegységet vált át rem-re. A visszatérési értékét változtatja a cofing-ban található $use-rem-unit változó. Amennyiben false, a kapott bemeneti pixel értékkel tér vissza.
Ez miért jó?
A typo.scss fájlban minden szöveg stílust egy @mixin text($size, $line, $margin: 0) mixinen keresztül adunk meg, amely használja a fent említett függvényt. Így a config fájl módosításával bármikor átállhatunk rem mértékegység használatára, amennyiben úgy döntünk.

Amiről még nem esett szó, azok a csendes osztályok, azaz silent classok. Ezek az osztályok nem jelennek meg sehol a CSS kódban. Viszont a tulajdonságok, amelyekkel rendelkeznek, örököltethetőek. Például adott egy kép, amelyet alap állapotban szürke árnyalatosan szeretnénk megjeleníteni, hover állapotában pedig szeretnénk a színét vissza adni:



@import '../silents/mixins.scss';

img {
    width: 100%;
    height: auto;
    @extend %grayscale;
    
    &:hover {
        @extend %colorful;
    }
}

Ezeknek az osztályoknak a számát még bővítjük. Jelenleg olyan prototípusok vannak benne, mint elem középre helyezése, szöveg túlfolyás kipontozása, elem tükrözése, vagy a legegyszerűbb a kör, azaz %circle, de még sorolhatnám.

Ne maradj szégyenben!

Mi az a shame.scss? Az ötlet Harry Roberts, Chris Coyier és Dave Rupert viccelődéséből származik. Végül rájöttek, hogy ez nem is olyan rossz ötlet.
Elkerülhetetlenek azok a helyzetek, amikor „hackelned” kell, vagy át kell hágnod a saját konvencióidat. Valamit gyorsan fixálni kell, a bemutatóig már nincs elég idő. Az ilyenkor szükséges csúnya megoldások kerülnek a shame.scss-be. A fájl elnevezése már magában beszédes (szégyen), hogy inkább kerüld a használatát.

A tartalma alap állapotban csak egy kommentár:


@import 'units/mixins.scss';
@import 'units/silents.scss';

/**
* Please, leave me empty!
*/

Ne felejtsd el: a shame-ben nem megoldások vannak, hanem „hibák”. Ha használod ezt a fájlt, később mindenképp térj vissza és írj valódi megoldást a gyorsan orvosolt problémára. Nehogy szégyenben maradj!

Tóth Gábor

Front-end fejlesztő. A letisztult megoldások híve, aki szerint nem elég, ha működik, annak jól is kell kinéznie. Ha épp nem programnyelven ír, akkor lírában.

Tóth Gábor

Hozzászólások