Skip to content

Instantly share code, notes, and snippets.

@simonc
Last active August 9, 2017 11:46
Show Gist options
  • Save simonc/e84cf36b85c3f460f243 to your computer and use it in GitHub Desktop.
Save simonc/e84cf36b85c3f460f243 to your computer and use it in GitHub Desktop.
Tinci CSS Guide

Tinci CSS Guide

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.

  1. Tools
  2. Files Organization
  3. Bootstrap Override
  4. Colors
  5. Typography
  6. Mixins
  7. Utils
  8. Components
  9. Modifiers
  10. States
  11. JavaScript
  12. Syntax
  13. Inspiration

1. Tools

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

2. Files Organization

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.

2.1. Bootstrap Override

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;

2.2 Colors

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

2.3 Typography

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;

2.4. Mixins

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;
  }
}

2.5. Utils

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.

3. Components

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 {}

3.1 Modifiers

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
  }
}

3.2 States

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.

4. JavaScript

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.

5. Syntax

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>

6. Inspiration

This Guide has been inspired by the following guides/articles:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment