articles, css

CSS: Κληρονομικότητα (inheritance) και cascade

08/11/2010

Εάν θα μπορούσα να δηλώσω expert σε κάτι, αυτό θα ήταν σίγουρα το CSS. Δουλεύω με αυτό από την πρώτη του version και γενικά είναι μέρος της καθημερινότητας μου. Έχω γράψει άπειρες γραμμές σε πολύ μεγάλα αλλά και πολύ μικρά sites, και με ενθουσιάζει το γεγονός πως ένα τόσο φαινομενικά απλό πρότυπο, ζωντανεύει την markup μας. Στην προηγούμενη πρόταση γράφω “φαινομενικά απλό” γιατί το “γράφω CSS” από το “γνωρίζω CSS” έχει τεράστια διαφορά. Ένας γνώστης μπορεί να γράψει μέσα σε ελάχιστες γραμμές, αυτό που κάποιος newbie γράφει και ξαναγράφει! Το όλο μυστικό κρύβεται σε 2 χαρακτηριστικά του CSS που θέλουν λίγο χρόνο για να εξοικειωθείτε, η κληρονομικότητα (inheritance) και το cascade.

Στο παρακάτω αρθράκι λοιπόν, θα προσπαθήσω να εξηγήσω όσο καλύτερα γίνεται αυτά τα δύο χαρακτηριστικά του CSS, τα οποία ποτέ δεν μου εξήγησε κανείς και τελικά τα έμαθα με τον δύσκολο τρόπο (hard way που λένε και οι Εγγλέζοι). Το περίεργο είναι πως και ολόκληρα βιβλία αφιερωμένα στο θέμα, αποφεύγουν να τα εξηγήσουν αναλυτικά - μάλλον δεν θέλουν να γίνουν όλοι experts ;-). Ας ξεκινήσουμε λοιπόν.

Κληρονομικότητα (Inheritance)

Γενικά δουλεύει όπως μπορείτε να φανταστείτε και όπως έχετε συνηθίσει και σε γλώσσες προγραμματισμού (αν έχετε ασχοληθεί τέλος πάντων). Είναι ο μηχανισμός με τον οποίο συγκεκριμένες ιδιότητες (properties) μεταφέρονται από το parent element στα “παιδιά” του. Είναι αρκετά εύκολο στην κατανόηση, και στην ουσία το μόνο πράγμα που προκαλεί μπέρδεμα είναι ποιες ιδιότητες (properties) κληρονομούνται τελικά, μιας και δεν κληρονομούνται όλες. Σε αυτόν τον πίνακα (κοιτάξτε την 5η στήλη) μπορείτε να δείτε ποιες από αυτές κληρονομούνται και ποιες όχι. Προσωπικά δεν τον θυμάμαι απέξω, άλλωστε δεν έχει και πολύ νόημα μιας και γιαυτό υπάρχουν οι DOM inspectros (όπως πχ. το firebug), ωστόσο κρατήστε πως ότι έχει να κάνει με fonts κληρονομείτε (γι’ αυτό και το declaration του font στο body είναι ο πιο σημαντικός CSS κανόνας ενός site).

Cascade

Η κληρονομικότητα όπως είδατε είναι αρκετά εύκολη στην κατανόηση. Ας εξηγήσουμε όμως και το Cascade το οποίο είναι κάπως πιο πολύπλοκο. Το Cascade (δεν νομίζω να μπορεί μεταφραστεί κάπως αξιόλογα στα ελληνικά) είναι ίσως το πιο δυσνόητο κομμάτι του CSS γιατί κρύβει αρκετή θεωρία από πίσω του, ωστόσο είναι και το πιο σημαντικό και γι αυτόν τον λόγο αποτελεί και την πρώτη λέξη του ακρώνυμου CSS (Cascading Style Sheets). To Casade λοιπόν αποτελείται από 3 βασικές έννοιες οι οποίες καθορίζουν πως το CSS θα εφαρμόσει τελικά τους κανόνες των style sheets μας. Οι 3 έννοιες είναι οι παρακάτω:

  • Importance (σπουδαιότητα)
  • Specificity (ειδικότητα)
  • Η σειρά που εμφανίζονται μέσα στον κώδικα

Και για να μην μπερδευτούμε ας τα πάρουμε ένα-ένα.

Importance (Σπουδαιότητα)

Η σπουδαιότητα έχει να κάνει με το που δηλώθηκε ο CSS κανόνας. Οι κανόνες που θα κάνουν conflict μεταξύ τους θα εφαρμοστούν με την παρακάτω σειρά, με τις νεότερες να υπερισχύσουν:

  1. User agent style sheets
  2. Κανονικοί style sheet κανόνες συγγραφέα (author)
  3. Κανονικοί style sheet κανόνες χρήστη (user)
  4. Σημαντικοί style sheet κανόνες συγγραφέα (author)
  5. Σημαντικοί style sheet κανόνες χρήστη (user)

Αλλά ας εξηγήσουμε λίγο τι είναι τα παραπάνω style sheets και από που έρχονται!

Λέγοντας user agent style sheets εννοούμε όλα τα ενσωματωμένα (default) style sheet του browser (πχ. margin/padding σε headers, παραγράφους, λίστες, χρώματα link, κτλ.).

Οι style sheet κανόνες συγγραφέα (author), είναι τα κλασικά style sheets που γράφουν οι web designers του εκάστοτε site.

Οι style sheet κανόνες χρήστη (user), είναι κάποιοι ειδικοί κανόνες που μπορεί να θέσει ο ίδιος ο χρήστης. Οι περισσότεροι browsers δεν επιτρέπουν τέτοιου είδους κανόνες, ωστόσο πιο ειδικοί browsers (πχ. για δυσλεκτικούς ή screen readers οι οποίοι επιτρέπουν κυρίως aural style sheets) δίνουν αρκετές επιλογές και δυνατότητες στον ίδιο χρήστη (και μάλιστα υπερτερούν!).

Τέλος, τα δύο τελευταία είδη style sheet, μπορούν να εφαρμοστούν είτε ως κανονικοί (normal) κανόνες, είτε ως σημαντικοί (important) κανόνες (πχ. p { font-size: 1em <strong>!important</strong>; }), με τους δεύτερους να είναι ισχυρότεροι από τους πρώτους.

Γενικότερα εμείς που ασχολούμαστε με την κατασκευή web sites δεν έχουμε να κάνουμε και πολλά πράγματα με την σπουδαιότητα, γιατί πολύ απλά δεν είναι στο χέρι μας, ωστόσο θα πρέπει να έχουμε στο μυαλό μας τι style sheets δέχεται ένα document, τι είναι τα user agent style sheets, ή πως λειτουργεί ο !important κανόνας.

Specificity (ειδικότητα)

Η ειδικότητα είναι το πιο σημαντικό κομμάτι του cascade, και αυτό που πρέπει να κατανοήσει ο κάθε web designer. Ο γενικός κανόνας είναι σχετικά απλός, όσο πιο συγκεκριμένος (ειδικός) είναι o selector ενός κανόνα, ο συγκεκριμένος κανόνας υπερισχύει! Αν και είναι εύκολο και λογικό, κάποιος νέος στον χώρο μπορεί να χάσει πολύ εύκολα την μπάλα σε ένα πολύπλοκο έγγραφο (document), και να καταντήσει να γράφει ξανά και ξανά τα ίδια πράγματα.

Ο πιο συγκεκριμένος selector, ο οποίος αναιρεί όλους τους άλλους, αλλά δεν πρέπει να χρησιμοποιούμε ποτέ, είναι το style attribute σε οποιοδήποτε element. Δεν το χρησιμοποιούμε για να μην μπλέκουμε την markup με τα styles, και για πολλούς άλλους λόγους που έχουμε εξηγήσει σε άλλα posts. Από εκεί και πέρα έχουμε ένα περίεργο point system για το κάθε selector, το οποίο παίζει ως εξής:

  • Το κάθε element (ή pseudo-element) που εμφανίζεται στον selector μας παίρνει 1 βαθμό
  • Η κάθε κλάση (class) που που εμφανίζεται στον selector μας παίρνει 10 βαθμούς
  • Το κάθε id που εμφανίζεται στον selector μας παίρνει 100 βαθμούς

Εδώ μπορείτε να βρείτε και μια πιο χιουμοριστική εξήγηση του point system που περιγράφω, ωστόσο με τα παρακάτω παραδείγματα του πίνακα, πιστεύω πως θα καταλάβετε καλύτερα το πως δουλεύει.

<th>
  id
</th>

<th>
  class
</th>

<th>
  element
</th>

<th>
  Specificity
</th>
<td>
</td>

<td>
</td>

<td>
  1
</td>

<td>
  001
</td>
<td>
</td>

<td>
  1
</td>

<td>
</td>

<td>
  010
</td>
<td>
</td>

<td>
  1
</td>

<td>
  1
</td>

<td>
  011
</td>
<td>
  1
</td>

<td>
</td>

<td>
</td>

<td>
  100
</td>
<td>
  1
</td>

<td>
  1
</td>

<td>
</td>

<td>
  110
</td>
<td>
  1
</td>

<td>
  1
</td>

<td>
  1
</td>

<td>
  111
</td>
<td>
</td>

<td>
</td>

<td>
  1+1
</td>

<td>
  002
</td>
<td>
</td>

<td>
  1+1
</td>

<td>
</td>

<td>
  020
</td>
Το Point system της ειδικότητας (specificity)
Selector
p
.class
p.class
#id
#id .class
#id p.class
p a
.classa .classb

Κάπως έτσι υπολογίζεται το specificity και ο selector με τον μεγαλύτερο αριθμό υπερτερεί.

Η σειρά που εμφανίζονται μέσα στον κώδικα

Τι γίνεται όμως όταν 2 κανόνες έχουν ακριβώς το ίδιο specifity; Για παράδειγμα:

.nav a {
  color: green;
}

.nav a {
  color: red;
}

Και οι 2 παραπάνω selectors έχουν 011, ωστόσο όλοι οι browsers θα κάνουν rendering τα links με κόκκινο χρώμα για τον πολύ απλό λόγο πως ήταν ο πιο πρόσφατος κανόνας που συναντήθηκε. Το μόνο που πρέπει να έχουμε υπόψη μας εδώ είναι πως εάν έχουμε πολλά style sheets η σειρά που φορτώνονται έχει σημασία, οπότε το προσέχουμε και αυτό.

Αυτά τα λίγα για την κληρονομικότητα (inheritance) και το cascade. Ελπίζω να ξεκαθαρίσατε κάποια πράγματα που έχουν να κάνουν με την θεωρία που κρύβεται πίσω από το CSS, η οποία πολλές φορές δεν αναφέρεται και δεν εξηγείτε όπως θα έπρεπε.