...well, kind of. Here at We Can't Stop Thinking, we often find ourselves in discussions about process, patterns, and styles. It seems to be just the kind of thing developers do. As the team here is growing, we decided it was high time to mark down (get it, markdown?!?! hahaha) some of our procedures so that they may be preserved for future generations. The following is an overview of our general workflow and some of our adopted styles and should be regarded as an eternally incomplete compendium of epic magnitude (henceforth known as ICEM). We have included a few choice design patterns, syntax rules, references, and code snippets that are the result of several years of trial and error.
Instead of re-writing a bunch of well-done guides and ideas, we decided to point you to them directly. Here are a few style-guides and pattern references to look over at some point.
- Javascript
- CSS
- PHP:
The project scaffolding will vary depending on the type of application and its scope. The client-side code should however, remain consistent.
The following demonstrates a basic WCST project structure:
.
├── public
│ ├── css
│ │ ├── app
│ │ │ └── app.css
# If using SCSS/SASS :
│ │ └── scss
│ │ ├── _settings.scss
│ │ └── app.scss
# Or, if using LESS :
│ │ └── less
│ │ ├── app.less
│ ├── img
│ │ └── ui
│ ├── index.html
│ ├── js
│ │ ├── lib
│ │ └── templates
│ └── templates
Selectors that are intened for consumption via JS only shoule be prefixed with an _
underscore
<!-- Nope -->
<div id="selectorName"></div>
<div id="selector_name"></div>
<!-- Yep -->
<div id="_selector_name"></div>
Presentational classes and ids should be _
underscore separated
<!-- Nein -->
<div id="_redbox"></div>
<div id="_redBox"></div>
<div id="redBox"></div>
<div id="redbox"></div>
<div class="theRedBox"></div>
<div class="theredbox"></div>
<div class="_theredbox"></div>
<!-- Ja -->
<div id="red_box"></div>
<div class="the_red_box"></div>
Following OOCSS principles not only improves code comprehension, but it improves team-wide maintainability. Concerns for both styling and behavior as dictated by the CSS should be encapsulated and kept DRY!
When defining styles of a selector, separate layout/positioning, presentation/type, and functionality within tags
#charlie_conway_bio {
position: relative;
margin: 10% auto;
width: 25%;
height: 2em;
float: left;
font-size: 1.4em;
font-weight: 200;
text-transform: uppercase;
text-align: center;
opacity: 0.5;
transform: translate3d(0, 2%, 0);
transition: transform 122ms ease-out;
}
#charlie_conway_bio:hover {
opacity: 1;
transform: translate3d(0, 4%, 0);
}
While a majority of our projects use LESS for CSS pre-compilation, SCSS/SASS has been introduced into the workflow. WCST generally uses Foundation and in some instances Twitter bootstrap when intiating a new project or application.
/**
* Colors (LESS or SCSS)
* Use generic, yet descriptive color declarations
* Do not use standard CSS color names (http://www.w3schools.com/cssref/css_colornames.asp)
* Use camelCase for color names to ensure differentiation for CSS defaults
* **Note** this snippet uses the `$` to denote a SCSS variable, LESS uses `@`
**/
/* Bad */
$white: white;
$white: #FFF;
$coolblue: blue;
$coolblue: #0066FF;
/* Good */
$baseWhite: #FEFEFE;
$coolBlue: #0066FF;
/* -------- */
/**
* Measurements
* Use specific and decriptive names for measurements
* Use camelCase
**/
/* Bad */
$fHeight: 6em;
$scrollersize: 50%;
/* Good */
$footerHeight: 6em;
$heroScrollwerWidth: 50%;
Whether using a collection of individual files and compiling via @import()
of $include
, keep similar rules and styles grouped.
Define each segment of styles with /* === <name> === */
and insert at least 5 lines above
/* === Globals === */
html, body {
height: 100%;
}
h1 {
font-weight: 200;
}
/* ===
*
* Example Of
* A multi-line CSS comment
*
=== */
#app {
transform: rotate(98deg);
}
/* === Nav View (#nav_view) === */
#nav_view {
#nav_view_slider {
width: 50%;
a {
text-decoration: none;
}
}
}
/* === Footer (footer) === */
footer {
/* footer styles here */
}
If using SASS, follow this guide.
If using LESS, see below:
Serve @2x sprites for retina displays. Create a global class of .sprite
and define rules at the introduction of your document:
@sprite: '/path/to/sprite.png';
@sprite2x: '/path/to/sprite@2x.png';
/* Declare .sprite class */
.sprite{
display: block;
background: url(@sprite) no-repeat;
text-indent: -9999em;
}
/* Retina display media query */
@media only screen and (-webkit-min-device-pixel-ratio: 1.5),
only screen and (min--moz-device-pixel-ratio: 1.5),
only screen and (min-resolution: 240dpi){
.sprite{
background-image: url(@sprite2x);
background-size: 440px 280px; /* 1/2 the size of the original */
}
}
[ S e p a r a t e ] [ c o n c e r n s ] [ i n t o ] [ m o d u l e s ] [ ! ]
####Namespacing
Avoid pollution of the global namespace as much as possible! If using AMD, consider tying application level-events and configurations to a re-useable app
object which can then be exported and passed around as needed.
// app.js
define(['someDependency'], function () {
var app = {
api: {
urls: {
'people': {url:'/people'},
'places': {url: '/places'},
'things': {url: '/things'}
}
},
getApiUrl: function (req) {
return this.api.urls[req].url;
}
};
// Export the app object
return app;
});
// Other modules throughout your app can then use app
define(['app'], function(app) {
console.log( app.getApiUrl('people') ); // '/people'
});
If not using AMD, attach a single namespace reference to the window object for app-level access. Our example above could be re-written as:
// app.js
(function (window) {
var app = window.app || {};
app.api = {
urls: {
'people': {url:'/people'},
'places': {url: '/places'},
'things': {url: '/things'}
}
};
app.getApiUrl = function (req) {
return this.api.urls[req];
};
})(window, undefined);
// Other JS files (added *after* app.js) can then access the app object
(function (window) {
console.log( app.getApiUrl('things') ); // '/things'
})(window, undefined);
####Variable declaration & naming
Declare variables at the beginning of closures. This is important not only for readability, but it also helps to prevent the declaration of unused variables.
- Use one
var
statement - Separate each variable into its own line
- Undefined variables should be added at the end of the statement
- When possible, separate similar variables in the statement order (Example B)
// Example A
function ExampleA () {
var a = 0,
b = 1,
c;
}
// Example B
function ExampleB () {
// States
var a = 0,
b = 1,
count = 0,
// Methods
_updateCount,
_getCount;
_updateCount = function () { /*...*/ }
_getCount = function () { /*...*/ }
}
Depending on the scope of the project and the depth of requirements, the set of libraries and frameworks will change. The followin list represents libraries most commonly used in WCST project and applications.
DOM access & manipulation (default to vanilla JS first)
- jQuery
- Zepto
Utility
- LoDash – Drop in replacement for Underscore.js
- Underscore.js
Architecture/Routing/Events
- Backbone.js
- RequireJS
UI
- jQuery.transit
Templating
- Handlebars.js
Scaffolding & Build
- Grunt
- Yeoman
Node.js
- Typically, our Node.js applications use Express to fire up HTTP servers