Skip to content

CSS Styleguide

Ryan Johnson edited this page Oct 23, 2019 · 15 revisions

!! IN PROGRESS !!

Standards

  • TODO: separate each bullet point into its own section
  • 2 spaces per indent. No tabs.
  • CSS imports before all other content in stylesheet (including banner comments)
  • Always quote URLs and attribute values.
  • Always use double-quotes (matches HTML)
  • No unit for 0 values.
  • one selector per line
  • one property per line
    • never on same line as a selector
  • open block on same line as last selector
  • close block on line after last property in block
  • one space after colon. no space before.
  • one space after comma. no space before.
  • alphabetize property names
  • Always prefix classes with hx using hxLowerCamelCase notation

Use Shorthand Properties with Caution

Although CSS shorthand properties are useful to reduce the size of compiled assets, related properties may get defaulted to a value that is not desirable.

  • Shorthands have long effects
  • Double-check expanded properties being set by CSS shorthand
    • background: lime; isn't the same as background-color: lime;

Custom Properties

(a.k.a. CSS Variables) Not all browser support custom properties, so you'll need to make sure you have a fallback property for legacy browsers.

IE Edge Chrome Safari Firefox Opera
n/a 15+ 49+ 9.1+ 31+ 36+
.hxFoobar {
  /* Fallback Styles (legacy browsers) */
  background-color: gray;

  /* Modern Styles (modern browsers) */
  /* overrides above, legacy browsers ignore it */
  background-color: var(--background-color, gray);
}

Alternatively, you could start with the fallback and use a @supports query to apply CSS Custom Properties. (The custom property and value used in the query just needs to be valid CSS and doesn't need to match the exact custom property and value.)

/* Fallback Styles */
.hxFoobar {
  background-color: gray;
}

/* Modern Styles */
@supports (--modern: true) {
  .hxFoobar {
    background-color: var(--background-color, gray);
  }
}

Modified ITCSS

draft

ITCSS Cheatsheet

The design of this structure is to allow for CSS specificity to gradually increase as you read the CSS from top to bottom.

1. Configuration

  • CSS Imports
    • Must be at the very top of the file to work properly across browsers.
  • Global Variables (LESS or CSS variables)
    • Color Palette
    • Fonts
    • Spacing
    • etc.

example:

/* LESS Variables */
@border-radius: 2px;
@font-size: 16px;
@red-900: #d32f2f;
/* ... */

/* CSS Variables */
:root {
  --red-900: @red-900; // Generated CSS: "--red-900: #d32f2f;"
  /* ... */
}

2. Mixins

Declared immediately after variables to provide quick creation of CSS styles.

example:

.rounded-top() {
  border-top-left-radius: @border-radius;
  border-top-right-radius: @border-radius;
}

3. Resets

Levels the playing field across browsers.

example:

html {
  box-sizing: border-box;
}
*,
*::before,
*::after {
  box-sizing: inherit;
}

4. Base

CSS to define basic appearance of unclassified elements to come.

  • Element Selectors ONLY
  • No Class Selectors

example:

html {
  font-family: 'Roboto', sans-serif;
  font-size: @font-size;
}

5. Components

Though much of the styling for many custom elements will be embedded into their individual ShadowDOM, LightDOM styling may still be necessary.

Components that will not be made into custom elements will still have CSS defined using the BEM naming convention in this layer.

  • Class Selectors ONLY
  • NO Element Selectors

6. Helpers

CSS classes to aid consumers in building their site.

  • Class Selectors ONLY
  • NO Element Selectors

example:

.text-left { text-align: left; }
.text-right { text-align: right; }
.text-center { text-align: center; }

7. Overrides

There will be times where we'll need to use !important (though it should be extremely limited). This layer is where you'd add such styling.

  • This is the ONLY level where !important should be seen.

Theming API

Custom Property Naming Convention

Element + Property + Modifier (EPM)

Naming should follow one of the following formats:

--hxPropName: value;
--hxPropName--modifier: value;
--hxElementName-propName: value;
--hxElementName-propName--modifier: value;
  1. Prefix
    • always use --hx prefix to avoid naming conflicts with 3rd party CSS
  2. Element (optional)
    • always UpperCamelCase
    • always followed by a single hyphen (-) to separate from Property
  3. Property
    • lowerCamelCase when Element present
      • e.g., backgroundColor, borderColor, boxShadow, etc.
    • otherwise UpperCamelCase
      • e.g., BackgroundColor, BorderColor, BoxShadow, etc.
  4. Modifier (optional)
    • always lead with double hyphen (--)
    • always lowerCamelCase
    • useful to differentiate states
      • omit for default state
      • e.g., --hover, --focus, --active, etc.

SEEK: 👍

:root {
  --hxBackgroundColor: black;
  --hxBackgroundColor--hover: blue;
  --hxBackgroundColor--active: navy;
  --hxBackgroundColor--active-focus: cyan;
}

AVOID: 👎

hx-thing {
  /* may conflict with 3rd party CSS */
  --backgroundColor: black; 

  /* confusing prefix + prop capitalization */
  --hxbackgroundColor--hover: blue; 

  /* too BEM-like and doesn't adhere to '-' delimiter */
  --hxThing__backgroundColor: white;
}

OTHER

DO

hx-custom-element { 
  // No other way around this. This is vanilla CSS. ^_^
}

.hxModifier { 
  /* 
    All CSS classes should act as modifiers to their applied element. 
    If you need something to differentiate a modifier from a block, 
    chances are you need to create a custom element.
  */ 
}

DON'T

.hx-block-element { 
  // Too similar to kebab-case-element selector
}

.hxBlockElement { 
  // You likely need a custom element.
}

.hxBlockElement--modifierClass { 
  /* 
    Class is too verbose, bloats HTML 
  */
}
Clone this wiki locally