Skip to content

Coding Standards

Taufik Nurrohman edited this page Apr 15, 2022 · 31 revisions

Mecha mostly contains CSS, HTML, JavaScript, JSON, PHP, and YAML files.

CSS

Color

Always use HEX color code to declare a solid color, and RGBA color code to declare a color with opacity. Always use lower-case letter, and use the shortest color code version:

button {
  background-color: #b4d455;
  border-color: rgba(255, 255, 0, .5);
  color: #def;
}

Declaration

Sort declarations alphabetically, unless you want to override the previous declaration:

button {
  border: 1px solid #000;
  border-top-width: 0;
  margin-left: 1px;
  margin-right: 1px;
}

Fraction Value

Always remove zero prefix in fractions:

button {
  margin: 1.25em;
  padding: .25em .5em;
}

Indentation

Use two <Space>s to represent single indent:

@media print {
  .hidden-print {
    display: none;
  }
}

Key-Value Pairs

Add a <Space> after colon:

@media (max-width: 1024px) {
  body {
    font-size: 80%;
  }
}

Pseudo Class

Pseudo classes don’t have to be in alphabetical order. In common, they will be ordered like this:

button {}
button:focus {}
button:hover {}
button:active {}

But you can also order them like this to make sure that focus state will remain as-is when hovered:

button {}
button:hover {}
button:focus {}
button:active {}

Be sure to put disabled states at the end, so it will be easier to override other states:

input {}
input:hover {}
input:focus {}
input:active {}

input:valid {}
input:invalid {}

input:read-only {}
input:disabled {} 

Selector

Add a line-break after comma, sort selectors alphabetically:

h1,
h2,
h3,
h4,
h5,
h6 {}

Use single quote for attribute selector value, and for non-empty string value. Use double quote for empty string value (except for @charset rule value that must be using double quote):

@charset "utf-8";
@import url('./style.css');
[rel='nofollow']::before {
  background-image: url('./image.jpg');
  content: "";
}

Semi-Colon

Ensure semi-colon at the end of declaration:

body {
  margin-bottom: 1px;
  margin-top: 1px;
}

Zero Value

Remove unit in zero values except 0% and 0deg:

body {
  margin: 0 0 1px 1px;
  margin-top: 0%;
}

HTML

Attribute and Name

Use lower-case letter, sort attributes alphabetically:

<input class="input" id="input-0" name="input-0" type="text">

Attribute’s Value

Always use double quote, even on empty value:

<img alt="" src="./image.jpg">

Exception for attribute that contains JSON or JavaScript commands:

<div class="gallery" data-state='{"caption":true,"overlay":true}'></div>

Boolean Attribute

Always remove values:

<button disabled type="submit">

Indentation

Use two <Space>s to represent single indent:

<ul>
  <li></li>
  <li></li>
</ul>

Void Element

Do not add / before > in void elements:

<img alt="" src="/photo.jpg">
<hr>

JavaScript

Comparison

Use Yoda notation in equal/not-equal comparison to quickly detect typos:

if (-1 !== pairs.indexOf(pair)) {}

Function

Use parseFloat() and parseInt() sparingly, simply prefix your variable with a + sign if you know that the value will always be a valid number:

const value = input.value;

// :(
console.log(parseFloat(value));

// :)
console.log(+value);

Increment/Decrement

Prefers pre-increment/decrement over post-increment/decrement; always cache the data length before iteration using for loop:

// :(
for (let i = 0, j = data.length; i < j; i++) {}

// :)
for (let i = 0, j = data.length; i < j; ++i) {}

Indentation

Use four <Space>s to represent single indent:

function foo(bar = 'baz') {
    return bar ?? 'qux';
}

Operator

Always add a <Space> around operators:

let value = a + b * (1 / (c - 2));
let value = a + 'asdf' + b;

value += 'asdf';
value += 'asdf';

String

Use single quote for non-empty string or for string that contains " character, so you don’t have to escape. Use double quote for empty string or for string that contains ' character, so you don’t have to escape:

'asdf'
"asdf's"
""
'"asdf"'
'"asdf\'s"'
"'asdf'"
"'asdf\"s'"

Only use backtick-style string for templating. E.g. to write a block of CSS and HTML snippet in a JavaScript file.

Variable

Join multiple variables, unless its indentation looks ugly such as when used with const, or when making undefined variables. Sort them aplhabetically where possible:

let bar = 1,
    baz = 2,
    x, y, z;

const bar = 1;
const baz = 2;

PHP

Class

Order constants, methods and properties alphabetically, including the visibility state:

class Foo implements A, B, C {
    private function _internal() {}
    public function get() {}
    public function let() {}
    public function set() {}
    public function __construct() {}
    public static function __callStatic() {}
}

Comparison

Use Yoda notation in equal/not-equal comparison to quickly detect typos:

if (false !== strpos($foo, $bar)) {}

Function

Use is_dir or is_file instead of file_exists:

// :(
if (file_exists($path)) {}

// :)
if (is_file($path)) {}

If you just want to check whether a path does exist, use stream_resolve_include_path instead of file_exists:

// :(
if (file_exists($path)) {}

// :\
if (is_dir($path) || is_file($path)) {}

// :)
if (stream_resolve_include_path($path)) {}

Use strtr instead of str_replace:

// :(
echo str_replace('a', 'b', $value);
echo str_replace('a', "", $value);
echo str_replace(['a', 'b'], ['c', 'd'], $value);
echo str_replace(['aa', 'bb'], ["", ""], $value);

// :)
echo strtr($value, 'a', 'b');
echo strtr($value, ['a' => ""]);
echo strtr($value, 'ab', 'cd');
echo strtr($value, [
    'aa' => "",
    'bb' => ""
]);

If you know that a path exists, use stream_resolve_include_path to normalize the path instead of realpath:

$path = stream_resolve_include_path($path);

If you just want to escape/un-escape HTML, use htmlspecialchars and htmlspecialchars_decode instead of htmlentities:

// :(
echo '<input value="' . htmlentities($value) . '">';

// :)
echo '<input value="' . htmlspecialchars($value) . '">';

Prefers static anonymous function if $this context is not used:

$map = static function(array $array, callable $fn) {
    foreach ($array as &$v) {
        $v = $fn($v);
    }
    unset($v);
    return $array;
};

Do not use count() to detect empty array, and strlen() to detect empty string. These should be enough:

if (!$array) {}
if ("" === $string) {}

Increment/Decrement

Prefers pre-increment/decrement over post-increment/decrement; always cache the data length before iteration using for loop:

// :(
for ($i = 0, $j = count($data); $i < $j; $i++) {}

// :)
for ($i = 0, $j = count($data); $i < $j; ++$i) {}

Indentation

Use four <Space>s to represent single indent:

function foo(string $bar = 'baz') {
    return $bar ?? 'qux';
}

Language Construct

Use isset() sparingly:

// :(
echo '<' . $m[1] . (isset($m[2]) ? $m[2] : "") . '>';

// :)
echo '<' . $m[1] . ($m[2] ?? "") . '>';

Do not use empty() to detect empty string. Use empty() as a shortcut for !(isset($var) && $var):

$name = $_POST['name'] ?? "";

// :(
// If `$name` contains `0` string, this will return `true`
if (empty($name)) {}

// :)
// Use `trim()` as a guard, since even a single space is not considered empty
if ("" !== trim($name)) {}

// :)
// You don’t have to use `empty()` to detect empty array. This should be enough!
if (!$array) {}

Use empty() and isset() only to detect undefined variable as a whole.

Markup

Always think of PHP statements as other kind of HTML markup. They should get the same indentation treatment as the surrounding HTML markup.

<!-- :( -->
<h1>
  <a href="<?= $link; ?>"><?= $title; ?></a>
</h1>

<!-- :) -->
<h1>
  <a href="<?= $link; ?>">
    <?= $title; ?>
  </a>
</h1>
<!-- :( -->
<?php foreach ($pages as $page): ?>
<article>
  <h2><?= $page->title; ?></h2>
  <div><?= $page->content; ?></div>
</article>
<?php endforeach; ?>

<!-- :) -->
<?php foreach ($pages as $page): ?>
  <article>
    <h2>
      <?= $page->title; ?>
    </h2>
    <div>
      <?= $page->content; ?>
    </div>
  </article>
<?php endforeach; ?>

Operator

Always add a <Space> around operators:

$value = $a + $b * (1 / ($c - 2));
$value = $a . 'asdf' . $b;

$value .= 'asdf';
$value .= 'asdf';

Output

Use echo or not at all. Always add a semi-colon at the end of declaration, even if you are using the <?= syntax:

<h1>
  <?php

  $title  = do_task(1);
  $title .= do_task(2);
  $title .= do_task(3);

  echo $title;

  ?>
</h1>
<h1>
  <?= $title; ?>
</h1>

String

Use single quote for non-empty string or for string that contains " character, so you don’t have to escape. Use double quote for empty string or for string that contains ' character, so you don’t have to escape:

'asdf'
"asdf's"
""
'"asdf"'
'"asdf\'s"'
"'asdf'"
"'asdf\"s'"

Only use HEREDOC-style string for templating. E.g. to write a block of CSS and HTML snippet in a PHP region.

Always store HEREDOC string in a variable to overcome our first home-made PHP minifier bug.

// :(
echo implode("\n", ['<b></b>', <<<HTML
  <div></div>
HTML
]);

// :)
$content = <<<HTML
  <div></div>
HTML;
echo implode("\n", ['<b></b>', $content]);

Variable

Combine all variables with the same predefined value into one line. Sort them alphabetically:

$current = $next = $prev = "";

YAML

Indentation

Use two <Space>s to represent single indent:

foo:
  bar: 1
  baz: 2
  qux: 3

Do not indent sequence list:

# :(
foo:
  - bar
  - baz
  - qux

# :)
foo:
- bar
- baz
- qux

Key-Value Pairs

Enclose values containing special characters in quotation marks:

foo: Bar Baz
qux: '[email protected]'

String

Use single quote for non-empty string or for string that contains " character, so you don’t have to escape. Use double quote for empty string or for string that contains ' character, so you don’t have to escape:

foo:
  bar: 'http://example.com'
  baz: ""

To be continued… 🧠

Clone this wiki locally