-
Notifications
You must be signed in to change notification settings - Fork 26
CSS Styleguide
!! IN PROGRESS !!
- 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
usinghxLowerCamelCase
notation
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 asbackground-color: lime;
-
(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);
}
}
draft
The design of this structure is to allow for CSS specificity to gradually increase as you read the CSS from top to bottom.
-
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;"
/* ... */
}
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;
}
Levels the playing field across browsers.
example:
html {
box-sizing: border-box;
}
*,
*::before,
*::after {
box-sizing: inherit;
}
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;
}
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
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; }
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.
Element + Property + Modifier (EPM)
Naming should follow one of the following formats:
--hxPropName: value;
--hxPropName--modifier: value;
--hxElementName-propName: value;
--hxElementName-propName--modifier: value;
-
Prefix
- always use
--hx
prefix to avoid naming conflicts with 3rd party CSS
- always use
-
Element (optional)
- always
UpperCamelCase
- always followed by a single hyphen (
-
) to separate from Property
- always
-
Property
-
lowerCamelCase
when Element present- e.g.,
backgroundColor
,borderColor
,boxShadow
, etc.
- e.g.,
- otherwise
UpperCamelCase
- e.g.,
BackgroundColor
,BorderColor
,BoxShadow
, etc.
- e.g.,
-
-
Modifier (optional)
- always lead with double hyphen (
--
) - always
lowerCamelCase
- useful to differentiate states
- omit for default state
- e.g.,
--hover
,--focus
,--active
, etc.
- always lead with double hyphen (
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;
}
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
*/
}