Sass Guidelines
Ένα δογματικό styleguide για συγγραφή ισορροπημένης, συντηρήσιμης και επεκτάσιμης Sass.
Βλέπετε την ελληνική μετάφραση των Μόδεστο Καφφέ, Σεμπαστιέν Νικολάου, Άδωνη Κακουλίδη και Κωνσταντίνου Μαργαρίτη για τις πρωτότυπες Οδηγίες για Sass των Kitty Giraudel.
Αυτή η έκδοση συντηρείται αποκλειστικά από συνεισφέροντες χωρίς τον έλεγχο του κύριου συντάκτη, επομένως μπορεί να μην είναι εντελώς αυθεντική.
Πως μπορείτε να συνεισφέρετε
Το Sass Guidelines είναι ένα ελεύθερο project που συντηρώ στον ελεύθερό μου χρόνο. Περιττό να πω ότι απαιτείται πάρα πολλή δουλειά για να διατηρηθεί το project ενημερωμένο, τεκμηριωμένο και συναφές. Ευτυχώς, έχω τη βοήθεια πολλών σπουδαίων ανθρώπων που συνεισφέρουν, ειδικά όσον αφορά τη συντήρηση δεκάδων διαφορετικών μεταφράσεων. Be sure to thank them!
Τώρα αν ενδιαφέρεστε να συνεισφέρετε, παρακαλώ γνωρίζετε πως ένα tweet που αναφέρει το project, ή την διάδοσή του, ακόμα και η διόρθωση ενός ορθογραφικού λάθους ανοίγοντας ένα issue ή pull-request στο GitHub repository θα ήταν υπέροχο!
Τέλος αν απολαύσατε αυτό το έγγραφο ή αν ήταν χρήσιμο σε εσάς ή την ομάδα σας, παρακαλώ σκεφτείτε το ενδεχόμενο να το υποστηρίξετε για να συνεχίσω αυτή την προσπάθεια!
Σχετικά με τη Sass
Η Sass αυτοπροσδιορίζεται στο documentation ως εξής:
Η Sass είναι μία επέκταση της CSS η οποία προσθέτει ισχύ και κομψότητα στη βασική γλώσσα.
Ο απώτερος στόχος της είναι να διορθώσει τα ελλατώματα της CSS. Όπως όλοι γνωρίζουμε, Η CSS δεν είναι και η καλύτερη γλώσσα στον κόσμο [εκκρεμεί παραπομπή]. Αν και είναι πολύ απλή στην εκμάθηση, μπορεί να γίνει ακατάστατη πολύ γρήγορα, ειδικά σε μεγάλα projects.
Σ’αυτό το σημείο έρχεται η Sass, ως μία μετα-γλώσσα, για να βελτιώσει τη σύνταξη της CSS ώστε να της παρέχει επιπλέον δυνατότητες και βολικά εργαλεία. Παράλληλα, η Sass επιδιώκει να παραμείνει συντηρητική σε σχέση με τη γλώσσα CSS.
Το ζητούμενο δεν είναι να μετατρέψει τη CSS σε μία γλώσσα προγραμματισμού πλήρη δυνατοτήτων· η Sass επιδιώκει να βοηθήσει μόνο εκεί που η CSS αποτυγχάνει. Εξαιτίας αυτού, το να ξεκινήσεις να μαθαίνεις Sass δεν είναι πιο δύσκολο από το να μαθαίνεις CSS: απλά προσθέτει μερικές επιπλέον δυνατότητες πάνω στις ήδη υπάρχουσες.
Εντούτοις, υπάρχουν πολλοί τρόποι να χρησιμοποιήσουμε αυτές τις δυνατότητες. Κάποιοι καλοί, κάποιοι κακοί και κάποιοι ασυνήθιστοι. Αυτά τα guidelines έχουν σκοπό να σου δώσουν μία συνεκτική και τεκμηριωμένη προσέγγιση για τη συγγραφή κώδικα σε Sass.
Ruby Sass ή LibSass
Το πρώτο commit της Sass ανάγεται στα τέλη του 2006, πάνω από 10 χρόνια πριν. Περιττό να πούμε ότι έχει διανύσει πολύ δρόμο από τότε. Αρχικά αναπτύχθηκε σε Ruby, και διάφορα ports ξεφύτρωσαν από δω κι από κει. Το πιο δημοφιλές, το LibSass (γραμμένο σε C/C++), είναι πλέον κοντά στο να είναι πλήρως συμβατό με την πρωτότυπη έκδοση σε Ruby.
Το 2014, οι ομάδες του Ruby Sass και του LibSass αποφάσισαν να περιμένουν και τις δύο εκδόσεις να συγχρονιστούν πριν προχωρήσουν παραπέρα. Από τότε, το LibSass δημοσιεύει τακτικά νέες εκδόσεις μέχρι να φτάσει τον μεγαλύτερο αδερφό του σε δυνατότητες. Οι τελευταίες ασυνέπειες που έχουν απομείνει έχουν συγκεντρωθεί και τις παραθέτω στο Sass-Compatibility project. Αν έχεις υπόψη σου κάποια ασυνέπεια μεταξύ των δύο εκδόσεων που δεν αναφέρεται, μπορείς να ανοίξεις ένα issue αν έχεις την καλοσύνη.
Επιστρέφουμε στην επιλογή του compiler. Βασικά εξαρτάται από το project σου. Αν είναι ένα project σε Ruby on Rails, καλύτερα να χρησιμοποιήσεις το Ruby Sass, που ταιριάζει απόλυτα στην περίπτωση. Επίσης, να ξέρεις ότι το Ruby Sass θα είναι πάντα το σημείο αναφοράς όσον αφορά την υλοποίηση της Sass και πάντα θα προηγείται του LibSass σε δυνατότητες. Αν θέλετε να μεταβείτε απο Ruby Sass σε LibSass, αυτό το άρθρο είναι για σας.
Όταν θέλεις να εντάξεις τη Sass στη ροή εργασίας σου σε κάποιο project που δεν είναι σε Ruby, το LibSass είναι πιθανώς καλύτερη ιδέα επειδή είναι εξειδικευμένο γι’ αυτή την περίπτωση. Οπότε αν θες να χρησιμοποιήσεις ας πούμε NodeJS, το node-sass είναι το πιο επιθυμητό.
Sass ή SCSS
Επικρατεί μεγάλη σύγχυση σχετικά με τη σημειολογία της ονομασίας Sass, για έναν καλό λόγο: ως Sass εννοούμε και τον preprocessor και τη σύνταξη της γλώσσας. Λίγο άβολο, έτσι δεν είναι;
Βλέπεις, η Sass αρχικά περιέγραφε μία σύνταξη στην οποία το βασικό χαρακτηριστικό ήταν η ευαισθησία στο indentation. Σύντομα οι συντηρητές της Sass αποφάσισαν να γεφυρώσουν το χάσμα μεταξύ Sass και CSS παρέχοντας μια σύνταξη φιλική ως προς τη CSS με το όνομα SCSS, που σημαίνει Sassy CSS (ζωηρή CSS). Το σύνθημα είναι το εξής: αν είναι έγκυρη CSS, τότε είναι έγκυρη SCSS.
Από τότε, η Sass (ο preprocessor) παρέχει δύο διαφορετικές συντάξεις: τη Sass (χωρίς κεφαλαία παρακαλώ), επίσης γνωστή ως την indented σύνταξη, και την SCSS. Το ποιά σύνταξη θα χρησιμοποιήσεις είναι στο χέρι σου μιας και οι δύο έχουν ακριβώς τις ίδιες δυνατότητες. Σ’ αυτό το σημείο είναι θέμα προτίμησης.
Η whitespace-sensitive σύνταξη της Sass βασίζεται στο indentation για να απαλλαγεί από τα άγκιστρα (braces), τα ερωτηματικά (semi-colons) και άλλα σημεία στίξης, πράγμα που οδηγεί σε μια πιο λιτή και πιο σύντομη σύνταξη. Παράλληλα, η SCSS είναι πιο εύκολη στην εκμάθηση μιας και πρόκειται για μερικά μικρά επιπλέον κομμάτια πάνω στη CSS.
Εγώ προσωπικά προτιμώ την SCSS από τη Sass γιατί είναι πιο κοντά στη CSS και πιο φιλική για τους περισσότερους developers. Γι’ αυτό το λόγο, θα χρησιμοποιώ SCSS αντί για Sass σ’ αυτά τα guidelines.
Λοιποί preprocessors
Η Sass είναι ένας preprocessor μεταξύ άλλων. Ο πιο σοβαρός ανταγωνιστής της είναι η Less, ένας preprocessor που βασίζεται σε NodeJS, ο οποίος έχει γίνει αρκετά δημοφιλής χάρη στο γνωστό CSS framework Bootstrap που το χρησιμοποιεί (μέχρι την 4η έκδοση). Επίσης υπάρχει και το Stylus, ένας πολύ ανεκτικός και ευέλικτο preprocessor όμως ελαφρώς δυσκολότερο στην χρήση και με μικρότερη κοινότητα.
Το γιατί να επιλέξω Sass αντί κάποιου άλλου preprocessor είναι μία βάσιμη απορία ακόμα και σήμερα. Μέχρι πρόσφατα συνιστούσαμε Sass για projects σε Ruby γιατί ο preprocessor ήταν φτιαγμένος σε Ruby και κούμπωνε καλά με το Ruby on Rails. Τώρα που το LibSass έχει συμβαδίσει (σχεδόν) με το πρωτότυπο Sass, πλέον δεν τίθεται τέτοιο θέμα.
Αυτό που μ’ αρέσει στη Sass είναι η συντηρητική της προσέγγιση απέναντι στη CSS. Ο σχεδιασμός της Sass βασίζεται σε ισχυρές αρχές: οι περισσότερες σχεδιαστικές προσεγγίσεις προέρχονται φυσικά από τις πεποιθήσεις των ιδρυτών της πως α) το να προσθέτεις επιπλέον δυνατότητες έχει μία επιβάρυνση σε πολυπλοκότητα η οποία πρέπει να δικαιολογείται από τη χρησιμότητα και β) πρέπει να είναι απλό να κατανοήσεις τι κάνει ένα συγκεκριμένο κομμάτι από styles μελετώντας το απομονωμένα. Επίσης, η Sass δίνει πολύ αυστηρότερη έμφαση στη λεπτομέρεια σε σχέση με άλλους preprocessors. Απ’ όσο μπορώ να πω, οι βασικοί σχεδιαστές νοιάζονται πολύ για την υποστήριξη της κάθε παραμικρής συμβατότητας με τη CSS και φροντίζουν η γενική συμπεριφορά της γλώσσας να είναι συνεπής.
Πέρα από τους preprocessors, πρέπει επίσης να επισημάνουμε εργαλεία όπως το PostCSS και το cssnext τα οποία έχουν γίνει αρκετά δημοφιλή τους τελευταίους μήνες.
Το PostCSS συνηθίζεται να αποκαλείται (λανθασμένα) ως “postprocessor”. Η υπόθεση, συνδιασμένη με το ατυχές όνομα, είναι πως το PostCSS κάνει parse τη CSS η οποία έχει ήδη επεξεργαστεί από έναν preprocessor. Ένω μπορεί να δουλέψει και με αυτόν τον τρόπο, δεν είναι απαιτούμενο και έτσι το PostCSS είναι στην πραγματικότητα απλώς ένας “processor”.
Παρέχει την πρόσβαση σε “tokens” των stylesheets σας (όπως τους selectors, τα properties και τις τιμές), τα επεξεργάζεται μέσω JavaScript για να εκτελέσει κάποια εργασία και (τέλος) κάνει compile τα αποτελέσματα σε CSS. Για παράδειγμα, η δημοφιλής prefixing βιβλιοθήκη Autoprefixer είναι φτιαγμένη με PostCSS. Κάνει parse κάθε κανόνα CSS για να δει αν χρειάζονται vendor prefixes με βάση το εργαλείο υποστήριξης χαρακτηριστικών στους browsers CanIUse, κι έπειτα διαγράφει vendor prefixes που δεν χρειάζονται και προσθέτει αυτά που χρειάζονται.
Αυτό είναι εξαιρετικά ισχυρό και καλό για την δημιουργία βιβλιοθηκών που λειτουργούν με οποιονδήποτε preprocessor (όπως επίσης και με απλή CSS), αλλά το PostCSS δεν είναι ιδιαίτερα εύκολο στη χρήση ακόμη. Πρέπει να γνωρίζετε Javascript για μπορείτε να χτίσετε κάτι με αυτό, και το API του μπορεί να σας μπερδέψει κατά καιρούς. Ενώ η Sass παρέχει μόνο ένα σετ από χαρακτηριστικά που είναι χρήσιμα για να γράψει κάποιος CSS, το PostCSS παρέχει απευθείας πρόσβαση στο CSS AST (abstract syntax tree) και στη JavaScript.
Εν συντομία, η Sass είναι σχετικά εύκολη και θα λύσει τα περισσότερα από τα προβλήματά σας. Από την άλλη, το PostCSS είναι αρκετά δύσκολο στην κατανόηση (ιδίως αν δε γνωρίζετε JavaScript), αλλά αποδεικνύεται ότι είναι ένα εξαιρετικά ισχυρό εργαλείο. Δεν υπάρχει κάποιος λόγος για τον οποίο δε μπορείτε και δεν πρέπει να χρησιμοποιείτε και τα δύο. Στην πραγματικότητα, το PostCSS προσφέρει επίσημα SCSS parser γι’ αυτόν ακριβώς το λόγο.
Ευχαριστώ τον Cory Simmons για τη βοήθεια και την εμπειρογνωμοσύνη που πρόσφερε σε αυτό το τμήμα.
Εισαγωγή
Λόγοι για ένα styleguide
Ένα styleguide δεν είναι ένα έγγραφο απλά ευχάριστο στην ανάγνωση, που απεικονίζει μια ιδανική κατάσταση για τον κώδικά σου. Είναι ένα έγγραφο βασικής σημασίας για τη ζωή ενός project, το οποίο περιγράφει γιατί και πώς πρέπει να γράφεται ο κώδικας. Μπορεί να ακούγεται πλεονασμός για μικρά projects, αλλά βοηθάει πολύ στη διατήρηση ενός καθαρού, επεκτάσιμου και ευκολοσυντήρητου κώδικα.
Περιττό να πούμε πως όσο περισσότεροι developers εμπλέκονται σε ένα project, τόσο περισσότερο χρειάζονται guidelines για τον κώδικα. Στα ίδια πλαίσια, όσο μεγαλύτερο το project, τόσο αναγκαίο καθιστάται ένα styleguide.
Ο Harry Roberts αναφέρει πολύ καλά στο CSS Guidelines:
Ένα code styleguide (σημ., όχι οπτικό styleguide) είναι ένα πολύτιμο εργαλείο για ομάδες οι οποίες:
- αναπτύσσουν και συντηρούν προϊόντα για ένα εύλογο χρονικό διάστημα·
- απασχολούν developers με διαφορετικές ικανότητες και ειδικότητες·
- απασχολούν έναν αριθμό από διαφορετικούς developers οι οποίοι εργάζονται πάνω σε ένα προϊόν ανά πάσα στιγμή·
- προσλαμβάνουν τακτικά νέο προσωπικό·
- έχουν έναν αριθμό από codebases στα οποία οι developers συχνάζουν.
Disclaimer
Πρώτα απ’ όλα: δεν πρόκειται για ένα CSS styleguide. Αυτό το έγγραφο δεν εξετάζει συμβάσεις ονοματοδοσίας για κλάσεις CSS, modular patterns, ούτε το ζήτημα του ID στη σφαίρα της CSS. Αυτά τα guidelines έχουν μοναδικό στόχο να εξετάσουν θέματα ειδικά για τη Sass.
Επίσης, αυτό το styleguide είναι δικό μου και επομένως ιδιαίτερα δογματικό. Δες στο σαν μία συλλογή από μεθοδολογίες και συμβουλές τις οποίες έχω τελειοποιήσει και έχω προσφέρει την πάροδο των χρόνων. Μου δίνεται επίσης η ευκαιρία να παραθέσω κάποιες αξιοσημείωτες πηγές, οπότε μην αμελήσετε να διαβάσετε τα περαιτέρω αναγνώσματα.
Προφανώς, αυτός δεν είναι ο μοναδικός τρόπος να αντιμετωπίσεις τα πράγματα, οπότε μπορεί να αρμόζει ή να μην αρμόζει στο project σου· επέλεξε ελεύθερα και οτιδήποτε προσάρμοσέ το στις ανάγκες σου. Όπως λέμε, your mileage may vary.
Βασικές αρχές
Στο τέλος της μέρας, αν μπορείς να συγκρατήσεις ένα πράγμα απ’ όλο το styleguide, είναι ότι η Sass πρέπει να είναι όσο πιο απλή γίνεται.
Χάρη στα ανόητα πειράματά μου όπως οι bitwise operators, οι iterators and generators και ένας JSON parser σε Sass, ξέρουμε όλοι τι μπορεί να επιτευχθεί με αυτόν τον preprocessor.
Παράλληλα, η CSS είναι μια απλή γλώσσα. Η Sass που προορίζεται για την εξαγωγή CSS, δεν θα έπρεπε να είναι αρκετά πιο περίπλοκη απο την CSS. Η αρχή KISS (Keep It Simple Stupid) είναι το κλειδί και μπορεί να πάρει προτεραιότητα έναντι της DRY αρχής (Don’t Repeat Yourself) σε κάποιες περιπτώσεις.
Μερικές φορές, είναι καλύτερο να επαναλάμβανόμαστε λίγο για να κρατήσουμε τον κώδικα συντηρήσιμο, αντι να φτιάξεις κάτι βαρή, δυσμεταχείριστος και αδικαιολόγητα περίπλοκο σύστημα που είναι αδύνατο να συντηρηθεί επειδή είναι υπερβολικά περίπλοκο.
Επίσης, και επιτρέψτε μου να παραθέσω τον Harry Roberts για ακόμη μια φορά, ο πραγματισμός υπερέχει τις τελειότητας. Μετά από κάποιο σημείο, μάλλον θα βρείτε τον εαυτό σας να πηγαίνει ενάντια στα πράγματα που περιγράφονται εδώ. Αν βγάζουν νόημα και πιστεύετε πως είναι ορθά, μην διστάσετε να το κάνετε. Ο κώδικας είναι ένα μέσο, όχι αυτοσκοπός.
Επέκταση των guidelines
Ένα μεγάλο μέρος αυτού του styleguide είναι αρκετά δογματικό. Έχω διαβάσει και γράψει Sass αρκετά χρόνια τώρα, σε βαθμό πού τώρα έχω πολλές αρχές όσον αφορά τη συγγραφή καθαρών stylesheets. Καταλαβαίνω ότι μπορεί να μην ικανοποιεί ούτε να ταιριάζει σε όλους, και αυτό είναι απολύτως φυσιολογικό.
Αν και, πιστεύω πως τα guidelines φτιάχνονται για να επεκταθούν. Επεκτείνοντας τα Sass Guidelines θα μπορούσε να είναι τόσο απλό όσο έχοντας ένα έγγραφο που πιστοποιεί ότι ο κώδικας ακολουθεί guidelines απο αυτό το styleguide εκτός από μερικά πράγματα· περίπτωση στην οποία ειδικοί κανόνες θα εξηγούνται παρακάτω.
Ένα παράδειγμα απο την επέκταση του styleguide μπορεί να βρεθεί στο SassDoc repository:
Είναι μια επέκταση του Node Styleguide από τον Felix Geisendörfer. Οτιδήποτε από αυτό το έγγραφο υπερισχύει των λεγομένων του Node Styleguide.
Σύνταξη & μορφοποίηση
Αν με ρωτάς, το πρώτο πράγμα που πρέπει να κάνει ένα styleguide είναι να περιγράφει τον τρόπο που θέλουμε να φαίνεται ο κώδικάς μας.
Όταν διάφοροι developers συμμετέχουν στην συγγραφή CSS στο ίδιο project, είναι απλά θέμα χρόνου μέχρι ένας από αυτούς να ξεκινήσει να δρα με το δικό του τρόπο. Τα guidelines κώδικα που προωθούν την ομοιομορφία όχι μόνο προλαμβάνουν κάτι τέτοιο, αλλά επίσης βοηθούν στο διάβασμα και την ενημέρωση του κώδικα.
Γενικά, θέλουμε (εμπνευσμένα από τα CSS Guidelines):
- δύο (2) κενά για indentation, όχι tabs,
- ιδανικά, 80 χαρακτήρες ανά γραμμή,
- ορθά γραμμένη CSS πολλαπλών γραμμών,
- εποικοδομητική χρήση κενών,
// Yep
.foo {
display: block;
overflow: hidden;
padding: 0 1em;
}
// Nope
.foo {
display: block; overflow: hidden;
padding: 0 1em;
}
// Εφόσον η εμφωλευμένη σύνταξη Sass επιβάλει αυτά τα πρότυπα κώδικα
// Δεν υπάρχει λάθος τρόπος για να προχωρήσεις
.foo
display: block
overflow: hidden
padding: 0 1em
Strings
Είτε το πιστεύεις είτε όχι, τα strings παίζουν πολύ μεγάλο ρόλο και στο οικοσύστημα της CSS αλλά και της Sass. Οι περισσότερες τιμές CSS είναι είτε μήκη ή αναγνωριστικά, οπότε στην πραγματικότητα είναι πολύ σημαντικό να ακολουθούμε κάποια guidelines όταν έχουμε να κάνουμε με strings στη Sass.
Κωδικοποίηση
Για την αποφυγή πιθανού προβλήματος με την κωδικοποίηση χαρακτήρων, συνιστάται ιδιαίτερα να εφαρμοστεί κωδικοποίηση UTF-8 στο main stylesheet χρησιμοποιώντας το @charset
directive. Βεβαιώσου ότι είναι το πρώτο πρώτο στοιχείο του stylesheet και ότι δεν υπάρχει κάποιος χαρακτήρας οποιουδήποτε είδους πριν από αυτό.
@charset 'utf-8';
@charset 'utf-8'
Εισαγωγικά
Η CSS δεν απαιτεί τα strings να έχουν εισαγωγικά, ακόμη και αυτά που περιέχουν κενά. Πάρε για παράδειγμα τα font-family names: δεν έχει σημασία αν περικλείεις εσύ τα strings με εισαγωγικά ή ο CSS parser.
Εξαιτίας αυτού, ούτε η Sass απαιτεί τα strings να έχουν εισαγωγικά. Ακόμη καλύτερα (και ευτυχώς πρέπει να παραδεχτούμε), ένα string με εισαγωγικά είναι αυστηρά ισοδύναμο με ένα χωρίς εισαγωγικά (π.χ. το 'abc'
είναι αυστηρά ισοδύναμο με το abc
).
Παρόλα αυτά, οι γλώσσες που δεν απαιτούν τα strings να έχουν εισαγωγικά είναι σαφώς μειοψηφία οπότε, τα strings πρέπει πάντοτε να περικλείονται από μονά εισαγωγικά ('
) στη Sass (μονά επειδή είναι πιο εύκολο από τα διπλά να πληκτρολογηθούν στα qwerty πληκτρολόγια). Εκτός της ομοιομορφίας με άλλες γλώσσες, συμπεριλαμβανομένης της συγγενούς με τη CSS Javascript, υπάρχουν διάφοροι λόγοι γι’ αυτή την επιλογή:
- τα ονόματα των χρωμάτων αντιμετωπίζονται σαν χρώματα όταν είναι χωρίς εισαγωγικά, πράγμα που μπορεί να οδηγήσει σε σοβαρά προβλήματα·
- οι περισσότεροι syntax highlighters κολλάνε στα strings χωρίς εισαγωγικά·
- βοηθάει στην γενικότερη αναγνωσιμότητα·
- δεν υπάρχει κάποιος βάσιμος λόγος για να μην χρησιμοποιούμε εισαγωγικά.
// Yep
$direction: 'left';
// Nope
$direction: left;
// Yep
$direction: 'left'
// Nope
$direction: left
Σύμφωνα με τις προδιαγραφές της CSS, το @charset
directive πρέπει να δηλώνεται με διπλά εισαγωγικά για να θεωρείται έγκυρο. Παρόλα αυτά, η Sass φροντίζει γι’ αυτό όταν κάνει compile σε CSS οπότε ο τρόπος που θα το γράψεις δεν έχει αντίκτυπο στο τελικό αποτέλεσμα. Μπορείς να μείνεις με ασφάλεια στα μονά εισαγωγικά, ακόμη και για το @charset
.
Strings σαν τιμές CSS
Ορισμένες τιμές (αναγνωριστικά) CSS όπως το initial
ή το sans-serif
απαιτούν να μην έχουν εισαγωγικά. Πράγματι, η δήλωση font-family: 'sans-serif'
θα αποτύχει χωρίς προειδοποίηση επειδή η CSS περιμένει ένα identifier, όχι ένα string σε εισαγωγικά. Εξαιτίας αυτού, δεν βάζουμε εισαγωγικά σε αυτές τις τιμές.
// Yep
$font-type: sans-serif;
// Nope
$font-type: 'sans-serif';
// Okay I guess
$font-type: unquote('sans-serif');
// Yep
$font-type: sans-serif
// Nope
$font-type: 'sans-serif'
// Okay I guess
$font-type: unquote('sans-serif')
Συνεπώς, μπορούμε να κάνουμε μια διάκριση μεταξύ strings που προορίζονται για χρήση ως τιμές CSS (CSS identifiers) όπως στο προηγούμενο παράδειγμα, και strings όταν παραμένουμε σε τύπο αρχείου Sass, για παράδειγμα map keys.
Δεν βάζουμε εισαγωγικά στα πρώτα, όμως στα δεύτερα βάζουμε μονά εισαγωγικά.
Strings που περιέχουν εισαγωγικά
Αν ένα string περιέχει ένα ή περισσότερα μονά εισαγωγικά, μπορεί κανείς να περικλείσει το string με διπλά εισαγωγικά ("
), για να αποφύγει να κάνει escape σε χαρακτήρες μέσα στο string.
// Okay
@warn 'You can\'t do that.';
// Okay
@warn "You can't do that.";
// Okay
@warn 'You can\'t do that.'
// Okay
@warn "You can't do that."
URLs
Τα URL θα πρέπει επίσης να έχουν εισαγωγικά, για τους ίδιους λόγους με παραπάνω:
// Yep
.foo {
background-image: url('/images/kittens.jpg');
}
// Nope
.foo {
background-image: url(/images/kittens.jpg);
}
// Yep
.foo
background-image: url('/images/kittens.jpg')
// Nope
.foo
background-image: url(/images/kittens.jpg)
Αριθμοί
Στη Sass, ο αριθμός (number) είναι ένας τύπος δεδομένων που περιλαμβάνει τα πάντα, από αριθμούς χωρίς μονάδες μέχρι μήκη, διάρκειες, συχνότητες, γωνίες κτλ. Αυτό επιτρέπει να γίνονται υπολογισμοί σε αυτά τα μέτρα.
Μηδενικά
Οι αριθμοί θα πρέπει να εμφανίζονται με μηδενικά πριν από μια δεκαδική τιμή μικρότερη της μονάδας. Ποτέ μην εμφανίζεις μηδενικά στο τέλος ενός δεκαδικού.
// Yep
.foo {
padding: 2em;
opacity: 0.5;
}
// Nope
.foo {
padding: 2.0em;
opacity: .5;
}
// Yep
.foo
padding: 2em
opacity: 0.5
// Nope
.foo
padding: 2.0em
opacity: .5
Στο Sublime Text και σε άλλους editors που παρέχουν αναζήτηση και αντικατάσταση με regular expressions, είναι πολύ εύκολο να προσθέσουμε ένα μηδενικό στους (περισσότερους, αν όχι όλους) αριθμούς κινητής υποδιαστολής. Απλά αντικατάστησε το \s+\.(\d+)
με \ 0.$1
. Μην ξεχάσεις όμως το κενό πριν το 0
.
Μονάδες
Όταν έχουμε να κάνουμε με μήκη, μια τιμή 0
δεν πρέπει ποτέ μα ποτέ να έχει μονάδα.
// Yep
$length: 0;
// Nope
$length: 0em;
// Yep
$length: 0
// Nope
$length: 0em
Προσοχή, αυτή η πρακτική πρέπει να περιορίζεται μόνο στα μήκη. Το να έχεις ένα μηδέν χωρίς μονάδα για ένα property χρόνου όπως το transition-delay
δεν επιτρέπεται. Θεωρητικά, αν ένα μηδέν χωρίς μονάδα οριστεί για διάρκεια, η δήλωση θεωρείται άκυρη και θα πρέπει να παραλειφθεί. Δεν είναι όλοι οι browsers τόσο αυστηροί, όμως μερικοί είναι. Με λίγα λόγια: απλά παράλειψε τη μονάδα στα μήκη.
Το πιο συνηθισμένο λάθος που μου έρχεται στο μυαλό όσον αφορά τους αριθμούς στη Sass, είναι το να πιστεύουμε ότι οι μονάδες είναι απλά κάποια strings που μπορούμε να προσαρτήσουμε με ασφάλεια σε έναν αριθμό. Ενώ ακούγεται σωστό, σίγουρα οι μονάδες δεν λειτουργούν κατ’ αυτόν τον τρόπο. Σκέψου τις μονάδες σαν αλγεβρικά σύμβολα. Για παράδειγμα, στον πραγματικό κόσμο, ο πολλαπλασιασμός 5 ίντσες επί 5 ίντσες μας δίνει 25 τετραγωνικές ίντσες. Η ίδια λογική εφαρμόζεται και στη Sass.
Για να προσθέσεις μια μονάδα σε έναν αριθμό, πρέπει να πολλαπλασιάσεις αυτόν τον αριθμό επί 1 μονάδα.
$value: 42;
// Yep
$length: $value * 1px;
// Nope
$length: $value + px;
$value: 42
// Yep
$length: $value * 1px
// Nope
$length: $value + px
Σημειώστε ότι το να προσθέσουμε 0 μέλη αυτής της μονάδας επίσης λειτουργεί, αλλά θα προτιμούσα να προτείνω την προαναφερθείσα μέθοδο επειδή η πρόσθεση 0 μονάδων μπορεί να μας μπερδέψει. Πράγματι, όταν προσπαθούμε να μετατρέψουμε έναν αριθμό σε μία άλλη συμβατή μονάδα, το να προσθέσουμε το 0 δεν έχει το αναμενόμενο αποτέλεσμα. Μπορείτε να διαβάσετε περισσότερα για αυτό το θέμα σε αυτό το άρθρο.
$value: 42 + 0px;
// -> 42px
$value: 1in + 0px;
// -> 1in
$value: 0px + 1in;
// -> 96px
$value: 42 + 0px
// -> 42px
$value: 1in + 0px
// -> 1in
$value: 0px + 1in
// -> 96px
Τελικά, στην πραγματικότητα εξαρτάται από το τι προσπαθείς να πετύχεις. Θυμήσου ότι το να προσθέσουμε τη μονάδα σαν string δεν είναι καλός τρόπος για να προχωρήσουμε.
Για να αφαιρέσεις τη μονάδα από μια τιμή, πρέπει να τη διαιρέσεις με μια μονάδα του είδους της.
$length: 42px;
// Yep
$value: $length / 1px;
// Nope
$value: str-slice($length + unquote(''), 1, 2);
$length: 42px
// Yep
$value: $length / 1px
// Nope
$value: str-slice($length + unquote(''), 1, 2)
Η προσάρτηση μιας μονάδας σαν string σε έναν αριθμό έχει σαν αποτέλεσμα string, που εμποδίζει περαιτέρω πράξεις σε αυτήν την τιμή. Ο διαχωρισμός του αριθμητικού μέρους ενός αριθμού με μια μονάδα επίσης έχει σαν αποτέλεσμα string. Αυτό είναι κάτι που δεν θέλεις. Use lengths, not strings.
Υπολογισμοί
Οι αριθμητικοί υπολογισμοί υψηλότερου επιπέδου πρέπει πάντα να βρίσκονται μέσα σε παρενθέσεις. Αυτή η απαίτηση όχι μόνο βελτιώνει δραματικά την αναγνωσιμότητα, αλλά προλαμβάνει και κάποιες ακραίες περιπτώσεις υποχρεώνοντας την Sass να χρησιμοποιήσει τις τιμές των περιεχομένων των παρενθέσεων.
// Yep
.foo {
width: (100% / 3);
}
// Nope
.foo {
width: 100% / 3;
}
// Yep
.foo
width: (100% / 3)
// Nope
.foo
width: 100% / 3
Μαγικοί αριθμοί
Ο “Μαγικός αριθμός” είναι ένας όρος της παλιάς σχολής προγραμματισμού για την unnamed αριθμητική σταθερά. Βασικά, είναι απλά ένας τυχαίος αριθμός ο οποίος συμβαίνει απλά να δουλεύει (just work™) ενώ δεν συνδέεται με καμία λογική εξήγηση.
Περιττό να πω ότι οι μαγικοί αριθμοί είναι κατάρα και πρέπει να αποφεύγονται πάση θυσία. Όταν δεν καταφέρνεις να βρεις μια λογική εξήγηση γιατί ένας αριθμός λειτουργεί, πρόσθεσε ένα εκτενές σχόλιο που να εξηγεί πώς έφτασες εκεί και γιατί πιστεύεις ότι λειτουργεί. Το να παραδεχτείς ότι δεν ξέρεις για ποιο λόγο λειτουργεί κάτι, είναι πιο βοηθητικό για τον επόμενο developer από το να τον αφήσεις να καταλάβει μόνος του από το μηδέν τι συμβαίνει.
/**
* 1. Μαγικός αριθμός. Αυτή η τιμή είναι η μικρότερη που μπορούσα να βρω
* για να ευθυγραμμίσω την κορυφή του `.foo` με τον γονέα του.
* Ιδανικά, πρέπει να το διορθώσουμε κατάλληλα.
*/
.foo {
top: 0.327em; /* 1 */
}
/**
* 1. Μαγικός αριθμός. Αυτή η τιμή είναι η μικρότερη που μπορούσα να βρω
* για να ευθυγραμμίσω την κορυφή του `.foo` με τον γονέα του.
* Ιδανικά, πρέπει να το διορθώσουμε κατάλληλα.
*/
.foo
top: 0.327em /* 1 */
Πάνω στο θέμα, το CSS-Tricks έχει ένα καταπληκτικό άρθρο σχετικά με τα magic numbers στη CSS το οποίο σας ενθαρρύνω να διαβάσετε.
Χρώματα
Τα χρώματα έχουν σημαντική θέση στη CSS. Φυσικά, η Sass καταλήγει να είναι ένας πολύτιμος σύμμαχος όσον αφορά τη χρήση χρωμάτων, κυρίως προσφέροντας πολλές δυνατές συναρτήσεις.
Η Sass είναι τόσο χρήσιμη σε ό,τι έχει να κάνει με την διαχείριση χρωμάτων που έχουν εμφανιστεί διάφορα άρθρα στο internet σχετικά με αυτό ακριβώς το θέμα. Επιτρέψτε μου να σας συστήσω μερικά:
- How to Programmatically Go From One Color to Another
- Using Sass to Build Color Palettes
- Dealing with Color Schemes in Sass
Τύποι χρωμάτων
Για να κάνεις τα χρώματα όσο πιο απλά γίνεται, η συμβουλή μου είναι να τηρήσεις την ακόλουθη σειρά προτίμησης για τους τύπους χρωμάτων:
- Συμβολισμός HSL;
- Συμβολισμός RGB;
- Δεκαεξαδικός συμβολισμός (με μικρά γράμματα και συντομευμένος).
Δεν πρέπει να χρησιμοποιούνται οι λέξεις κλειδιά CSS χρωμάτων, εκτός αν πρόκεται για γρήγορα πρωτότυπα. Πράγματι, είναι αγγλικές λέξεις και μερικές από αυτές δεν περιγράφουν πολύ καλά το χρώμα που αντιπροσωπεύουν, ειδικά για κάποιους που η μητρική τους γλώσσα δεν είναι τα αγγλικά. Εκτός αυτού, οι λέξεις κλειδιά δεν είναι απόλυτα σωστές εννοιολογικά· για παράδειγμα το grey
(γκρι) είναι στην πραγματικότητα πιο σκούρο από το darkgrey
(σκούρο γκρι), και η σύγχυση μεταξύ του grey
και του gray
μπορεί να οδηγήσει σε αντιφατικές χρήσεις του χρώματος.
Ο συμβολισμός HSL είναι όχι μόνο ο πιο ευκατανόητος για το ανθρώπινο μυαλό, αλλά επίσης διευκολύνει τους συγγραφείς των stylesheet να αλλάξουν το χρώμα, επεμβαίνοντας στα hue (απόχρωση), saturation (κορεσμός), και lightness (φωτεινότητα) ξεχωριστά.
Το RGB έχει το πλεονέκτημα του να δείχνει αμέσως αν το χρώμα αποτελείται από περισσότερο μπλε, πράσινο ή κόκκινο. Συνεπώς μπορεί να είναι καλύτερο από το HSL σε ορισμένες περιπτώσεις, ειδικά όταν περιγράφουμε ένα καθαρό κόκκινο, πράσινο ή μπλε. Ωστόσο δεν είναι εύκολο να “χτίσουμε” ένα χρώμα από τα τρία μέρη.
Τέλος, το δεκαεξαδικό είναι σχεδόν ακατανόητο για το ανθρώπινο μυαλό. Χρησιμοποίησέ το μόνο σαν τελευταία λύση αν πρέπει.
// Yep
.foo {
color: hsl(0, 100%, 50%);
}
// Also yep
.foo {
color: rgb(255, 0, 0);
}
// Meh
.foo {
color: #f00;
}
// Nope
.foo {
color: #FF0000;
}
// Nope
.foo {
color: red;
}
.foo
color: hsl(0, 100%, 50%)
// Also yep
.foo
color: rgb(255, 0, 0)
// Nope
.foo
color: #f00
// Nope
.foo
color: #FF0000
// Nope
.foo
color: red
Όταν χρησιμοποιείς συμβολισμό HSL ή RGB, πάντα να προσθέτεις ένα κενό μετά το κόμμα (,
) και καθόλου κενά μεταξύ των παρενθέσεων ((
, )
) και του περιεχομένου.
// Yep
.foo {
color: rgba(0, 0, 0, 0.1);
background: hsl(300, 100%, 100%);
}
// Nope
.foo {
color: rgba(0,0,0,0.1);
background: hsl( 300, 100%, 100% );
}
// Yep
.foo
color: rgba(0, 0, 0, 0.1)
background: hsl(300, 100%, 100%)
// Nope
.foo
color: rgba(0,0,0,0.1)
background: hsl( 300, 100%, 100% )
Χρώματα και μεταβλητές
Όταν χρησιμοποιείς ένα χρώμα πάνω από μια φορά, αποθήκευσέ το σε μια μεταβλητή με όνομα που να έχει νόημα και να αντιπροσωπεύει το χρώμα.
$sass-pink: hsl(330, 50%, 60%);
$sass-pink: hsl(330, 50%, 60%)
Τώρα είσαι ελεύθερος να χρησιμοποιήσεις τη μεταβλητή όποτε θέλεις. Παρόλα αυτά, αν η χρήση είναι στενά συνδεδεμένη με ένα θέμα, θα πρότεινα να μην χρησιμοποιείται η μεταβλητή όπως είναι. Αντ’ αυτού, αποθήκευσέ το σε μια άλλη μεταβλητή με όνομα που να εξηγεί πώς θα έπρεπε να χρησιμοποιείται.
$main-theme-color: $sass-pink;
$main-theme-color: $sass-pink
Με αυτό τον τρόπο προλαμβάνουμε μια αλλαγή θέματος που να οδηγεί σε κάτι σαν το $sass-pink: blue
. Αυτό το άρθρο κάνει πολύ καλή δουλειά στο να εξηγήσει το πόσο σημαντικό είναι να δώσετε προσοχή στις μεταβλητές χρωμάτων.
Κάνοντας τα χρώματα πιο φωτεινά και πιο σκόυρα
Τόσο η συνάρτηση lighten
όσο και η darken
τροποποιούν την φωτεινότητα ενός χρώματος στο διάστημα HSL προσθέτοντας ή αφαιρώντας από τη φωτεινότητα σε αυτό το διάστημα. Βασικά, δεν είναι τίποτα παραπάνω από ψευδώνυμα για την παράμετρο $lightness
της συνάρτησης adjust-color
.
Το θέμα είναι ότι αυτές οι συναρτήσεις συχνά δεν παρέχουν το αναμενόμενο αποτέλεσμα. Από την άλλη η συνάρτηση mix
είναι ένας ωραίος τρόπος για να κάνεις πιο φωτεινό ή πιο σκούρο ένα χρώμα αναμιγνύοντάς το είτε με το white
(άσπρο) ή με το black
(μαύρο).
Το πλεονέκτημα του να χρησιμοποιείς το mix
αντί για κάποια από τις δύο προαναφερθείσες συναρτήσεις είναι ότι πηγαίνει προοδευτικά στο μαύρο (ή το άσπρο) καθώς μειώνεις το ποσοστό του χρώματος, ενώ το darken
και το lighten
υπερκαλύπτουν γρήγορα όλο το χρώμα με μαύρο ή άσπρο.
Αν δεν θέλεις να γράφεις τη συνάρτηση mix
κάθε φορά, μπορείς να δημιουργήσεις δύο εύχρηστες συναρτήσεις, την tint
και την shade
(οι οποίες είναι επίσης μέρος του Compass) για να κάνεις το ίδιο πράγμα:
/// Φώτισε ελαφρά ένα χρώμα
/// @access public
/// @param {Color} $color - χρώμα το οποίο θα επεξεργαστούμε
/// @param {Number} $percentage - το ποσοστό του `$color` το οποίο θα περιέχεται μέσα στο χρώμα που θα επιστραφεί
/// @return {Color}
@function tint($color, $percentage) {
@return mix(white, $color, $percentage);
}
/// Σκούρυνε ελαφρά ένα χρώμα
/// @access public
/// @param {Color} $color - χρώμα το οποίο θα σκουρύνει
/// @param {Number} $percentage - το ποσοστό του `$color` το οποίο θα περιέχεται μέσα στο χρώμα που θα επιστραφεί
/// @return {Color}
@function shade($color, $percentage) {
@return mix(black, $color, $percentage);
}
/// Φώτισε ελαφρά ένα χρώμα
/// @access public
/// @param {Color} $color - χρώμα το οποίο θα επεξεργαστούμε
/// @param {Number} $percentage - το ποσοστό του `$color` το οποίο θα περιέχεται μέσα στο χρώμα που θα επιστραφεί
/// @return {Color}
@function tint($color, $percentage)
@return mix($color, white, $percentage)
/// Σκούρυνε ελαφρά ένα χρώμα
/// @access public
/// @param {Color} $color - χρώμα το οποίο θα σκουρύνει
/// @param {Number} $percentage - το ποσοστό του `$color` το οποίο θα περιέχεται μέσα στο χρώμα που θα επιστραφεί
/// @return {Color}
@function shade($color, $percentage)
@return mix($color, black, $percentage)
Η συνάρτηση scale-color
είναι σχεδιασμένη έτσι ώστε να αυξομειώνει πιο ομαλά τα properties λαμβάνοντας υπόψη πόσο υψηλά η χαμηλά είναι ήδη. Παράγει αποτελέσματα που είναι το ίδιο όμορφα με τα αποτελέσματα της mix
αλλά με πιο καθαρές κλήσεις. Ωστόσο ο συντελεστής προσαύξησης δεν είναι ακριβώς ο ίδιος.
Λίστες
Οι λίστες είναι οι πίνακες της Sass. Μια λίστα είναι μια επίπεδη δομή δεδομένων (σε αντίθεση με τα maps) που έχει σαν σκοπό να αποθηκεύει τιμές οποιουδήποτε τύπου (ακόμη και λίστες, που μας οδηγεί σε εμφωλευμένες λίστες).
Οι λίστες πρέπει να ακολουθούν τα εξής guidelines:
- είτε σε μία σειρά, ή σε πολλές·
- αναγκαστικά σε πολλές σειρές αν δεν χωράνε σε γραμμή 80 χαρακτήρων·
- αν δεν χρησιμοποιούνται αυτούσιες για σκοπούς CSS, πάντα να διαχωρίζονται με κόμμα·
- πάντα να περικλείονται από παρενθέσεις·
- να έχουν κόμμα στο τέλος της γραμμής αν επεκτείνονται σε πολλές σειρές, να μην έχουν αν είναι στην ίδια σειρά.
// Yep
$font-stack: ('Helvetica', 'Arial', sans-serif);
// Yep
$font-stack: (
'Helvetica',
'Arial',
sans-serif,
);
// Nope
$font-stack: 'Helvetica' 'Arial' sans-serif;
// Nope
$font-stack: 'Helvetica', 'Arial', sans-serif;
// Nope
$font-stack: ('Helvetica', 'Arial', sans-serif,);
// Yep
$font-stack: ('Helvetica', 'Arial', sans-serif)
// Nope (not supported)
$font-stack: (
'Helvetica',
'Arial',
sans-serif,
)
// Nope
$font-stack: 'Helvetica' 'Arial' sans-serif
// Nope
$font-stack: 'Helvetica', 'Arial', sans-serif
// Nope
$font-stack: ('Helvetica', 'Arial', sans-serif,)
Όταν προσθέτεις νέα αντικείμενα σε μια λίστα, να χρησιμοποιείς πάντα το παρεχόμενο API. Μην δοκιμάζεις να προσθέσεις νέα αντικείμενα χειροκίνητα.
$shadows: (0 42px 13.37px hotpink);
// Yep
$shadows: append($shadows, $shadow, comma);
// Nope
$shadows: $shadows, $shadow;
$shadows: (0 42px 13.37px hotpink)
// Yep
$shadows: append($shadows, $shadow, comma)
// Nope
$shadows: $shadows, $shadow
Σε αυτό το άρθρο, σας προσφέρω αρκετές συμβουλές και κόλπα για το πώς να διαχειριστείτε σωστά lists στη Sass.
Maps
Με την Sass 3.3, οι συγγραφείς των stylesheet μπορούν να ορίσουν maps — τον όρο στη Sass για τους #fixme σχετιστικούς πίνακες, τα hash ή ακόμη και τα αντικείμενα Javascript. Το map είναι μια δομή δεδομένων που αντιστοιχίζει κλειδιά με τιμές. Και τα κλειδιά αλλά και οι τιμές μπορούν να είναι οποιουδήποτε τύπου δεδομένων, ακόμη και maps, αν και δεν θα συνιστούσα τη χρήση σύνθετων τύπων δεδομένων σαν κλειδιά ενός map, ας είμαστε λίγο λογικοί.
Τα maps πρέπει να είναι γραμμένα ως εξής:
- κενό μετά την άνω και κάτω τελεία (
:
)· - άνοιγμα παρένθεσης (
(
) στην ίδια γραμμή με την άνω και κάτω τελεία· - κλειδιά σε εισαγωγικά αν είναι strings (που αναπαριστά το 99% των περιπτώσεων)·
- κάθε ζευγάρι κλειδιού/τιμής μόνο του σε νέα σειρά·
- κόμμα (
,
) στο τέλος κάθε κλειδιού/τιμής· - κόμμα στο τέλος της σειράς (
,
) του τελευταίου αντικειμένου για να να είναι πιο εύκολο να προσθέσεις, να αφαιρέσεις ή να ανακατατάξεις τα αντικείμενα· - κλείσιμο παρένθεσης (
,
) σε νέα, δική της γραμμή· - όχι κενό ή νέα γραμμή μεταξύ της τελευταίας παρένθεσης (
)
) και του semi-colon (;
).
Παράδειγμα:
// Yep
$breakpoints: (
'small': 767px,
'medium': 992px,
'large': 1200px,
);
// Nope
$breakpoints: ( small: 767px, medium: 992px, large: 1200px );
// Yep
$breakpoints: ('small': 767px, 'medium': 992px, 'large': 1200px,)
// Nope
$breakpoints: ( 'small': 767px, 'medium': 992px, 'large': 1200px )
// Nope
$breakpoints: (small: 767px, medium: 992px, large: 1200px,)
// Nope (since it is not supported)
$breakpoints: (
'small': 767px,
'medium': 992px,
'large': 1200px,
)
Τα αρθρα σχετικά με τα Sass maps είναι πολλά και προδίδουν πόσο πολυπόθητο ήταν αυτό το χαρακτηριστικό. Εδώ είναι 3 άρθρα που σας συστήνω να διαβάσετε: Using Sass Maps, Extra Map functions in Sass, Real Sass, Real Maps.
Σετ κανόνων CSS
Σε αυτό το σημείο, αυτό είναι πάνω κάτω μια επανάληψη όσων γνωρίζουν όλοι, αλλά ορίστε πώς πρέπει να γράφεται ένα σετ κανόνων CSS (τουλάχιστον σύμφωνα με τα περισσότερα guidelines, συμπεριλαμβανομένων και των CSS Guidelines):
- σχετικοί selectors στην ίδια γραμμή· άσχετοι selectors σε νέες γραμμές·
- η αγκύλη που ανοίγει τις δηλώσεις (
{
) να χωρίζεται από τον τελευταίο selector με ένα κενό· - κάθε δήλωση να είναι σε νέα, δική της γραμμή·
- ένα κενό μετά την άνω και κάτω τελεία (
:
)· - ένα semi-colon (
;
) στο τέλος όλων των δηλώσεων· - η αγκύλη που κλείνει τις δηλώσεις (
}
) να είναι σε νέα, δική της γραμμή· - μία νέα γραμμή μετά την τελευταία αγκύλη
}
.
Παράδειγμα:
// Yep
.foo, .foo-bar,
.baz {
display: block;
overflow: hidden;
margin: 0 auto;
}
// Nope
.foo,
.foo-bar, .baz {
display: block;
overflow: hidden;
margin: 0 auto }
// Yep
.foo, .foo-bar,
.baz
display: block
overflow: hidden
margin: 0 auto
// Nope
.foo,
.foo-bar, .baz
display: block
overflow: hidden
margin: 0 auto
Επιπρόσθετα με αυτά τα guidelines που είναι σχετικά με CSS, θέλουμε να δώσουμε προσοχή και στα παρακάτω:
- τοπικές μεταβλητές που δηλώνονται πριν από όλες τις δηλώσεις, και χωρίζονται από τις δηλώσεις με μια νέα γραμμή·
- κλήσεις σε mixin που δεν έχουν
@content
και εμφανίζονται πριν από όλες τις δηλώσεις· - στους εμφωλευμένους selectors που εμφανίζονται πάντα μετά από νέα γραμμή·
- κλήσεις σε mixin που έχουν
@content
και εμφανίζονται μετά από εμφωλευμένο selector· - όχι νέα γραμμή πριν την τελευταία αγκύλη (
}
).
Παράδειγμα:
.foo, .foo-bar,
.baz {
$length: 42em;
@include ellipsis;
@include size($length);
display: block;
overflow: hidden;
margin: 0 auto;
&:hover {
color: red;
}
@include respond-to('small') {
overflow: visible;
}
}
.foo, .foo-bar,
.baz
$length: 42em
+ellipsis
+size($length)
display: block
overflow: hidden
margin: 0 auto
&:hover
color: red
+respond-to('small')
overflow: visible
Ταξινόμηση των δηλώσεων
Δεν μπορώ να σκεφτώ πολλά θέματα όπου οι απόψεις διίστανται τόσο όσο αυτές που αφορούν την ταξινόμηση των δηλώσεων στη CSS. Συγκεκριμένα, υπάρχουν δύο παρατάξεις εδώ:
- παραμονή στην αλβαφητική ταξινόμηση·
- ταξινόμηση δηλώσεων κατά τύπο (position, display, colors, font, διάφορα…).
Υπάρχουν πλεονεκτήματα και μειονεκτήματα και στους δύο τρόπους. Από τη μία, η αλφαβητική ταξινόμηση είναι καθολική (τουλάχιστον για τις γλώσσες που χρησιμοποιούν το λατινικό αλφάβητο) και έτσι δεν υπάρχει επιχείρημα για την ταξινόμηση ενός property πριν από ένα άλλο. Παρόλα αυτά μου φαίνεται εξαιρετικά περίεργο να βλέπω properties όπως τα bottom
και top
να μην είναι ακριβώς δίπλα το ένα στο άλλο. Γιατί θα ‘πρεπε τα animations να εμφανίζονται πριν το display type; Υπάρχουν πολλές παραξενιές με την αλφαβητική ταξινόμηση.
.foo {
background: black;
bottom: 0;
color: white;
font-weight: bold;
font-size: 1.5em;
height: 100px;
overflow: hidden;
position: absolute;
right: 0;
width: 100px;
}
.foo
background: black
bottom: 0
color: white
font-weight: bold
font-size: 1.5em
height: 100px
overflow: hidden
position: absolute
right: 0
width: 100px
Από την άλλη, η ταξινόμηση των properties κατά τύπο βγάζει πολύ νόημα. Όλες οι δηλώσεις σχετικές με fonts είναι συγκεντρωμένες, τα top
και bottom
επανενώνονται και το διάβασμα ενός ruleset μοιάζει κάπως με το διάβασμα μιας μικρής ιστορίας. Αλλά εκτός αν παραμείνεις σε ορισμένες συμβάσεις όπως το Idiomatic CSS, υπάρχουν πολλά περιθώρια ερμηνείας σε αυτό τον τρόπο δράσης. Πού θα πήγαινε το white-space
: στο font ή στο display; Πού ακριβώς ανήκει το overflow
; Ποια είναι η σειρά των properties μέσα σε ένα γκρουπ (θα μπορούσε να είναι αλφαβητική, τι ειρωνία);
.foo {
height: 100px;
width: 100px;
overflow: hidden;
position: absolute;
bottom: 0;
right: 0;
background: black;
color: white;
font-weight: bold;
font-size: 1.5em;
}
.foo
height: 100px
width: 100px
overflow: hidden
position: absolute
bottom: 0
right: 0
background: black
color: white
font-weight: bold
font-size: 1.5em
Υπάρχει επίσης ακόμη ένα ενδιαφέρον υποδένδρο ταξινόμησης κατά τύπο που λέγεται Ομόκεντρη (Concentric) CSS και φαίνεται να είναι επίσης αρκετά δημοφιλές. Βασικά, η Ομόκεντρη CSS βασίζεται στο box-model για να για να ορίσει μια σειρά: ξεκινάει από έξω και προχωράει προς τα μέσα.
.foo {
width: 100px;
height: 100px;
position: absolute;
right: 0;
bottom: 0;
background: black;
overflow: hidden;
color: white;
font-weight: bold;
font-size: 1.5em;
}
.foo
width: 100px
height: 100px
position: absolute
right: 0
bottom: 0
background: black
overflow: hidden
color: white
font-weight: bold
font-size: 1.5em
Πρέπει να πω ότι ούτε εγώ δεν μπορώ να αποφασίσω. Μία πρόσφατη δημοσκόπηση στο CSS-Tricks είχε ως αποτέλεσμα ότι πάνω από το 45% των developers ταξινομεί τις δηλώσεις κατά τύπο ενώ το 14% ταξινομεί αλφαβητικά. Ακόμη, υπάρχει κι ένα 39% που τις ταξινομεί τελείως τυχαία, συμπεριλαμβανομένου και εμού.
Εξαιτίας αυτού, δεν θα επιβάλω κάποια επιλογή σε αυτό το styleguide. Διάλεξε όποια προτιμάς, αρκεί να είσαι σταθερός σε όλα τα stylesheets σου (πχ. όχι την τυχαία επιλογή).
Μια πρόσφατη έρευνα έδειξε ότι η χρήση του CSS Comb (το οποίο χρησιμοποιεί ταξινόμηση κατά τύπο) για την ταξινόμηση των δηλώσεων CSS, καταλήγει στη μείωση του μέσου μεγέθους του αρχείου με συμπίεση Gzip κατά 2.7%, έναντι του 1.3% της ταξινόμησης με αλφαβητική σειρά.
Εμφώλευση Selectors
Ένα συγκεκριμένο χαρακτηριστικό που προσφέρει η Sass στο οποίο γίνεται υπερβολική κατάχρηση από τους developers είναι η εμφώλευση των selectors. Η εμφώλευση των selectors προσφέρει έναν τρόπο στους συγγραφείς stylesheet για να υπολογίσουν τους μεγάλους selectors εμφωλεύοντας μικρούς selectors μέσα σε άλλους.
Γενικός κανόνας
Για παράδειγμα, η ακόλουθη εμφώλευση Sass:
.foo {
.bar {
&:hover {
color: red;
}
}
}
.foo
.bar
&:hover
color: red
… παράγει αυτή τη CSS:
.foo .bar:hover {
color: red;
}
Παρομοίως, από την Sass 3.3 και μετά είναι δυνατόν να χρησιμοποιήσεις την αναφορά στον τρέχοντα selector (&
) για να παράγεις εξειδικευμένους selectors. Για παράδειγμα:
.foo {
&-bar {
color: red;
}
}
.foo
&-bar
color: red
… παράγει αυτή τη CSS:
.foo-bar {
color: red;
}
.foo-bar
color: red
Αυτή η μέθοδος χρησιμοποιείται συχνά μαζί με τις Συνθήκες ονομασίας BEM για να παράγει selectors .block__element
και .block--modifier
βασισμένους στον αρχικό selector (πχ. .block
σε αυτή την περίπτωση).
Μπορεί να είναι ανεπίσημο, αλλά η παραγωγή νέων selectors με αναφορά στον τρέχοντα selector (&
) καθιστά αδύνατη την αναζήτηση αυτών των selectors στην codebase αφού δεν υπάρχουν καθ’ εαυτοί.
Το πρόβλημα με την εμφώλευση των selectors είναι ότι τελικά κάνει τον κώδικα πιο δύσκολο στην ανάγνωση. Πρέπει κανείς να υπολογίσει νοητά τον selector που παράγεται από τα επίπεδα εμφώλευσης· δεν είναι πάντα αρκετά εμφανές τι θα καταλήξει να είναι η CSS.
Αυτή η δήλωση αληθεύει όλο και περισσότερο όσο οι selectors γίνονται μακρύτεροι και οι αναφορές στον τρέχοντα selector (&
) όλο και συχνότερες. Σε ένα σημείο, ο κίνδυνος να μην μπορείς να παρακολουθήσεις και να μην καταλαβαίνεις πια τι συμβαίνει είναι τόσο υψηλός που δεν αξίζει τον κόπο.
Για να αποφύγουμε μια τέτοια κατάσταση, αποφεύγουμε την εμφώλευση των selectors όσο το δυνατόν περισσότερο. Παρόλα αυτά, προφανώς υπάρχουν μερικές εξαιρέσεις σε αυτόν τον κανόνα.
Για να αποφύγουμε μια τέτοια κατάσταση, συνηθίζαμε να μιλάμε για το Inception rule πριν απο μερικά χρόνια. Αυτό συμβούλευε κατά της εμφώλευσης πέραν των 3 επιπέδων, έχοντας ως σημείο αναφοράς την ταινία Inception του Christopher Nolan. Θα ήθελα να γίνω λίγο πιο δραστικός και να προτείνω την αποφυγή εμφωλευμένων selectors όσο το δυνατόν περισσότερο.
Ενώ υπάρχουν πολλές προφανείς εξαιρέσεις στον κανόνα όπως θα δούμε στο επόμενο τμήμα, αυτή η άποψη φαίνεται να είναι αρκετά δημοφιλής. Μπορείτε να διαβάσετε γι’ αυτό με περισσότερες λεπτομέρειες στο Beware of Selector Nesting και στο Avoid nested selectors for more modular CSS.
Εξαιρέσεις
Για αρχή, επιτρέπεται και ακόμη προτείνεται να εμφωλεύετε τα pseudo-classes και pseudo-elements μέσα στον αρχικό selector.
.foo {
color: red;
&:hover {
color: green;
}
&::before {
content: 'pseudo-element';
}
}
.foo
color: red
&:hover
color: green
&::before
content: 'pseudo-element'
Η χρήση εμφώλευσης των selectors για pseudo-classes και pseudo-elements όχι μόνο βγάζει νόημα (επειδή έχει να κάνει με στενά συνδεδεμένους selectors), αλλά και επειδή βοηθάει στο να κρατήσετε τα πάντα σχετικά με ένα component στο ίδιο σημείο.
Ακόμη, όταν χρησιμοποιείς classes κατάστασης όπως το .is-active
που δεν έχουν να κάνουν με ένα μόνο component, είναι απολύτως εντάξει να το εμφωλεύσετε κάτω από τον selector του component για να κρατήσετε τα πράγματα τακτοποιημένα.
.foo {
// …
&.is-active {
font-weight: bold;
}
}
.foo
// …
&.is-active
font-weight: bold
Τελευταίο αλλά εξίσου σημαντικό, όταν γράφετε τα styles για ένα element επειδή τυχαίνει να εμπεριέχεται σε ένα άλλο συγκεκριμένο element, είναι επίσης εντάξει να χρησιμοποιήσετε εμφώλευση για να κρατήσετε τα πάντα σχετικά με αυτό το component στο ίδιο σημείο.
.foo {
// …
.no-opacity & {
display: none;
}
}
.foo
// …
.no-opacity &
display: none
Όπως με όλα, οι λεπτομέρειες είναι κάπως άσχετες, η συνέπεια είναι το κλειδί. Αν αισθάνεστε εντελώς σίγουροι για την εμφώλευση των selectors, τότε χρησιμοποιήστέ την. Απλά σιγουρευτείτε ότι όλη σου η ομάδα είναι εντάξει με αυτό.
Αν εκτίμησες τα Sass Guidelines, στήριξε την προσπάθεια.
Υποστηρίξτε το Sass GuidelinesΣυμβάσεις ονομασίας
Σ’ αυτήν την ενότητα δε θα ασχοληθούμε με τις καλύτερες συμβάσεις ονομασίας στη CSS για συντηρησιμότητα (maintainability) και κλιμάκωση (scale); όχι μόνο γιατί είναι στην κρίση σου, αλλά είναι εκτός του πεδιού εφαρμογής ενός Sass styleguide. Προτείνω αυτά που συνιστώνται στα CSS Guidelines.
Υπάρχουν κάποια πράγματα που μπορείς να ονομάσεις στη Sass, και είναι σημαντικό να τα ονομάσεις σωστά ώστε όλος ο κώδικας να φαίνεται τόσο συνεπής όσο και ευανάγνωστος:
- μεταβλητές·
- συναρτήσεις·
- mixins.
Οι Sass placeholders παραλείπονται σκόπιμα από αυτή τη λίστα αφού μπορούν να θεωρηθούν κανονικοί CSS selectors, εκ τούτου ακολουθούν το ίδιο μοτίβο ονοματοδοσίας όπως οι κλάσεις.
Όσον αφορά τις μεταβλητές, τις συναρτήσεις και τα mixins, τηρούμε κάτι πολύ CSS-ικό: πεζά με-παύλες, και κυρίως να βγάζουν νόημα.
$vertical-rhythm-baseline: 1.5rem;
@mixin size($width, $height: $width) {
// …
}
@function opposite-direction($direction) {
// …
}
$vertical-rhythm-baseline: 1.5rem
=size($width, $height: $width)
// …
@function opposite-direction($direction)
// …
Αν πραγματικά θέλετε να παίξετε με τις ιδέες των σταθερών στη Sass, θα πρέπει να διαβάσετε αυτό το ειδικό άρθρο.
Σταθερές
Αν τυγχάνει να είσαι framework developer ή συγγραφέας μιας βιβλιοθήκης, ενδέχεται να αντιμετωπίσεις κάποιες μεταβλητές που δεν πρέπει να αλλάξουν σε καμία περίπτωση: οι σταθερές. Δυστυχώς (ή ευτυχώς;), η Sass δεν παρέχει κάποιον τρόπο για να ορίσουμε τέτοιες οντότητες, οπότε πρέπει να τηρήσουμε αυστηρές συμβάσεις όσον αφορά την ονομασία για να τις επισημάνουμε.
Όπως σε πολλές γλώσσες, προτείνω μεταβλητές με κεφαλαία και κάτω παύλες όταν είναι σταθερές. Όχι μόνο είναι μία πολύ παλιά σύμβαση, αλλά δημιουργεί καλή αντίθεση με τις μεταβλητές που είναι με πεζά και παύλες.
// Yep
$CSS_POSITIONS: (top, right, bottom, left, center);
// Nope
$css-positions: (top, right, bottom, left, center);
// Yep
$CSS_POSITIONS: (top, right, bottom, left, center)
// Nope
$css-positions: (top, right, bottom, left, center)
Περαιτέρω ανάγνωση:
Namespace
Αν σκοπεύεις να διανείμεις τον κώδικά σου, στην περίπτωση μιας βιβλιοθήκης, ενός framework, ενός grid system ή οτιδήποτε, μπορεί να θες να εξετάσεις το ενδεχόμενο να χρησιμοποιήσεις ένα namespace για όλες τις μεταβλητές, τις συναρτήσεις, τα mixins και τους placeholders ώστε να μην συγκρουστούν με τον κώδικα αλλωνών.
Για παράδειγμα, αν δουλεύεις σε ένα project που λέγεται Sassy Unicorn που προορίζεται να είναι κατανεμημένο, θα μπορούσες να χρησιμοποιήσεις το su-
ως namespace. Είναι αρκετά συγκεκριμένο ώστε να αποκλειστεί οποιαδήποτε σύγκρουση ονομάτων και αρκετά σύντομο ώστε να μην είναι κουραστικό να το γράφεις.
$su-configuration: ( … );
@function su-rainbow($unicorn) {
// …
}
$su-configuration: ( … )
@function su-rainbow($unicorn)
// …
Το Kaelig έχει ένα πολύ διορατικό άρθρο σχετικά με το global CSS namespace, σε περίπτωση που αυτό το θέμα σας ενδιαφέρει.
Σημείωσε ότι το αυτόματο namespacing είναι οπωσδήποτε ένας σχεδιαστικός στόχος για την ανερχόμενη ανανέωση του @import
στη Sass 4.0. Δεδομένου ότι πλησιάζουμε στην κυκλοφορία, θα γίνεται όλο και λιγότερο χρήσιμο το χειροκίνητο namespacing· ενδεχομένως οι βιβλιοθήκες με μη αυτόματο namespacing να είναι δυσκολότερες στη χρήση.
Αρχιτεκτονική
Η δόμηση ενός CSS project είναι ίσως ένα απο τα δυσκολότερα πράγματα που θα κάνετε κατα την διαρκεια ζωής του project. Το να συντηρήσετε την δόμηση αυτή συνεπή και ουσιώδης είναι ακόμα δυσκολότερο.
Ευτυχώς, ένα απο τα βασικά πλεονεκτήματα της χρήσης ενός CSS preprocessor είναι η παροχή της δυνατότητας τμηματοποίησης του κώδικα σε πολλά αρχεία χωρίς να επηρεάζεται η απόδοση του (όπως με το @import
CSS directive). Λόγο της υπερφόρτωσης που κάνει η Sass στο @import
directive, είναι απολύτως ασφαλή (και συνιστάται ανεπιφύλακτα) η χρήση όσο αρχείων χρειάζεται κατα την διάρκεια της ανάπτυξης, αφού όλα τα αρχεία θα συγκεντρωθούν σε ένα αρχείο CSS σε production περιβάλλον.
Πέρα από αυτό, δεν μπορώ να τονίσω αρκετά την ανάγκη για χρήση φακέλων, ακόμα και σε μικρά projects. Στο σπίτι, δεν πετάς όλα τα χαρτιά στο ίδιο κουτί. Χρησιμοποιείς φακέλους, εναν για το σπίτι/διαμέρισμα, έναν για την τράπεζα, έναν για τους λογαριασμούς και τα λοιπά. Δεν υπάρχει λόγος να γίνει διαφορετικά και για την δόμηση του CSS project σας. Διαχωρίστε τον κώδικα σε διαφορετικούς φακέλους, ονομασμένους λογικά, έτσι ώστε αργότερα να σας είναι εύκολο να βρείτε αυτό που ψάχνετε εύκολα και γρήγορα.
Υπάρχουν πολλές δημοφιλείς αρχιτεκτονικές για CSS project(s) όπως: OOCSS, Atomic Design, projects βασισμένα σε Bootstrap ή σε Foundation… Τα οποία έχουν πλεονεκτήματα και μειονεκτήματα.
Εγώ, προσωπικά, χρησιμοποιώ μια προσέγγιση που μοιάζει πολύ με αυτή του SMACSS του Jonathan Snook, η οποία επικεντρώνεται στην διατήρηση της κατάστασης όσο πιο απλής και φανερής γίνεται.
Έχω μάθει πως η δόμηση του κώδικα τις περισσότερες φορές αλλάζει ανάλογα με το project. Μη διστάσετε να απορρίψετε εντελώς ή να προσαρμόσετε την προτεινόμενη λύση έτσι ώστε να φτάσετε σε ένα αποτέλεσμα που θα ταιριάζει στις ανάγκες σας.
Components
Υπάρχει μια τεράστια διαφορά μεταξύ του να κάνεις κάτι να δουλεύει και να κάνει κάτι καλά. Πάλι, η CSS είναι πολύ «ακατάστατη» γλώσσα [citation needed]. Όσο λιγότερη CSS έχουμε, τόσο το καλύτερο. Δεν θέλουμε να αντιμετωπίσουμε καταστάσεις στις οποίες θα έχουμε megabytes απο κώδικα CSS. Για να κρατήσουμε τα stylesheets μικρά και αποδοτικά — και προφανώς δεν θα σας ξαφνιάσει — είναι καλό να σκεφτόμαστε το interface ως μια συλλογή απο components.
Τα Components μπορεί να είναι οτιδήποτε, αρκεί:
- να κάνουν μόνο ένα πράγμα·
- να είναι επαναχρησιμοποιήσιμα και να επαναχρησιμοποιούνται μέσα στο project·
- να είναι ανεξάρτητα.
Για παράδειγμα, μια φόρμα αναζήτησης θα πρέπει να θεωρείται ως ένα component. Πρέπει να είναι επαναχρησιμοποιήσιμο, σε διαφορετικές τοποθεσίες, σε διαφορετικές σελίδες, σε διαφορετικές καταστάσεις. Δεν πρέπει να εξαρτάται απο την θέση του στο DOM (footer, sidebar, κύριο περιεχόμενο…).
Σχεδόν όλα τα interface μπορούμε να τα θεωρήσουμε ως components και είναι αυτό που σας συνιστώ. Αυτό θα μικρύνει κατά πολύ την ποσότητα CSS κώδικα που χρειάζεται το project, αλλά τυγχάνει επίσης να είναι και ευκολότερο στην συντήρηση από ένα χάος όπου όλα είναι ακατάστατα.
Δομή Component
Ιδανικά, τα components πρέπει να βρίσκονται μέσα σε δικά τους Sass partial (μέσα στον φάκελο components/
, όπως περιγράφεται στο 7-1 pattern), π.χ. components/_button.scss
. Τα styles που περιγράφονται μέσα σε κάθε αρχείο component πρέπει να έχουν να κάνουν μόνο με:
- Το style του ίδιου του component·
- Το style παραλλαγών, τροποποιητών ή/και καταστάσεων του component·
- Τα styles των απογόνων του component (λ.χ. children), εάν είναι απαραίτητο.
Αν θέλετε τα components σας να παίρνουν το θέμα τους απο εξωτερικούς παράγοντες (π.χ. απο ένα θέμα μέσα στο φάκελο themes/
), περιορίστε τις δηλώσεις σας σε δομικά styles, όπως είναι οι διαστάσεις (width/height), padding, margins, alignment, και τα λοιπά. Αποκλείστε styles όπως τα χρώματα, σκιές, font rules, background rules, και τα λοιπά.
Ένα component partial μπορεί να περιέχει παραλλαγές σχετικές με το component, placeholders, ακόμα και mixins ή functions. Κρατήστε στο μυαλό σας, όμως, ότι πρέπει να αποφύγετε το referencing (π.χ. να κάνετε @import
) component αρχεία μέσα απο άλλα αρχεία component, γιατί αυτό μπορεί να κάνει το dependency graph του project σας αδύνατο να συντηρηθεί.
Εδώ είναι ένα παράδειγμα component partial ενός button:
// Button-specific variables
$button-color: $secondary-color;
// … include any button-specific:
// - mixins
// - placeholders
// - functions
/**
* Buttons
*/
.button {
@include vertical-rhythm;
display: block;
padding: 1rem;
color: $button-color;
// … etc.
/**
* Inlined buttons on large screens
*/
@include respond-to('medium') {
display: inline-block;
}
}
/**
* Icons within buttons
*/
.button > svg {
fill: currentcolor;
// … etc.
}
/**
* Inline button
*/
.button--inline {
display: inline-block;
}
// Button-specific variables
$button-color: $secondary-color
// ... include any button-specific:
// - mixins
// - placeholders
// - functions
/**
* Buttons
*/
.button
+vertical-rhythm
display: block
padding: 1rem
color: $button-color
// ... etc.
/**
* Inlined buttons on large screens
*/
+respond-to('medium')
display: inline-block
}
/**
* Icons within buttons
*/
.button > svg
fill: currentcolor
// ... etc.
/**
* Inline button
*/
.button--inline
display: inline-block
Ευχαριστώ τον David Khourshid για τη βοήθεια και την εμπειρογνωμοσύνη που προσέφερε σε αυτό το τμήμα.
Το 7-1 pattern
Επιστρέφουμε στην αρχιτεκτονική. Συνηθίζω να ακολουθώ το 7-1 pattern: 7 φακέλους, 1 αρχείο. Ουσιαστικά, έχεις όλα τα partials μέσα σε 7 διαφορετικούς φακέλους, και ένα αρχείο στο πρώτο επίπεδο (συνήθως με την ονομασία main.scss
) το οποίο κάνει import όλα τα άλλα για να τα κάνει compile σε ένα CSS stylesheet.
base/
components/
layout/
pages/
themes/
abstracts/
vendors/
Και φυσικά:
main.scss
Αν σας ενδιαφέρει να χρησιμοποιήσετε το 7-1 pattern, υπάρχει ήδη το boilerplate έτοιμο στο GitHub. Πρέπει να περιέχει όλα όσα χρειάζεστε για να ξεκινήσετε με αυτή την αρχιτεκτονική.
Ιδανικά, μπορούμε να καταλήξουμε σε κάτι σαν αυτό:
sass/
|
|– abstracts/
| |– _variables.scss # Μεταβλητές Sass
| |– _functions.scss # Συναρτήσεις Sass
| |– _mixins.scss # Sass Mixins
| |– _placeholders.scss # Sass placeholders
|
|– base/
| |– _reset.scss # Reset/normalize
| |– _typography.scss # Κανόνες τυπογραφίας
| … # Κλπ.
|
|– components/
| |– _buttons.scss # Κουμπιά
| |– _carousel.scss # Carousel
| |– _cover.scss # Cover
| |– _dropdown.scss # Dropdown
| … # Κλπ.
|
|– layout/
| |– _navigation.scss # Μενού πλοήγησης
| |– _grid.scss # Πλέγμα
| |– _header.scss # Header
| |– _footer.scss # Footer
| |– _sidebar.scss # Sidebar
| |– _forms.scss # Φόρμες
| … # Κλπ.
|
|– pages/
| |– _home.scss # Styles αρχικής σελίδας
| |– _contact.scss # Styles φόρμας επικοινωνίας
| … # Κλπ.
|
|– themes/
| |– _theme.scss # Κύριο theme
| |– _admin.scss # Διαχειριστικό theme
| … # Κλπ.
|
|– vendors/
| |– _bootstrap.scss # Bootstrap
| |– _jquery-ui.scss # jQuery UI
| … # Κλπ.
|
`– main.scss # Κύριο αρχείο Sass
Τα αρχεία ακολουθούν την ίδια ονοματική σύμβαση που περιγράψαμε παραπάνω: είναι οριοθετημένα με κάτω παύλα.
Φάκελος Base
O φάκελος base/
περιέχει αυτό που αποκαλούμε κώδικα boilerplate για το project. Εκεί μπορεί να βρεθεί το reset αρχείο, κάποια τυπογραφικά rules, και πιθανότητα ένα stylesheet (το οποίο συνηθίζω να αποκαλώ _base.scss
), στο οποίο ορίζω διάφορα standard στύλ για HTML elements που χρησιμοποιούνται συνήθως.
_base.scss
_reset.scss
_typography.scss
Αν το project σας χρησιμοποιεί πολλά CSS animations, ίσως πρέπει να σκεφτείτε την προσθήκη του αρχείου \_animations.scss
μέσα το οποίο θα περιέχει τους @keyframes
ορισμούς απο όλα τα animations σας. Εάν τα χρησιμοποιείτε περιστασιακά, αφήστε τα να βρίσκονται μαζί τους selectors που τα χρησιμοποιούν.
Φάκελος Layout
Ο φάκελος layout/
περιέχει όλα όσα έχουν να κάνουν με την δομή του site ή την εφαρμογής. Αυτός ο φάκελος μπορεί να περιέχει stylesheets για τα βασικά κομμάτια του site (header, footer, navigation, sidebar…), το grid system ή ακόμα και CSS styles για όλα τα forms.
_grid.scss
_header.scss
_footer.scss
_sidebar.scss
_forms.scss
_navigation.scss
Ο layout/
φάκελος θα μπορούσε επίσης να ονομαστεί partials/
, αναλόγως τι προτιμάτε.
Φάκελος Components
Για μικρότερα components, υπάρχει ο φάκελος components/
. Ενώ ο φάκελος layout/
είναι macro (καθορίζει το γενικό μοντέλο της σελίδας), ο φάκελος components/
είναι επικεντρωμένος στα widgets. Περιέχει modules ολών των ειδών όπως slider, loader, widget, και οτιδήποτε άλλο προς αυτή την κατεύθυνση. Συνήθως υπάρχουν πολλά αρχεία μέσα στον φάκελο components/
αφού όλο το site ή η εφαρμογή απαρτίζεται απο μικρά modules.
_media.scss
_carousel.scss
_thumbnails.scss
Ο φάκελος components/
θα μπορούσε επίσης να ονομαστεί modules/
, αναλόγος τι προτιμάται.
Φάκελος Pages
Αν έχετε στυλιστικό κώδικα μόνο για συγκεκριμένες σελίδες, είναι προτιμότερο να μπούν στον φάκελο pages/
, σε ένα αρχείο που παίρνει το ονομά του από την σελίδα. Για παράδειγμα, δεν είναι ασυνήθιστο το να έχεις στυλιστικό κώδικα για την αρχική σελίδα εξού και η ανάγκη για ένα _home.scss
αρχείο μέσα στον φάκελο pages/
.
_home.scss
_contact.scss
Ανάλογα με τη διαδικασία deployment σας, αυτά τα αρχεία θα μπορούσαν να χρησιμοποιηθούν απο μόνα τους για να να αποφευχθεί η συγχώνευσή τους στο τελικό stylesheet. Είναι πραγματικά στο χέρι σας.
Φάκελος Themes
Σε μεγάλα sites και εφαρμογές, δεν είναι ασυνήθιστο το να έχεις διαφορετικά θέματα. Υπάρχουν πάρα πολλοί τρόποι για να αντιμετώπισης το θεμα αυτό αλλά προσωπικά προτιμό να τα έχω όλα μέσα στον φάκελο themes/
.
_theme.scss
_admin.scss
Αυτό είναι πολύ συγκεκριμένο στο project και είναι πολύ σπάνιο να υπάρχει σε άλλα projects αφού τα περισσότερα μεγάλα sites και εφαρμογές έχουν διαφορετικές απαιτήσεις και αρχιτεκτονική.
Φάκελος Abstracts
Ο Φάκελος abstracts/
συγκεντρώνει όλα τα Sass tools και helpers που χρησιμοποιούνται σε όλο το project. Κάθε global μεταβλητή, συνάρτηση, mixin και placeholder πρέπει να μπει εκεί.
O γενικός κανόνας του φακέλου αυτού είναι ότι δεν πρέπει να παράγεται ούτε μια γραμμή CSS όταν γίνει compile μόνος του γιατί απλά αποτελείται από Sass helpers.
_variables.scss
_mixins.scss
_functions.scss
_placeholders.scss
Όταν δουλεύεις σε ένα πολύ μεγάλο project με πολλά αφηρημένα utilities, θα μπορούσες να τα ομαδοποιήσεις ανάλογα με το θέμα τους αντί για τον τύπο τους, για παράδειγμα τυπογραφία (_typography.scss
), theming (_theming.scss
), κτλ. Κάθε αρχείο περιέχει όλα τα σχετικά helpers: μεταβλητές, functions, mixins και placeholders. Με αυτόν τον τρόπο ο κώδικας μπορεί να γίνει πιο εύκολος στην ανάγνωση και την συντήρηση, ειδικά όταν τα αρχεία γίνονται πολύ μεγάλα.
Ο φάκελος abstracts/
θα μπορούσε επίσης να ονομαστεί utilities/
ή helpers/
, αναλόγως τι προτιμάς.
Φάκελος Vendors
Και τελευταίο αλλά εξίσου σημαντικό, τα περισσότερα projects θα έχουν έναν vendors/
φάκελο ο οποίος περιέχει όλα τα CSS αρχεία από εξωτερικές βιβλιοθήκες όπως Normalize, Bootstrap, jQueryUI, FancyCarouselSliderjQueryPowered, και ούτω καθεξής. Βάζοντας τα σε αυτόν τον φάκελο είναι ένας καλός τρόπος για να πείς “Αυτός δεν είναι δικός μου κώδικας, δεν είναι δικιά μου ευθύνη”.
_normalize.scss
_bootstrap.scss
_jquery-ui.scss
_select2.scss
Αν θέλετε να παρακάμψετε τμήμα κάποιου vendor, προτείνω να φτιάξετε έναν όγδοο φάκελο με όνομα vendors-extensions/
στο οποίο μπορείς να βάλεις αρχεία που έχουν το ίδιο όνομα με το αρχείο που θες να παρακάμψεις απο τον φάκελο vendors.
Για παράδειγμα, vendors-extensions/_boostrap.scss
είναι ένα αρχείο που περιέχει όλα τα CSS rules που αποσκοπούν στην εκ νέου δηλώση κάποιων απο τις προεπιλεγμένες του Bootstrap. Έτσι δεν χρειάζεται να να πειράξεις απευθείας τα vendor αρχεία, το οποίο γενικά δεν είναι καλή ιδέα.
Το αρχείο Main
Το αρχείο main (το οποίο συνήθως ονομάζεται main.scss
) πρέπει να είναι το μόνο Sass αρχείο απο το ολόκληρο το code base του οποίου το όνομα δεν ξεκινάει απο τον χαρακτήρα της κάτω παύλας. Το αρχείο αυτό δεν πρέπει να περιέχει τίποτα εκτός απο γραμμές @import
και σχολίων.
Τα αρχεία πρέπει να γίνονται import με βάση τον φάκελο στον οποίο βρίσκονται, το ένα μετά το άλλο με την ακόλουθη σειρά:
abstracts/
vendors/
base/
layout/
components/
pages/
themes/
Προκειμένου να διατηρηθεί η αναγνωσιμότητα, το αρχείο main θα πρέπει να ακολουθεί τις παρακάτω κατευθυντήριες γραμμές:
- ένα αρχείο ανα
@import
· - ενα
@import
ανα γραμμή· - καμία κενή γραμμή μεταξύ δύο import απο τον ίδιο φάκελο·
- μια κενή γραμμή μετά απο το τελευταίο import ενός φακέλου·
- οι επεκτάσεις των αρχείων και οι χαρακτήρες κάτω παύλας που προηγούνται πρέπει να παραλειφθούν.
@import 'abstracts/variables';
@import 'abstracts/functions';
@import 'abstracts/mixins';
@import 'abstracts/placeholders';
@import 'vendors/bootstrap';
@import 'vendors/jquery-ui';
@import 'base/reset';
@import 'base/typography';
@import 'layout/navigation';
@import 'layout/grid';
@import 'layout/header';
@import 'layout/footer';
@import 'layout/sidebar';
@import 'layout/forms';
@import 'components/buttons';
@import 'components/carousel';
@import 'components/cover';
@import 'components/dropdown';
@import 'pages/home';
@import 'pages/contact';
@import 'themes/theme';
@import 'themes/admin';
@import vendors/bootstrap
@import vendors/jquery-ui
@import utils/variables
@import utils/functions
@import utils/mixins
@import utils/placeholders
@import base/reset
@import base/typography
@import layout/navigation
@import layout/grid
@import layout/header
@import layout/footer
@import layout/sidebar
@import layout/forms
@import components/buttons
@import components/carousel
@import components/cover
@import components/dropdown
@import pages/home
@import pages/contact
@import themes/theme
@import themes/admin
Υπάρχει ακόμα ένας τρόπος για να κάνεις import partial αρχεία τον οποίο θεωρώ έγκυρο. Στη θετική πλευρά, κάνει τα αρχεία ευανάγνωστα. Απο την άλλη, τα κάνει δυσκολότερα στην ενημέρωση. Εν πάση περιπτώσει, θα αφήσω εσάς να αποφασίσετε ποια είναι η καλύτερη, δεν έχει πολύ σημασία. Για αυτόν τον τρόπο, το αρχείο main θα πρέπει να τηρεί τις ακόλουθες κατευθυντήριες γραμμές:
- ένα
@import
ανά φάκελο· - ένα linebreak ανά
@import
· - κάθε αρχεία σε δικιά του γραμμή·
- μια κενή γραμμή μετά το τελευταίο import ενός φακέλου·
- οι επεκτάσεις των αρχείων και οι χαρακτήρες κάτω παύλας που προηγούνται πρέπει να παραλειφθούν.
@import
'abstracts/variables',
'abstracts/functions',
'abstracts/mixins',
'abstracts/placeholders';
@import
'vendors/bootstrap',
'vendors/jquery-ui';
@import
'base/reset',
'base/typography';
@import
'layout/navigation',
'layout/grid',
'layout/header',
'layout/footer',
'layout/sidebar',
'layout/forms';
@import
'components/buttons',
'components/carousel',
'components/cover',
'components/dropdown';
@import
'pages/home',
'pages/contact';
@import
'themes/theme',
'themes/admin';
@import
vendors/bootstrap,
vendors/jquery-ui
@import
utils/variables,
utils/functions,
utils/mixins,
utils/placeholders
@import
base/reset,
base/typography
@import
layout/navigation,
layout/grid,
layout/header,
layout/footer,
layout/sidebar,
layout/forms
@import
components/buttons,
components/carousel,
components/cover,
components/dropdown
@import
pages/home,
pages/contact
@import
themes/theme,
themes/admin
Σχετικά με το globbing
Στον προγραμματισμό ηλεκτρονικών υπολογιστών, τα glob patterns καθορίζουν σύνολα ονομάτων αρχείων με χαρακτήρες μπαλαντέρ, όπως *.scss
. Γενικά, το globbing είναι η επιλογή ενός σύνολο αρχείων βασιζόμενη σε ένα expression αντί κάποιας λίστας ονομάτων αρχείων. Όταν εφαρμόζεται στη Sass, σημαίνει το import partial αρχείων μέσα στο αρχείο main με ένα glob pattern αντί του να τα απαριθμήσουμε μεμονωμένα. Αυτό θα έκανε το αρχείο main να μοιάζει κάπως έτσι:
@import 'abstracts/*';
@import 'vendors/*';
@import 'base/*';
@import 'layout/*';
@import 'components/*';
@import 'pages/*';
@import 'themes/*';
@import 'abstracts/*'
@import 'vendors/*'
@import 'base/*'
@import 'layout/*'
@import 'components/*'
@import 'pages/*'
@import 'themes/*'
Η Sass δεν υποστηρίζει το file globbing απο μόνο του γιατί μπορεί να είναι μια επικίνδυνη λειτουργία γιατί στη CSS υπάρχει προτεραιότητα στην σειρά των δηλώσεων. Όταν κάνουμε import αρχείων δυναμικά (το οποίο συνήθως γίνεται με αλφαβητική σειρά), χάνεται ο έλεγχος της σειράς προτεραιότητας, κάτι που μπορεί να οδηγήσει σε παρενέργειες.
Κατόπιν αυτού, σε μια αυστηρή component-based αρχιτεκτονική με επιπλέον προσοχή προσοχή στο να μη διαρρεύσει κανένα style από ένα partial στο άλλο, η σειρά δεν θα ‘πρεπε να έχει σημασία πια, κάτι το οποίο θα επέτρεπε τα glob imports. Αυτό θα καθιστούσε ευκολότερη την πρόσθεση ή αφαίρεση partials, μιας και δεν θα ήταν πλέον απαραίτητη η προσεκτική ενημέρωση του αρχείου main.
Για τη χρήση Ruby Sass, υπάρχει ένα Ruby gem που ονομάζεται sass-globbing που επιτρέπει ακριβώς αυτή τη συμπεριφορά. Αν όμως χρησιμοποιείτε node-sass, μπορείτε να βασιστείτε είτε στο Node.js, είτε σε οποιοδήποτε build tool χρησιμοποιείτε για να κάνετε το compilation (Gulp, Grunt, etc.).
Το αρχείο Shame
Υπάρχει μια ενδιαφέρουσα ιδέα που έχει γίνει δημοφιλής απο τους Harry Roberts, Dave Rupert και Chris Coyier η οποία συνιστά να βάζουμε όλα τα CSS declarations, hacks και πράγματα για τα οποία δεν είμαστε περήφανοι μέσα στο αρχείο shame. Αυτό το αρχείο, με τον δραματικό τίτλο _shame.scss
, θα γινόταν import μετά από όλα τα άλλα αρχεία στο τέλος του stylesheet.
/**
* Διόρθωση του προβλήματος στο specificity του μενού πλοήγησης.
*
* Κάποιος χρησιμοποίησε ένα ID στον κώδικα του header (`#header a {}`) το οποίο υπερβαίνει
* τα nav selectors (`.site-nav a {}`). Χρησιμοποιούμε !important για να το παρακάμψουμε μέχρι
* να βρω χρόνο να διορθώσω τα θέματα του header.
*/
.site-nav a {
color: #BADA55 !important;
}
/**
* Διόρθωση του προβλήματος στο specificity του μενού πλοήγησης.
*
* Κάποιος χρησιμοποίησε ένα ID στον κώδικα του header (`#header a {}`) το οποίο υπερβαίνει
* τα nav selectors (`.site-nav a {}`). Χρησιμοποιούμε !important για να το παρακάμψουμε μέχρι
* να βρω χρόνο να διορθώσω τα θέματα του header.
*/
.site-nav a
color: #BADA55 !important
Responsive Web Design και breakpoints
Δε νομίζω ότι χρειάζεται να κάνω κάποια εισαγωγή για το Responsive Web Design τώρα που βρίσκεται παντού. Πάραυτα μπορεί να αναρωτηθείς γιατί υπάρχει ενότητα για το RWD στο Sass styleguide; Βασικά υπάρχουν μερικά πράγματα που μπορούν να γίνουν για να δουλεύουμε πιο εύκολα με τα breakpoints, οπότε σκέφτηκα ότι δε θα ήταν κακή ιδέα να τα παρουσιάσω εδώ.
Ονομάζοντας τα breakpoints
Νομίζω μπορούμε να πούμε με ασφάλεια ότι τα media queries δεν πρέπει να δεσμεύονται σε συγκεκριμένες συσκευές. Για παράδειγμα, είναι πραγματικά κακή ιδέα να στοχεύουμε iPads ή κινητά Blackberry συγκεκριμένα. Τα media queries πρέπει να μεριμνούν για ένα εύρος μεγέθων οθονών, έως ότου ο σχεδιασμός να διακοπεί και το επόμενο media αναλαμβάνει.
Για τους ίδιους λόγους, τα breakpoints δεν πρέπει να ονομάζονται βάσει συσκευών αλλά με πιο γενικά κριτήρια. Ειδικά δεδομένου ότι μερικά κινητά είναι πλέον μεγαλύτερα από tablets, μερικά tablets μεγαλύτερα από μικρές οθόνες υπολογιστών, και πάει λέγοντας…
// Yep
$breakpoints: (
'medium': (min-width: 800px),
'large': (min-width: 1000px),
'huge': (min-width: 1200px),
);
// Nope
$breakpoints: (
'tablet': (min-width: 800px),
'computer': (min-width: 1000px),
'tv': (min-width: 1200px),
);
// Yep
$breakpoints: ('medium': (min-width: 800px), 'large': (min-width: 1000px), 'huge': (min-width: 1200px))
// Nope
$breakpoints: ('tablet': (min-width: 800px), 'computer': (min-width: 1000px), 'tv': (min-width: 1200px))
Σ’ αυτό το σημείο, οποιαδήποτε ονοματολογική σύμβαση ξεκαθαρίζει ότι ένα design δεν είναι άμεσα συνδεδεμένο με ένα συγκεκριμένο είδος συσκευής, μας κάνει, αρκεί να προκύπτει μια τάξη μεγέθους από το όνομα.
$breakpoints: (
'σπόρος': (min-width: 800px),
'βλαστός': (min-width: 1000px),
'φυτό': (min-width: 1200px),
);
$breakpoints: ('σπόρος': (min-width: 800px), 'βλαστός': (min-width: 1000px), 'φυτό': (min-width: 1200px))
Τα προηγούμενα παραδείγματα χρησιμοποιούν nested maps για να καθορίσουν breakpoints, παρ’ όλ’ αυτά εξαρτάται από το είδος διαχειριστή των breakpoints που χρησιμοποιείς. Μπορείς να προτιμήσεις strings αντί για inner maps για μεγαλύτερη ευελιξία (π.χ. '(min-width: 800px)'
).
Διαχειριστής των breakpoints
Αφού έχεις ονομάσει τα breakpoints σου όπως θες, πρέπει να τα χρησιμοποιήσεις σε πραγματικά media queries. Υπάρχουν πολλοί τρόποι να το κάνεις αλλά είμαι μεγάλος υποστηρικτής του breakpoint map το οποίο διαβάζεται από μία getter συνάρτηση. Αυτό το σύστημα είναι απλό και αποτελεσματικό.
/// Responsive manager
/// @access public
/// @param {String} $breakpoint - Breakpoint
/// @requires $breakpoints
@mixin respond-to($breakpoint) {
$raw-query: map-get($breakpoints, $breakpoint);
@if $raw-query {
$query: if(
type-of($raw-query) == 'string',
unquote($raw-query),
inspect($raw-query)
);
@media #{$query} {
@content;
}
} @else {
@error 'Δεν βρέθηκε τιμή για το `#{$breakpoint}`. '
+ 'Παρακαλώ βεβαιώσου πως το έχεις ορίσει μέσα στο `$breakpoints` map.';
}
}
/// Responsive manager
/// @access public
/// @param {String} $breakpoint - Breakpoint
/// @requires $breakpoints
=respond-to($breakpoint)
$raw-query: map-get($breakpoints, $breakpoint)
@if $raw-query
$query: if(type-of($raw-query) == 'string', unquote($raw-query), inspect($raw-query))
@media #{$query}
@content
@else
@error 'Δεν βρέθηκε τιμή για το `#{$breakpoint}`. '
+ 'Παρακαλώ βεβαιώσου πως το έχεις ορίσει μέσα στο `$breakpoints` map.'
Προφανώς, πρόκειται για έναν απλουστευμένο διαχειριστή των breakpoints. Αν χρειάζεστε κάτι πιο ευέλικτο, προτείνω να μην ανακαλύψετε ξανά τον τροχό και να χρησιμοποιήσετε κάτι που έχει αποδειχτεί αποτελεσματικό όπως το Sass-MQ, το Breakpoint ή το include-media.
Αν ψάχνετε περισσότερο υλικό για διάβασμα στο πώς να προσεγγίσετε τα Media Queries στη Sass, τόσο το SitePoint (από τον υποφαινόμενο) όσο και το CSS-Tricks έχουν ωραία άρθρα σχετικά με το θέμα αυτό.
Χρήση των media Queries
Μέχρι πρόσφατα υπήρχε μια διαμάχη για το πού πρέπει να γράφονται τα media queries: ανήκουν μέσα στους selectors (η Sass το επιτρέπει) ή πρέπει να είναι αυστηρά εκτός; Μπορώ να πω ότι είμαι θερμός υποστηρικτής του συστήματος media-queries-μέσα-σε-selectors, γιατί πιστεύω πως συνδιάζεται καλά με τη λογική των components.
.foo {
color: red;
@include respond-to('medium') {
color: blue;
}
}
.foo
color: red
+respond-to('medium')
color: blue
Παράγει το εξής αποτέλεσμα σε CSS:
.foo {
color: red;
}
@media (min-width: 800px) {
.foo {
color: blue;
}
}
Μπορεί να έχετε ακούσει ότι αυτή η σύμβαση οδηγεί σε επαναλαμβανόμενα media queries στη CSS. Πράγμα που ισχύει. Παρ’ όλα αυτά, έχουν γίνει δοκιμές και το πόρισμα είναι ότι δεν έχει σημασία εφόσον το Gzip (ή κάτι ανάλογο) έχει κάνει ό,τι κάνει:
… we hashed out whether there were performance implications of combining vs scattering Media Queries and came to the conclusion that the difference, while ugly, is minimal at worst, essentially non-existent at best.
— Sam Richards, regarding Breakpoint
Οπότε, αν πραγματικά σας απασχολούν τα επαναλαμβανόμενα media queries, μπορείτε να χρησιμοποιήσετε ένα εργαλείο για να τα συγχωνεύσετε όπως αυτό το gem, αν και πρέπει να προειδοποιήσω ότι μπορεί να έχετε παρενέργειες με το να μετακινείτε CSS πάνω-κάτω. Γνωρίζετε πολύ καλά ότι η σειρά του πηγαίου κώδικα είναι σημαντική.
Αν εκτίμησες τα Sass Guidelines, στήριξε την προσπάθεια.
Υποστηρίξτε το Sass GuidelinesΜεταβλητές
Οι μεταβλητές είναι η ουσία κάθε προγραμματιστικής γλώσσας. Μας επιτρέπουν να επαναχρησιμοποιούμε τιμές χωρίς να χρειάζεται να τις αντιγράφουμε ξανά και ξανά. Κυρίως, κάνουν την ενημέρωση μιας τιμής πολύ εύκολη. Δε χρειάζεται πλέον να κάνουμε αναζήτηση και αντικατάσταση ή χειροκίνητη σάρωση.
Παρ’ όλα αυτά η CCS δεν είναι τίποτα άλλο παρά ένα μεγάλο καλάθι που περιέχει όλα μας τα αβγά. Σε αντίθεση με πολλές γλώσσες, δεν υπάρχουν πραγματικά scopes στη CSS. Εξαιτίας αυτού, πρέπει να προσέχουμε πάρα πολύ όταν προσθέτουμε μεταβλητές διότι υπάρχει ο κίνδυνος να αντιμετωπίσουμε προβλήματα.
Η συμβουλή μου θα ήταν να δημιουργείτε μεταβλητές μόνο όταν έχει νόημα να το κάνετε. Μην αρχικοποιείτε μεταβλητές απλά για να το κάνετε, δεν θα βοηθήσει. Μία νέα μεταβλητή πρέπει να δημιουργείται μόνο όταν ισχύουν όλα τα παρακάτω κριτήρια:
- η τιμή επαναλαμβάνεται τουλάχιστον δύο φορές·
- η τιμή κατά πάσα πιθανότητα θα ανανεωθεί τουλάχιστον μια φορά·
- όλες οι εμφανίσεις της τιμής είναι συνδεδεμένες με τη μεταβλητή (π.χ. όχι από σύμπτωση)
Βασικά, δεν υπάρχει λόγος να δηλώσουμε μια μεταβλητή η οποία δεν θα ανανεωθεί ποτέ ή χρησιμοποιείται σε ένα μόνο μέρος.
Scoping
Το scoping των μεταβλητών στη Sass έχει αλλάξει με τα χρόνια. Μέχρι αρκετά πρόσφατα, οι δηλώσεις μεταβλητών μέσα σε ένα σετ κανόνων και σε άλλα scopes ήταν τοπικές από προεπιλογή. Παρ’ όλα αυτά όταν υπήρχε ήδη μία global μεταβλητή με το ίδιο όνομα, η τοπική ανάθεση άλλαζε την global μεταβλητή. Από την έκδοση 3.4 και μετά, η Sass χειρίζεται σωστά την έννοια των scopes και δημιουργεί μια καινούρια τοπική μεταβλητή.
Τα έγγραφα αναφέρονται στην επισκίαση global μεταβλητής. Όταν δηλώνουμε μια μεταβλητή η οποία υπάρχει ήδη στο global scope, σε ένα εσωτερικό scope (selector, συνάρτηση, mixin…), λέμε ότι η τοπική μεταβλητή επισκιάζει την global. Βασικά, την παρακάμπτει μόνο για το local scope.
Το ακόλουθο κομμάτι κώδικα εξηγεί την έννοια της επισκίασης μεταβλητής.
// Αρχικοποίησε μια global μεταβλητή σε επίπεδο root.
$variable: 'initial value';
// Δημιούργησε ένα mixin που παρακάμπτει την global μεταβλητή.
@mixin global-variable-overriding {
$variable: 'mixin value' !global;
}
.local-scope::before {
// Δημιούργησε μια τοπική μεταβλητή που επισκιάζει την global.
$variable: 'local value';
// Κάνε include το mixin: παρακάμπτει την global μεταβλητή.
@include global-variable-overriding;
// Τύπωσε την τιμή της μεταβλητής.
// Είναι η **τοπική** μεταβλητή, εφόσον επισκιάζει την global.
content: $variable;
}
// Τύπωσε την μεταβλητή σε άλλον selector που δεν κάνει επισκίαση.
// Είναι η **global** μεταβλητή, όπως ήταν αναμενόμενο.
.other-local-scope::before {
content: $variable;
}
// Αρχικοποίησε μια global μεταβλητή σε επίπεδο root.
$variable: 'initial value'
// Δημιούργησε ένα mixin που παρακάμπτει την global μεταβλητή.
@mixin global-variable-overriding
$variable: 'mixin value' !global
.local-scope::before
// Δημιούργησε μια τοπική μεταβλητή που επισκιάζει την global.
$variable: 'local value'
// Κάνε include το mixin: παρακάμπτει την global μεταβλητή.
+global-variable-overriding
// Τύπωσε την τιμή της μεταβλητής.
// Είναι η **τοπική** μεταβλητή, εφόσον επισκιάζει την global.
content: $variable
// Τύπωσε την μεταβλητή σε άλλον selector που δεν κάνει επισκίαση.
// Είναι η **global** μεταβλητή, όπως ήταν αναμενόμενο.
.other-local-scope::before
content: $variable
!default
flag
Όταν φτιάχνουμε μια βιβλιοθήκη, ένα framework, ένα grid system ή ένα άλλο κομμάτι Sass το οποίο έχουμε σκοπό να το διανείμουμε και να χρησιμοποιηθεί από εξωτερικούς developers, όλες οι μεταβλητές παραμετροποίησης πρέπει να δηλωθούν με το !default
flag έτσι ώστε να μπορούν να αντικατασταθούν.
$baseline: 1em !default;
$baseline: 1em !default
Χάρη σ’ αυτό, ο developer μπορεί να ορίσει τη δική του μεταβλητή $baseline
προτού εισάγει την βιλιοθήκη σας χωρίς να επαναπροσδιοριστεί η τιμή του.
// Η μεταβλητή του developer
$baseline: 2em;
// Η δήλωση `$baseline` της βιβλιοθήκης σας
@import 'your-library';
// $baseline == 2em;
// Η μεταβλητή του developer
$baseline: 2em
// Η δήλωση `$baseline` της βιβλιοθήκης σας
@import your-library
// $baseline == 2em
!global
flag
Το !global
flag πρέπει μόνο να χρησιμοποιείται όταν παρακάπτουμε μία global μεταβλητή από ένα τοπικό scope. Όταν δηλώνουμε μια μεταβλητή σε επίπεδο root, το !global
flag πρέπει να παραλείπεται.
// Yep
$baseline: 2em;
// Nope
$baseline: 2em !global;
// Yep
$baseline: 2em
// Nope
$baseline: 2em !global
Πολλαπλές μεταβλητές ή maps
Υπάρχουν πλεονεκτήματα στο να χρησιμοποιούμε maps παρά να χρησιμοποιούμε πολλαπλές ξεχωριστές μεταβλητές. Το κυριότερο πλεονέκτημα είναι η δυνατότητα σάρωσης ενός map, πράγμα που δεν είναι δυνατό με ξεχωριστές μεταβλητές.
Ένα ακόμη πλεονέκτημα χρήσης maps είναι η δυνατότητα δημιουργίας μιας μικρής getter συνάρτησης για να παρέχουμε ένα πιο φιλικό API. Για παράδειγμα, δείτε τον παρακάτω κώδικα Sass:
/// Z-indexes map, το οποίο συλλέγει όλα τα επίπεδα Z της εφαρμογής
/// @access private
/// @type Map
/// @prop {String} key - όνομα επιπέδου
/// @prop {Number} value - τιμή Z για το key
$z-indexes: (
'modal': 5000,
'dropdown': 4000,
'default': 1,
'below': -1,
);
/// Πάρε την τιμή του z-index απο το όνομα του επίπεδου
/// @access public
/// @param {String} $layer - Το όνομα του επιπέδου
/// @return {Number}
/// @require $z-indexes
@function z($layer) {
@return map-get($z-indexes, $layer);
}
/// Z-indexes map, το οποίο συλλέγει όλα τα επίπεδα Z της εφαρμογής
/// @access private
/// @type Map
/// @prop {String} key - όνομα επιπέδου
/// @prop {Number} value - τιμή Z για το key
$z-indexes: ('modal': 5000, 'dropdown': 4000, 'default': 1, 'below': -1,)
/// Πάρε την τιμή του z-index απο το όνομα του επίπεδου
/// @access public
/// @param {String} $layer - Το όνομα του επιπέδου
/// @return {Number}
/// @require $z-indexes
@function z($layer)
@return map-get($z-indexes, $layer)
Extend
Το @extend
directive είναι μία ισχυρή δυνατότητα που είναι συχνά παρεξηγημένη. Σε γενικές γραμμές, προσφέρει τη δυνατότητα να πεις στη Sass να σχεδιάσει ένα element A σαν να έχει επιλέξει έναν selector B. Περιττό να πούμε ότι αυτό μπορεί να γίνει πολύτιμος σύμμαχος όταν γράφουμε modular CSS.
Παρ’ όλ’ αυτά, ο πραγματικός σκοπός του @extend
είναι να διατηρεί τις σχέσεις (περιορισμούς) εντός επεκταμένων selectors μεταξύ των rulesets. Τι σημαίνει αυτό ακριβώς;
- Οι selectors έχουν περιορισμούς (π.χ. ο
.bar
στο.foo > .bar
πρέπει να έχει έναν γονέα.foo
); - Αυτοί οι περιορισμοί μεταφέρονται στον επεκταμένο selector (π.χ. ο
.baz { @extend .bar; }
θα παράξει.foo > .bar, .foo > .baz
); - Τα declarations του επεκταμένου selector θα μοιραστούν με τον εκτεινόμενο selector.
Με βάση τα παραπάνω, είναι εμφανές πως η επέκταση των selectors με επιεικείς περιορισμούς μπορεί να οδηγήσει σε μια έκρηξη από selectors. Αν ο .baz .qux
επεκτείνει τον .foo .bar
, ο παραγόμενος selector μπορεί να είναι .foo .baz .qux
ή .baz .foo .qux
, αφού και ο .foo
και ο .baz
είναι πρόγονοι. Μπορεί να είναι γονείς, παπούδες, κ.ο.κ.
Πάντα να προσπαθείς να ορίζεις σχέσεις μέσω selector placeholders, όχι μέσω πραγματικών selectors. Αυτό θα σου δώσει την ελευθερία να χρησιμοποιήσεις (και να αλλάξεις) οποιοδήποτε naming convention έχεις ορίσει για τους selectors σου, και αφού οι σχέσεις ορίζονται μόνο μία φορά μέσα στους placeholders, υπάρχουν πολύ μικρότερες πιθανότητες να παράξεις απροσδόκητους selectors.
Για να κληρονομήσεις styles, χρησιμοποίησε το @extend
μόνο αν ο εκτεινόμενος .class
ή %placeholder
selector είναι ένα είδος επεκταμένου selector. Για παράδειγμα, ένα .error
είναι ένα είδος .warning
, οπότε το .error
μπορεί να κάνει @extend .warning
.
%button {
display: inline-block;
// … styles των κουμπιών
// Σχέση: ένα %button που είναι παιδί ενός %modal
%modal > & {
display: block;
}
}
.button {
@extend %button;
}
// Yep
.modal {
@extend %modal;
}
// Nope
.modal {
@extend %modal;
> .button {
@extend %button;
}
}
%button
display: inline-block
// … styles των κουμπιών
// Σχέση: ένα %button που είναι παιδί ενός %modal
%modal > &
display: block
.button
@extend %button
// Yep
.modal
@extend %modal
// Nope
.modal
@extend %modal
> .button
@extend %button
Υπάρχουν πολλά σενάρια στα οποία η επέκταση βοηθάει και αξίζει τον κόπο. Να θυμάσαι πάντα τους εξής κανόνες για να μπορείς να κάνεις @extend
με προσοχή:
- Να επεκτείνεις σε
%placeholders
κυρίως, όχι σε κανονικούς selectors. - Όταν επεκτείνεις κλάσεις, να επεκτείνεις μόνο μία κλάση από μία άλλη κλάση, ποτέ από ένα σύνθετο selector.
- Να επεκτείνεις ευθέως έναν
%placeholder
όσο το δυνατόν λιγότερο. - Απόφυγε να επεκτείνεις γενικούς ancestor selectors (π.χ.
.foo .bar
) ή γενικούς sibling selectors (π.χ..foo ~ .bar
). Αυτό είναι που προκαλεί την έκρηξη από selectors.
Συχνά λένε ότι το @extend
βοηθάει στο μέγεθος των αρχείων επειδή συνδιάζει selectors αντί να επαναλαμβάνει τα properties. Αυτό ισχύει, αν και η διαφορά είναι αμελητέα εφόσον γίνει συμπίεση με Gzip.
Κατόπιν αυτού, αν δε μπορείς να χρησιμοποιήσεις Gzip (ή κάτι παρόμοιο) τότε η προσέγγιση με το @extend
μπορεί να φανεί πολύτιμη, ειδικά αν το βάρος του stylesheet επιβαρύνει το performance.
Επέκταση και media queries
Να επεκτείνεις selectors μόνο μέσα στο ίδιο media scope (@media
directive). Σκέψου το media query ως άλλο ένα εμπόδιο.
%foo {
content: 'foo';
}
// Nope
@media print {
.bar {
// Αυτό δεν δουλεύει. Ακόμα χειρότερα: διακόπτεται.
@extend %foo;
}
}
// Yep
@media print {
.bar {
@at-root (without: media) {
@extend %foo;
}
}
}
// Yep
%foo {
content: 'foo';
&-print {
@media print {
content: 'foo print';
}
}
}
@media print {
.bar {
@extend %foo-print;
}
}
%foo
content: 'foo'
// Nope
@media print
.bar
// Αυτό δεν δουλεύει. Ακόμα χειρότερα: διακόπτεται.
@extend %foo
// Yep
@media print
.bar
@at-root (without: media)
@extend %foo
// Yep
%foo
content: 'foo'
&-print
@media print
content: 'foo print'
@media print
.bar
@extend %foo-print
Οι απόψεις φαίνεται να είναι άκρως αντιφατικές σχετικά με το @extend
σε σημείο που πολλοί developers συμπεριλαμβανομένου και του εαυτού μου δεν υποστηρίζουν την χρήση του, όπως μπορείτε να διαβάσετε στα παρακάτω άρθρα:
Κατόπιν αυτού για να συνοψίσουμε, προτείνω την χρήση του @extend
μόνο για την διατήρηση των σχέσεων εντός κάποιων selectors. Αν δύο selectors έχουν παρόμοια χαρακτηριστικά, τότε είναι η ιδανική περίπτωση για το @extend
. Αν δεν έχουν κάποια σχέση αλλά μοιράζονται μερικά rules, ένα @mixin
θα ταίριαζε καλύτερα. Περισσότερα για το πώς να επιλέξετε μεταξύ των δύο σε αυτό το άρθρο.
Ευχαριστώ τον David Khourshid για τη βοήθεια και την πείρα σ’ αυτή την ενότητα.
Mixins
Τα mixins είναι μία από τις πιο χρησιμοποιημένες δυνατότητες όλης της γλώσσας Sass. Είναι το κλειδί για το reusability και για DRY components. Και αυτό για έναν πολύ καλό λόγο: τα mixins επιτρέπουν τους δημιουργούς να ορίζουν styles τα οποία μπορούν να χρησιμοποιούν ξανά σε όλο το stylesheet χωρίς να χρειάζεται να καταφύγουν σε non-semantic κλάσεις όπως η .float-left
.
Μπορούν να περιέχουν ολόκληρα CSS rules και λίγο πολύ οτιδήποτε είναι επιτρεπτό μέσα σε ένα έγγραφο Sass. Μπορούν ακόμα να δεχτούν arguments, ακριβώς όπως οι συναρτήσεις. Περιττό να πούμε ότι οι δυνατότητες είναι άπειρες.
Αλλά οφείλω να σε προειδοποιήσω εναντίον της κατάχρησης της ισχύος των mixins. Και πάλι, η λέξη κλειδή εδώ είναι απλότητα. Μπορεί να φαίνεται δελεαστικό να φτιάξεις παντοδύναμα mixins με τεράστια ποσά λογικής. Αυτό λέγεται over-engineering και οι περισσότεροι developers πάσχουν απ’ αυτό. Μην υπεραναλύεις τον κώδικά σου, και πάνω απ’ όλα κράτησέ τον απλό. Αν ένα mixin καταλήγει να είναι μακρύτερο από 20 γραμμές πάνω κάτω, τότε πρέπει να διαχωριστεί σε μικρότερα κομμάτια ή αναθεωρήσεις εντελώς.
Τα βασικά
Κατόπιν αυτού, τα mixins είναι πολύ χρήσιμα και καλό είναι να τα χρησιμοποιείς. Εμπειρικά, αν εντοπίσεις κάποια CSS properties τα οποία εμφανίζονται πάντα μαζί για κάποιο λόγο (δηλ. όχι τυχαία), μπορείς να τα βάλεις σε ένα mixin. Το micro-clearfix hack του Nicolas Gallagher αξίζει να μπει σε ένα (argumentless) mixin για παράδειγμα.
/// Βοηθητικό mixin για να καθαρίσει τα εσωτερικά floats
/// @author Nicolas Gallagher
/// @link http://nicolasgallagher.com/micro-clearfix-hack/ Micro Clearfix
@mixin clearfix {
&::after {
content: '';
display: table;
clear: both;
}
}
/// Βοηθητικό mixin για να καθαρίσει τα εσωτερικά floats
/// @author Nicolas Gallagher
/// @link http://nicolasgallagher.com/micro-clearfix-hack/ Micro Clearfix
@mixin clearfix
&::after
content: ''
display: table
clear: both
Άλλο ένα αξιόλογο παράδειγμα θα ήταν ένα mixin που θα ορίζει το μέγεθος ενός element, ορίζονται το width
και το height
ταυτόχρονα. Όχι μόνο θα έκανε τον κώδικα ελαφρύτερο κατά την πληκτρολόγηση, αλλά και πιο ευανάγνωστο.
/// Βοηθητικό mixin για να ορίσουμε τις διαστάσεις ενός element
/// @author Kitty Giraudel
/// @param {Length} $width
/// @param {Length} $height
@mixin size($width, $height: $width) {
width: $width;
height: $height;
}
/// Βοηθητικό mixin για να ορίσουμε τις διαστάσεις ενός element
/// @author Kitty Giraudel
/// @param {Length} $width
/// @param {Length} $height
=size($width, $height: $width)
width: $width
height: $height
Για πιο περίπλοκα παραδείγματα των mixins, ρίξτε μια ματιά στα this mixin to generate CSS triangles, this mixin to create long shadows και this mixin to polyfill CSS gradients for old browsers.
Mixins χωρίς arguments
Μερικές φορές τα mixins χρησιμοποιούνται για να αποφύγουμε να επαναλαμβάνουμε τα ίδια declarations ξανά και ξανά, χωρίς να χρειάζονται παράμετρους ή έχοντας παράμετρους με εύλογες προεπιλεγμένες τιμές (sensible defaults) ώστε να μην χρειάζεται να περάσουμε arguments.
Σ’ αυτές τις περιπτώσεις, μπορούμε να παραλείξουμε άφοβα τις παρενθέσεις όταν τα καλούμε. Το @include
keyword (ή το σύμβολο +
σε indented-syntax) ήδη λειτουργεί ως δείκτης ότι σ’ αυτή η γραμμή καλείται ένα mixin· δε χρειάζονται επιπλέον παρενθέσεις εδώ.
// Yep
.foo {
@include center;
}
// Nope
.foo {
@include center();
}
// Yep
.foo
+center
// Nope
.foo
+center()
Arguments list
Όταν έχουμε να κάνουμε με έναν άγνωστο αριθμό από arguments σε ένα mixin, χρησιμοποιούμε πάντα μία arglist
αντί για μία λίστα. Δες την arglist
ως το όγδοο κρύφο undocumented data type της Sass που χρησιμοποιείται έμμεσα όταν περνάμε έναν αυθαίρετο αριθμό από arguments σε ένα mixin ή σε μία συνάρτηση της οποίας το signature περιέχει ...
.
@mixin shadows($shadows...) {
// type-of($shadows) == 'arglist'
// …
}
=shadows($shadows...)
// type-of($shadows) == 'arglist'
// …
Οπότε, όταν φτιάχνουμε ένα mixin που δέχεται αρκετά arguments (ας πούμε 3 ή περισσότερα), σκέψου καλά πριν τα συγχωνεύσεις σε μία λίστα ή ένα map με τη λογική ότι θα είναι πιο εύκολο από το να τα περάσεις ένα-ένα.
Η Sass είναι αρκετά έξυπνη όσον αφορά τα declarations στα mixins και στις συναρτήσεις, τόσο που μπορείς να περάσεις μία λίστα ή ένα map ως arglist σε μία συνάρτηση function/mixin ώστε να την αναγνωρίσει ως μια σειρά από arguments.
@mixin dummy($a, $b, $c) {
// …
}
// Yep
@include dummy(true, 42, 'kittens');
// Yep but nope
$params: (true, 42, 'kittens');
$value: dummy(nth($params, 1), nth($params, 2), nth($params, 3));
// Yep
$params: (true, 42, 'kittens');
@include dummy($params...);
// Yep
$params: (
'c': 'kittens',
'a': true,
'b': 42,
);
@include dummy($params...);
=dummy($a, $b, $c)
// …
// Yep
+dummy(true, 42, 'kittens')
// Yep but nope
$params: (true, 42, 'kittens')
$value: dummy(nth($params, 1), nth($params, 2), nth($params, 3))
// Yep
$params: (true, 42, 'kittens')
+dummy($params...)
// Yep
$params: ('c': 'kittens', 'a': true, 'b': 42,)
+dummy($params...)
Σχετικά με το αν είναι βέλτιστο να χρησιμοποιείτε πολλαπλά arguments, μια list ή ένα argument list, το SitePoint έχει ένα καλό άρθρο πάνω στο θέμα.
Mixins και vendor prefixes
Μπορεί να είναι δελεαστικό να ορίσεις δικά σου mixins που διαχειρίζονται τα vendor prefixes για ιδιότητες της CSS που υποστηρίζονται μερικώς ή καθόλου. Αλλά βασικά δε θέλουμε να το κάνουμε αυτό. Πρώτον, αν μπορείς να χρησιμοποιήσεις το Autoprefixer, χρησιμοποίησε το Autoprefixer. Θα αφαιρέσει τον κώδικα της Sass από το project σου, θα είναι πάντα ενημερωμένο και οπωσδήποτε θα κάνει καλύτερη δουλειά απο σένα στο να κάνεις prefix διάφορα.
Δυστυχώς, το Autoprefixer δε μπορεί να χρησιμοποιηθεί παντού. Αν χρησιμοποιείς Bourbon ή Compass, μάλλον θα ξέρεις πως και τα δύο προσφέρουν μία συλλογή από mixins που διαχειρίζονται τα vendor prefixes για σένα. Χρησιμοποίησέ τα.
Αν δε μπορείς να χρησιμοποιήσεις το Autoprefixer ούτε το Bourbon ούτε το Compass, τότε και μόνο τότε μπορείς να φτιάξεις το δικό σου mixin για να κάνεις prefix τις ιδιότητες της CSS. Αλλά. Μην φτιάξεις ένα mixin για κάθε ιδιότητα που εκτυπώνε όλους τους vendors.
// Nope
@mixin transform($value) {
-webkit-transform: $value;
-moz-transform: $value;
transform: $value;
}
// Nope
=transform($value)
-webkit-transform: $value
-moz-transform: $value
transform: $value
Κάντο με τον έξυπνο τρόπο.
/// Βοηθητικό mixin για να την παραγωγή vendor prefixes
/// @access public
/// @author KittyGiraudel
/// @param {String} $property - Unprefixed CSS property
/// @param {*} $value - Ακατέργαστη τιμή CSS
/// @param {List} $prefixes - Λίστα απο prefixes για παραγωγή
@mixin prefix($property, $value, $prefixes: ()) {
@each $prefix in $prefixes {
-#{$prefix}-#{$property}: $value;
}
#{$property}: $value;
}
/// Βοηθητικό mixin για να την παραγωγή vendor prefixes
/// @access public
/// @author KittyGiraudel
/// @param {String} $property - Unprefixed CSS property
/// @param {*} $value - Ακατέργαστη τιμή CSS
/// @param {List} $prefixes - Λίστα απο prefixes για παραγωγή
=prefix($property, $value, $prefixes: ())
@each $prefix in $prefixes
-#{$prefix}-#{$property}: $value
#{$property}: $value
Οπότε μετά η χρήση αυτού του mixin είναι προφανής:
.foo {
@include prefix(transform, rotate(90deg), ('webkit', 'ms'));
}
.foo
+prefix(transform, rotate(90deg), ('webkit', 'ms'))
Μην ξεχνάς ότι αυτή είναι μία κακή λύση. Για παράδειγμα, δε μπορεί να διαχειριστεί σύνθετα polyfills όπως αυτά που χρειάζονται για το Flexbox. Μ’ αυτή τη λογική, η χρήση του Autoprefixer είναι πολύ καλύτερη λύση.
Conditional statements
Πιθανώς ήδη γνωρίζετε ότι η Sass παρέχει conditional statements μέσω των @if
και @else
directives. Εκτός αν έχετε κάποια περίπλoκη λογική στον κώδικα σας, δεν συντρέχει λόγος χρήσης των conditional statements στα stylesheets σας. Στην πραγματικότητα, υπάρχουν κυρίως για την χρήση τους σε libraries και frameworks.
Εν πάση περιπτώσει, αν ποτέ βρεθείτε στην ανάγκη τους, παρακαλώ να σεβαστείτε τα ακόλουθα guidelines:
- αποφεύγετε τις παρενθέσεις εκτός και αν είναι αναγκαίο·
- Να αφήνεις πάντα καινούργια γραμμή πριν απο ένα
@if
· - Να αφήνεις πάντα καινούργια γραμμή μετά το αριστερό άγκιστρο (
{
)· - Το
@else
πρέπει να είναι στην ίδια γραμμή με το αριστερό άγκιστρο ({
) του προηγούμενου@if
· - Να αφήνεις πάντα καινούργια γραμμή μετά το τελευταίο δεξί άγκιστρο (
}
).
// Yep
@if $support-legacy {
// …
} @else {
// …
}
// Nope
@if ($support-legacy == true) {
// …
}
@else {
// …
}
// Yep
@if $support-legacy
// …
@else
// …
// Nope
@if ($support-legacy == true)
// …
@else
// …
Όταν ελέγχετε για κάποια μη-αληθή τιμή, να χρησιμοποιείτε πάντα την λέξη κλειδή not
αντί να ελέγχετε για false
ή null
.
// Yep
@if not index($list, $item) {
// …
}
// Nope
@if index($list, $item) == null {
// …
}
// Yep
@if not index($list, $item)
// …
// Nope
@if index($list, $item) == null
// …
Πάντα να βάζετε την μεταβλητή στην αριστερή πλευρά της δήλωσης και το (μη) αναμενόμενο αποτέλεσμα στην δεξιά πλευρά. Ανεστραμμένα conditional statements είναι συνήθως δυσκολότερα στην ανάγνωση, ειδικά απο τους άπειρους developers.
// Yep
@if $value == 42 {
// …
}
// Nope
@if 42 == $value {
// …
}
// Yep
@if $value == 42
// …
// Nope
@if 42 == $value
// …
Όταν χρησημοποιείτε conditional statements μέσα σε κάποιο function το οποίο θα επιστρέφει διαφορετική τιμή ανάλογα με τις προϋποθέσεις του conditional statement, βεβαιωθείτε πάντα ότι το function εξακολουθεί να έχει @return
έξω από το πλαίσιο του conditional statement.
// Yep
@function dummy($condition) {
@if $condition {
@return true;
}
@return false;
}
// Nope
@function dummy($condition) {
@if $condition {
@return true;
} @else {
@return false;
}
}
// Yep
@function dummy($condition)
@if $condition
@return true
@return false;
// Nope
@function dummy($condition)
@if $condition
@return true
@else
@return false
Αν εκτίμησες τα Sass Guidelines, στήριξε την προσπάθεια.
Υποστηρίξτε το Sass GuidelinesLoops
Επειδή η Sass παρέχει πολύπλοκες δομές δεδομένων όπως lists και maps, δεν αποτελεί έκπληξη το γεγονός ότι δίνει επίσης τη δυνατότητα στους συγγραφείς να μπορούν να σαρώσουν τις εν λόγω οντότητες.
Ωστόσο, η παρουσία των loops συνήθως υποδηλώνει σχετικά σύνθετη λογική που κατά πάσα πιθανότητα δεν ανήκει στη Sass. Πριν χρησιμοποιήσεις ένα loop, βεβαιώσου ότι έχει νόημα και ότι λύνει πραγματικά ένα πρόβλημα.
Each
Από τα τρία loops που παρέχονται από τη Sass, το @each
loop είναι σίγουρα αυτό που χρησιμοποιείται πιο συχνά. Παρέχει ένα καθαρό API για να μπορείς να σαρώσεις ένα list ή ένα map.
@each $theme in $themes {
.section-#{$theme} {
background-color: map-get($colors, $theme);
}
}
@each $theme in $themes
.section-#{$theme}
background-color: map-get($colors, $theme)
Οταν σαρώνεις ένα map, πρέπει πάντοτε να χρησιμοποιείς $key
και $value
ως ονόματα στις μεταβλητές για να υπάρχει συνοχή.
@each $key, $value in $map {
.section-#{$key} {
background-color: $value;
}
}
@each $key, $value in $map
.section-#{$key}
background-color: $value
Επίσης, φρόντισε να σεβαστείς τα παρακάτω guidelines για τη διατήρηση της αναγνωσιμότητας:
- Να αφήνεις πάντα καινούργια γραμμή πριν το
@each
· - Να αφήνεις πάντα καινούργια γραμμή μετά το δεξί άγκιστρο (
}
) εκτός και εαν η επόμενη γραμμή περιέχει δεξί άγκιστρο (}
).
For
Το @for
loop μπορεί να φανεί χρήσιμο όταν συνδυάζεται με τις ψευδοκλάσεις της CSS’ :nth-*
. Εκτός από αυτά τα σενάρια, να προτιμάς ένα @each
loop αν πρέπει να σαρώσεις κάτι.
@for $i from 1 through 10 {
.foo:nth-of-type(#{$i}) {
border-color: hsl($i * 36, 50%, 50%);
}
}
@for $i from 1 through 10
.foo:nth-of-type(#{$i})
border-color: hsl($i * 36, 50%, 50%)
Να χρησιμοποιείς πάντα $i
ως όνομα μεταβλητής για να διατηρήσεις τη συνήθη σύμβαση, και μην χρησιμοποιείς ποτέ την λέξη κλειδί to
: πάντοτε να χρησιμοποιείς through
, εκτός κι αν έχεις πραγματικά καλό λόγο. Πολλοί developers δεν γνωρίζουν καν ότι η Sass προσφέρει αυτή την παραλλαγή· με τη χρήση του ενδέχεται να προκαλέσει σύγχυση.
Επίσης, φρόντισε να σεβαστείς τα παρακάτω guidelines για τη διατήρηση της αναγνωσιμότητας:
- Να αφήνεις πάντα καινούργια γραμμή πριν το
@for
· - Να αφήνεις πάντα καινούργια γραμμή μετα το δεξί άγκιστρο (
}
) εκτός και εαν η επόμενη γραμμή περιέχει το δεξί άγκιστρο (}
).
While
Το @while
loop δεν έχει καμία απολύτως χρησιμότητα σε ένα πραγματικό Sass project, ιδίως επειδή δεν υπάρχει τρόπος να κάνεις break από το loop από μέσα. Μην το χρησιμοποιήσεις.
Προειδοποιήσεις και σφάλματα
Αν υπάρχει μια λειτουργία που παραβλέπεται συχνά από αυτούς που γράφουν Sass, αυτή είναι η δυνατότητα να εμφανίζονται δυναμικά προειδοποιήσεις και σφάλματα. Πράγματι, η Sass διαθέτει τρία ειδικά directives για να εμφανίζει περιεχόμενο στο standard output system (CLI, compiling app…):
@debug
·@warn
·@error
.
Ας βγάλουμε στην άκρη το @debug
μιας και προφανώς προορίζεται για το debugging της SassScript, πράγμα που δε μας αφορά εδώ. Οπότε μένουμε με το @warn
και το @error
τα οποία είναι εμφανώς ίδια, εκτός του ότι το ένα διακόπτει τον compiler ενώ το άλλο όχι. Σας αφήνω να μαντέψετε ποιο κάνει τί.
Τώρα, υπάρχουν πολλά περιθώρια σε ένα Sass project για προειδοποιήσεις και σφάλματα. Βασικά οποιοδήποτε mixin ή function προσδοκεί ένα συγκεκριμένο τύπο ή argument θα μπορούσε να πετάξει ένα σφάλμα αν κάτι πάει στραβά, ή να εμφανίσει μία προειδοποίηση όταν υποθέτει κάτι.
Προειδοποιήσεις
Δείτε αυτό το function του Sass-MQ που επιδιώκει να μετατρέψει μια τιμή από px
σε em
, για παράδειγμα:
@function mq-px2em($px, $base-font-size: $mq-base-font-size) {
@if unitless($px) {
@warn 'Assuming #{$px} to be in pixels, attempting to convert it into pixels.';
@return mq-px2em($px + 0px);
} @else if unit($px) == em {
@return $px;
}
@return ($px / $base-font-size) * 1em;
}
@function mq-px2em($px, $base-font-size: $mq-base-font-size)
@if unitless($px)
@warn 'Assuming #{$px} to be in pixels, attempting to convert it into pixels.'
@return mq-px2em($px + 0px)
@else if unit($px) == em
@return $px
@return ($px / $base-font-size) * 1em
Εάν η τιμή δεν έχει μονάδα μέτρησης, το function θεωρεί πως η τιμή εκφράζεται σε pixels. Σ’ αυτό το σημείο, μια υπόθεση ίσως είναι ριψοκίνδυνη, οπότε ο χρήστης θα έπρεπε να προειδοποιηθεί ότι το πρόγραμμα έκανε κάτι που θα μπορούσε να θεωρηθεί απροσδόκητο.
Σφάλματα
Τα σφάλματα, σε αντίθεση με τις προειδοποιήσεις, αποτρέπουν τον compiler να συνεχίσει παρακάτω. Βασικά διακόπτουν το compilation και εμφανίζουν ένα μήνυμα στο output stream όπως και στο stack trace, πράγμα που βοηθάει στο debugging. Εξαιτίας όλων αυτών, τα σφάλματα πρέπει να πετιούνται όταν δεν υπάρχει τρόπος να συνεχιστεί η εκτέλεση του προγράμματος. Όπου είναι εφικτό, δοκίμασε να διορθώσεις το πρόβλημα και προτίμησε να εμφανίσεις μία προειδοποίηση.
Για παράδειγμα, ας πούμε ότι φτιάχνεις μία βελτιωμένη συνάρτηση για να έχεις πρόσβαση σε τιμές από ένα συγκεκριμένο map. Θα μπορούσε να πετάξεις ένα σφάλμα αν το ζητούμενο key δεν υπάρχει στο map.
/// Z-indexes map, το οποίο συλλέγει όλα τα επίπεδα Z της εφαρμογής
/// @access private
/// @type Map
/// @prop {String} key - όνομα επιπέδου
/// @prop {Number} value - τιμή Z για το key
$z-indexes: (
'modal': 5000,
'dropdown': 4000,
'default': 1,
'below': -1,
);
/// Πάρε την τιμή του z-index απο το όνομα του επίπεδου
/// @access public
/// @param {String} $layer - όνομα του επιπέδου
/// @return {Number}
/// @require $z-indexes
@function z($layer) {
@if not map-has-key($z-indexes, $layer) {
@error 'Δεν υπάρχει επίπεδο με όνομα `#{$layer}` μέσα στα $z-indexes. '
+ 'Το επίπεδο πρέπει να είναι ένα απο τα #{map-keys($z-indexes)}.';
}
@return map-get($z-indexes, $layer);
}
/// Z-indexes map, το οποίο συλλέγει όλα τα επίπεδα Z της εφαρμογής
/// @access private
/// @type Map
/// @prop {String} key - όνομα επιπέδου
/// @prop {Number} value - τιμή Z για το key
$z-indexes: ('modal': 5000, 'dropdown': 4000, 'default': 1, 'below': -1,)
/// Πάρε την τιμή του z-index απο το όνομα του επίπεδου
/// @access public
/// @param {String} $layer - όνομα του επιπέδου
/// @return {Number}
/// @require $z-indexes
@function z($layer)
@if not map-has-key($z-indexes, $layer)
@error 'Δεν υπάρχει επίπεδο με όνομα `#{$layer}` μέσα στα $z-indexes. '
+ 'Το επίπεδο πρέπει να είναι ένα απο τα #{map-keys($z-indexes)}.'
@return map-get($z-indexes, $layer)
Για περισσότερες πληροφορίες σχετικά με το πώς να χρησιμοποιήσετε το @error
αποτελεσματικά, αυτή η εισαγωγή στο error handling θα βοηθούσε.
Εργαλεία
Το καλό με έναν CSS preprocessor τόσο δημοφιλή όσο η Sass είναι ότι έχει ένα ολόκληρο οικοσύστημα από frameworks, plugins, βιβλιοθήκες και εργαλεία. Μετά από 8 χρόνια ύπαρξης, κοντεύουμε όλο και περισσότερο στο σημείο που οτιδήποτε μπορεί να γραφτεί σε Sass, έχει γραφτεί σε Sass.
Παρόλα αυτά η συμβουλή μου είναι να ελαχιστοποιήσετε τον αριθμό των εξαρτήσεων στα απολύτως απαραίτητα. Το να διαχειρίζεστε εξαρτήσεις είναι ένας μπελάς στον οποίο δεν θέλετε να μπλέξετε. Επίσης, η ανάγκη για εξωτερικές εξαρτήσεις στη Sass είναι μικρή έως ανύπαρκτη.
Compass
Το Compass είναι το κυριότερο Sass framework που κυκλοφορεί. Έχοντας αναπτυχθεί από τον Chris Eppstein, έναν από τους δύο βασικούς σχεδιαστές της Sass, δεν το βλέπω να χάνει δραματικά σε δημοτικότητα για το επόμενο διάστημα, αν θέλετε τη γνώμη μου.
Όμως, δεν χρησιμοποιώ το Compass πια, κυρίως επειδή καθυστερεί πολύ την Sass. Η Ruby Sass είναι αρκετά αργή από μόνη της, οπότε το να προσθέτουμε περισσότερη Ruby και περισσότερη Sass δεν βοηθάει.
Το θέμα είναι ότι χρησιμοποιούμε πολύ λίγο από το όλο framework. Το Compass είναι τεράστιο. Τα mixins για συμβατότητα μεταξύ των browsers είναι απλά η κορυφή του παγόβουνου. Μαθηματικές συναρτήσεις, βοηθοί εικόνας, εργαλεία για sprites… Υπάρχουν ένα σωρό πράγματα που μπορούν να γίνουν με αυτό το θαυμάσιο λογισμικό.
Δυστυχώς, όλα αυτά είναι μικρής σημασίας και δεν υπάρχει κάποιο πραγματικά δυνατό χαρακτηριστικό εκεί μέσα. Μια εξαίρεση θα μπορούσε να γίνει για τον sprite builder που είναι πραγματικά υπέροχος, αλλά το Grunticon και το Grumpicon κάνουν την ίδια δουλειά και έχουν το πλεονέκτημα ότι μπορούν να ενσωματωθούν στην διαδικασία του build.
Τελοσπάντων, δεν απαγορεύω την χρήση του Compass αλλά και ούτε το προτείνω, κυρίως επειδή δεν είναι συμβατό με την LibSass (αν και έχουν γίνει προσπάθειες προς αυτή την κατεύθυνση). Αν αισθάνεστε καλύτερα χρησιμοποιώντας το, κάντε το, αλλά δεν νομίζω ότι θα κερδίσετε πολλά από αυτό τελικά.
Η Ruby Sass δέχεται αυτή τη στιγμή σημαντικές βελτιστοποιήσεις που στοχεύουν συγκριμένα στα styles που περιέχουν πολλή λογική με πολλές συναρτήσεις και mixins. Αυτές θα βελτιώσουν δραματικά την απόδοση σε σημείο που το Compass και άλλα frameworks δεν θα καθυστερούν πια τη Sass.
Συστήματα Grid
Το να μην χρησιμοποιείτε ένα σύστημα grid δεν είναι πλέον επιλογή τώρα που το Responsive Web Design είναι παντού. Για να κάνουμε τα designs να φαίνονται ομοιόμορφα και σταθερά σε όλα τα μεγέθη, χρησιμοποιούμε κάποιου είδους grid για να τοποθετούμε τα αντικείμενα. Για να αποφύγουμε να γράφουμε τον κώδικα του grid ξανά και ξανά, μερικά λαμπρά μυαλά έκαναν τα δικά τους grid επαναχρησιμοποιήσιμα.
Για να το θέσω σαφώς: Δεν πολυσυμπαθώ τα συστήματα grid. Φυσικά και βλέπω τις προοπτικές, αλλά νομίζω ότι τα περισσότερα από αυτά είναι τελείως υπερβολικά και χρησιμοποιούνται κυρίως για να σχεδιάζουμε κόκκινες στήλες σε λευκό φόντο στις σημειώσεις ομιλιών κάποιων φυτών designers. Πότε ήταν η τελευταία φορά που σκέφτηκατε πάλι καλά που έχω αυτό το εργαλείο για να στήσω αυτό το 2-5-3.1-π grid; Πολύ σωστά, ποτέ. Επειδή τις περισσότερες φορές, απλά θέλετε το συνηθισμένο κανονικό grid με 12 στήλες, τίποτα φανταχτερό.
Αν χρησιμοποιείτε ένα CSS framework για το project σας όπως το Bootstrap ή το Foundation, κατά πάσα πιθανότητα αυτό εμπεριέχει ήδη ένα σύστημα grid και σε αυτή την περίπτωση συνιστώ να το χρησιμοποιήσετε για να αποφύγετε να ασχοληθείτε με ακόμα μία εξάρτηση.
Αν δεν είστε προσκολλημένοι σε ένα συγκεκριμένο σύστημα grid, θα χαρείτε να μάθετε ότι υπάρχουν δύο κορυφαίες μηχανές grid γραμμένες σε Sass: το Susy και το Singularity. Και οι δύο κάνουν πολλά περισσότερα από ότι θα χρειαστείτε ποτέ οπότε μπορείτε να διαλέξετε αυτήν που προτιμάτε μεταξύ των δύο και να είστε σίγουροι ότι όλες οι ακραίες περιπτώσεις σας—ακόμη και οι πιο παράξενες—θα έχουν καλυφθεί. Αν με ρωτάτε, το Suzy έχει λίγο καλύτερη κοινότητα, αλλά αυτή είναι απλά η γνώμη μου.
Αλλιώς μπορείς να απευθυνθείτε σε κάτι πιο απλό, όπως το csswizardry-grids. Τελικά, η επιλογή δεν θα έχει σημαντικό αντίκτυπο στο δικό σας στυλ κώδικα, οπότε είναι λίγο πολύ στο χέρι σας ποιο θα διαλέξετε.
SCSS-lint
Ο έλεγχος (lint) του κώδικα είναι πολύ σημαντικός. Συνήθως, το να ακολουθείτε οδηγίες από ένα styleguide βοηθάει να ελαχιστοποιηθούν τα λάθη ποιότητας του κώδικα, αλλά κανείς δεν είναι τέλειος και πάντοτε υπάρχουν πράγματα που επιδέχονται βελτίωση. Έτσι μπορείτε να πείτε ότι ο έλεγχος του κώδικα είναι εξίσου σημαντικός όσο και ο σχολιασμός του.
Το SCSS-lint είναι ένα εργαλείο που σε βοηθάει να κρατάτε τα SCSS αρχεία σας καθαρά και ευανάγνωστα. Είναι πλήρως παραμετροποιήσιμο και εύκολο να ενσωματωθεί στα εργαλεία σας.
Ευτυχώς, οι προτεινόμενες ρυθμίσεις του SCSS-lint είναι αρκετά παρόμοιες με αυτές που περιγράφονται στο παρόν έγγραφο. Αν θέλετε να παραμετροποιήσετε το SCSS-lint σύμφωνα με τα Sass Guidelines, προτείνω το ακόλουθο setup:
linters:
BangFormat:
enabled: true
space_before_bang: true
space_after_bang: false
BemDepth:
enabled: true
max_elements: 1
BorderZero:
enabled: true
convention: zero
ChainedClasses:
enabled: false
ColorKeyword:
enabled: true
ColorVariable:
enabled: false
Comment:
enabled: false
DebugStatement:
enabled: true
DeclarationOrder:
enabled: true
DisableLinterReason:
enabled: true
DuplicateProperty:
enabled: false
ElsePlacement:
enabled: true
style: same_line
EmptyLineBetweenBlocks:
enabled: true
ignore_single_line_blocks: true
EmptyRule:
enabled: true
ExtendDirective:
enabled: false
FinalNewline:
enabled: true
present: true
HexLength:
enabled: true
style: short
HexNotation:
enabled: true
style: lowercase
HexValidation:
enabled: true
IdSelector:
enabled: true
ImportantRule:
enabled: false
ImportPath:
enabled: true
leading_underscore: false
filename_extension: false
Indentation:
enabled: true
allow_non_nested_indentation: true
character: space
width: 2
LeadingZero:
enabled: true
style: include_zero
MergeableSelector:
enabled: false
force_nesting: false
NameFormat:
enabled: true
convention: hyphenated_lowercase
allow_leading_underscore: true
NestingDepth:
enabled: true
max_depth: 1
PlaceholderInExtend:
enabled: true
PrivateNamingConvention:
enabled: true
prefix: _
PropertyCount:
enabled: false
PropertySortOrder:
enabled: false
PropertySpelling:
enabled: true
extra_properties: []
PropertyUnits:
enabled: false
PseudoElement:
enabled: true
QualifyingElement:
enabled: true
allow_element_with_attribute: false
allow_element_with_class: false
allow_element_with_id: false
SelectorDepth:
enabled: true
max_depth: 3
SelectorFormat:
enabled: true
convention: hyphenated_lowercase
class_convention: '^(?:u|is|has)\-[a-z][a-zA-Z0-9]*$|^(?!u|is|has)[a-zA-Z][a-zA-Z0-9]*(?:\-[a-z][a-zA-Z0-9]*)?(?:\-\-[a-z][a-zA-Z0-9]*)?$'
Shorthand:
enabled: true
SingleLinePerProperty:
enabled: true
allow_single_line_rule_sets: false
SingleLinePerSelector:
enabled: true
SpaceAfterComma:
enabled: true
SpaceAfterPropertyColon:
enabled: true
style: one_space
SpaceAfterPropertyName:
enabled: true
SpaceAfterVariableColon:
enabled: true
style: at_least_one_space
SpaceAfterVariableName:
enabled: true
SpaceAroundOperator:
enabled: true
style: one_space
SpaceBeforeBrace:
enabled: true
style: space
allow_single_line_padding: true
SpaceBetweenParens:
enabled: true
spaces: 0
StringQuotes:
enabled: true
style: single_quotes
TrailingSemicolon:
enabled: true
TrailingZero:
enabled: true
TransitionAll:
enabled: false
UnnecessaryMantissa:
enabled: true
UnnecessaryParentReference:
enabled: true
UrlFormat:
enabled: false
UrlQuotes:
enabled: true
VariableForProperty:
enabled: false
VendorPrefixes:
enabled: true
identifier_list: base
include: []
exclude: []
ZeroUnit:
enabled: true
Αν δεν είστε πεπεισμένοι για την αναγκαιότητα της χρήσης του SCSS-lint, σας προτείνω να διαβάσετε αυτά τα εξαιρετικά άρθρα: Clean Up your Sass with SCSS-lint, Improving Sass code quality on theguardian.com και An Auto-Enforceable SCSS Styleguide.
Αν θέλετε να ενσωματώσετε έλεγχο της SCSS στην διακασία Grunt build, θα χαρείτε να μάθετε ότι υπάρχει ένα Grunt plugin γι’ αυτό το σκοπό που λέγεται grunt-scss-lint.
Επίσης αν ψάχνετε μια ωραία εφαρμογή που να δουλεύει με το SCSS-lint και παρόμοια εργαλεία, οι τύποι στην Thoughtbot (Bourbon, Neat…) δουλεύουν πάνω στο Hound.
Ανακεφαλαίωση
Τα guidelines αυτά είναι αρκετά εκτενή και καμιά φορά είναι χρήσιμο να υπάρχουν συνοπτικά σε μια πιο σύντομη έκδοση. Η περίληψη παρακάτω.
Βασικές αρχές
- Η ύπαρξη ενός styleguide έχει να κάνει με τη συνοχή. Αν διαφωνείς με κάποιους κανόνες των Sass Guidelines, δεν τρέχει κάτι, αρκεί να διατηρείς τη συνοχή.
- Η Sass πρέπει να διατηρείται όσο πιο απλή γίνεται. Αποφεύγουμε πολύπλοκα συστήματα εκτός κι αν είναι απολύτως αναγκαία.
- Να θυμάσαι ότι το KISS (Keep It Simple, Stupid) είναι καλύτερο από το DRY (Don’t Repeat Yourself).
Σύνταξη & μορφοποίηση
- Μία εσοχή (indentation) αποτελείται από δύο (2) κενά, όχι tabs.
- Οι αράδες πρέπει να είναι — όσο το δυνατόν — μικρότερες από 80 χαρακτήρες. Μη διστάσεις να τις διαχωρίσεις σε πολλές γραμμές όταν είναι απαραίτητο.
- Η CSS πρέπει να είναι ορθά γραμμένη, ενδεχομένως ακολουθώντας τα CSS Guidelines του Harry Roberts.
- Δεν υπάρχουν περιορισμοί στα κενά, χρησιμοποίησέ τα για να διαχωρίσεις αντικείμενα, κανόνες και ορίσματα. Μη διστάσεις να αφήσεις κενές γραμμές, ποτέ δε βλάπτει.
Strings
- Συνιστάται ιδιαίτερα να ορίζουμε το
@charset
directive στην κορυφή του stylesheet. - Με εξαίρεση τους CSS identifiers, τα strings πρέπει να έχουν μονά εισαγωγικά (‘). Τα URL επίσης θέλουν εισαγωγικά.
Αριθμοί
- Η Sass δεν κάνει διαχωρισμούς ανάμεσα σε αριθμούς, ακέραιους και δεκαδικούς, οπότε τα μηδενικά (0) μετά το τέλος ενός δεκαδικού πρέπει να παραλείπονται. Πάραυτα, τα μηδενικά πριν από τους δεκαδικούς μικρότερους της μονάδας (0) βοηθάνε στην αναγνωσιμότητα και πρέπει να εμφανίζονται.
- Ένα μηδενικό (0) μήκος δεν πρέπει να έχει μονάδα μέτρησης.
- Οι μετατροπές μονάδων μέτρησης πρέπει να υπολογίζονται με αριθμητικές πράξεις, όχι με string operations.
- Για τη βελτίωση της αναγνωσιμότητας, οι υπολογισμοί υψηλού επιπέδου πρέπει να μπαίνουν σε παρένθεση. Επίσης, σύνθετες μαθηματικές πράξεις πρέπει να διαχωρίζονται σε μικρότερα κομμάτια.
- Οι μαγικοί αριθμοί βλάπτουν δραματικά την συντηρησιμότητα του κώδικα και πρέπει πάντα να αποφεύγονται. Όταν δεν είσαι σίγουρος, να εξηγείς εκτενώς τον αμφιλεγόμενο αριθμό.
Χρώματα
- Τα χρώματα πρέπει να ορίζονται σε HSL προτίστως, μετά σε RGB, και μετά σε δεκαεξαδικούς (με πεζούς χαρακτήρες και συντομευμένη μορφή). Τα ονόματα των χρωμάτων καλό είναι να αποφεύγονται.
- Προτιμούμε το
mix(..)
αντί για τοdarken(..)
και τοlighten(..)
όταν λευκαίνουμε ή σκουραίνουμε ένα χρώμα.
Lists
- Τα lists πρέπει να διαχωρίζονται με κόμμα, εκτός όταν χρησιμοποιούνται για απευθείας αντιστοίχιση σε CSS values που διαχωρίζονται με κενά.
- Η χρήση παρενθέσεων επίσης βοηθάει στη βελτίωση της αναγνωσιμότητας.
- Τα lists που ορίζονται σε μία γραμμή δεν πρέπει να έχουν κόμμα στο τέλος, ενώ τα lists σε πολλαπλές γραμμές πρέπει να έχουν.
Maps
- Τα maps που περιέχουν περισσότερα από ένα ζεύγος γράφονται σε πολλαπλές γραμμές.
- Για να βοηθήσουμε τη συντηρησιμότητα, το τελευταίο ζεύγος ενός map πρέπει να τελειώνει με κόμμα.
- Τα keys των maps που τυγχάνει να είναι strings πρέπει να έχουν εισαγωγικά όπως όλα τα strings.
Ταξινόμηση των ορισμάτων (declarations)
- Η λογική που χρησιμοποιούμε για να ταξινομήσουμε τα ορίσματα (αλφαβητικά, ανά τύπο, κλπ.) δεν έχει σημασία αρκεί να υπάρχει συνοχή.
Εμφώλευση των selectors (nesting)
- Αποφεύγουμε να εμφωλεύουμε selectors όταν δε χρειάζεται (στις περισσότερες περιπτώσεις).
- Χρησιμοποιούμε την εμφώλευση των selectors για ψευδο-κλάσεις και ψευδο-αντικείμενα.
- Τα media queries μπορούν επίσης να εμφωλευτούν μέσα στον selector που τους αντιστοιχεί.
Συμβάσεις ονομασιών
- Το καλύτερο είναι να ακολουθούμε τις συμβάσεις ονομασιών της CSS, οι οποίες (με εξαίρεση κάποια λάθη) είναι με πεζούς χαρακτήρες και διαχωρίζονται με παύλες.
Σχόλια
- Η CSS είναι ζόρικη γλώσσα· μη διστάσεις να γράψεις εκτενέστατα σχόλια για οτιδήποτε φαίνεται (ή είναι) ασαφές.
- Όσον αφορά μεταβλητές, συναρτήσεις, mixins και placeholders που καθορίζουν κάποιο public API, χρησιμοποιούμε SassDoc σχόλια.
Μεταβλητές
- Μη χρησιμοποιείς το
!default
flag για οποιαδήποτε μεταβλητή είναι μέρος κάποιου public API και μπορεί να αλλαχτεί άφοβα. - Μη χρησιμοποιείς το
!global
flag στο root level γιατί μπορεί μελλοντικά να θεωρηθεί συντακτική παράβαση στη Sass.
Extend
- Να επεκτείνεις μόνο placeholders, όχι πραγματικούς CSS selectors.
- Να επεκτείνεις έναν placeholder όσο το δυνατόν λιγότερες φορές για να αποφύγεις παρενέργειες.
Αν εκτίμησες τα Sass Guidelines, στήριξε την προσπάθεια.
Υποστηρίξτε το Sass Guidelines
Σχόλια
Η CSS είναι ζόρικη γλωσσα, γεμάτη με hacks και παραξενιές. Εξαιτίας αυτού, θα πρέπει να περιέχει αρκετά σχόλια, ειδικά αν εσύ ή κάποιος άλλος έχει σκοπό να διαβάσει τον κώδικα σε μισό με ένα χρόνο από τώρα. Μην αφήσεις τον εαυτό σου ή κάποιον άλλον να έρθει σε αυτή τη θέση: δεν-υπάρχει-περίπτωση-να-το-έγραψα-εγώ-αυτό-για-τον-θεόοοο.
Δεν έχει σημασία ποσο απλή απλή μπορεί να μοιάζει η CSS, υπάρχει πάντα χώρος για σχόλια. Αυτά θα μπορούσαν να εξηγήσουν:
Σίγουρα έχω ξεχάσει να αναφέρω και άλλες περιπτώσεις. Τα σχόλια απαιτούν πολύ λίγο χρόνο αν τα γράψεις την ώρα που γράφεις τον κώδικα, γι’αυτό καλό θα ήταν να μην διστάσεις να τα γράψεις την εκείνη τη στιγμή. Το να επιστρέψεις μετά για να γράψεις σχόλια δεν είναι μονο εξωπραγματικό αλλα και υπερβολικά ενοχλητικό.
Γράφοντας Σχόλια
Ιδανικά, κάθε CSS ruleset πρέπει να προηγείται απο ενα ένα C-style σχόλιο εξηγώντας το νόημα του CSS μπλοκ. Αυτό το σχόλιο επίσης φιλοξενεί αριθμημένες διευκρινίσεις σχετικά με συγκεκριμένων τμημάτων του ruleset. Για παράδειγμα:
Πρακτικά οτιδήποτε δεν είναι προφανές με την πρώτη ματιά πρέπει να έχει σχόλια. Υπάρχει πάντα χώρος για παραπάνω documentation. Να θυμάστε πως ποτέ δεν θα έχετε σχολιάσει αρκετά, γι αυτό γράψτε όσα περισσότερα σχόλια μπορείτε για οτιδήποτε θεωρείται σημαντικό.
Όταν σχολιάζετε ένα τμήμα σχετικό με την Sass, χρησιμοποιείστε inline Sass σχόλια αντί για σχόλια C-style block ετσι ώστε αυτά να μην εμφανιστούν στο τελικό αποτέλεσμα, ακόμα και σε λειτουργία expanded κατα την διάρκεια ανάπτυξης του κώδικα.
Σημείωση ότι αυτός ο τρόπος αντιμετώπισης των πραγμάτων υποστηρίζεται επίσης απο τα CSS Guidelines στο Commenting κεφάλαιο.
Documentation
Κάθε μεταβλητή, συνάρτηση, mixin και placeholder τα οποία έχουν ως σκοπό να ξαναχρησιμοποιηθούν παντού στο code base σας πρέπει να έχουν documentation στο πλαίσιο του global API χρησιμοποιώντας το SassDoc.
Απαιτούνται τρία slashes (
/
).Το SassDoc έχει δύο σημαντικούς ρόλους:
Παρακάτω μπορείτε να δείτε ένα παράδειγμα ενός mixin το οποίο είναι εκτενώς documented με το SassDoc: