Code Guidelines

Project structure

Projects should be organised according to the following structure:

craft/
app/
config/
plugins/
public_html/
resources
css/
fonts/
img/
js/
min/
sass/
templates/
uploads/
index.php .htaccess
config.codekit
_site.details.md .gitignore

Craft

  • craft - The Craft CMS folder.
  • craft/app - Core files used by Craft - do not alter any files in this directory.
  • craft/config - Configuration files for Craft, including database settings, general settings and license file.
  • craft/plugins - Where all Craft plugins get installed.

Site Files

  • public_html - The root of your web directory - this is where your Mamp Pro host should point to.
  • public_html/resources - This contains all assets for the site, including pre-compiled Sass, Javascript, images, fonts, along with the source Sass and Javascript files.
  • /public_html/resources/css - Compiled and minified Sass. Do not edit these files - they will be overwritten.
  • /public_html/resources/fonts - Any local fonts, most commonly icon fonts.
  • /public_html/resources/img - Any non-user editable images needed for the site.
  • /public_html/resources/js - All Javascript files. Minified and concatenated version are stored in the min/ subdirectory.
  • /public_html/resources/sass - All Sass files should be placed here.
  • /public_html/uploads - Where all Craft Asset sources should point to. This will be where Craft stores all user uploads.
  • /public_html/templates - Where the Twig-based Craft templates reside. These are the templates that make the website.
  • /public_html/index.php - Craft's index.php file. Store the domain names for multi-environment setup.
  • _site_details.md - Details of the production server, hosting account and domain. Not to be uploaded to any server.

Version control

We use Git to manage our version control. It keeps track of all our code changes and stores them in central Beanstalk repositories.

A quick breakdown of our versioning and branching philosophy:

master

Where all changes should be made.

staging

Any change to the staging branch will be automatically pushed to our staging server.

production

Changes to the production branch should only be made after thorough local testing. Changes will not be pushed to the production server automatically, and must be done manually through the Beanstalk user interface.

Additional branches can be made freely, and there are no naming conventions for these. Branches should be made when undergoing heavy refactoring of work, or breaking changes, so as not to effect the master branch.

Markup

We use standard HTML5 for markup and favour using class names over id's due to specificity issues. Any identifier whether it be a class name or id, should well describe the element without being too verbose, and separate words with hyphens.

All links to assets should be preceeded by a / to reflect the path being from the web root. This should also be the case for relative links.

Header

While each site may vary in some fashion, the following boilerplate should be used for any page header:

<!doctype html>
<html lang="en">
<head>
    <!-- Responsive-ness -->
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- SE-Oh -->
{{ craft.sproutSeo.optimize() }}
<meta name="google-site-verification" content="" /> <meta name="designer" content="www.sgroup.com.au" /> <meta name="author" content="{{ siteName }}" /> <meta name="dcterms.rightsHolder" content="Copyright {{ siteName }} {{ now | date('Y') }}. All rights reserved.">
<!-- Favicon --> <link rel="shortcut icon" type="image/x-icon" href="/resources/img/favicon.ico">
<!-- Google Fonts -->
<!-- CSS --> <link href="/resources/css/style.css" media="all" rel="stylesheet" /> </head>

We use the HTML5 doctype, and importantly, the X-UA-Compatible meta tag needs to be first in order to ensure Internet Explorer is never put into Compatibility Mode.

We use Sprout SEO to handle title, and meta description and keyword tags. Ancillary meta tags as shown are also useful.

A favicon should be created for any site, in an .ico format. While Google Fonts is the preferred font service, occasionally Typekit fonts will be loaded, and should be placed in the corresponding area.

Body

The main body tag should have an id set thats specific to the page. In fact, we prefix the page slug with page- to ensure it is indeed unique. Only a single class is required, and that is preload. Additional classes should be added where necessary and applicable.

<body id="page-project" class="preload category-creative entry-super-project">

Content

Page components are commonly separated into blocks, and follow a basic structure as below:

<div class="wrap-header">
<div class="container">
<div class="row">
<div class="col col-md-6"></div>
</div>
</div>
</div>

Page components should be prefixed with wrap- and clearly define the purpose of the particular block. You may notice the rest of the structure is similar to Bootstrap, which is what our grid framework is based on. As such, any additional class names or structure should follow similar conventions as popularised in Bootstrap.

Footer

The footer is very brief, and is for including any Javascript code before the final body tag.

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="/resources/js/min/jquery.min.js"><\/script>')</script>
<script src="/resources/js/min/main.min.js"></script>
</body>
</html>

Spacing between tags

Each nested HTML tag should appear on its own line, unless the declaration is very brief (a list item wrapping a anchor element for example). Each line of HTML must not exceed 100 characters long, and all content should be properly indented with tabs. Please refrain from using HTML comments inside the body.

Each end tag should be followed by an empty line in the case more elements follow directly afterwards. See below to illustrate best practices.

// Bad
<div class="container">
    <span class="block"><h1>Heading</h1></span><span class="main"></span>
</div>

// Good
<div class="container">
    <span class="block">
        <h1>Heading</h1>
    </span>

    <span class="main"></span>
</div>

// Permissible
<ul>
    <li><a href="#">Link</a></li>
    <li><a href="#">Link</a></li>
</ul>


CSS

All styles are written using Sass. All source files can be found in /resources/sass/.

We have build a custom framework for all our web projects, based on Skeleton, Skyline and Bootstrap. The framework's only dependancy is Bourbon, which is used for mixins and vendor prefixing. We use a highly modular approach when authoring our Sass and break all of our pieces into files. This helps keep things organized and easy to modify.

Every element group, component, and module should have it's own file where we define everything except colour. All colour directives should be a part of the theme folder (also broken up into elements and components).

We support all modern desktop and mobile browsers including Internet Explorer 10 and up.

Framework

While we may call it a framework, we haven't build it to be a drop-in solution that you use variables to configure (ie, Bootstrap or Foundation). Instead, to be far more flexible, you should feel free to modify any of the files directly to fit to the current site's requirements. In this sense, the framework can be considered a 'living framework'.

For example, instead of changing a few variables to style a button for a site, you can edit the _button.scss file directly. This means that we don't have to overcomplicate the framework by providing variables for everything, and giving the ultimate flexibility to the developer.

There are essentially 5 layers to the framework:

  • Base contains global settings, variables, resets, and mixins.
  • Elements contains all the global styling for basic stand-alone elements; such as links, quotes, tables, and text.
  • Layout contains structural helper classes like .container, which restricts content to a consistent max-width, and a responsive grid system as well.
  • Site is where site-specific styles should be placed for the site you're working on. These include global files like the site header and footer, but also other reusable components.
  • Vendor should be where you keep any third-party styles. These should be renamed to start with an underscore and with the .scss extension. This prevents Codekit from generating a separate css files for each third-party Sass file. Instead, we want to finish up with a single CSS file containing all our code.

style.css

This is the main file that pulls in all the partials and compiles into css/style.css, which is minified and concatenated. The header of this file should look similar to the below:

// ==========================================================================
// Website Name - http://sitename.com.au // Author: Josh Crawford - http://sgroup.com.au/
// ==========================================================================
// Custom Sass framework for S. Group web projects @import "framework";
// Add all third-party stylesheets here @import "vendor/fontello";
// ========================================================================== // Site Styles // ==========================================================================
body {
}
// ========================================================================== // Header // ==========================================================================
.wrap_header {
}

The Website Name should be updated to reflect the URL of the site you're working on, along with the primary author. Include any third-party frameworks below the line that imports the previously mentioned framework.

All well-defined areas of the page should start with the 3-line comment as per above. These should be used to mark only block-level components of the page such as the site header, site footer, and any other content blocks.

If you wish to separate two relatively different sections within one of these logical blocks, please use the slightly briefer 3-line comment:

//
// Special Menu
//

Of course, you should also use as many single line comments (//) as possible to describe your code. Please note that we do not use the traditional /* */ CSS commenting tags.

CSS Declarations

Each declaration block must have a single declaration on each line - no exceptions. Attribute declarations should be indented by a single tab, and each line must end with a semicolon. The opening brace should be on the first line with the selector, following a space. The end brace should also be on its own line, followed by a empty line. The end of a block (as described above) should allow for at least 3 blank lines. If using multiple selectors, please define each on a new line.

// Bad
.my-class { font-size: 10px; }
.another-class, .yet-another-class { font-weight: 600; margin: 0 20px 0 10px }
// Good .my-class { font-size: 10px; }
.another-class, .yet-another-class { font-weight: 600; margin: 0 20px 0 10px }

Media Queries

Media queries should be defined inline with the selector you wish to target. This can be achieved using the provided mixins. Media queries should always be defined at the end of the parent selector block with an empty line above it, separating it from rules for the parent selector.

.menu {
    margin: 20px 0;
@include breakpoint-min($breakpoint-ms) { margin: 10px 0; }
@include breakpoint-min($breakpoint-xs) { margin: 0; } }

Pseudo-classes

When defining pseudo-classes on elements, they should utilise Sass's parent reference selector to allow these definitions to be nested under the same selector. Styles for hover, active, before, after and other pseudo-classes should be kept with the parent selector. Pseudo-classes should always be defined at the end parent selector block (above Media Queries however) with an empty line above the selector, separating it from rules for the parent selector. If using multiple selectors, please define each on a new line.

// Bad
a {
    color: red;
}
a:hover { color: blue; }
// Good
a { color: red;
&:focus, &:hover { color: blue; } }

A word on nesting - please use nesting sparingly, if at all - unless for the situation described above. We find that unnecessarily nesting declarations doesn't allow for easy code re-use.



Javascript

Like our CSS and HTML, we try to keep our JavaScript modular so you can use only what you need.

All Javascript is concatenated and minified to provide optimum performance for pages, with the exception of jQuery, which is served from Google's CDN. The final concatenated and minified file is stored in resources/js/min/main.min.js

A single file - main.js contains all Javascript code. A typical main.js will look similar to the below:

// General
// @codekit-prepend "vendor/_collapse.js"
// Slider/Carousels // @codekit-prepend "vendor/_OwlCarousel.js"
$(document).ready(function() { // Fixes initial transitions firing on page load $('body').removeClass('preload');
// ---------------------------------------- // THIRD-PARTY PLUGIN CONFIG // ----------------------------------------
// ---------------------------------------- // GLOBAL SCRIPTS (header/footer, etc) // ----------------------------------------
// ---------------------------------------- // HOMEPAGE-SPECIFIC SCRIPTS // ----------------------------------------
});

You'll first notice that we are using @codekit-prepend to import our third-party scripts into the main.js file. You can choose to either remove the import line for script you won't use, or simply remove the @ character to not include it.

Further down, we have any code depending on the included plugins wrapped in a $(document).ready() call. All third-party plugin instantiation and configuration should be placed under the defined header. Global functions for site-wide functionality (header, footer, etc) should also be placed under the respective heading. Code specific to a particular page or template should be clearly commented, by using similar comment blocks.

Third-party scripts

We organize all third-party scripts like jQuery plugins in public_html/resources/js/vendor/. For a typical project, there are a collection of hand-picked third-party libraries we use. Not all are necessarily included in the final code however.

All files should be renamed to start with an underscore. This prevents Codekit from generating a minified file for each Javascript file in your resources directory. Instead, we want to finish up with a single Javascript file containing all our code.

When selecting your own Javascript third-party components, please try to select well-supported, responsive and lean plugins to ensure the total Javascript payload doesn't get too overwhelming.