# Coding Guidelines # CSS ===================================================================== ## CSS 1 Avoid using more than 2 levels of nesting #### Don't ``` .selector { .level-2 { .level-3 { .child-1 {} .child-2 {} } } } ``` #### Do ``` .selector { .level-3 .child-1 {} .level-3 .child-2 {} } ``` ===================================================================== ===================================================================== ## CSS 2 Use nested media queries #### Don't ``` .selctor1 {} .selctor2 {} .selctor3 {} @media (max-width) { .selctor1 {} .selctor2 {} .selctor3 {} } ``` #### Do ``` .selctor1 { @media (max-width) {} } .selctor2 { @media (max-width) {} } .selctor3 { @media (max-width) {} } ``` ===================================================================== ===================================================================== ## CSS 3 Group rules by meaning i.e. fonts, colors, size, position #### Don't ``` .selector { position: absolute; font-size: 14px; background-color: red; height: 50%; top: 50%; line-height: 1.3; left: 50%; color: blue; width: 50; } ``` #### Do ``` .selector { width: 50%; height: 50%; position: absolute; top: 50%; left: 50%; font-size: 14px; line-height: 1.3 color: blue; background-color: red; } ``` ===================================================================== ===================================================================== ## CSS 4 Use shorthand rules #### Don't ``` .selector { padding-top: 10px; padding-right: 20px; padding-bottom: 50px; padding-left: 10px; } ``` #### Do ``` .selector { .padding: 10px 20px 50px 10px; } ``` ===================================================================== ===================================================================== ## CSS 5 Use hex instead of rgb #### Don't ``` .selector { .color: rgb(255, 255, 255); } ``` #### Do ``` .selector { .color: #000 } ``` ===================================================================== ===================================================================== ## CSS 6 Comma separated selectors on new lines #### Don't ``` .selector1, .selecto2, .selector3, .selector4 {} ``` #### Do ``` .selector1, .selecto2, .selector3, .selector4 {} ``` ===================================================================== ===================================================================== ## CSS 7 Use global or local variables to avoid repetition #### Don't ``` .selector1 { color: #1e1e1e; } .selector2 { color: #1e1e1e; } .selector3 { color: #1e1e1e; } ``` #### Do ``` $formLabelGray: '#1e1e1e'; .selector1 { color: formLabelGray; } .selector2 { color: formLabelGray; } .selector3 { color: formLabelGray; } ``` ===================================================================== ===================================================================== ## CSS 8 Use single quotes #### Don't ``` .selector1 { background-image: url("path-to-file") } ``` #### Do ``` .selector1 { background-image: url('path-to-file') } ``` ===================================================================== ===================================================================== ## CSS 9 Use stateful selectors #### Don't ``` .active {} .clicked {} .hidden {} ``` #### Do ``` .is-active {} .is-clicked {} .is-hidden {} ``` ===================================================================== ===================================================================== ## CSS 10 Add trailing semicollons #### Don't ``` .selector { color: red; background-color: blue; display: block } ``` #### Do ``` .selector { color: red; background-color: blue; display: block; } ``` ===================================================================== # Liquid ===================================================================== ## Liquid 1 Use {% render %} instead of {% include %} #### Don't ``` {% include 'icon-misc', icon: 'search', colour: 'red' %} ``` #### Do ``` {% render 'icon-misc' with icon: 'search', colour: 'red' %} ``` ===================================================================== ===================================================================== ## Liquid 2 Break to multiple lines when snippets have more than 2 params or the whole snippet goes over 80 characters #### Don't ``` {% render 'social-sharing' with share_title: product.title, share_permalink: product.url, share_image: product.featured_image %} ``` #### Do ``` {% render 'social-sharing' with share_image: product.featured_image, share_permalink: product.url, share_title: product.title, %} ``` ===================================================================== ===================================================================== ## Liquid 3 Use {% break %} and {% continue %} to exit out of a loop iteration early and to break out of the loop ``` {% for tag in product.tags %} {% if tag != 'value' %} {% continue %} {% endif %} {% render 'tag-snippet' %} {% break %} {% endfor %} ``` ===================================================================== ===================================================================== ## Liquid 4 Add how-to-use comments for liquid snippets at the top of the file ``` {% comment %} Usage: In your liquid template file, copy the following line - {% render 'responsive-image' with image: featured_image, image_class: "css-class", wrapp er_class: "wrapper-css-class", max_width: 700, max_height: 800 %} {% endcomment %} ``` ===================================================================== ===================================================================== ## Liquid 5 - In areas where the client can customize the content, do not assume that they will want to display every part of a section's settings - Wrap each setting in a {% if %} to hide it if no content is entered - Use != '' rather than {% if condition %} or != blank as it is more reliable, it is possible for a setting to exist if it previously had a value - When testing make sure the section does not appear visually broken, the client will expect it to work with missing settings #### Don't ``` {% for block in section.blocks %} {% assign _block = block.settings %} <div class="block"> <img src="{{ _block.image | img_url: '2000x' }}" alt="{{ _block.image.alt }}"> <h2 class="block__title">{{ _block.title }}</h2> <div class="block__text rte">{{ _block.text }}</div> <a class="block__button" href="{{ _block.button_url }}"> {{ _block.button_text }} </a> </div> {% endfor %} ``` #### Do ``` {% for block in section.blocks %} {% assign _block = block.settings %} <div class="block"> {% if _block.image != '' %} <img alt="{{ _block.image.alt }}" src="{{ _block.image | img_url: '2000x' }}" > {% endif %} {% if _block.title != '' %} <h2 class="block__title">{{ _block.title }}</h2> {% endif %} {% if _block.text != '' %} <div class="block__text rte"> {{ _block.text }} </div> {% endif %} {% if _block.button url != '' and _block.button_text != '' %} <a class="block__button" href="{{ _block.button_url }}"> {{ _block.button_text }} </a> {% endif %} </div> {% endfor %} ``` ===================================================================== ===================================================================== ## Liquid 6 Don't use variable names that are already allocated in Shopify #### Don't ``` {% assign section = section.settings %} ``` #### Do ``` {% assign _section = section.settings %} ``` ===================================================================== ===================================================================== ## Liquid 7 Hoist settings variables in _section and _block #### Don't ``` {% if section.settings.main_image != blank %} <img src="{{- section.settings.main_image.src -}}" alt="{{- section.settings.main_image.alt -}}"> {% endif %} ``` #### Do ``` {% assign _section = section.settings %} {% assign main_image = _section.main_image %} {% assign section_title = _section.title %} {% if main_image != blank %} <img src="{{- main_image.src -}}" alt="{{- main_image.alt -}}"> {% endif %} ``` ===================================================================== ===================================================================== ## Liquid 8 Don't use multiple inline if statements #### Don't ``` <div class="row {% if section.settings.width == 'full' or section.settings.display == 'ful l' %}row--full-width{% endif %} {% if is_hidden %}is-hidden{% endif %}"></div> ``` #### Do ``` {% if section.settings.width == 'full' or section.settings.display == 'full' %} {% assign row_class = 'row--full-width' %} {% endif %} <div class=" row {{ row_class }} {% if is_hidden %}is-hidden{% endif %} " > <!-- Content --> </div> ``` ===================================================================== ===================================================================== ## Liquid 9 Use proper indenting for nested code #### Don't ``` {% if variable %} <h1>{{ product.title }}</h1> {% endif %} ``` #### Do ``` {% if variable %} <h1>{{ product.title }}</h1> {% endif %} ``` ===================================================================== ===================================================================== ## Liquid 10 Spacing and line character limits - Add spaces inside each object and tag - Add spaces around filters - Separate blocks of Liquid code with a newline - Opening {% if %} tags should be on separate lines - {% if %} tags with more than two filters and exceeding 80 characters should be split onto multiple lines - {% assign %} tags with more than two filters and exceeding 80 characters should be broken up over multiple lines and indented - Once you are writing something over multiple lines, each line should only have one attribute or value on it #### Don't ``` {% if template contains 'search' or template contains 'account' or template contains 'cust omer' or template contains 'cart' %}<meta name="robots" content="noindex, nofollow">{% end if %} {% assign sanitized_var = string|downcase|split: '/'|last|remove:'<p>'|remove:'</p>'|money _with_currency %} {%if variable%}<h1 class="product__title">{{ product.title }}</h1> <div class="product__price product__price--large money subtitle-1">{{ product.price | mo ney }}</div>{% else %}<h2 class="product__title">{{ product.title }}</h2>{%endif%} ``` #### Do ``` {% if template contains 'search' or template contains 'account' or template contains 'customer' or template contains 'cart' %} <meta content="noindex, nofollow" name="robots"> {% endif %} {% assign sanitized_variable = string | downcase | split: '/' | last | remove:'<p>' | remove:'</p>' %} | money_with_currency %} {% if variable %} <h1 class="product__title">{{ product.title }}</h1> <div class=" product__price product__price--large money subtitle-1 " > {{ product.price | money }} </div> {% else %} <h2 class="product__title">{{ product.title }}</h2> {% endif %} ``` ===================================================================== # Javascript ===================================================================== ## JS 1 Write explicit code #### Don't ``` // implicitly convert to integer const dataIndex = +item.dataset.index; ``` #### Do ``` // explicitly convert to integer const dataIndex = parseInt(item.dataset.index); ``` ===================================================================== ===================================================================== ## JS 2 Add comments even on simple pieces of code #### Don't ``` function sumTwoIntegers(a, b) { return a + b; } ``` #### Do ``` /** * Return the sum of two integers * @param {Integer} a * @param {Integer} b * @returns Integer */ function sumTwoIntegers(a, b) { return a + b; } ``` ===================================================================== ===================================================================== ## JS 3 Use full name variables #### Don't ``` const accPass = '...'; ``` #### Do ``` const accountPassword = '...'; ``` ===================================================================== ===================================================================== ## JS 4 Always null check #### Don't ``` const item = document.querySelector(selector); item.classList.add('class'); ``` #### Do ``` const item = document.querySelector(selector); if (item !== null) { item.classList.add('class'); } ``` ===================================================================== ===================================================================== ## JS 5 Hoist variables at the top of a js module #### Don't ``` const var1 = ''; function useVar1() { return var1; } const var2 = ''; function useVar2() { return var2; } const var3 = ''; function useVar3() { return var3; } ``` #### Do ``` const var1 = ''; const var2 = ''; const var3 = ''; function useVar1() { return var1; } function useVar1() { return var2; } function useVar1() { return var3; } ``` ===================================================================== ===================================================================== ## JS 6 Define long conditions as variables #### Don't ``` if (window.width > 767 && window.height > 600 && window.scrollY > section.offset.top) { ... } ``` #### Do ``` const isDevice = window.width > 767 && window.height > 600; const isSectionInView = window.scrollY > section.offset.top; if (isDevice && isSectionInView) { ... } ``` ===================================================================== ===================================================================== ## JS 7 Always leave trailing commas #### Don't ``` const object = { prop: 'value', prop2: 'value2', prop3: 'value3' } ``` #### Do ``` const object = { prop: 'value', prop2: 'value2', prop3: 'value3', } ``` ===================================================================== ===================================================================== ## JS 8 Use arrow functions whenever it's possible and makes sense to do so #### Do ``` array.map(item => { ... }) const sumTwoIntegers = (a, b) => { return a + b; } ``` ===================================================================== ===================================================================== ## JS 9 Use stateful naming for stateful variables #### Don't ``` const mobile = window.width < 767; const children = item.children.length; ``` #### Do ``` const isMobile = window.width < 767; const hasChildren = item.children.length; ``` ===================================================================== ===================================================================== ## JS 10 Brake multiple methods on their own line #### Don't ``` array.map(item => item.props).sort().reverse(); ``` #### Do ``` array .map(item => item.props) .sort() .reverse(); ``` =====================================================================