This guide is for Tinci developers and any Tinci collaborator that will write CSS that Tinci has to later maintain.
This is a work in progress and may change in the future but for now we're happy with this.
- Tools
- Files Organization
- Bootstrap Override
- Colors
- Typography
- Mixins
- Utils
- Components
- Modifiers
- States
- JavaScript
- Syntax
- Inspiration
Don't use sprockets, use @import
instead. It allows variables and mixins sharing across files.
We may use most of what SCSS can provide, when it makes sense. Coupling ourselves to SCSS is not an issue since we're using Rails and are not planning on switching gears in the forseable future.
Nonetheless be carful of the version of SASS you're using. Some versions of Rails may lock the version of SASS thus limiting its features. If you're dealing with the design integration outside of Rails, simply make sure you're using the same SASS version than the project.
To make sure your styles are respecting the conventions, use the scss-lint tool with the following configuration:
---
linters:
NameFormat:
exclude:
- '*/_bootstrap-override.scss'
mixin_convention: '^[a-z][a-zA-Z]*(-[a-z][a-zA-Z]*\d*)?(--[a-z][a-zA-Z]*)?$'
mixin_convention_explanation: Mixins should be of the form myMixin
placeholder_convention: '.+'
variable_convention: '^[a-z][a-zA-Z]*(-[a-z][a-zA-Z]*\d*)?(--[a-z][a-zA-Z]*)?$'
variable_convention_explanation: >
Variables should be of the form $color-someColorName or $fontSize-small
PlaceholderInExtend:
enabled: false
SelectorFormat:
convention: '^[a-z][a-zA-Z]*(-[a-z][a-zA-Z0-9]*)?$'
convention_explanation: >
Selectors should be of the form .componentName or
.componentName-propertyName
SpaceBeforeBrace:
exclude:
- '*/_bootstrap-override.scss'
StringQuotes:
style: double_quotes
UrlFormat:
enabled: false
Files follow a simple layout:
app/assets/stylesheets/
base/
_bootstrap_override.scss
_colors.scss
_headings.scss
_layout.scss
_mixins.scss
_type.scss
_utils.scss
components/
_my-component.scss
_an-other-component.scss
admin.css.scss
application.css.scss
The application
and admin
CSS file will respectively import their own components.
The _bootstrap_override.scss
file contains all overrides to Bootstrap. As much as possible, try to use SCSS variables — you can find a list of those variables in the bootstrap-sass repository.
NOTE: Always use a 24-column grid by setting $grid-columns: 24;
. It gives more flexibility on sizes while keeping the division capacity of 12.
$grid-columns: 24;
This file is imported after the colors and type definitions, you can set $brand-primary
and all other BS variables based on the defined values.
$brand-primary: $color-darkBlue;
$font-family-sans-serif: $font-primary;
Every color used in the application must be referenced in the _colors.scss
file.
All basic colors must be of the form $color-someName
. If you need to define a special variant for a component use $color-someName--componentName
(avoid it unless necessary).
Use the #RRGGBB
format for main colors and the shortand version (#RGB
) when possible.
If you are to create a variation of a color, like darker or lighter use the $color-nameDark
or $color-nameLight
naming. For instance if you have a $color-facebookBlue
color, the darker variant would be $color-facebookBlueDark
.
If you need to define a transparent color, use the following:
$color-black: #000;
$color-black20: transparentize($color-black, .8);
$color-black15: transparentize($color-black, .85);
// For more details on transparentize see:
// http://sass-lang.com/documentation/Sass/Script/Functions.html#transparentize-instance_method
Everything related to typography should be placed in the _type.scss
file.
Font families should be written as $font-primary
, $font-second
and $font-special
. Only use $font-second
if needed, simply use $font-primary
if you use a single font family.
$font-primary: "Helvetica Neue", Helvetica, Arial, sans-serif;
$font-second: Georgia, "Times New Roman", Times, serif;
Fonts imported from external services like Google or gems like FontAwesome should be place at the top of this file:
@import url('//fonts.googleapis.com/css?family=Oswald:300,700');
@import url('//fonts.googleapis.com/css?family=Roboto:300&subset=latin,latin-ext');
@import 'font-awesome-sprockets';
@import 'font-awesome';
All font sizes used across the application should be listed in the following manner:
// The following sizes are an example
$fontSize-micro: 8px;
$fontSize-smallest: 10px;
$fontSize-smaller: 12px;
$fontSize-small: 16px;
$fontSize-base: 18px;
$fontSize-large: 24px;
$fontSize-larger: 32px;
$fontSize-largest: 36px;
$fontSize-huge: 50px;
$fontSize-jumbo: 60px;
All font weight should be listed as follows:
$fontWeight-thin: 100;
$fontWeight-extralight: 200;
$fontWeight-light: 300;
$fontWeight-normal: 400;
$fontWeight-medium: 500;
$fontWeight-semibold: 600;
$fontWeight-bold: 700;
$fontWeight-extrabold: 800;
$fontWeight-black: 900;
Same goes for the letter spacing and line height properties:
$letterSpacing-tight: -1px;
$letterSpacing-normal: 0;
$letterSpacing-loose: 1px;
$lineHeight-tight: 1.1;
$lineHeight-base: 1.4;
$lineHeight-loose: 1.7;
All mixins should be defined in the _mixins.scss
file.
By default you should always have those mixins defined:
@mixin xxs { @media(max-width: $screen-xs) { @content; } }
@mixin xs { @media(min-width: $screen-xs) { @content; } }
@mixin sm { @media(min-width: $screen-sm) { @content; } }
@mixin md { @media(min-width: $screen-md) { @content; } }
@mixin lg { @media(min-width: $screen-lg) { @content; } }
This file is imported after the bootstrap overrides and has access to the BS variables regarding screen sizes and breakpoints.
This mixins should be used to provide different styles for elements depending on the screen size. Always start with the mobile version and style up to large desktop:
.someComponent {
// default/mobile styles
width: 100%;
@include sm {
margin: 0 auto;
width: 80%;
}
@include md {
// inherits default and sm styles
color: red;
}
@include lg {
// inherits default, md and sm styles
color: blue;
}
}
If you need a small, independent and dedicated style (ie. .u-hidden
), you can define it in the _utils.scss
file with a selector of the form .u-utilName
.
Every element of the application should be related to a component. The goal is to encapsulate the styling logic and organize CSS properly. It makes it easier to reason about components and aspects of the site — it also gives a common vocabulary when talking about the app.
Use the .componentName-propertyName
form.
Don't use .componentName-propertyName-propertyName
. If a property has its own sub-properties, it becomes its own component but is defined in the parent component's file:
// components/_awesome-list.scss
.awesomeList {}
.awesomeListItem {}
.awesomeListItem-title {}
It may happen that you need to create a variation of a component instead of creating a whole new one. In this situation, define a component modifier with .mod-modifierName
. A modifier should never be defined separately from a component.
// components/_article.scss
.article {
// component style here
&.mod-highlithed {
// modified component style here
}
}
Similarly to modifiers, states should be defined along with their component using .is-stateName
:
.article-body {
// component style here
&.is-collapsed {
// component style when state is-collapsed
}
}
Usually those states are controlled with JavaScript or conditions.
When an element should have a specific behavior defined with JavaScript, it should have a dedicated class like .js-geocomplete
and no style should be defined for this class.
As mentioned earlier, use scss-lint to check your SCSS syntax. There are some details that scss-lint cannot check:
- In your markup, order classes like so
<div class="component mod util state js"></div>
- …
This Guide has been inspired by the following guides/articles: