Skip to content

Latest commit

 

History

History
595 lines (507 loc) · 19 KB

STYLEGUIDE.md

File metadata and controls

595 lines (507 loc) · 19 KB

Style guide

The style guide for the HubSpot CMS boilerplate. Please use this style guide as a reference when making pull requests to the cms-theme-boilerplate repository.

Table of contents


HTML

HTML best practices

  1. Two elements should never contain the same id.
  2. Avoid inline CSS whenever possible.
  3. Avoid unnecessary parent elements/wrappers whenever possible.
<!-- Good example -->
<img class="featured-image" src="test.img" alt="Test Image">

<!-- Bad example -->
<div class="featured-image">
  <img src="test.img" alt="Test Image">
</div>
  1. Render scripts at the end of the body which can be accomplished in HubSpot using the require_js HubL function.
  2. Use unicode characters over entity refererences, with the exception of characters with special meanings.
  3. Do not use tables for layout. Only use tables when displaying tabular data.
  4. For external links/files, if the asset you need is available on SSL, always use https://.

Accessibility

  1. Use semantic markup whenever possible.
<!-- Good example -->
<section>
  <article>
    <header>
      <time datetime="2020-09-09">September 9th, 2020</time>
      <h1>
        <a href="/blog-post-title">My Title</a>
      </h1>
    </header>

    <section>
      <p>Here is some preview text!</p>
    </section>

    <footer>
      <a href="/blog-post-title">Read More</a>
    </footer>
  </article>
<section>

<!-- Bad example -->
<div class="blog-listing">
  <div class="blog-post">
    <div class="post-header">
      <p>September 9th, 2020</p>
      <h1>
        <a href="/blog-post-title">My Title</a>
      </h1>
    </div>

    <div class="post-body">
      <p>Here is some preview text!</p>
    </div>

    <div class="post-footer">
      <a href="/blog-post-title">Read More</a>
    </div>
  </div>
</div>
  1. Use the alt attribute for all images that are used as more than decoration.
  2. Use the tabindex="0" attribute to allow elements besides links and forms to recieve keyboard focus. Use the tabindex="-1" attribute to allow elements besides links and forms to receive programattic focus, meaning focus that can be set to the element through scripting. You can read more about this topic here.
  3. Use aria attributes and landmarks when appropriate.

HTML code formatting

  1. Write tag names, attributes, and values in lowercase.
    Good example:
    <button type="button>Click Me</button>
    Bad example:
    <Button TYPE="Button">Click Me</Button>

  2. Avoid spaces around attribute equal signs.
    Good example:
    href="/test.html"
    Bad example:
    href = "/test.html"

  3. Use double quotation marks for attribute values.
    Good example:
    alt="Cheese wheel"
    Bad example:
    alt='Cheese wheel'

  4. Remove trailing whitespace.
    Good example:
    <p>Here is a paragraph</p>
    Bad example:
    <p>Here is a paragraph</p>___

  5. Avoid new lines between tag names and content.

<!-- Good example -->
<p>This is my best paragraph yet!</p>

<!-- Bad example -->
<p>
  This is my best paragraph yet!
</p>
  1. Use a new line for every block, list, or table element and indent their child elements.
<!-- Good example -->
<ul>
  <li>Here is a list item</li>
</ul>

<!-- Bad example -->
<ul><li>Here is a list item</li></ul>
  1. Indent tags by two spaces.
  2. Boolean attributes:
  • When adding Boolean attributes to elements, be sure their placement is at the end of the element tag for optimal legibility.
  • Booleans do not need a declared value, only the name of the boolean is necessary for a "true" value to occur.
    Good example:
    <input type="checkbox" value="..." checked>
    Bad example:
    <input type="checkbox" checked="true" value="...">"
  1. Use comments where appropriate to make it easier for another developer to understand your HTML.
  • HubL comments (e.g. {# comment #}) should be used if your comment is intended to help developers using your code (HubL comments wouldn't show in the source code of a website page). HTML comments should be used if the comment is something that you want to show in the page's source code.
  • Add a comment above and below sections so that it is easy to determine where sections are.
  1. Wrap long lines to increase readability (wrap at 100 characters).
  2. Don't close void elements.
  • <br> over <br />
  1. Omit type attributes for style sheets and scripts.
<!-- Good example -->
<link rel="stylesheet" href="mystyle.css">

<!-- Bad example-->
<link rel="stylesheet" type="text/css" href="mystyle.css">

HubL

HubL code formatting

  1. HubL variables should have a space between the brackets on either side of the variable name.
    Good example:
    {{ variable }}
    Bad example:
    {{variable}}

  2. HubL filters should be added directly following a statement or expression.
    Good example:
    {{ variable|filter }}
    Bad example:
    {{ variable | filter }}

  3. Double quotation marks are preferred for HubL, though single quotation marks may be used when necessary.

  4. Variable and macro names should clearly indicate their purpose.

  5. When coding rgba values from a HubSpot color field the opacity field should be divided by 100 to represent the appropriate value.
    Example:
    rgba({{ path.to.color.field.color|convert_rgb }}, {{ path.to.color.field.opacity / 100 }});

  6. Variables that require a unit value should include that concatenation inside of the HubL brackets.
    Example:
    {{ path.to.a.field ~ "px" }}


CSS

CSS best practices

  1. Use a consistent box model style for the entire document.

  2. Avoid float and clearfixes whenever possible (flex is preferred).

  3. Avoid overloading selectors if you don't have to.
    Good example:
    .featured-image { }
    Bad example:
    div.wrapper div.wrapper-inner img.featured-image { }

  4. Avoid !important tags whenever possible.

Accessibility

  1. Do not set your site's link focus to outline: none;. Never. Ever.
  2. Style hover and focus classes, items should be reactive to both mouse and keyboard inputs.
  3. For text that needs to be visually hidden but allow for screenreaders to see it, please use the following snippet rather than visibility: hidden or display: none:
.show-for-sr {
  border: 0 !important;
  clip: rect(0, 0, 0, 0) !important;
  height: 1px !important;
  overflow: hidden !important;
  padding: 0 !important;
  position: absolute !important;
  white-space: nowrap !important;
  width: 1px !important;
}

Vertical rhythm

Responsive vertical rhythm is a CSS pattern that we use on the HubSpot CMS boilerplate. This article explains the concept in more detail. Below is a quick example of how line-height and margins should match in order to create this consistent spacing.

/* set line height on html */
html {
  line-height: 1.4;
}

/* use that value as a rem for margins around the site */
p {
  margin: 1.4rem;
}

CSS code formatting

  1. CSS declarations should be alphabetized.
/* Good example */
.css-class {
    color: red;
    height: 200px;
    padding: 10px;
    width: 10px;
}

/* Bad example */
.css-class {
    width: 10px;
    height: 200px;
    color: red;
    padding: 10px;
}
  1. Use the BEM class structure.
  • Make names as short as possible, but as long as necessary to convey meaning. When in doubt, make a name descriptive enough to where you don't have concerns about it overlapping with another class name in another similar component.
  • Flatten grandchild elements.
<!-- Example of BEM Structure on a component -->
<div class="card card--modifier-one"> <!-- block w/ modifier -->
	<h1 class="card__title">Lorem ipsum</h1> <!-- element -->
	<div class="card__content"> <!-- element -->
		<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Eius quod, eaque dolores voluptatibus dolorem sit.</p>
	</div>
	<div class="card__footer"> <!-- element -->
		<a href="#">Impedit sit</a>
		<img class="card__logo" src="#"> <!-- grandchild (flattened) -->
		<div class="card__cta"> <!-- grandchild (flattened) -->
			<button class="card__button">Delectus Alias</button> <!-- grandchild (flattened) -->
			<button class="card__button">Porro Nesciunt</button> <!-- grandchild (flattened) -->
		</div>
	</div>
</div>

When utilizing these classnames in CSS, the following code is an example of how to call the selectors:

/* Examples of the selectors from the above example in use */
.card {} /* block */
.card--modifier-one {} /* block w/ modifier */
.card__title {} /* element */
.card--modifier-one .card__title {} /* modified element */
.card__content {} /* element */
.card__footer {} /* element */
.card__logo {} /* grandchild */
.card__cta {} /* grandchild */
.card__button {} /* grandchild */
  1. Use single quotation marks for CSS.
  2. End every declaration with a semicolon.
/* Good example */
.css-class {
    color: #000;
    text-decoration: none;
}

/* Bad example */
.css-class {
    color: #000;
    text-decoration: none
}
  1. Use shorthand properties where available to keep code terse.
/* Good example */
.css-class {
    padding: 5px 10px 10px;
}

/* Bad example */
.css-class {
    padding-top: 5px;
    padding-bottom: 10px;
    padding-right: 10px;
    padding-left: 10px;
}
  1. Use leading 0's before values.
    Good example:
    animation-duration: 0.5s;
    Bad example:
    animation-duration: .5s;

  2. Separate selectors and declarations by new lines.

/* Good example */
.css-class {
    color: #000;
    margin-top: 10px;
}

/* Bad example */
.css-class { color: #000; margin-top: 10px; }
  1. Indent all block conent.
/* Good example */
.css-class {
  font-size: 20px;
  padding: 10px;
}

/* Bad example */
.css-class {
font-size: 20px;
padding: 10px;
}
  1. Always use a single space between the property and value.
    Good example:
    float: none;
    Bad example:
    float:none;

  2. When grouping together, Selectors should be placed on their own lines and separated by a comma.

/* Good example */
.css-class,
.css-class-two {
  border: 1px solid #000;
}

/* Bad example */
.css-class, .css-class-two {
  border: 1px solid #000;
}
  1. One space should be used between selectors and the opening brace of the declaration block. In addition, closing braces should be placed on a new line by themselves.
/* Good example */
.css-class {
  font-weight: 700;
}

/* Bad example */
.css-class{
  font-weight: 700;}
  1. Include a space after each comma in separated property values.
    Good example:
    background-color: rgba(0, 0, 0, 0.5);
    Bad example:
    background-color: rgba(0,0,0,0.5);

  2. Don't include the unit identifier for length values that are set to 0.
    Good example:
    margin-top: 0;
    Bad example:
    margin-top: 0px;

  3. Media queries should be written directly next to the non-media queried element.

.css-class {
    width: 50%;
}
@media screen and (max-width: 767px) {
    .css-class {
        width: 100%;
    }
}
  1. Avoid duplicating style declarations if they'll be inherited or overridden.
/* Good example */
li + li {
  visibility: hidden;
}

/* Bad example */
li {
  visibility: hidden;
}
li:first-child {
  visibility: visible;
}
  1. Avoid type selectors whenever possible.
  2. Preferred units:
  • Use seconds over milliseconds.
  • Use hexadecimal unless transparency is specifically needed. Hexadecimal should use shorthand if possible and should be in all caps (e.g. #D01).
  • Use relative units for font size, such as ems or rems. While modern browsers can smoothly zoom pixel-based layouts, sizing type in relative units ensures an entire layout can be scaled up or down by simply updating the font-size of the body element.
  1. Use comments where appropriate to make it easier for another developer to understand your CSS.
  • Group sections by section comment to delineate your code more easily.

Javascript

We generally use ES5 as it is more compatibile with older browsers such as Internet Explorer 11. ES6 can be used if you're using a build step with a transpiler like Babel. We don't use jQuery.

JavaScript best practies

  1. Leverage event bubbling whenever possible.
  2. Functions should return new objects instead of mutating existing ones. Here is a good reference on the problems with mutating objects.
  3. Minimize dependencies.

Accessibility

  1. It is important to remember that not everyone has JavaScript enabled on their browser so the website should still generally function properly if JavaScript is disabled (add CSS fallbacks when possible).

JavaScript code formatting

  1. Use single quotation marks for JavaScript and JSON.
    Good example:
    var navToggle = document.querySelector('#nav-toggle');
    Bad example:
    var navToggle = document.querySelector("#nav-toggle");

  2. Variable and function names should clearly indicate their purpose.
    Good example:
    var navToggle = document.querySelector('#nav-toggle');
    Bad example:
    var z = document.querySelector("#nav-toggle");

  3. Use comments where appropriate to make it easier for another developer to understand your JavaScript.


File Structure

General naming conventions:

  1. Avoid special characters and spaces in file names.
  2. File names should be clear and descriptive; providing immediate insight of their intended use or content at first glance.
  3. Use lower case names separated by hyphens.
  4. Use an underscore at the start of a style sheet if it isn't directly included in a template.
**Good examples:**
home.html
_dnd-areas.css

**Bad examples:**
Home.html
home!.html
page-1.html
dndareas.css
dnd_areas.css

Asset labeling:

  1. All assets (templates, partials, modules, module settings, theme settings) should include a label and the label should use sentence casing.
  2. Template names should omit the word page in their file names or their related assets/code unless it is the Landing page template.
****Good example:**
home.html

Bad example:**
home-page.html

Module structure:

General folder structure:

/module-name.module
    fields.json
    meta.json
    module.html
    module.css*
    module.js*

* Denotes optional files. If your module doesn't require CSS and/or JavaScript, please exclude these files from your module.

For more information on module file structure and building modules please reference our documentation.

Fields.json:

  • Modules should include a minimal amount of field parameters that are required for setting defaults and usage. This helps keep our fields.json files concise and legible.
  • Module fields should be ordered in the following order:
label:
name:
id:
type:
help_text:
visibility:
(other params)
inheritance:
default:

Meta.json:

  • All modules should include an icon. More information on adding an icon to a module can be found in this article.
  • meta.json parameters should be ordered in the following order:
{
  "label": "Icon",
  "css_assets": [],
  "external_js": [],
  "global": false,
  "host_template_types": ["PAGE", "BLOG_LISTING", "BLOG_POST"],
  "icon": "",
  "js_assets": [],
  "other_assets": [],
  "smart_type": "NOT_SMART",
  "tags": [],
  "is_available_for_new_content": true
}

Module IDs

  • All modules should have a module ID assigned

Template structure:

Drag and drop object formatting:

  1. Opening and closing tags should be on their own line to increase legibility.
  2. Parameters (after the name or path) should be written on their own line to increase legibility.
  3. After path/name and label, all other parameters should be ordered alphabetically to ensure consistency and increase legibility.
  4. For margin and padding parameters, the values should be ordered: top, right, bottom, left to match CSS shorthand for those properties.
{# Good example: #}
{% dnd_module path="../modules/button",
  button_link="#",
  button_text="Get Started"
%}
{% end_dnd_module %}

{# Bad example: #}
{% dnd_module path="../modules/button", button_text="Get Started", button_link="#" %}{% end_dnd_module %}

Template meta data:

The top of each template should include a YAML code block formatted to match the example below. Blog and system templates should have their labels prefixed with the theme's name. Ex. label: Boilerplate - blog post.

Requirements for screenshots can be found below at Template Screenshots.

<!--
  templateType: page
  isAvailableForNewContent: true
  label: Home
  screenshotPath: ../images/template-previews/home.png
-->

Template screenshots:

Screenshots should be taken for all templates and linked in the template's meta data section (see Template Meta Data above). The process for creating a screenshot is:

  • Take a full page screenshot of the template
  • Resize screenshot image to 1000px wide.
  • Save to /images/template-previews in the theme.

Note: Screenshots should be named after their template. For example the template home.html should have a screenshot named home.png


Theme structure

Theme.json

The theme.json file should be structured like the code below. The file should include a label to match the theme's name, a preview_path to set the theme's default preview template, and a screenshot_path to set the theme's preview image which displays when a user selects which theme they want to use. The image used for the screenshot_path should be stored under the /images/template-previews/ folder.

{
  "label": "Theme name",
  "preview_path": "./templates/home.html",
  "screenshot_path": "./images/template-previews/theme-name.png"
}