-
Notifications
You must be signed in to change notification settings - Fork 3
sass styleguide
#Grillo Framework Sass Styleguide Note: Every line of code should appear to be written by a single person, no matter the number of contributors.
##Syntax
- Use soft tabs with two spaces—they're the only way to guarantee code renders the same in any environment.
- When grouping selectors, keep individual selectors to a single line.
- Include one space before the opening brace of declaration blocks for legibility.
- Nested elements should be indented once (two spaces).
- Place closing braces of declaration blocks on a new line.
- Include one space after : for each declaration.
- Each declaration should appear on its own line for more accurate error reporting.
- End all declarations with a semi-colon. The last declaration's is optional, but your code is more error prone without it.
- Comma-separated property values should include a space after each comma e.g.,
box-shadow
. - Comma-seperated function arguments should be seperated with comma only, not with spaces e.g.
rgba(14,231,3,.3);
. - Don't prefix property values or color parameters with a leading zero e.g., use
.5
instead of0.5
and-.5px
instead of-0.5px
. - Avoid specifying units for zero values, e.g.,
margin: 0;
instead ofmargin: 0px;
. - Use shorthand whenever possible, e.g.,
font
instead offont-size
andfont-family
. - Avoid specifying units for line-heights. Unit-less
line-height
is preferred because it does not inherit a percentage value of its parent element, but instead is based on a multiplier of the font-size. - Use
!important
ONLY when necessary, but as much as possible avoid using it. - Use single quotes and never double quotes.
- Stay consistent with units, e.g., do not use a mixture of
rem
andpx
for typography, only use one or the other. - Use the
rem-calc()
function to translate pixel units to rem. It also converts to any other unit based on environmental factors, so it is recommended that you use it instead of directly writing the unit. - Do not include a line-break after related declarations.
- Separate unrelated declarations with one line-break.
- Don't include vendor prefixes. It should be automatically added on compilation by the grunt tool.
// Not recommended
.selector, .selector-secondary, .selector[type=text] {
padding:15px;
margin:0px 0px 15px;
border: 1px solid #ccc;
background-color:rgba(0, 0, 0, 0.5);
background-repeat:none;
-webkit-border-radius:5px;
-moz-border-radius:5px;
-o-border-radius:5px;
border-radius:5px;
box-shadow:0px 1px 2px #CCC,inset 0 1px 0 #FFFFFF
}
// Preferred
.selector,
.selector-secondary,
.selector[type='text'] {
padding: rem-calc(15);
margin-bottom: rem-calc(15);
border: rem-calc(1) solid #ccc;
background: rgba(0,0,0,.5) none;
border-radius: rem-calc(5);
box-shadow: rem-calc(0 1 2) #ccc, inset rem-calc(0 1 0) #fff;
}
##Inline Styles You should only use inline styles to load declarations for content "above the fold". This is only an advantage if your CSS document is very small. It is disadvantageous and inconvenient for larger stylesheets.
##Style Attributes Avoid using the style attribute in HTML elements. On occasion, it is appropriate to use it, but it should be avoided 95% of the time.
<!-- Avoid this -->
<span style="background-color:#fff; color:#555;"></span>
##Color Properties and Values Always use either RGBA or RGB color values whenever possible. Write values in all lowercase with no space.
color: rgba(72,74,76,1);
color: rgb(72,74,76);
When writing hex values, use all lowercase values, e.g., #ed7f3b
, and shorthand whenever possible, e.g., #fff
instead of #ffffff
. Always define variables for commonly used colors and write functions, e.g., fadeOut($red,25%);
. Don't include spaces after commas within rgb(), rgba(), hsl(), hsla(), or rect() values. This helps differentiate multiple color values (comma, no space) from multiple property values (comma with space).
##Selectors
- Use class selectors and avoid ID selectors.
- Use classes over generic element tag for optimum rendering performance.
- Never use the universal selector. This should only be used in the CSS reset stylesheet.
- Avoid combined type selectors, also known as descendant selectors, e.g.,
ul li a
- Always group several selectors that share the same declarations together, e.g.,
h1, h2, h3, h4, h5, h6
.
###Class Selector
Unless a specific case requires otherwise, always use class selectors. Do not combine class selectors with type selectors, e.g., h1.bold
; instead use .heading-bold
.
###ID Selector
Avoid ID selectors and instead use class selectors. Never combine ID selectors with type selectors, e.g., h1#primary
.
###Type Selector
Avoid using lengthy type selectors, e.g., ul li a
. Since browsers read selectors from right to left, not left to right as humans do, longer selectors can greatly impact performance.
Quote attribute values in selectors, e.g., input[type='text']
. They’re only optional in some cases, and it’s a good practice for consistency.
###Pseudo-elements and pseudo-class When grouping pseudo-elements and classes with other selectors, include them last.
Always declare the pseudo elements :before first and :after second, but declare them after the element they affect. Include the content property first in the declaration.
When combining pseudo-classes, use two colons for the second class, e.g., a:visited::hover
.
##Class names
- Keep classes lowercase and use dashes (not underscore or camelCase). Dashes provide for readability and natural breaks in related classes, e.g.,
.btn
and.btn-danger
. - Be specific and concise when naming classes. Always use meaningful names that describe the action or functionality of a class rather than is appearance unless where necessary, e.g.
.btn-danger
instead of.btn-red
. - Keep classes as short and succinct as possible. Abbreviate some class names, but make sure anyone can understand the class, e.g.,
.btn
instead of.button
. - Avoid excessive and arbitrary shorthand notation.
.btn
is useful for button, but.s
doesn't mean anything. - Prefix classes based on the closest parent element or base class.
- Always use a base class for elements with different states. If you have a success and a failure label, make the base class
.label
and the classes.success
and.warning
will give it the specific styles needed for different states. - Use
.js-*
classes to denote behavior (as opposed to style), but keep these classes out of your CSS.
##Comments Code is written and maintained by people. Ensure your code is descriptive, well commented, and approachable by others. Great code comments convey context or purpose. Do not simply reiterate a component or class name.
Never simply reiterate a component or selector name. Always write short comments in the third person, present tense. Longer comments may be written in any person or tense. Use inline comments to add notes after certain properties.
.example {
@base: 25px;
width: round((@base*2)/3.14); // => 16.0px
background: #555; // background will match footer
}
Never feel limited to one line with comments; use as many lines as necessary to explain the function/purpose of a declaration. It is rare to regret leaving a comment in code. It is either helpful or easily ignorable. Comments get stripped when compiling to compressed code, so there is no cost.
Use //
for comment blocks (instead of /* */
). Comments denoted by // are hidden in the generated CSS, whereas /* */ are passed along to the generated source.
##Sass Declaration Order
- Scoped variables.
- Selector extensions with
@extend
. Knowing right off the bat that this class inherits another whole set of rules from elsewhere is good. - Mixin inclusions with
@include
with the exception of media-query stuff. You should also group user-authored @includes and vendor-provided @includes seperately, seperating them with a line break. - Regular property: value pairs.
- Pseudo-class/element nesting with & after an empty line.
- Regular selector nesting after an empty line.
- Media query stuff (with or without a mixin), but it is recommended that you use mixins.
.element {
$scoped-variable: whatever;
@extend .other-element;
@include mixin($argument);
property: value;
&:pseudo {
/* styles here */
}
.nested {
/* styles here */
}
@include breakpoint($size) {
/* styles here */
}
}
##Regular Styles Declaration Order Start from the "outside and work back in". Group related properties in the following order:
- Positioning
- Box model (including flexbox related properties)
- Typographic
- Visual
- Functional
- Pseudo-elements/classes
- Nested rulesets
Positioning comes first because it declares the nature of an element. The box model comes next as it dictates the dimensions and placement of an element. Typography and visual declaration declarations take place on the "inside" of the element and generally do not affect the "outside". Functional declarations (animations, transitions, transforms, etc.) are last. Include (after one full line-break) your nested rules and pseudo elements last. In the case that a declaration contains the content property, include it first. Take a look at Recess.
##Variables
###Variablize All Common Numbers, and Numbers with Meaning If you find yourself using a number other than 0 or 100% over and over, it likely deserves a variable. Since it likely has meaning and controls consistency, being able to tweak it enmasse may be useful.
If a number clearly has strong meaning, that's a use case for variablizing as well.
Variables specific to a specific file are placed at the top of the file.
###Variablize All Colors Except perhaps white and black. Chances are a color isn't one-off, and even if you think it is, once it's in a variable you might see uses for it elsewhere. Variations on that color can often be handled by the Sass color functions like lighten() and darken() - which make updating colors easier (change in one place, whole color scheme updates).
##Media Queries
###Nest and Name Your Media Queries The ability to nest media queries in Sass means 1) you don't have to re-write the selector somewhere else which can be error prone 2) the rules that you are overriding are very clear and obvious, which is usually not the case when they are at the bottom of your CSS or in a different file.
##Nesting
###Maximum Nesting: Four Levels Deep Chances are, if you're deeper than that, you're writing a crappy selector. Crappy in that it's too reliant on HTML structure (fragile), overly specific (too powerful), and not very reusable (not useful). It's also on the edge of being difficult to understand. If you find yourself going further, think about reorganizing your rules (either the specificity needed or the layout of the nesting).
// Not recommended
.profile {
background: #dedede;
color: #3a3a3a;
.heading {
font-size: rem-calc(18);
a {
color: #00f;
&:hover {
color: lighten(#00f, 10%);
i {
line-height: 1;
}
}
}
}
}
// Preferred
.profile {
background: #dedede;
color: #3a3a3a;
}
.profile-heading {
font-size: rem-calc(18);
}
.profile-link {
color: #00f;
&:hover {
color: lighten(#00f, 10%);
i {
line-height: 1;
}
}
}
If you really want to use tag selectors because the class thing is getting too much for you, you may want to get pretty specific about it to avoid undesired cascading. And possibly even make use of extend so it has the benefit on the CSS side of re-usability.
###Maximum Nesting: 50 Lines If a nested block of Sass is longer than that, there is a good chance it doesn't fit on one code editor screen, and starts becoming difficult to understand. The whole point of nesting is convenience and to assist in mental grouping. Don't use it if it hurts that.
##File Organisation
One of the most useful features of Sass is being able to separate your stylesheets into separate files. You can then use the @import
directive to include the source of your individual files into one master stylesheet.
This helps to keep the styles organised and easy to maintain when needed without having to go through one extra large file containing thousands of lines of styles.
All your styles should be split into many small modular files. However, do not overdo it. All of the individual files that are imported into the main stylesheet are prefixed with an underscore. This tells the Sass compiler that they are to be imported to another file and not to be compiled on their own.
Also take note that all file and folder names within each sub-project should generally be in plural form because they contain multiple files.
In general, the SCSS file organization should follow something like this:
scss/
|
|-- global/ # Global stuffs
| |-- components/ # Partials
| | |-- _base.sass
| | |-- _buttons.scss # buttons
| | |-- _figures.scss # figures
| | |-- _grids.scss # grids
| | |-- _typography.scss # typography
| | |-- _reset.scss # reset
| | ...
| `-- _all.scss
|
|-- desktop/ # Desktop sub-project
| |-- modules/
| |-- components/
| |-- pages/
| `-- _base.scss # imports for all mixins + global project variables
|
|-- events/ # Events sub-project
| |-- modules/
| |-- components/
| |-- pages/
| `-- _base.scss
|
|-- vendor/ # CSS or Sass from other projects
| |-- selectize/
| | |-- _selectize.scss
| |-- _colorpicker-1.1.scss
| |-- _jquery.ui.core-1.9.1.scss
| ...
|
|-- styles.scss # Primary stylesheets for each project
|-- events.scss
`-- movies.scss
###Primary project Sass file Each sub-project would have a primary SCSS file to import all the necessary styles and mixins and compile to output the required CSS file. This file is just a table of content. You should not write any styles directly in them. Force yourself to keep all styles organized into component parts. Within this file, list vendor dependencies first, then author global dependencies, then components, then pages. The content of a typical primary Sass file would look like this:
@import "desktop/base";
// Vendor Components
@import "vendor/selectize/selectize";
// Global Components
@import "global/components/gallery";
@import "global/components/productlist";
//Desktop Components
@import "global/components/textchanger";
@import "global/components/rating";
//Desktop Pages
@import "desktop/pages/home";
@import "desktop/pages/listing";
@import "desktop/pages/details";
@import "desktop/pages/directions";
@import "desktop/pages/faq";
@import "desktop/pages/about";
@import "desktop/pages/products";
The stylesheets are divided into various parts, as seen in the folder structure above:
- The modules folder is reserved for Sass code that doesn't cause Sass to actually output CSS. Things like mixin declarations, functions, and variables.
- The components folder contains the various components of the project. This includes things like header, footer, gallery, links, buttons, etc.
- The pages folder contains the code for the different pages that make up the project.
###The base file The base partial within every individual sub-project is the first import in the primary Sass files. It loads up all the necessary mixins, global components and variables that will be used within the sub-project. This makes it easy to construct multiple stylesheets without the need to identify and import each individual module for each stylesheet. It might look something like this:
// Font weights
$light: 100;
$regular: 400;
$bold: 600;
// Base Font
$base-font-family: sans-serif;
$base-font-weight: $regular;
$base-font-size: 13px;
$base-line-height: 1.4;
// Fixed Font
$fixed-font-family: monospace;
$fixed-font-size: 85%;
$fixed-line-height: $base-line-height;
// Headings
$header-font-weight: $bold;
@import "../vendor/normalize";
@import "../vendor/foundation.desktop";
@import "../global/modules/colors";
@import "../global/fonts/vc-icon";
@import "../global/fonts/nexa";
@import "../global/components/rating-stars";
@import "../global/components/buttons";
@import "../global/components/links";
@import "../global/components/typography";
@import "../global/components/topbar";
##Compilation ###Locally, Compile Expanded with Line Mapping This means dev tools can tell you exactly what file and on what line rules are coming from, even if it is an imported partial. This should be taken care of by the grunt task runner during development.
###In Deployment, Compile Compressed Live websites should only ever have compressed CSS. This should be taken care of by the grunt task runner before deployment.
###*Don't Even Commit .css Files (Huh?) This might take some DevOps work, but it's pretty nice if .css files aren't even in your repository. The compilation happens during deployment. So the only thing you see in the repo are your nicely formatted hand authored Sass files. This makes the diffs useful as well. A diff is a comparison view of what changed provided by version control providers. The diff for a compressed CSS file is useless.
##Editor preferences Set your editor to the following settings to avoid common code inconsistencies and dirty diffs:
- Use soft-tabs set to two spaces.
- Trim trailing white space on save.
- Set encoding to UTF-8.
- Add new line at end of files.
For an example, click here.