НовостиАдминистрированиеУправления хостингомАрхив
10 марта 2015

Правила хорошего тона для front-end-а с практическими примерами

Front-end требует от разработчика не только знания нескольких вариантов того, как можно решить поставленную задачу, но и умения выбрать оптимальное решение. Кроме того, не стоит забывать и о таких понятиях, как читаемость и простота поддержки кода, так как довольно часто, ведение вашего проекта может быть отдано в чужие руки. О том, что такое хорошо и плохо в front-end разработке, мы и поговорим сегодня.

HTML

Семантика

HTML5 предоставляет нам множество новых элементов, основная задача которых точное описание и структурирование контента. Убедитесь, что вы используете всю выгоду от этого:

<!-- Плохо -->
<div id=\"main\">
  <div class=\"article\">
    <div class=\"header\">
      <h1>Статья</h1>
      <p>Опубликовано: <span>05.03.2015</span></p>
    </div>
    <p>…</p>
  </div>
</div>
<!-- Хорошо -->
<main>
  <article>
    <header>
      <h1> Статья </h1>
      <p>Опубликовано: <time datetime=\"2015-03-05\">05.03.2015</time></p>
    </header>
    <p>…</p>
  </article>
</main>

Убедитесь, что вы понимаете семантику элементов, которые вы используете. Лучше отказаться от использования элемента, чем применять его неправильно.

<!-- Плохо --><h1>  <figure>    <img alt=Company src=logo.png>  </figure></h1>
<!-- Хорошо -->
<h1>
  <img alt=Company src=logo.png>
</h1>

Краткость

Старайтесь писать максимально лаконично, откажитесь от своих вредных привычек.

<! - Плохо ->
<html lang=en>
  <head>
    <meta http-equiv=Content-Type content=\"text/html; charset=utf-8\" />
    <title>Контакты</title>
    <link rel=stylesheet href=style.css type=text/css />
  </head>
  <body>
    <h1>Свяжитесь со мной</h1>
    <label>
      Email:
      <input type=email placeholder=you@email.com required=required />
    </label>
    <script src=main.js type=text/javascript></script>
  </body>
</html>
<! - Хорошо -><html lang=en>  <meta charset=utf-8>  <title> Контакты </title>  <link rel=stylesheet href=style.css>
  <h1> Свяжитесь со мной</h1>  <label>    Email:    <input type=email placeholder=you@email.com required>  </label>  <script src=main.js></script></html>

Доступность

Доступность не должна быть второстепенным свойством. Вы не должны быть экспертом WCAG, чтобы улучшить свой веб-сайт. Вы можете начать немедленно, используя мелочи, которые создают огромную разницу, например:

  • научитесь правильно использовать атрибут alt;
    • убедитесь, что ваши ссылки и кнопки помечены правильно (без );
    • не полагайтесь исключительно на цвета, чтобы передавать информацию;
    • выделяйте элементы управления формой.
<! - Плохо -> 
<h1><img alt=\"Logo\" src=\"logo.png\"></h1>
<! - Хорошо -> <h1><img alt=\"Logo\" src=\"logo.png\"></h1>

Язык

Рекомендуется всегда объявлять язык и кодировку на уровне документа, даже если они указаны в HTTP. Отдавайте предпочтение UTF-8.

<!- Плохо ->
<!doctype html>
<title>Hello, world.</title>
<!-- Хорошо -->
<!doctype html>
<html lang=en>
  <meta charset=utf-8>
  <title>Hello, world.</title>
</html>

Производительность

Если у вас нет уважительной причины загружать скрипты перед контентом, не затормаживайте загрузку вашей страницы. Если ваш CSS-файл слишком большой, выделите второстепенные стили и соберите их в отдельном файле с отложенной загрузкой. Конечно, два HTTP-запроса выполняются дольше, чем один, но таким образом вы создаете иллюзию быстрой загрузки, так как уменьшается время первого взаимодействия.

<!-- Плохо --><!doctype html><meta charset=utf-8><script src=analytics.js></script><title>Hello, world.</title><p>...</p>
<!-- Хорошо -->
<!doctype html>
<meta charset=utf-8>
<title>Hello, world.</title>
<p>...</p>
<script src=analytics.js></script>

CSS

Точка с запятой

Хотя точка с запятой воспринимается как чисто технический разделитель, не забывайте его ставить.

/* Плохо */div {  color: red}
/* Хорошо */div {  color: red;}

Box model

В идеале, модель должна быть общая для всего документа. Глобальная * { box-sizing: border-box; } это хорошо, но постарайтесь не изменять стандартные свойства модели на конкретных элементах, если это возможно.

/* Плохо */div {  width: 100%;  padding: 10px;  box-sizing: border-box;}
/* Хорошо */div {  padding: 10px;}

Поток

Не изменяйте поведение элемента по умолчанию, если вы можете этого избежать. Например, удаление пустого пространства под изображением не должно выполняться за счет изменения способа отображения.

/* Плохо */img {  display: block;}
/* Хорошо */img {  vertical-align: middle;}

Кроме того, не стоит менять или явно указывать позиционирование, если в этом нет необходимости.

/* Плохо */div {  width: 100px;  position: absolute;  right: 0;}
/* Хорошо */div {  width: 100px;  margin-left: auto;}

Позиционирование

Есть много способов, чтобы позиционировать элементы в CSS, но старайтесь ограничивать себя. Вот список решений, которые стоит использовать, в порядке их предпочтительности:display: block;display: flex;position: relative;position: sticky;position: absolute;position: fixed;

Селекторы

Минимизация селекторов тесно связана с DOM. Постарайтесь не использовать более трех уровней селекторов.

/* Плохо */div:first-of-type :last-child > p ~ *
/* Хорошо */div:first-of-type .info

Избегайте использования лишних селекторов:

/* Плохо */img[src$=svg], ul > li:first-child {  opacity: 0;}
/* Хорошо */[src$=svg], ul > :first-child {  opacity: 0;}

Приоритетность селекторов

Не делайте значение селекторов трудным для понимания. Сведите к минимуму использование ID и избегайте !important.

/* Плохо */.bar {  color: green !important;}.foo {  color: red;}
/* Хорошо */.foo.bar {  color: green;}.foo {  color: red;}

Переопределение

Переопределение стилей усложняет отладку и чтение кода. Избегайте его, если это возможно.

/* Плохо */li {  visibility: hidden;}li:first-child {  visibility: visible;}

/* Хорошо */li + li {  visibility: hidden;}

Наследование

Не дублируйте объявление стилей, которые и так будут наследоваться.

/* Плохо */div h1, div p {  text-shadow: 0 1px 0 #fff;}

/* Хорошо */div {  text-shadow: 0 1px 0 #fff;}

Краткость

Используйте сокращенные свойства, не объявляйте ненужные свойства и значения, которые стоят по умолчанию.

/* Плохо */div {  transition: all 1s;  top: 50%;  margin-top: -10px;  padding-top: 5px;  padding-right: 10px;  padding-bottom: 20px;  padding-left: 10px;}
/* Хорошо */
div {  transition: 1s;  top: calc(50% - 10px);  padding: 5px 10px 20px;}

Язык

Предпочитайте английский математике.

/* Плохо */:nth-child(2n + 1) {  transform: rotate(360deg);}
/* Хорошо */:nth-child(odd) {  transform: rotate(1turn);}

Префиксы

Не используйте их, если это возможно. Если вы вынуждены их использовать, пишите их перед стандартными свойствами.

/* Плохо */div {  transform: scale(2);  -webkit-transform: scale(2);  -moz-transform: scale(2);  -ms-transform: scale(2);  transition: 1s;  -webkit-transition: 1s;  -moz-transition: 1s;  -ms-transition: 1s;}
/* Хорошо*/div {  -webkit-transform: scale(2);  transform: scale(2);  transition: 1s;}

Анимация

Transition лучше, чем animation. Избегайте использовать анимацию для чего-либо, кроме opacity и transform.

/* Плохо */div:hover {  animation: move 1s forwards;}@keyframes move {  100% {    margin-left: 100px;  }}
/* Хорошо */div:hover {  transition: 1s;  transform: translateX(100px);}

Единицы

Используйте безразмерное значение, когда можете. Используйте rem, если вы используете относительные единицы. Секунды лучше миллисекунд.

/* Плохо */div {  margin: 0px;  font-size: .9em;  line-height: 22px;  transition: 500ms;}
/* Хорошо*/div {  margin: 0;  font-size: .9rem;  line-height: 1.5;  transition: .5s;}

Цвета

Если вам нужна прозрачность, используйте RGBA . В противном случае, всегда используйте шестнадцатеричный формат.

/* Плохо */div {  color: hsl(103, 54%, 43%);}
/* Хорошо*/div {  color: #5a3;}

Рисование

Избегайте HTTP запросов, если необходимое содержимое легко реализуется с помощью CSS.

/* Плохо */div::before {  content: url(белый-круг.svg);}
/* Хорошо*/div::before {  content: \"\";  display: block;  width: 20px;  height: 20px;  border-radius: 50%;  background: #fff;}

Хаки

Не используйте их.

/* Плохо */div {  // position: relative;  transform: translateZ(0);}
/* Хорошо*/div {  /* position: relative; */  will-change: transform;}

JavaScript

Производительность

Отдайте предпочтение читаемости и выразительности кода. JavaScript довольно редко становится узким местом кода, если не доводить его до абсурда. Гораздо эффективней в плане производительности провести оптимизацию, облегчить изображения или оптимизировать DOM.

// Плохо (хотя намного быстрее) const arr = [1, 2, 3, 4];const len = arr.length;var i = -1;var result = [];while (++i < len) {  var n = arr[i];  if (n % 2 > 0) continue;  result.push(n * n);}
// Хорошоconst arr = [1, 2, 3, 4];const isEven = n => n % 2 == 0;const square = n => n * n;const result = arr.filter(isEven).map(square);

Аккуратность

Старайтесь, чтобы ваши функции не давали побочных результатов, не влияли на глобальную область видимости и не возвращали новых объектов. Не изменяйте свойства существующих объектов.

// Плохоconst merge = (target, ...sources) => Object.assign(target, ...sources);merge({ foo: \"foo\" }, { bar: \"bar\" }); // => { foo: \"foo\", bar: \"bar\" }
// Хорошоconst merge = (...sources) => Object.assign({}, ...sources);merge({ foo: \"foo\" }, { bar: \"bar\" }); // => { foo: \"foo\", bar: \"bar\" }

Независимость

Старайтесь использовать родные методы.

// Плохоconst toArray = obj => [].slice.call(obj);
// Хорошоconst toArray = (() =>  Array.from ? Array.from : obj => [].slice.call(obj))();

Присвоение

Используйте неявное присвоение, только если это имеет смысл.

// Плохоif (x === undefined || x === null) { ... }
// Хорошоif (x == undefined) { ... }

Циклы

Не используйте циклы для изменения объектов. Использование встроенных методов работы с объектами повышает читаемость и упрощает сопровождение кода.

// Плохоconst sum = arr => {  var sum = 0;  var i = -1;  for (;arr[++i];) {    sum += arr[i];  }  return sum;};
sum([1, 2, 3]); // => 6
// Хорошоconst sum = arr =>  arr.reduce((x, y) => x + y);
sum([1, 2, 3]); // => 6

Если вы по каким-то причинам не можете использовать эти методы обратите внимание на рекурсию

// Плохоconst createDivs = howMany => {  while (howMany--) {    document.body.insertAdjacentHTML(\"beforeend\", \"<div></div>\");  }};createDivs(5);
// Плохоconst createDivs = howMany =>  [...Array(howMany)].forEach(() =>    document.body.insertAdjacentHTML(\"beforeend\", \"<div></div>\")  );createDivs(5);
// Хорошоconst createDivs = howMany => {  if (!howMany) return;  document.body.insertAdjacentHTML(\"beforeend\", \"<div></div>\");  return createDivs(howMany - 1);};createDivs(5);

Аргументы

Забудьте о arguments объекта; rest будет значительно эффективней, потому что:

  1. ему можно присвоить имя, так что это дает вам более полное представление о том, какие именно аргументы ожидает получить функция;
    1. это реальный массив, что делает его проще в использовании.
// Плохоconst sortNumbers = () =>  Array.prototype.slice.call(arguments).sort();
// Хорошоconst sortNumbers = (...numbers) => numbers.sort();

Apply

Забудьте о Apply () . Вместо этого используйте оператор распространения:

const greet = (first, last) => `Hi ${first} ${last}`;const person = [\"John\", \"Doe"];
// Плохоgreet.apply(null, person);

// Хорошоgreet(...person);

Bind

Не используйте Bind () , когда есть более традиционное решение.

// Плохо[\"foo\", \"bar"].forEach(func.bind(this));

// Хорошо[\"foo\", \"bar"].forEach(func, this);
// Плохоconst person = {  first: \"John\",  last: \"Doe\",  greet() {    const full = function() {      return `${this.first} ${this.last}`;    }.bind(this);    return `Hello ${full()}`;  }}
// Хорошоconst person = {  first: \"John\",  last: \"Doe\",  greet() {    const full = () => `${this.first} ${this.last}`;    return `Hello ${full()}`;  }}

Функции высшего порядка

Избегайте вложенности функций, когда это возможно.

// Плохо[1, 2, 3].map(num => String(num));

// Хорошо[1, 2, 3].map(String);

Кэширование

Кэшируйте

// Плохоconst contains = (arr, value) =>  Array.prototype.includes    ? arr.includes(value)    : arr.some(el => el === value);contains([\"foo\", \"bar"], \"baz\"); // => false
// Хорошоconst contains = (() =>  Array.prototype.includes    ? (arr, value) => arr.includes(value)    : (arr, value) => arr.some(el => el === value))();contains([\"foo\", \"bar"], \"baz\"); // => false

Переменные

Const лучше, чем let, а let лучше, чем var.

// Плохоvar obj = {};obj[\"foo\" - \"bar"] = \"baz\";
// Хорошоconst obj = {  [\"foo\" - \"bar"]: \"baz\"};

Окружение

Лучше использовать несколько IF и вернуть необходимое значение, чем использовать else if, и switch.

// Плохоvar grade;if (result < 50)  grade = \"Плохо\";else if (result < 90)  grade = \"Хорошо\";else  grade = \"excellent\";

// Хорошоconst grade = (() => {  if (result < 50)    return \"Плохо\";  if (result < 90)    return \"Хорошо\";  return \"excellent\";})();

Работа с объектом

Избегайте for...in, когда вы можете.

const shared = { foo: \"foo\" };const obj = Object.create(shared, {  bar: {    value: \"bar\",    enumerable: true  }
// Плохоfor (var prop in obj) {  if (obj.hasOwnProperty(prop))    console.log(prop);}
// ХорошоObject.keys(obj).forEach(prop => console.log(prop));Объекты или картыКарты, как правило, лучше и мощнее.// Плохоconst me = {  name: \"Ben\",  age: 30};var meSize = Object.keys(me).length;meSize; // => 2me.country = \"Belgium\";meSize++;meSize; // => 3
// Хорошоconst me = Map();me.set(\"name\", \"Ben\");me.set(\"age\", 30);me.size; // => 2me.set(\"country\", \"Belgium\");me.size; // => 3

Каррирование

Каррирование, возможно, уместно в других языках, но избегайте его в JavaScript, так как оно усложняет читабельность кода.

// Плохо const sum = a => b => a + b;sum(5)(3); // => 8
// Хорошоconst sum = (a, b) => a + b;sum(5, 3); // => 8

Читабельность

Не усложняйте чтение вашего кода, используя, казалось бы, умные трюки.

// Плохоfoo || doSomething();
// Хорошоif (!foo) doSomething();

// Плохоvoid function() { /* IIFE */ }();
// Хорошо(function() { /* IIFE */ }());
// Плохоconst n = ~~3.14;
// Хорошоconst n = Math.floor(3.14);

Повторное использование кода

Не бойтесь создавать множество мелких компонуемых и многоразовых функций.

// Плохоarr[arr.length - 1];
// Хорошоconst first = arr => arr[0];const last = arr => first(arr.slice(-1));last(arr);
// Плохо
const product = (a, b) => a * b;
const triple = n => n * 3;
// Хорошо
const product = (a, b) => a * b;
const triple = product.bind(null, 3);

Зависимость

Минимизируйте зависимости, старайтесь не использовать сторонний код и не подгружать целые библиотеки для пары функций.

// Плохо
var _ = require(\"underscore\");
_.compact([\"foo\", 0]));
_.unique([\"foo\", \"foo"]);
_.union([\"foo"], [\"bar"], [\"foo"]);
// Хорошо
const compact = arr => arr.filter(el => el);
const unique = arr => [...Set(arr)];
const union = (...arr) => unique([].concat(...arr));
compact([\"foo\", 0]);
unique([\"foo\", \"foo"]);
union([\"foo"], [\"bar"], [\"foo"]);
По материалам github.com