├── CSS └── README.md ├── Environment ├── README.md ├── branches-and-requests.md ├── conventional-commits.md ├── husky.md └── lint-staged.md ├── HTML └── README.md ├── Initiation.md ├── JS └── README.md ├── README.md └── React ├── Optimization.md └── README.md /CSS/README.md: -------------------------------------------------------------------------------- 1 | # CSS 2 | 3 | 1. [Общие требования](#1) 4 | 2. [Правила](#2) 5 | 3. [Шрифты](#3) 6 | 4. [БЭМ](#4) 7 | 5. [Возможные ошибки](#5) 8 | 9 | 10 | 11 | ## Общие требования 12 | 13 | 14 | 15 | - [1.1](#1.1) Главное! Используем [pixel-perfect](https://chrome.google.com/webstore/detail/perfectpixel-by-welldonec/dkaagdgjmgdmbnecmcefdhjekcoceebi?hl=ru), если заказчик предоставил макет. 16 | 17 | 18 | 19 | - [1.2](#1.2) Не подключать стили с удаленных источников — только с наших серверов. 20 | 21 | 22 | 23 | - [1.3](#1.3) CSS — опасная сила. 24 | 25 | Все стили, подключаемые к странице, являются глобальными, и, если этим злоупотреблять, то можно легко довести проект до состояния крайне болезненного внедрения любого нового элемента или изменения старого. Это чаще всего происходит, когда создаются "общие" классы, потом крепятся к разным элементам на странице (банальный пример — шапка, у которой внутри форма поиска, которая есть на всех страницах с одинаковыми классами) и в итоге, когда по дизайну на разных страницах появляются небольшие отличия в шапке, плодятся классы, переписывающие свойства. И так почти для всех элементов каждой страницы. В итоге, меняя крайнюю правую ссылку в сайдбаре на странице новостей, вы можете поломать верстку всего сайдбара на какой-нибудь другой странице, например, на странице личного кабинета. 26 | 27 | Для того чтобы такого не происходило, существуют разные методологии, например, `БЭМ` (прочитать про него обязательно хотя бы в общих чертах) или, например, [rscss](https://ricostacruz.com/rscss/index.html). Для начала можете изучить [небольшой подход](https://isobar-us.github.io/code-standards/), который используют ребята из `Isobar` — он описан в рамках их стандарта и состоит из 7 небольших абзацев. 28 | 29 | Для решения проблемы уникальности имён классов на программном уровне, мы используем [CSS Modules](https://github.com/css-modules/css-modules). Некоторые разработчики предпочитают [styled-components](https://styled-components.com/) или [tailwindcss](https://tailwindcss.com/). 30 | 31 | 32 | 33 | 34 | - [1.4](#1.4) Отступы делать пробелами, один уровень — 2 пробела. 35 | 36 | 37 | 38 | - [1.5](#1.5) Использовать одинарные кавычки. 39 | 40 | 41 | 42 | - [1.6](#1.6) Перед началом работы обязательно четко знать все приоритеты селекторов и все 4 вида возможных отношений. 43 | 44 | Отношения элементов между собой могут быть: 45 | 46 | - `div p` – элементы p, являющиеся потомками div 47 | - `div > p` – только непосредственные потомки 48 | - `div ~ p` – правые соседи: все p на том же уровне вложенности, которые идут после div 49 | - `div + p` – первый правый сосед: p на том же уровне вложенности, который идёт сразу после div (если есть) 50 | 51 | А про приоритеты можно почитать [здесь](https://habrahabr.ru/post/137588/) и во многих других местах. 52 | 53 | 54 | 55 | - [1.7](#1.7) Не использовать `@import` внутри файлов. 56 | 57 | Имеется в виду, что в конечном `css` файле, который получает клиент, не должно быть этих конструкций. Но если настроен `WebPack` и `css-loader`, который как раз этот случай обрабатывает, либо используются компилируемые аналоги, которые умеют вместо импортов подставлять непосредственное содержимое файлов, то импорты возможны, так как браузер все равно их не увидит и не получит никогда в реальной работе. 58 | 59 | Можно выделить пару причин, почему не стоит использовать `@import`: 60 | 61 | - Некоторые старые браузеры не поддерживают использование правила `@import`, и стили, которые мы подгружаем через это правило, будут потеряны 62 | - `@import` блокирует параллельную загрузку стилей, а это означает, что браузер будет ожидать завершения загрузки импортированного файла, прежде чем начнёт обрабатывать остальную часть содержимого. 63 | - Более подробно можно почитать [здесь](http://www.stevesouders.com/blog/2009/04/09/dont-use-import/). 64 | 65 | 66 | 67 | - [1.8](#1.8) Все правила должны быть разбиты на разные файлы по страницам и блокам, каждый файл должен быть не длиннее, чем 1000 строк. 68 | 69 | 70 | 71 | - [1.9](#1.9) Каждое CSS-правило должно быть на отдельной строке. 72 | 73 | Это очень поможет как минимум при просмотре diff-ов в системе контроля версий. Плюс это позволит избежать горизонтальной прокрутки. 74 | 75 | 76 | 77 | - [1.10](#1.10) Для всех интерактивных элементов (ссылки, кнопки, дропдауны, инпуты, селекты) дизайнер может прорисовать отдельные состояния и спрятать в ближайшем слое — всегда проверять для каждого элемента, есть ли отрисованное состояние. 78 | 79 | 80 | 81 | - [1.11](#1.11) Дизайнеры могут ошибаться — иногда надо делать запросы на изменение макета, если они нарисовали что-то переусложненное. 82 | 83 | Например, в макете может быть отцентрированная по вертикали относительно текста полоска: 84 | 85 | | ![Пример](https://user-images.githubusercontent.com/12808495/55335190-df687980-54c4-11e9-8623-13ecdb996ebc.png) | 86 | | :-------------------------------------------------------------------------------------------------------------: | 87 | | _эта картинка просто пример, не факт, что тут как раз такая ошибка_ | 88 | 89 | Дизайнер может просто на глаз положить эту полоску на среднем уровне нижних букв текста, однако вы как верстальщики просто примените vertical-align: middle и увидите, что полоска выше/ниже уровня, который показал дизайн, и Pixel Perfect явно это подсвечивает. Чаще всего не надо хардкодить какой-нибудь неочевидный отступ, просто чтобы идеально соответствовать макету — лучше сказать дизайнеру, что автоматом полоска ставится на другое место и её лучше там и оставить. А дизайнеру подучить типографику. 90 | 91 | 92 | 93 | - [1.12](#1.12) Пытаться по максимуму делать сайт резиновым (ставьте ширину в процентах и выставляйте max-width, min-width) — прибегайте к фиксированной ширине элемента, только если по макету от этого никак не уйти. 94 | 95 | Если все-таки сайт должен быть с фиксированный шириной, обязательно проверяйте правую сторону каждой страницы на маленьких экранах. Очень частая ошибка новичков не все элементы делать с min-width, и при горизонтально прокрутке получается такая штука: 96 | 97 | ![image](https://rizzoma.com/r/files/a87a0a28b84d6326d4f3909e8801dab7-60dd9b15a5f2c5e495726e74545edcae-0-0.7016728184648524) 98 | 99 | 100 | 101 | - [1.13](#1.13) При сборке проекта при отсутствии дизайна (на CSS-фреймворках, например) избегать "лепки". 102 | 103 | Если вы разрабатываете проект, у которого нет дизайна (при помощи CSS-фреймворков, например), то старайтесь избегать лепки. 104 | 105 | Правила те же, что и при написании программных модулей: старайтесь придать пространства между компонентами, ограничить их друг от друга визуально (осуществляется слабое зацепление), но вместе с этим, сами компоненты должны выглядеть самодостаточно, т.е. обладать всем необходимым, но без избыточности, функционалом, чтобы это можно было назвать полноценной компонентой (осуществляется сильная связанность). 106 | 107 | Хорошим детектором является тут БЭМ: старайтесь делать отступы между блоками минимум в два раза больше, чем внутри блока между элементами. 108 | 109 | 110 | 111 | - [1.14](#1.14) Все стили одного блока должны быть в одном месте и отсортированы по порядку их расположения на странице. 112 | 113 | То есть, если есть шапка, а внутри нее поисковая форма, то в .css файлах нельзя сначала определить стили шапки, потом кучу стилей тела страницы и потом стили поисковой формы шапки. Должны идти стили самой шапки и сразу под ней стили формы. 114 | 115 | При этом стили сайдбара не могут идти раньше стилей шапки, а стили футера идти раньше стилей сайдбара. Лучше вообще эти стили разнести по разным файлам. 116 | 117 | 118 | 119 | - [1.15](#1.15) Футер страницы должен быть всегда прижат к низу страницы, даже если на странице мало контента ([5 методов, как сделать это](http://dimox.name/press_footer_bottom_with_css/)). 120 | 121 | 122 | 123 | - [1.16](#1.16) Имена. 124 | 125 | Использовать `lower-case-hyphenated` (то есть не `mySuperAwesomeElement` и не `my_super_awesome_element`) 126 | 127 | Имена должны отражать смысл, а не описание стилей (`"loading"`, а не `"big-yellow-spinny-thing"`) 128 | 129 | 130 | 131 | ## Правила 132 | 133 | 134 | 135 | - [2.1](#2.1) Не использовать `!important`. 136 | 137 | В 99% случаях проблему можно решить, грамотно используя `БЭМ` или `CSS modules`. В сложных редких случаях лучше увеличивать приоритет селекторов (например, когда надо стили библиотеки переопределить). 138 | 139 | 140 | 141 | - [2.2](#2.2) Не использовать `position: absolute` для стилизации, где это можно заменить другими подходами. 142 | 143 | 144 | 145 | - [2.3](#2.3) Не двигать элемент при помощи `top`, `left`, `right` или `bottom` при `position: relative`, где это можно заменить другими подходами. 146 | 147 | Можно использовать сам `position: relative` (без свойств `top`, `left`, `right` или `bottom`) для `z-index` и для того, чтобы указать потомкам элемента ориентир. 148 | 149 | 150 | 151 | - [2.4](#2.4) Не использовать отрицательные margin. 152 | 153 | На самом деле, отрицательные `margin` — это валидные правила, они поддерживаются спецификацией `CSS`, и их даже используют такие гиганты, как Bootstrap (посмотрите стили для `.row`). 154 | 155 | Но это очень неочевидные правила, их тяжело обнаружить, и их почти всегда можно заменить более легкими и предсказуемыми свойствами. 156 | 157 | 158 | 159 | - [2.5](#2.5) Избегать фиксирования высоты. 160 | 161 | Почти всегда использование фиксированного в пикселях, процентах и других единицах `height` является признаком неправильного кода. Это делает очень неочевидным поведение элементов, которые следуют за зафиксированным по высоте, может произойти обрезание контента или его наложение на следующие элементы. 162 | 163 | Когда это все-таки может быть нужно: 164 | 165 | - У элемента надо ручками подстроиться под высоту потомков, которых "убрали" из общего потока. "Убрать" из потока можно через `position: absolute`, например. Это может быть слайдер, у которого потомки крутятся как раз через позиционирование, а не смещение `margin`-ом 166 | 167 | - По дизайну надо подстроить все элементы под определенную высоту, а контент, вылезающий за пределы, обрезать. 168 | 169 | 170 | 171 | - [2.6](#2.6) Избегать фиксированных выравниваний. 172 | 173 | Если блок должен быть отцентрирован (хоть по горизонтали, хоть по вертикали), то центрировать его динамически, а не фиксированным `margin-top`. 174 | 175 | Например: 176 | 177 | ![Пример](https://user-images.githubusercontent.com/12808495/55335190-df687980-54c4-11e9-8623-13ecdb996ebc.png) 178 | 179 | Здесь картинку, текст и полоску надо центрировать через `vertical-align`, а не `top: 55px` у полоски. 180 | 181 | Часто будут попадаться случаи более сложного центрирования — почти для каждого есть свой метод, надо их отдельно изучать. 182 | 183 | [Статья про vertical-align](http://web-standards.ru/articles/vertical-align/) 184 | 185 | Что нужно сделать, чтобы центрировать по высоте _элемент1_ внутри _элемента2_: 186 | 187 | - Оба элемента должны быть любыми inline элементами 188 | 189 | - У _элемента2_ должен быть указан font-size или line-height. _Элемент2_ отцентрируется только в зависимости от font-size или line-height и не обратит внимания на height. 190 | 191 | 192 | 193 | - [2.7](#2.7) Прописывать дефолтный цвет фона, цвет шрифта, `font-size` и семейство шрифта у `html`. 194 | 195 | Далее размер шрифта будет ориентиром для всех элементов, у которых используется rem для единиц измерения кегля. 196 | 197 | 198 | 199 | - [2.8](#2.8) При тестировании обязательно посмотреть цвет `:visited` ссылки. 200 | 201 | Браузер по умолчанию такие ссылки фиолетовыми делает, что чаще всего недопустимо в дизайне. 202 | 203 | 204 | 205 | - [2.9](#2.9) Добавлять элементу `cursor: pointer`, если он кликабелен и по умолчанию этого не поддерживает. 206 | 207 | 208 | 209 | - [2.10](#2.10) Удалять все неиспользуемые правила и правила, которые никак не влияют на отображение (например, дублирующие свойства по умолчанию или нулевые `margin`, если они и так не выставлены) — они могут в дальнейшем при правках внести неочевидное поведение и из-за них тяжело разбираться в проекте. 210 | 211 | 212 | 213 | - [2.11](#2.11) Слова, целиком состоящие из верхнего регистра, предпочтительно делать через стиль `text-transform: uppercase`, а не реальным вводом текста заглавными буквами. 214 | 215 | 216 | 217 | - [2.12](#2.12) При установке элементу `outline: none` обязательно выставить стили для `:focus` этому элементу. 218 | 219 | `outline` очень полезен, когда юзер заполняет форму, используя клавишу `tab` для переключения между инпутами и кнопками. Если `outline` убрать, станет менее заметно (или незаметно вовсе для кнопок), какой элемент сейчас выбран. 220 | 221 | 222 | 223 | - [2.13](#2.13) Все использования `@media` должны идти сразу после основных правил элемента, для того чтобы можно было увидеть все правила и все возможные состояния элемента в одном экране без прокручивания. 224 | 225 | 226 | 227 | - [2.14](#2.14) Вендорные префиксы должны идти перед общим стилем. 228 | 229 | Стандартное правило всегда должно быть под специфичными правилами для каждого движка. 230 | 231 | Пример: 232 | 233 | ```css 234 | .thing { 235 | -webkit-transition: all 100ms; 236 | -moz-transition: all 100ms; 237 | -o-transition: all 100ms; 238 | transition: all 100ms; 239 | } 240 | ``` 241 | 242 | 243 | 244 | ## Шрифты 245 | 246 | 247 | 248 | - [3.1](#3.1) Если клиент предоставил макеты с кастомными шрифтами, проверить, свободные ли они и, если нет, то запросить купленные файлы шрифтов. 249 | 250 | 251 | 252 | - [3.2](#3.2) Если не требуется поддержка старых браузеров, шрифты должны быть в форматах `.woff2`, `.woff`. Сначала подключать `.woff2` шрифты, затем — `.woff` (пример ниже). 253 | 254 | 255 | 256 | - [3.3](#3.3) Если в проекте должна быть поддержка нелатинских символов (например, русских), проверьте, что в файле шрифта эти символы есть. 257 | 258 | 259 | 260 | - [3.4](#3.4) Разные начертания одного и того же шрифта подключайте под одним именем, но для разных `font-weight` и `font-style`. 261 | 262 | ```css 263 | @font-face { 264 | font-family: "Lato"; 265 | src: url("../fonts/lato-regular.woff2"), url("../fonts/lato-regular.woff"); 266 | font-weight: 400; 267 | font-style: normal; 268 | } 269 | @font-face { 270 | font-family: "Lato"; 271 | src: url("../fonts/lato-italic.woff2"), url("../fonts/lato-italic.woff"); 272 | font-weight: 400; 273 | font-style: italic; 274 | } 275 | @font-face { 276 | font-family: "Lato"; 277 | src: url("../fonts/lato-light.woff2"), url("../fonts/lato-light.woff"); 278 | font-weight: 300; 279 | font-style: normal; 280 | } 281 | @font-face { 282 | font-family: "Lato"; 283 | src: url("../fonts/lato-lightitalic.woff2"), 284 | url("../fonts/lato-lightitalic.woff"); 285 | font-weight: 300; 286 | font-style: italic; 287 | } 288 | ``` 289 | 290 | 291 | 292 | - [3.5](#3.5) Всегда использовать как минимум один запасной шрифт и одно запасное семейство. 293 | 294 | Их перечисляют через запятую в `font-family`, так что каждое использование `font-family` должно происходить по схеме: 295 | 296 | ```css 297 | block { 298 | font-family: Helvetica, Arial, sans-serif; 299 | } 300 | ``` 301 | 302 | Здесь `Helvetica` — нестандартный подключаемый шрифт. 303 | 304 | `Arial` — стандартный шрифт, который используется почти на всех клиентах, он будет использоваться, если не удалось подключить `Helvetica`. 305 | 306 | `sans-serif` — это семейство всех шрифтов без засечек (каковыми являются и `Helvetica`, и `Arial`). Если даже `Arial-а` на компе нет, то поставится какой-то системный дефолтный шрифт без засечек. Выбор здесь надо делать из `"serif,"` `"sans-serif,"` или `"monospace"`. Для шрифтов без засечек использовать по умолчанию `Arial`, для шрифтов с засечками — `Georgia` (а не `Times New Roman`), а для моноширинных — `"Courier New"` 307 | 308 | 309 | 310 | - [3.6](#3.6) Названия шрифтов, содержащие пробелы, цифры или знаки пунктуации, кроме дефисов, заключать в кавычки. 311 | 312 | Пример: 313 | 314 | ```css 315 | block { 316 | font-family: 'Times New Roman', serif; 317 | } 318 | ``` 319 | 320 | 321 | 322 | ## БЭМ 323 | 324 | 325 | 326 | - [4.1](#4.1) Именование БЭМ-сущностей должно следовать следующим ограничениям: 327 | 328 | Блок, элемент — всегда имя существительное (noun) 329 | 330 | Модификатор — должен удовлетворять свойствам [модификатора из английского языка](https://en.wikipedia.org/wiki/Grammatical_modifier). Всегда `adjective` или `adjectival phrase`. 331 | 332 | Таким образом, фразы на английском языке `"$BLOCK_NAME [is] $MODIFIER_NAME"`, `"$ELEMENT_NAME [is] $MODIFIER_NAME"` или `"$MODIFIER_NAME $BLOCK_NAME"`, `"$MODIFIER_NAME $ELEMENT_NAME"`, `"$ELEMENT_NAME WITH $MODIFIER_NAME $MODIFIER_KEY"` должны быть синтаксически корректными словосочетаниями. 333 | 334 | Примеры _корректных имён_: 335 | 336 | - `input_selected` — `selected input` — выделенный инпут или `input is selected` — инпут выделен 337 | - `header_size_large` — `header with large size` — заголовок с большим размером. 338 | 339 | Примеры _**НЕ**корректных имён_: 340 | 341 | - `form__`**_save_**`_small`, для элемента save (который, например, вешается на кнопку) — `small save` — маленький сохранить, `save small` — сохранить маленький. Правильно будет употребить noun вместо `verb` и переименовать элемент в **_`save-button;`_** `small save-button` — маленькая кнопка сохранения 342 | 343 | - `input_`**_focus_** — `input focus` — инпут сфокусировать или `input is focus` — инпут это фокус. Правильно будет употребить `adjective` вместо `noun/verb` и переименовать модификатор в `focused; input_`**_focused_** — `focused input` — сфокусированный инпут 344 | 345 | - `row_`**_error_** — `row error` — ошибка строки или `row is error` — строка это ошибка. Правильно будет употребить `adjectival phrase` вместо `noun` и переименовать модификатор в `with-error`. `row_`**_with_**`-error` — `row with error` — строка с ошибкой. 346 | 347 | Обоснование: мы сможем всегда однозначно и без лишних затрат энергии истолковать сущность элемента вёрстки и накладываемые на него свойства. 348 | 349 | 350 | 351 | - [4.2](#4.2) Верстаем всегда по БЭМу, архитектура верстки должна быть компонентной. 352 | 353 | Каждый блок должен лежать в своей папке. 354 | 355 | Папки блоков нельзя вкладывать друг в друга. 356 | 357 | 358 | 359 | - [4.3](#4.3) Каждый компонент — отдельный блок из методологии БЭМ. 360 | 361 | 362 | 363 | - [4.4](#4.4) Каждый компонент должен иметь только явные зависимости, быть самодостаточным. 364 | 365 | Все зависимости делать явно, импортируя в начале компонента и вставляя в нужное место верстки. 366 | 367 | Самодостаточность говорит о том, что каждый компонент должен внутри себя содержать все необходимое — всю верстку, все стили и все js-скрипты. 368 | 369 | Ничего лишнего в компоненте быть не должно: 370 | 371 | - Не должно быть определения других блоков внутри этого блока 372 | - Не должно быть стилей, которые бы влияли на другие блоки любым способом 373 | - Не должно быть глобальных стилей (например, на все теги `span`) 374 | - Компонент не должен влиять на `DOM` другого компонента (менять верстку крайне запрещено) 375 | 376 | 377 | 378 | - [4.5](#4.5) Кастомизировать компоненты только через модификаторы, никаких примесей. 379 | 380 | Почти в любом проекте возникает необходимость кастомизировать блоки. Например, есть вёрстка из 20 страниц. На 15 из этих страниц встречается хэдер, причём у 10 из них хэдер синего цвета, на трёх — серый, и на двух — прозрачный. Это значит, что компонент хэдер должен быть кастомизируемым, и осуществляются подобного рода кастомизации через добавление модификаторов к блоку, а не путём передачи отдельных классов со стилями. 381 | 382 | Предположим, что на фоне у промо страницы есть видео, и по дизайну нам нужно сделать прозрачный хэдер со светлым шрифтом (по умолчанию — тёмный). 383 | 384 | Плохо: 385 | 386 | ```pug 387 | .promo-page 388 | +header({ classname: 'promo-page__header' }) 389 | ``` 390 | 391 | Хорошо: 392 | 393 | ```pug 394 | .promo-page 395 | +header({ theme: 'transparent', font: 'light' }) 396 | ``` 397 | 398 | При правильном подходе, естественно, надо будет научиться принимать эти два параметра, добавлять самому модификаторы к нужным классам и в CSS компонента прописывать правила для этих модификаторов. 399 | 400 | Это правило внедрено после болезненного опыта поддержки проекта средней сложности, и вот какие шишки набиты с использованием примесей: 401 | 402 | - Нарушается инкапсуляции — использование внешних стилей внутри компоненты ведёт к проблемам в сопровождении в дальнейшем. Дело в том, что стили компоненты являются её составной частью и не должны влиять на то, что её окружает. Также справедливо обратное — внешние стили не должны влиять на компоненту. Иными словами, компонента должна быть самодостаточна. Прибегая к использованию внешних стилей, мы создаём зависимость между двумя стилями — внешним и внутренним. Каждому из стилей нужно знать, из чего состоит другой, чтобы глобальный стиль не поломал стиль компоненты. Это и есть нарушение инкапсуляции 403 | 404 | - Если компонента используется на 20 разных страницах, то после изменения одного свойства в самом компоненте придется пройти по всем 20 страницам вручную и проверить, что ничего не сломалось, потому что неизвестно, какие могут быть стили навешаны в местах использования через кастомные классы, и надо самому проверить все комбинации 405 | 406 | - Примесь обычно вешается только на верхний уровень компонента, но иногда надо кастомизировать что-нибудь внутреннее, тогда получается, надо уже две примеси передавать и принимать в компоненте, одна примесь — для свойств всего блока, вторая — для какого-то элемента, а когда понадобится еще другой элемент кастомизировать, придется добавить третью примесь :) 407 | 408 | - Не получится четко составить список всех возможных состояний компоненты, а при подходе с модификаторами мы явно видим все возможные параметры на входе, и когда их число будет зашкаливать, можем пнуть дизайнера, что он слишком расфантазировался и пора бы переходить к единому стайлгайду 409 | 410 | 411 | 412 | - [4.6](#4.6) Для позиционирования блока в родительском контейнере тоже не надо использовать миксы — решается данная проблема путем добавления специальных контейнеров. 413 | 414 | Допустим, есть родительский блок, в нем — дочерний блок, который нам и необходимо спозиционировать. Для позиционирования внутреннего блока создаем в родительском элемент-обертку и просто задаем свойства (_margin, padding, position_ etc) этому контейнеру. Таким образом, позиционирование блока у нас находится в файле родительского блока и никак не влияет на стили самого блока. 415 | 416 | Данный способ позволяет, не используя миксы, спозиционировать дочерний блок. 417 | 418 | Например, в хэдере у нас находится обычная голубая кнопка, но именно тут, в шапке, она должна иметь отступ с левой стороны, для этого мы добавим `div.header__button`: 419 | 420 | ```pug 421 | div.header 422 | div.header__button 423 | +button({ color:blue }) 424 | ``` 425 | 426 | А в стили хэдера просто добавим: 427 | 428 | ```css 429 | .header__button { 430 | margin-left: 3rem; 431 | } 432 | ``` 433 | 434 | 435 | 436 | ## Возможные ошибки 437 | 438 | > В css есть несколько очень неочевидных правил, лучше изучить их на теории заранее, чем ломать голову часами, почему верстка едет 439 | 440 | 441 | 442 | - [5.1](#5.1) Верхний margin первого элемента смещает за собой всех родителей вниз. 443 | 444 | Допустим, желаемый вид должен быть таким: 445 | 446 | ![image](https://user-images.githubusercontent.com/12808495/55340918-d92bca80-54cf-11e9-9701-eed499af7a05.png) 447 | 448 | Чтобы заголовок имел отступ от верхней границы, мы добавляем ему margin: 20px 0 0; однако получаем такое поведение: 449 | 450 | ![image](https://user-images.githubusercontent.com/12808495/55340961-f52f6c00-54cf-11e9-8506-09894ce1988e.png) 451 | 452 | Несмотря на то, что маржин был поставлен только заголовку, все его родители тоже съехали вниз: 453 | 454 | ![image](https://user-images.githubusercontent.com/12808495/55341005-0a0bff80-54d0-11e9-8ac2-1ca16dbc40a3.png) 455 | 456 | 457 | 458 | - [5.2](#5.2) Родители игнорируют всех детей, у которых установлены `float: left` или `float: right` 459 | 460 | 461 | 462 | - [5.3](#5.3) `z-index` свойство работает только для элементов, у которых значение position задано как `absolute`, `fixed` или `relative`. 463 | 464 | 465 | 466 | - [5.4](#5.4) А еще на `z-index` может повлиять `opacity` Почитать про это можно [тут](https://habrahabr.ru/post/166435/). 467 | 468 | 469 | 470 | - [5.5](#5.5) `height` в процентах не работает, если высота родителя формируется от контента. 471 | 472 | На `learn.javascript.ru` даже [статья](https://learn.javascript.ru/height-percent) есть. 473 | 474 | 475 | 476 | - [5.6](#5.6) Все `:hover` эффекты проверять на мобильных устройствах внимательно в отдельном порядке, если проект поддерживает отображения на мобилах. 477 | 478 | В разных браузерах ховеры ведут себя по-разному и это надо согласовывать с дизайнерами отдельно — иногда, чтобы он заработал, надо, например, отдельный тап по элементу делать. Соответственно, чтобы сработал клик, надо тапнуть два раза, что тоже для некоторых элементов будет очень странно. 479 | 480 | 481 | 482 | - [5.7](#5.7) Псевдоэлементы (`::after/before`) [не работают](https://stackoverflow.com/questions/14585070/css-after-pseudo-element-not-showing-up-on-img/14586588#14586588) с `self-closing tags` (``, ``, etc.). 483 | 484 | 485 | 486 | - [5.8](#5.8) Не использовать простой :hover для отображения новых элементов, которые нелегко достигнуть мышкой. 487 | 488 | Очень часто встречаются неудачные случаи с выпадающим меню, которое реализовано через псевдо-класс `:hover`, мало того, что это меню практически неработоспособно на мобильном устройстве, оно еще и доставляет немало головной боли пользователям десктопов. Решением в данном случае будет использование JavaScript. 489 | 490 | ![image](https://habrastorage.org/files/45f/aa7/1eb/45faa71eb7e74d3b8c39773cd181f298.gif) 491 | 492 | 493 | 494 | - [5.9](#5.9) В ряде браузеров (Chrome, Opera, Edge, Firefox 62-, Safari 10-) теги форм, такие как `button`, `fieldset` и `legend`, не могут стать flex-контейнерами. 495 | 496 | Возможное решение — использовать элемент-обертку внутри тега (например, `span class="button__text"` внутри кнопки), и уже для него указать свойство `display: flex`: 497 | 498 | ```html 499 | 502 | ``` 503 | 504 | ```css 505 | .button__text { 506 | display: flex; 507 | ...; 508 | } 509 | ``` 510 | 511 | Подробнее об этом и других багах, возникающих при работе с флексами, можно прочитать на [Flexbugs](https://github.com/philipwalton/flexbugs), перевод материала на русский [здесь](https://css-live.ru/articles/brauzernye-bagi-flexbox.html). 512 | 513 | Для решения проблем с флексами можно воспользоваться неплохим [postcss-плагином](https://github.com/luisrudge/postcss-flexbugs-fixes), который автоматически фиксит некоторые баги в написании стилей для флексов. 514 | -------------------------------------------------------------------------------- /Environment/README.md: -------------------------------------------------------------------------------- 1 | # Окружение 2 | 3 | Помимо написания кода и реализации функционала, нам, программистам, необходимо думать и о других вещах. О качестве и читаемости написанного кода, о написании кода в едином стиле, о создании качественной git истории и о многом другом. 4 | 5 | К счастью для нас, есть множество инструментов, которые нам в этом помогают. Именно о таких инструментах пойдёт речь в этом разделе. 6 | 7 | 1. [Git hooks with husky](./husky.md) 8 | 2. [Lint-staged](./lint-staged.md) 9 | 3. [Conventional Commits](./conventional-commits.md) 10 | 4. [Branches & Pull Requests](./branches-and-requests.md) -------------------------------------------------------------------------------- /Environment/branches-and-requests.md: -------------------------------------------------------------------------------- 1 | # Branches и Pull Requests 2 | 3 | Здесь можно найти небольшой свод правил и возможностей по именованию веток и ведению Pull Requests (или Merge Requests в GitLab). 4 | 5 | ## Branches 6 | 7 | Существует [множество](https://byurrer.ru/git-workflow) подходов к именованию и организации веток - GitFlow, GitHub flow, GitLab flow и др. Выберете вы один из этих или будете использовать свой, зависит от требований вашего проекта и от того, как вы договоритесь с командой. 8 | 9 | Вот простой вариант который можно использовать на проекте: 10 | 11 | - `main` (или `master`) - в этой ветке содержится самая стабильная версия вашего проекта, которая как правило используется для деплоя в production (хотя для этого может быть отдельная ветка `prod`). 12 | - `dev` - ветка разработки. В ней содержатся последние готовые фичи, добавленные в ваш проект. Ветка может быть развёрнута на стейдж для полной проверки функционала перед слиянием в `main` и деплоем в production. 13 | - Ветки с новым функционалом или любой другой задачей из инструмента по трекингу задач ответвляются от `dev` и именуются `issueNumber-short-task-description`. 14 | 15 | **Минимальная рекомендация** - если у вас на проекте есть трекинг задач (GitHub/GitLab issues, Jira и др), ветка должна именоваться в формате `label-issueNumber-short-task-description`, например: `feature-234-add-product-card`. Вы можете использовать лейблы из вашей системы трекинга задач. Если таковых не имеется, вот примеры для `label`: `feature, fix, docs, refactor, test, build, perf`. Если у вас на проекте нет трекинга задач, название ветки должно отражать суть ваших изменений. Название должно быть коротким и в тоже время понятным. 16 | 17 | ## Pull Requests 18 | 19 | Вы можете связать ваш Pull Request с одним или несколькими issues, которых он касается, используя синтаксис `#issueNumber` в описании Pull Request, например: `#234 #235`. 20 | 21 | Вы также можете сделать так, что бы issue автоматически закрылся после слияния ветки, добавив в описание Pull Request слово `closes` перед номером issue, например: `closes #234, closes #235`. 22 | 23 | Вы можете упомянуть какого-то человека в описании или комментариях Pull Request, используя синтаксис `@username`. 24 | 25 | Если ваш Pull Request содержит незаконченную задачу и не готов к слиянию, вы можете пометить его как `Draft` во время или после создания Pull Request. Интерфейс будет зависеть от того, где вы работаете, в GitHub или GitLab. Pull Request нельзя слить пока активна метка `Draft`. -------------------------------------------------------------------------------- /Environment/conventional-commits.md: -------------------------------------------------------------------------------- 1 | # Соглашение о коммитах 2 | 3 | Мы пишем коммиты в соответствии с [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) ([RU](https://www.conventionalcommits.org/ru/v1.0.0/)). В этом топике будет гайд о том, как использовать `Conventional Commits` в вашем проекте. 4 | 5 | Помимо Conventional Commits в сообществе есть несколько устоявшихся правил, которых мы придерживаемся: 6 | 7 | - Не использовать прошедшее время. То есть вместо `added` будет `add`, вместо `updated` будет `update` и так далее. 8 | - Текст коммитов писать в `lower case`. Например: `feat: add transaction component`, `fix: translation`. 9 | 10 |
11 | Содержание 12 | 13 | - [Зачем использовать соглашение о коммитах?](#зачем-использовать-соглашение-о-коммитах) 14 | - [Prerequisites](#prerequisites) 15 | - [Установка](#установка) 16 | - [Использование](#использование) 17 | - [Конфигурация](#конфигурация) 18 | - [[Опционально] Commitizen](#commitizen) 19 | 20 |
21 | 22 | ## Зачем использовать соглашение о коммитах? 23 | 24 | - Позволяет проще ориентироваться в истории Git как участникам проекта, так и новичкам. 25 | - Стимулирует делать более осмысленные и более качественные коммиты. Простые сообщения `fix` или `update` не подойдут. 26 | - Стимулирует делать коммиты меньших размеров благодаря ограничениям по типу (type) и контексту (scope) коммита. 27 | - Conventional Commits полностью совместимо с [семантическим версионированием](https://semver.org/) ([RU](https://semver.org/lang/ru/)). А это значит, что вы можете использовать множество инструментов для автоматической генерации CHANGELOG и выпуска релизов. Если однажды вам придётся разрабатывать и/или поддерживать какой-либо npm пакет, вам не придётся заново учиться писать коммиты. 28 | 29 | К сожалению даже с Conventional Commits чисто технически можно делать большие коммиты и писать непонятные текста коммитов. Но коллеги вам за это спасибо не скажут, а будущий "вы" будете ругать себя при попытке найти коммит с очередным багом. Соглашение о коммитах стимулирует и помогает думать в правильном направлении при оформлении коммитов. 30 | 31 | ## Prerequisites 32 | 33 | Прежде чем переходить к установке, прочтите официальную документацию [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) ([RU](https://www.conventionalcommits.org/ru/v1.0.0/)) и убедитесь, что вы установили [husky](./husky.md). 34 | 35 | ## Установка 36 | 37 | Мы будем использовать `husky` и `commitlint` ([документация](https://commitlint.js.org/#/)). 38 | 39 | 1. Установите следующие пакеты в качестве devDependencies используя ваш пакетный менеджер, например: 40 | 41 | `npm install --save-dev @commitlint/config-conventional @commitlint/cli` 42 | 43 | 2. Создайте в корне проекта файл `commitlint.config.js` со следующим содержимым: 44 | 45 | ```js 46 | module.exports = { 47 | extends: ['@commitlint/config-conventional'], 48 | rules: { 49 | 'subject-case': [2, 'always', ['lower-case']], 50 | } 51 | }; 52 | ``` 53 | 54 | 3. Добавьте скрипт в ваш `package.json`: 55 | 56 | ```json 57 | { 58 | "scripts": { 59 | "commitlint": "commitlint --edit" 60 | } 61 | } 62 | ``` 63 | 4. Создайте файл `.husky/commit-msg` со следующим содержимым: 64 | 65 | ```shell 66 | #!/usr/bin/env sh 67 | . "$(dirname -- "$0")/_/husky.sh" 68 | 69 | npm run commitlint 70 | # pnpm run commitlint <- if you're using pnpm 71 | # yarn commitlint <- if you're using yarn 72 | ``` 73 | 74 | Ура! Теперь сообщения ваших коммитов будут проверяться на соответствие Conventional Commits. 75 | 76 | ## Использование 77 | 78 | По умолчанию в `@commitlint/config-conventional` доступны следующие типы коммитов: 79 | 80 | - **feat:** Новый функционал. 81 | - **fix:** Фикс бага. 82 | - **docs:** Изменения документации. 83 | - **style:** Изменения, не затрагивающие поведение кода - (отступы, форматирование, кавычки и др.). Не путать с изменениями CSS стилей. 84 | - **refactor:** Изменение кода, которое не исправляет ошибку и не добавляет новый функционал. 85 | - **perf:** Изменение кода, улучшающее производительность. 86 | - **test:** Добавление тестов или исправление существующих. 87 | - **build:** Изменения, влиюящие на систему сборки или внешние зависимости. 88 | - **ci:** Изменения файлов и скриптов CI. 89 | - **chore:** Другие изменения не меняющие исходные или тестовые файлы. 90 | - **revert:** Отмена предыдущего коммита. 91 | 92 | Вы можете пользоваться этим как шпаргалкой, но через пару недель активного использования вам это не понадобится :). 93 | 94 | Один из возможных вариантов использования `scope` - в нём можно указывать путь к добавляемому/изменяемому модулю, например `feat(some-path/to/module): some-changes-description`. Это может существенно облегчить поиск по коммитам. В случаях, когда нет однозначного пути, его можно опустить. 95 | 96 | ## Конфигурация 97 | 98 | Вы так же можете расширить базовый конфиг, например, добавив новые типы коммитов. Для этого переопределите правила в объекте `rules` файла `commitlint.config.js`: 99 | 100 | ```js 101 | module.exports = { 102 | // Включение базового конфига 103 | extends: ['@commitlint/config-conventional'], 104 | rules: { 105 | // ваши правила 106 | }, 107 | }; 108 | ``` 109 | 110 | Подробнее о самих правилах можно почитать [здесь](https://commitlint.js.org/#/reference-rules). 111 | 112 | ## Commitizen (опционально) 113 | 114 | Commitizen - это инструмент, позволяющий создавать коммиты в соответствии с `Conventional Commits` в формате вопрос-ответ. Это необязательно, но возможно кому-то он понравится. Сначала в командной строке вас попросят выбрать тип коммита, затем его контекст (scope), затем его описание и так далее. Commitizen сам создаст коммит в правильном формате. 115 | 116 | ![1](https://raw.githubusercontent.com/commitizen/cz-cli/master/meta/screenshots/add-commit.png) 117 | 118 | Изначально, `commitizen` это самостоятельный инструмент, никак не связанный с `commitlint`. Но у `commitlint` есть адаптер, который позволяет запускать `commitizen`, который будет следовать конфигурации `commitlint.config.js`. 119 | 120 | ### Установка 121 | 122 | 1. Установите следующие пакеты в качестве devDependencies используя ваш пакетный менеджер, например: 123 | 124 | `npm install --save-dev @commitlint/cz-commitlint commitizen` 125 | 126 | 2. Добавьте следующие строчки в ваш `package.json`: 127 | 128 | ```json 129 | { 130 | "scripts": { 131 | "commit": "cz" 132 | }, 133 | "config": { 134 | "commitizen": { 135 | "path": "@commitlint/cz-commitlint" 136 | } 137 | } 138 | } 139 | ``` 140 | 141 | ### Использование 142 | 143 | Просто вызовите скрипт `commit` используя ваш пакетный менеджер, например: `npm run commit`. И всё! -------------------------------------------------------------------------------- /Environment/husky.md: -------------------------------------------------------------------------------- 1 | # Git hooks with husky 2 | 3 | Этот топик является предварительным условиям для некоторых инструментов из раздела **Окружение**. Здесь вкратце рассказывается о том, что такое `git hooks`, `husky` и как установить `husky` в ваш проект. 4 | 5 | ## Что такое `git hooks`? 6 | 7 | Хуки Git - это встроенный функционал Git, который позволяет вызывать пользовательские скрипты в случае возникновения определённых Git-событий. Например хук `pre-commit` будет вызван после вызова команды `git commit`, но перед фактическим созданием коммита. В этом хуке можно запустить тесты, линтеры или выполнить любую другую проверку кода. Если выполнение хука завершится с кодом, отличным от нуля, создание коммита будет отменено. Или хук `commit-msg` позволяет проверить сообщение коммита на соответствие заданному шаблону. Подробнее о хуках Git можно почитать в [официальной документации](https://git-scm.com/book/ru/v2/%D0%9D%D0%B0%D1%81%D1%82%D1%80%D0%BE%D0%B9%D0%BA%D0%B0-Git-%D0%A5%D1%83%D0%BA%D0%B8-%D0%B2-Git). 8 | 9 | ## Что такое `husky`? 10 | 11 | [Husky](https://typicode.github.io/husky/) — это инструмент, который позволяет нам легко использовать хуки Git и запускать нужные нам сценарии на разных событиях. Для этого достаточно добавить скрипт в файл `.husky/[название-хука]` вашего проекта. 12 | 13 | ### Установка 14 | 15 | 1. Используя ваш пакетный менеджер установите husky в качестве devDependency, 16 | например: 17 | 18 | `npm install husky --save-dev` 19 | 20 | 2. Активируйте хуки Git от `husky` выполнив команду: 21 | 22 | `npx husky install` 23 | 24 | После активации в корне вашего проекта появится папка `.husky`, внутри которой вы можете добавлять свои скрипты для разных [Git событий](https://git-scm.com/book/ru/v2/%D0%9D%D0%B0%D1%81%D1%82%D1%80%D0%BE%D0%B9%D0%BA%D0%B0-Git-%D0%A5%D1%83%D0%BA%D0%B8-%D0%B2-Git). Эта папка будет использоваться для некоторых инструментов из раздела [Окружение](../Environment/README.md). 25 | 26 | Эту команду необходимо будет выполнять после скачивания репозитория и установки зависимостей, так что рекомендуем добавить это в `README` вашего проекта, что бы ваши коллеги были в курсе использования `husky`. Ниже описан способ автоматической активации хуков Git после установки зависимостей. 27 | 28 | ### Опционально 29 | 30 | 1. Для автоматической активации хуков Git после установки зависимостей добавьте в ваш `package.json` следующую строчку: 31 | 32 | ```json 33 | { 34 | "scripts": { 35 | "prepare": "husky install" 36 | } 37 | } 38 | ``` 39 | Скрипт `prepare` является [скриптом жизненного цикла](https://docs.npmjs.com/cli/v10/using-npm/scripts#life-cycle-scripts), который будет выполняться после каждой установки зависимостей. 40 | 41 | Будьте осторожны, такое поведение может привести к проблемам в некоторых тестовых/продакшен серверах. Если вы столкнулись с такими проблемами, лучше использовать ручную активацию. 42 | 43 | Если вы используете Yarn 2+, замените `prepare` на `postinstall`. 44 | 45 | 46 | 4. Если вы используете Yarn 2+, ваш репозиторий публичный и вы публикуете его в реестре (напр. **npmjs.com**), вам необходимо установить `yarn add pinst --dev` и добавить в `package.json` следующее: 47 | 48 | ```json 49 | { 50 | "scripts": { 51 | "postinstall": "husky install", 52 | "prepack": "pinst --disable", 53 | "postpack": "pinst --enable" 54 | } 55 | } 56 | ``` 57 | Подробнее в [документации](https://typicode.github.io/husky/getting-started.html#yarn-2). 58 | 59 | -------------------------------------------------------------------------------- /Environment/lint-staged.md: -------------------------------------------------------------------------------- 1 | # Lint-staged 2 | 3 | [Lint-staged](https://github.com/lint-staged/lint-staged) - это небольшая утилита, которая позволяют запускать набор команд для файлов, которые были проиндексированы Git (добавлены с помощью `git add`). Нам это полезно тем, что мы можем настроить Git hooks и перед каждым коммитом запускать линтеры только для проиндексированных файлов. 4 | 5 | ## Prerequisites 6 | 7 | Прежде чем переходить к установке, убедитесь, что вы установили [husky](./husky.md). 8 | 9 | ## Установка 10 | 11 | 1. Установите `lint-staged` в качестве devDependencies используя ваш пакетный менеджер, например: 12 | 13 | `npm install --save-dev lint-staged` 14 | 15 | 2. Создайте в корне проекта файл `.lintstagedrc` со следующим содержимым: 16 | 17 | ```json 18 | { 19 | "*.{css}": "stylelint --fix", 20 | "*.{ts,tsx}": ["eslint --fix", "prettier --write"], 21 | "*.{md,json}": "prettier --write" 22 | } 23 | ``` 24 | Файл конфигурации может зависеть от особенностей вашего проекта. Подробнее [здесь](https://github.com/lint-staged/lint-staged#configuration). 25 | 26 | 3. Добавьте скрипт в ваш `package.json`: 27 | 28 | ```json 29 | { 30 | "scripts": { 31 | "lint-staged": "lint-staged" 32 | } 33 | } 34 | ``` 35 | 4. Создайте файл `.husky/pre-commit` со следующим содержимым: 36 | 37 | ```shell 38 | #!/usr/bin/env sh 39 | . "$(dirname -- "$0")/_/husky.sh" 40 | 41 | npm run lint-staged 42 | # pnpm run lint-staged <- if you're using pnpm 43 | # yarn lint-staged <- if you're using yarn 44 | ``` 45 | 46 | ## Использование 47 | 48 | Просто делайте коммиты как обычно. Вышеупомянутый конфиг будет запускать скрипты линтеров с автоматическим исправлением для индексированных файлов. Если какой-то скрипт завершится с ошибкой, создание коммита будет отменено. -------------------------------------------------------------------------------- /HTML/README.md: -------------------------------------------------------------------------------- 1 | # HTML 2 | 3 | 1. [Семантика](#1) 4 | 2. [Теги](#2) 5 | 3. [Подключаемые файлы](#3) 6 | 7 | 8 | 9 | ## Семантика 10 | 11 | 12 | 13 | - [1.1](#1.1) Объединять блоки не по их визуальному расположению, а по их смыслу. 14 | 15 | Объединяем блоки вот так: 16 | ![хороший пример](https://github.com/fullstack-development/developers-roadmap/assets/90761929/db6e1f7c-59d9-41dd-8334-ca96d7a07049) 17 | 18 | А не вот так: 19 | ![плохой пример](https://github.com/fullstack-development/developers-roadmap/assets/90761929/16982193-66b0-447e-bf32-3956f2f3a584) 20 | Как минимум, это очень легко позволит потом добавить новый элемент, когда надо будет по требованию заказчика сделать лист из 4 элементов, а не трех, как здесь. Плюс второй подход очень неудобен, если контент генерируется динамически. Так что если вы создаете верстку, которую потом будут прикручивать к бэкенду заказчики, и сделаете такую верстку, проклятия от их программистов и порча всей нашей кармы обеспечены. 21 | 22 | 23 | 24 | - [1.2](#1.2) Если есть что-то похожее на список, проверяем, как будет выглядеть при большем количестве элементов. 25 | 26 | ![список](https://rizzoma.com/r/files/a87a0a28b84d6326d4f3909e8801dab7-97a135d68ad6e2e449e9c9f2dbf9766c-0-0.6276249218551724) 27 | 28 | Если непонятно, что будет при 4-х элементах, как в этом случае, обязательно спросить, а не принимать решение самостоятельно 29 | 30 | 31 | 32 | - [1.3](#1.3) Все элементы с текстом, контент которых формируется динамически, проверяем на то, чтобы они не ломались при большем количестве текста, чем на макете. 33 | 34 | В имена подставляем знаменитое [Константин Константинопольский](https://tema.livejournal.com/1322108.html). 35 | В идеале моменты, которые будет трудно масштабировать текстом, находить еще на стадии знакомства с макетом и задавать вопросы дизайнеру. 36 | 37 | 38 | 39 | - [1.4](#1.4) Проверять страницы на наличие ошибок [W3C валидатором](https://validator.w3.org/#validate_by_uri). Если требуется прогонять страницы локально, воспользоваться [расширением для браузера](https://chrispederick.com/work/web-developer/). Предупреждения можно устранять по мере необходимости, исходя из условий проекта. 40 | 41 | Часто встречающиеся ошибки: 42 | 43 | 44 | 45 | - [1.4.1](#1.4.1) Вставка блочных элементов внутрь инлайновых. 46 | 47 | Никаких `
`. 48 | 49 | 50 | 51 | - [1.4.2](#1.4.2) Не предназначенные для расширения другими файлами через какой-нибудь шаблонизатор .html файлы страниц начинаются не с ``, что противоречит HTML5 стандарту. 52 | 53 | 54 | 55 | - [1.4.3](#1.4.3) Используются самозакрывающиеся теги, если они поддерживают другой режим. 56 | 57 | Нельзя: 58 | 59 | ```html 60 |
61 | 62 | ``` 63 | 64 | Можно: 65 | 66 | ```html 67 | 68 | 69 | 70 | ``` 71 | 72 | 73 | 74 | - [1.4.4](#1.4.4) Не все изображения `` содержат `alt` атрибут. 75 | 76 | 77 | 78 | - [1.4.5](#1.4.5) Есть вложенные формы `
`. 79 | 80 | Полный список потенциальных ошибок описан [тут](https://validator.w3.org/docs/errors.html). 81 | 82 | 83 | 84 | - [1.5](#1.5) Использовать h1..h6 только для заголовков, причем h1 должен встречаться в одной странице всего один раз. 85 | 86 | 87 | 88 | - [1.6](#1.6) Использовать `` только для реальных таблиц. 89 | 90 | Если перед таблицей есть её текстовое описание, сделать это внутри тега `
` через `` и вложенные `
`. 91 | Если у таблицы первая строка идет заголовком, то использовать `
` для этого и использовать "scope" для этих ячеек. 92 | 93 | Пример: 94 | 95 | ```html 96 | 97 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 |
98 | First two U.S. presidents 99 |
NameTook officeParty
George WashingtonApril 30, 1789n/a
John AdamsMarch 4, 1797Federalist
120 | ``` 121 | 122 | 123 | 124 | - [1.7](#1.7) Не использовать `
` нигде, кроме случаев, когда соблюдены все требования: 125 | 126 | - Newlines are semantically meaningful. 127 | - Indentation is not semantically meaningful (otherwise you should use a `
`).
128 |   - There exists no other semantically appropriate tag, like a paragraph or header tag.
129 | 
130 | 
131 | 
132 | - [1.8](#1.8) Использовать семантические теги.
133 | 
134 |   Почему их нужно использовать, узнать можно [здесь](https://www.youtube.com/watch?v=bDYEnNzprzE) и [здесь](https://developer.mozilla.org/ru/docs/Learn/%D0%94%D0%BE%D1%81%D1%82%D1%83%D0%BF%D0%BD%D0%BE%D1%81%D1%82%D1%8C/HTML).  
135 |   [Блок-схема](http://html5doctor.com/downloads/h5d-sectioning-flowchart.pdf) для выбора семантических тегов.
136 | 
137 | 
138 | 
139 | ## Теги
140 | 
141 | 
142 | 
143 | - [2.1](#2.1) Все теги должны работать даже без CSS и JS.
144 | 
145 |   Все тексты, видимые сначала при открытии страницы так же должны быть доступны, формы должны сабмититься, ссылки должны переходить (а ссылки, по которым вообще не должно быть перехода и для которых принято ставить `href="#"`, вообще не использовать, это будет далее).
146 | 
147 | 
148 | 
149 | - [2.2](#2.2) Структура тегов в первую очередь должна идти от содержания, а не от дизайна
150 | 
151 |   ![пример](http://image.prntscr.com/image/a89c1aed00f14864851989caceacd59d.png) — например, такой элемент можно оформить как четыре идущих подряд элемента: иконка сообщений, бадж с цифрой 10, иконка аватара и имя пользователя. Но тут надо явно объединить с помощью `
` два блока, чтобы семантически они были отдельными — блок с информацией по сообщению и блок про пользователя. Для css потом, возможно, придется писать лишние стили, но верстка будет более осмысленной и не привязанной лишний раз к дизайну. 152 | 153 | 154 | 155 | - [2.3](#2.3) Перед `` не должно быть никаких символов, включая пробелы и переносы строк. 156 | 157 | 158 | 159 | - [2.4](#2.4) Внутри `` первым тегом должно идти ``. 160 | 161 | 162 | 163 | - [2.5](#2.5) У каждой страницы должны быть теги `title` и мета теги `keywords`, `description` (на содержимое спросить контент у менеджера). 164 | 165 | 166 | 167 | - [2.6](#2.6) В `head` добавлять `` — на мобильных браузерах можно избежать горизонтального скролла и масштабировать контент на всю ширину экрана. 168 | 169 | 170 | 171 | - [2.7](#2.7) Все атрибуты должны быть внутри двойных кавычек 172 | 173 | Нельзя: 174 | 175 | ```html 176 | 177 |
178 | 179 |
180 | ``` 181 | 182 | Можно: 183 | 184 | ```html 185 | 186 |
187 | 188 |
189 | ``` 190 | 191 | Плюс, если в проекте нет других соглашений, атрибуты должны именоваться lower-case-hyphenated (имена только маленькими буквами и через дефис) и, если значение строковое и показывает какое-то имя, то тоже должно быть lower-case-hyphenated. Кастомные атрибуты стараться начинать с data- (это стандартная практика, рекомендованная для HTML5). 192 | 193 | Пример: `Home` 194 | 195 | 196 | 197 | - [2.8](#2.8) Не использовать id, кроме случаев, когда они семантически востребованы. 198 | 199 | Когда гарантируется их уникальность, например, на уровне базы данных и когда вам нужно: 200 | 201 | - сделать рабочую навигацию в рамках одной страницы (например, как на Википедии или на этом сайте сборника [best-practices](https://isobar-idev.github.io/code-standards/#javascript_javascript). 202 | - связать `