Финал

1. Вступление
Итак, мы в самом конце начала пути. Мы изучили основы HTML и CSS, познакомились с JavaScript, научились пользоваться различными средствами разработки. Это последний урок нашего курса, но, действительно, самое начало дальнейшего пути развития frontend-разработчика. Всё самое интересное лишь впереди.
На данном уроке мы ещё немного поговорим о сторонних библиотеках, прикрутим валидацию для наших форм, разберём некоторые моменты, связанные с оптимизацией, а начнём с CSS.
2. Ещё немного CSS
2.1 CSS-переменные
CSS не стоит на месте, а развивается, и если раньше переменные были территорией CSS-препроцессоров, то теперь мы можем их использовать и в обычном CSS, хотя и со своими особенностями и ограничениями. Очень коротко разберём теоретическую часть.
Объявление переменной:
.element {
--main-color: red;
}
Использование переменной:
.element {
color: var(--main-color);
}
Переменные задаются внутри обычного CCS-правила и затем могут быть использованы для всех элементов, для которых действует данное правило. CSS-переменные наследуют значения от своих родителей и подчиняются каскаду.
Мы можем задать глобальные переменные, объявив их в правиле для псевдокласса :root
, который соответствует корневому элементу документа <html>
.
:root {
--main-color: red;
}
.element {
color: var(--main-color);
}
Благодаря CSS-переменным мы можем легко менять тему всего сайта, к примеру, изменив всего лишь один класс корневого элемента. Кроме того, мы можем сочетать их с переменными CSS-препроцессоров.
Пример:
@black: #02040E;
@white: #ffffff
:root {
--bg: @white;
--color: @black;
}
:root.theme-dark {
--bg: @black;
--color: @white;
}
body {
background-color: var(--bg);
color: var(--color);
}
В рамках учебного проекта CSS-переменные нам понадобятся в одном из примеров далее.
2.2 Нормализация стилей
Мы с вами знаем, что браузеры задают стили «по умолчанию» для многих HTML-элементов. Причём, в зависимости от браузера эти стили могут отличаться, что может привести к разному внешнему виду одних и тех же элементов.
Для решения проблемы существует два пути: сброс стилей и нормализация.
Первый путь предполагает «обнуление» всех стилей. Данное решение простое, но не очень хорошее — нам понадобится обязательно самостоятельно задать стили для всех используемых элементов — заголовков, абзацев текста, списков и так далее. Пример реализации reset.css
можно посмотреть по данной ссылке.
Гораздо более приемлемый путь — нормализация стилей, которая подразумевает их приведение к общему стандартному виду для всех браузеров.

Скачайте normalize.css
по ссылке, переименуйте в normalize.less
, положите в каталог src/styles/global
и подключите его самым первым в styles.less
.
3. Ещё немного JS
3.1 Библиотека Jquery
Начнём, пожалуй, с момента, который может вызвать споры у опытных разработчиков, а именно с jQuery.
Это JavaScript-библиотека, облегчающая взаимодействие с HTML и имеющая большое количество встроенных методов для самых разных целей, в том числе для асинхронных запросов, анимаций или обработки событий. Данная библиотека очень проста в освоении и имеет лёгкий синтаксис. Для неё создано огромное количество сторонних плагинов, которые мы можем использовать.
Но время не стоит на месте, развивается сам JavaScript, в нём постоянно появляются новые возможности, большой кусок рынка веб-разработки заняли библиотеки и фреймворки для создания веб-приложений, такие как Angular, React или Vue. Популярность jQuery значительно упала, многие разработчики даже считают использование данной библиотеки моветоном, предпочитая нативный JavaScript.
Однако, даже сейчас огромное количество команд и независимых разработчиков используют библиотеку jQuery в своих проектах, так как она по-прежнему отлично решает свои задачи, поэтому мы не можем пройти мимо. Помните, время — деньги. Если что-то помогает быстро и качественно решить вашу задачу, используйте это. А для простых проектов, подобных нашему, это отличный вариант.
Положите соответствующий файл в каталог src/scripts/vendor
и подключите библиотеку перед всеми прочими скриптами. Напоминаем, подключать используемые скрипты вы можете в самом конце <body>
или в <head>
с атрибутом defer
.
<html>
<body>
<!-- Содержимое страницы -->
<script src="scripts/jquery-3.6.0.min.js"></script>
<script src="scripts/swiper.min.js"></script>
<script src="https://maps.googleapis.com/maps/api/js?key="></script>
<script src="scripts/main.min.js"></script>
</body>
</html>
C синтаксисом jQuery и некоторыми возможностями познакомимся далее на практических примерах, отдельно разбирать не будем.
3.2 Кастомный селект для формы
Давайте вспомним, что в попапе с формой заявки на проведение мероприятия у нас остался стандартный и не очень красивый селект. Для селектов существует огромное количество плагинов, выбор — лишь дело вкуса. Воспользуемся jQuery Selectric, это очень простой и легковесный плагин. Подключите его аналогично тому, как мы подключали Swiper на прошлом уроке, но обязательно после библиотеки jQuery.
<html>
<body>
<!-- Содержимое страницы -->
<script src="scripts/jquery-3.6.0.min.js"></script>
<script src="scripts/jquery.selectric.min.js"></script>
<!-- прочие скрипты -->
</body>
</html>
Не забудьте и о родных стилях плагина. Второй раз на этом подробно останавливаться не будем, но в целях кастомной стилизации нам понадобится новый файл selectric_theme.less
со следующим содержимым:
.selectric-wrapper {
position: relative;
&::after,
&::before {
content: "";
position: absolute;
top: 27px;
width: 8px;
height: 2px;
background-color: @black;
transition: transform .2s;
z-index: 10;
}
&::after {
right: 22px;
transform: rotate(-45deg);
@media @bw500 {
right: 12px;
}
}
&::before {
right: 27px;
transform: rotate(45deg);
@media @bw500 {
right: 17px;
}
}
}
.selectric-open {
z-index: 10;
&.selectric-wrapper {
&:after {
transform: rotate(45deg);
}
&:before {
transform: rotate(-45deg);
}
}
& .selectric-items {
display: block;
margin-top: 5px;
width: 100% !important;
}
}
.selectric {
height: 55px;
border-radius: 5px;
border: none;
background-color: @white;
& .button {
display: none;
}
& .label {
display: flex;
align-items: center;
box-sizing: border-box;
padding: 17px 0 16px;
margin: 0 23px;
height: 100%;
font-size: 16px;
line-height: 1;
@media @bw400 {
font-size: 14px;
}
}
}
.selectric-items {
border-radius: 5px;
border: none;
background-color: @white;
box-shadow: 0px 0px 20px rgba(0, 0, 0, 0.2);
overflow: hidden;
& .selectric-scroll {
.overflow-x: hidden;
.overflow-y: auto;
}
& li {
padding: 10px 23px;
font-size: 16px;
@media @bw400 {
font-size: 14px;
}
}
}
Инициализацию для плагина сделаем в файле main.js
:
const jsSelectric = $(".js-selectric");
if (jsSelectric.length) {
jsSelectric.selectric({
nativeOnMobile: false
});
}
Что тут происходит? Взаимодействие с jQuery осуществляется с помощью метода $
. Если мы передаём в него CSS-селектор в качестве параметра, то получим jQuery-коллекцию найденных элементов.
Обратите внимание, возвращается всегда именно коллекция. Она будет пустой, если элементы не найдены. А значит, чтобы проверить наличие элементов на странице, мы должны обратиться к свойству length
, чтобы убедится, что его значение больше нуля.
Далее мы инициализируем плагин с желаемыми параметрами. Инициализация произойдёт для всех элементов коллекции, нам не нужно использовать цикл, если мы хотим применить jQuery-плагин для нескольких элементов.
В итоге должно получиться так:

3.3 Маска для номера телефона
Очень часто для полей ввода может понадобиться разрешить ввод только определённых символов в соответствии с заданным шаблоном. В нашем проекте в форме заявке есть поле для ввода номера в формате +7
.

Для решения этой задачи воспользуемся jQuery Mask Plugin. Скачайте плагин с главной страницы по предложенной ссылке или c репозитория на GitHub. Подключите его аналогично jQuery Selectric.
Сперва добавим js-класс полю ввода:
<input
class="field__input js-mobileMask"
type="tel"
placeholder="Телефон"
name="phone"
required
/>
Всё что осталось — применить плагин в нашем main.js.
const mobileMask = $('.js-mobileMask');
if (mobileMask.length) {
mobileMask.mask('+7 (000) 000 00 00', { placeholder: "+7 (___) ___ __ __" });
}
3.4 Календарь для выбора даты
Заставлять вводить пользователя дату вручную может быть очень неудобно, поэтому частое решение для таких полей — выбор даты с помощью календаря.
Таких плагинов достаточно много, в качестве примера воспользуемся Air Datepicker. Вы можете забрать скрипт и стили с репозитория на GitHub и подключить всё аналогично тому, как подключали предыдущие плагины.
В конечном счёте должен получиться следующий вид:

Разметка
Сначала изменим разметку и стили. У нас было три поля: день, месяц и год. Сделаем их нередактируемыми и недоступными для пользователя, они будут отвечать только за визуальную составляющую, поэтому не должны иметь атрибут name
.
Кроме того добавим ещё одно нередактируемое поле и разместим его над предыдущими трёмя. Оно будет полностью прозрачным, хранить полную дату и вызывать календарь по клику.
Все четыре поля и общая обёртка должны иметь свой js-класс.
<div class="form__field field js-dateField">
<h6 class="field__title">Дата проведения:</h6>
<div class="field__date">
<div class="field__date-inputs">
<input
class="field__date-input js-dateDay"
type="text"
placeholder="ДД"
readonly
/>
<input
class="field__date-input js-dateMonth"
type="text"
placeholder="ММ"
readonly
/>
<input
class="field__date-input field__date-input--year js-dateYear"
type="text"
placeholder="ГГГГ"
readonly
/>
</div>
<input
class="field__date-picker js-dateInput"
type="text"
name="date"
readonly
required
/>
</div>
</div>
Стили для полей:
.field {
&__date {
position: relative;
display: flex;
flex-direction: column;
width: 100%;
max-width: 250px;
}
&__date-inputs {
position: absolute;
top: 0;
left: 0;
display: flex;
width: 100%;
height: 55px;
pointer-events: none;
}
&__date-input {
box-sizing: border-box;
display: block;
width: 55px;
height: 55px;
margin-right: 15px;
border: none;
border-radius: 5px;
background-color: @white;
padding: 0 5px;
font-size: 16px;
line-height: 1.375;
text-align: center;
pointer-events: none;
@media @bw400 {
font-size: 14px;
}
&--year {
flex-grow: 1;
margin-right: 0;
}
}
&__date-picker {
box-sizing: border-box;
position: relative;
width: 100%;
max-width: 250px;
height: 55px;
border: none;
border-radius: 5px;
opacity: 0;
cursor: pointer;
}
}
Инициализация плагина
Для каждого блока .js-dateField
циклом найдём все поля, применим плагин, а по выбору даты в календаре будем подставлять соответствующие значения:
const dateField = $(".js-dateField");
if (dateField.length) {
const pickerInit = function (pick) {
const dateInput = pick.find(".js-dateInput");
const dateDay = pick.find(".js-dateDay");
const dateMonth = pick.find(".js-dateMonth");
const dateYear = pick.find(".js-dateYear");
const dateConfig = {
autoClose: true,
minDate: new Date(),
navTitles: {
days: "MMMM <i>yyyy</i>"
},
onSelect: function ({ date }) {
dateDay.val(date ? ("0" + date.getDate()).slice(-2) : "");
dateMonth.val(date ? ("0" + (date.getMonth() + 1)).slice(-2) : "");
dateYear.val(date ? date.getFullYear() : "");
}
};
new AirDatepicker(dateInput[0], dateConfig);
};
$.each(dateField, function (i) {
pickerInit($(this));
});
}
Здесь для перебора коллекции мы использовали jQuery-метод $.each()
;
Объект Date
на примере календаря
В конфиге календаря для ограничения минимальной доступной даты и вывода дня месяца и года в полях мы используем следующие встроенные методы:
new Date()
— при отсутствии аргумента возвращает текущую дату;getDate()
— возвращает день месяца указанной даты по местному времени, это число от1
до31
;getMonth()
— возвращает месяц указанной даты по местному времени, это число от0
до11
, нумерация месяцев начинается с нуля;getFullYear()
— возвращает год указанной даты по местному времени.
Подробнее с объектом Date
и доступными методами ознакомьтесь самостоятельно.
Стилизация календаря
Осталось стилизовать стили календаря в файле air-datepicker_theme.less
. Здесь нам пригодятся CSS-переменные, с которыми мы познакомились в начале данного урока.
.air-datepicker-overlay {
--adp-overlay-z-index: 119;
}
.air-datepicker {
--adp-z-index: 120;
--adp-width: 250px;
--adp-border-radius: 5px;
--adp-border-color-inner: @gray;
--adp-font-family: @font1;
--adp-day-name-color: @black;
--adp-day-name-color-hover: @red;
--adp-accent-color: @red_dark;
--adp-color-secondary: @red;
--adp-cell-background-color-selected: @red_dark;
--adp-cell-background-color-selected-hover: @red;
--adp-background-color-hover: @gray;
--adp-background-color-active: @gray_dark;
}
.air-datepicker-nav--title {
color: @black;
}
.air-datepicker-nav--title i {
color: inherit;
}
.air-datepicker-body--day-name,
.air-datepicker-cell {
font-weight: 700;
}
.air-datepicker-cell.-disabled- {
pointer-events: none;
}
4. Валидация форм
4.1 Плагин валидации
Перед отправкой данных формы следует проверить все поля на правильность заполнения. Стандартной валидации не всегда достаточно, кроме того её визуальная реализация отличается в разных браузерах.
Воспользуемся jQuery Validation Plugin, который отлично решает свою задачу. Вы можете скачать скрипт с репозитория на GitHub и подключить его аналогично предыдущим плагинам.
Помимо файла jquery.validate.js
в каталоге dist
вы сможете найти дополнительные методы и локализацию, но подключать их отдельное не будем.
Для валидации форм создадим новый файл, к примеру jquery.validate-init.js
, положим его в src/scripts/dev
и подключим после скрипта самого плагина. В этом файле добавим локализацию, пример собственного метода валидации, а далее будем валидировать сами формы.
(function () {
if (!$ || !$.validator) return;
$.extend($.validator.messages, {
required: "Это поле обязательно",
remote: "Пожалуйста, введите правильное значение.",
email: "Пожалуйста, введите корректный e-mail",
url: "Пожалуйста, введите корректный URL.",
date: "Пожалуйста, введите корректную дату.",
dateISO: "Пожалуйста, введите корректную дату в формате ISO.",
number: "Пожалуйста, введите число.",
digits: "Пожалуйста, вводите только цифры.",
creditcard: "Пожалуйста, введите правильный номер кредитной карты.",
equalTo: "Пароли не совпадают!",
extension: "Пожалуйста, выберите файл с правильным расширением.",
maxlength: $.validator.format(
"Пожалуйста, введите не больше {0} символов."
),
minlength: $.validator.format(
"Пожалуйста, введите не меньше {0} символов."
),
rangelength: $.validator.format(
"Пожалуйста, введите значение длиной от {0} до {1} символов."
),
range: $.validator.format("Пожалуйста, введите число от {0} до {1}."),
max: $.validator.format(
"Пожалуйста, введите число, меньшее или равное {0}."
),
min: $.validator.format(
"Пожалуйста, введите число, большее или равное {0}."
)
});
$.validator.addMethod(
"email",
function (value, element) {
return (
this.optional(element) ||
/^[-\w.]+@([A-z0-9][-A-z0-9]+\.)+[A-z]{2,6}$/.test(value)
);
},
"Введите корректный e-mail"
);
//дальнейший код для валидации форм
})();
jQuery Validation Plugin имеет собственные правила для валидации форм, но мы легко можем добавить новые или заменить существующие, если нас что-то не устраивает, как это и сделано в примере выше .
4.2 Форма заявки в попапе
Самый простой пример, для начала в разметке всем обязательным полям зададим атрибут required
, а самой форме — идентификатор id
.
<form class="pp__form form" id="js-eventForm"></form>
Код JacaScript совсем небольшой:
const eventForm = $('#js-eventForm');
if (eventForm.length) {
eventForm.validate({
errorElement: "span"
});
}
Добавим стили для сообщения об ошибке:
.field {
label.error,
span.error {
display: block;
margin: 5px 0 0;
}
}
Теперь всё должно работать как нужно, наша форма в попапе, наконец, полностью готова!

4.3 Форма подписки, AJAX-запрос
В футере нашего сайта расположена форма подписки. Разметку и стили задайте самостоятельно, они довольно простые. Подключите валидацию формы по предыдущему примеру. При попытке отправить невалидную форму вы должны получить следующий вид:

Такие формы должны работать без перезагрузки страницы. На помощь нам придёт удобный и простой jQuery-метод $.ajax()
. Подробно с методом можно ознакомиться по данной ссылке.
Кроме того нам понадобится адрес, по которому будет отправлен асинхронный запрос. Воспользуемся в тестовых целях бесплатным сервисом {JSON} Placeholder и зададим адрес в атрибуте формы action
.
<form
action="https://jsonplaceholder.typicode.com/posts"
class="page-footer__subscribe-form subscribe-form"
id="js-subscribeForm"
>
<!-- Разметка формы -->
</form>
const subscribeForm = $("#js-subscribeForm");
if (subscribeForm.length) {
const subscribeAction = subscribeForm.attr("action");
const subscribeEmail = subscribeForm.find("#js-subscribeEmail");
subscribeForm.validate({
errorElement: "span",
submitHandler: function (form, event) {
event.preventDefault();
$.ajax({
url: subscribeAction,
method: "POST",
data: {
email: subscribeEmail.val()
},
success: function () {
subscribeEmail.val("");
subscribeEmail.blur();
alert("Вы успешно подписались на рассылку новостей");
},
error: function () {
alert("Что-то пошло не так, попробуйте еще раз");
}
});
}
});
}
При успешной отправке формы очистим поле ввода, снимем с него фокус, а затем будет выведено сообщение о подписке.

В реальном проекте нам нужно будет создать стилизованное окно для вывода сообщения вместо стандартного. Очень быстро это можно сделать с помощью специально предназначенных для этого плагинов, например, toastr.
Самостоятельно ознакомьтесь с AJAX-запросами и Fetch API, это важные темы, которые обязательно нужно изучить, но они выходит за пределы нашего курса.
5. Ещё немного разметки
5.1 Favicons и мета-теги веб-приложения
Favicon – это небольшой значок веб-сайта, который отображается во вкладке браузера, закладках, а также может быть отражён в сниппетах результатов поиска. Он используется для улучшения пользовательского опыта и обеспечения узнаваемости бренда.
Пользователь может добавить страницу вашего сайта на главный экран телефона или сохранить как веб-приложение, в том числе и на персональном компьютере. В этом случае фавиконка будет использована как обычная иконка приложения на ряду с любыми другими.

Раньше в качестве основного формата для фавиконки использовался ICO
в размере 16*16 пикселей, но затем ему на смену пришел формат PNG
, и все современные браузеры его поддерживают. Формат ICO
на данный момент нужен лишь для поддержки устаревших браузеров.
Указываются фавиконки в шапке сайта <head>
, при этом для различных платформ и устройств желательно задать разные размеры.
Для десктопа достаточно 16*16
и 32*32
.
<link rel="shortcut icon" type="image/vnd.microsoft.icon" href="/assets/favicons/favicon.ico">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicons/favicon-16x16.png">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicons/favicon-32x32.png">
В Windows 8.1 появилась возможность закреплять ссылки на сайты в виде живых плиток. Иконки различных размеров можно задать с помощью мета-тегов и в файле browserconfig.xml
:
<meta name="msapplication-TileColor" content="#dedede">
<meta name="msapplication-TileImage" content="/assets/favicons/ms-icon-144x144.png">
<meta name="msapplication-config" content="/assets/favicons/browserconfig.xml">
Пример содержимого browserconfig.xml
:
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square70x70logo src="/assets/icons/favicon/favicon-70x70.png"/>
<square150x150logo src="/assets/icons/favicon/favicon-150x150.png"/>
<square310x310logo src="/assets/icons/favicon/favicon-310x310.png"/>
<TileColor>#dedede</TileColor>
</tile>
</msapplication>
</browserconfig>
В macOS необходимо использовать монохромную SVG-иконку чёрного цвета, являющийся маской фавиконки. Такая иконка будет использована в закрепленной вкладке, а при наведении будет окрашиваться в цвет, указанный в атрибуте color
:
<link rel="mask-icon" href="/assets/favicons/safari-pinned-tab.svg" color="#bc3324">
Для iOS основным размером фавиконки является 180*180
, кроме того может быть задан и ряд других размеров:
<link rel="apple-touch-icon" sizes="60x60" href="/assets/favicons/apple-touch-icon-60x60.png">
<link rel="apple-touch-icon" sizes="76x76" href="/assets/favicons/apple-touch-icon-76x76.png">
<link rel="apple-touch-icon" sizes="120x120" href="/assets/favicons/apple-touch-icon-120x120.png">
<link rel="apple-touch-icon" sizes="152x152" href="/assets/favicons/apple-touch-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicons/apple-touch-icon-180x180.png">
Для Android основной является фавиконка 192*192
, но Chrome на Android и другие браузеры могут использовать манифест веб-приложения, который можно расположить в одном каталоге с фавиконками:
<link rel="icon" type="image/png" sizes="192x192" href="/android-icon-192x192.png">
<link rel="manifest" href="/assets/favicons/site.webmanifest">
Содержимое site.webmanifest
может включать целый ряд фавиконок в различных размерах и некоторые другие опции:
{
"name": "Lenni Art",
"short_name": "Lenni Art",
"icons": [
{
"src": "/assets/favicons/android-chrome-36x36.png",
"sizes": "36x36",
"type": "image/png"
},
{
"src": "/assets/favicons/android-chrome-48x48.png",
"sizes": "48x48",
"type": "image/png"
},
{
"src": "/assets/favicons/android-chrome-72x72.png",
"sizes": "72x72",
"type": "image/png"
},
{
"src": "/assets/favicons/android-chrome-96x96.png",
"sizes": "96x96",
"type": "image/png"
},
{
"src": "/assets/favicons/android-chrome-144x144.png",
"sizes": "144x144",
"type": "image/png"
},
{
"src": "/assets/favicons/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/assets/favicons/android-chrome-256x256.png",
"sizes": "256x256",
"type": "image/png"
},
{
"src": "/assets/favicons/android-chrome-384x384.png",
"sizes": "384x384",
"type": "image/png"
},
{
"src": "/assets/favicons/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#dedede",
"background_color": "#dedede",
"display": "standalone"
}
Следующие мета-теги позволят задать имя приложения и цвет, в который можно закрасить адресную строку и строку уведомлений в мобильных браузерах:
<meta name="apple-mobile-web-app-title" content="Lenni Art">
<meta name="application-name" content="Lenni Art">
<meta name="theme-color" content="#dedede">
Забрать изображение для фавиконок учебного проекта можно в Figma на экране Icons.
Все варианты фавиконок необязательно создавать самостоятельно, можно воспользоваться онлайн-генераторами, которые автоматически из одного изображения создадут нужный набор и предоставят вам разметку. При желании вы можете настроить и интегрировать в свой проект локальный офлайн-генератор.
Ссылки на онлайн-генераторы фавиконок:
5.2 SEO мета-теги
Поисковая оптимизация и представление сайта — очень важная часть веб-разработки. Мета-теги учитываются при оценке поисковыми системами и оказывают влияние на продвижение.
Мы уже добавляли в шапку сайта обязательный тег <title>
. Конечно, это не мета-тег, но данный элемент является наиболее важным. Заголовок сайта должен быть указан всегда.
<title>Lenni Art</title>
Description — это описание текущей страницы. Один из ключевых тегов. На данный момент в силу некоторых причин, связанных с недобросовестной манипуляцияей поисковой выдачи значение данного тега снизилось, но его значение может быть выведено в сниппетах результатов поиска под заголовком.
<meta name="description" content="Арт—пространство для людей, горящих сердец и делом">
Keywords — ключевые слова, связанные с содержимым текущей страницы. Данному тегу поисковыми системами сейчас уделяется меньше всего внимания, но тем не менее он может быть учтён при ранжировании сайта.
<meta name="keywords" content="Lenni Art, пространство, мероприятия">
Большое значение имеют мета-теги разметки Open Graph:
<meta property="og:title" content="Lenni Art" />
<meta property="og:description" content="Арт пространство для людей, горящих сердцем и делом" />
<meta property="og:image" content="/assets/images/lenni-art.jpg">
<meta property="og:type" content="website" />
<meta property="og:url" content="https://lenni-art.ru/" />
Эти теги в том или ином виде поддерживают многие популярные социальные сети, мессенджеры и чаты. Когда вы делитесь ссылкой на веб-страницу, имеющей такие теги, будут загружены и отображены заголовок, описание и изображение, заданные для этой страницы.

6. Второе испытание
На этом наш курс подходит к концу. Мы постарались в сжатом виде дать вам самую необходимую информацию, которая может понадобиться начинающему frontend-разработчику. Впереди большая дорога и огромное количество информации, знаний, технологий, которые можно и нужно изучать в своём дальнейшем развитии.
Освоив полностью данный курс и потратив некоторое количество времени на самостоятельное изучение отдельных тем, вы сможете выполнять кроссбраузерную адаптивную вёрстку сайтов, писать несложный JavaScript-код, использовать средства контроля версий Git и автоматизировать процесс разработки.
Сейчас вам предлагается второе испытание: предоставить на проверку git-репозиторий с учебным проектом в соответствии с предложенными ниже критериями.
Время на выполнение учебной работы не ограничено.
6.1 Критерии
- Структура проекта и средства автоматизации соответствуют представленным на 5 уроке «Оптимизация и автоматизация«;
- Выполнена HTML-разметка всех страниц и всех элементов на страницах в соответствии со всеми предоставленными макетами с учётом адаптива учебного проекта в Figma.
- Собранные HTML-документы проходят проверку на валидность https://validator.w3.org/nu/#textarea и не содержат явных ошибок. Допускаются только предупреждения (
warning
, жёлтого цвета); - HTML-разметка соответствует гайдлайну, предоставленному на 1 уроке «Введение. Знакомство с HTML«;
- CCS-код соответствует гайдлайну, предоставленному на 2 уроке «Основы CSS и методологии«;
- CSS-код содержит стили в соответствии со всеми макетами адаптива;
- К страницам подключен один минифицированный стилевой файл внутри
<head>
; - HTML-разметка и CSS-код выполнены в соответствии с методологией БЭМ;
- Подобраны подходящие с точки зрения семантики HTML-теги для каждого элемента;
- Подключены правильные шрифты, их размеры, цвета и толщина соответствуют таковым в макетах;
- Отсутствует транслит в названиях классов, атрибутов и т.п.;
- Все расстояния между HTML-элементами соответствуют макету или округлены до
5px
в ближайшую сторону. Таким образом неточность вёрстки составляет+/-2
пикселя по высоте и ширине для всех размеров и расстояний. - Вёрстка на всём протяжении адаптива проходит тест на переполнение контентом: наполнение заголовков и текстовых блоков большим количеством текста, изображения неподходящего размера, а также изменение количества блоков в потоке не должны приводить к поломке вёрстки;
- Стили каждого БЭМ-блока вынесены в отдельный соответствующий файл CSS-препроцессора.
- Вложенность селекторов допускается только в крайних случаях: вложенные элементы, затронутые БЭМ-модификатором родительского блока, активные состояния элементов (например, при наведении мыши), состояния элементов форм в активном состоянии (например,
:checked
), и т.п.; - Все ссылки и кнопки реагируют на наведение мыши, подсвечивая элемент указанным в макете способом.
- На страницах отсутствует горизонтальная прокрутка. Элементы выступающие за пределы экрана должны быть обрезаны с помощью CSS;
- Должен быть написан весь необходимый для проекта JavaScript-код:
— доступ к мобильному меню;
— доступ к попапу заявки;
— слайдер карточек;
— интерактивная карта на главной странице (на ваш выбор);
— всё формы должны валидироваться кастомным образом перед отправкой, вы можете использовать сторонний плагин для решения данной задачи;
— для элемента формы селект используйте сторонний плагин, улучшающий его внешний вид.
— для выбора даты используйте соответствующий плагин, повышающий удобство пользователя (календарь).
— для поля ввода телефона используйте маску (плагин); - Ваш JavaScript-код должен находится внутри анонимной функции и работать в режиме «use strict»;
- Должны быть добавлены фавиконки и соответствующая разметка в
<head>
. - Код должен быть максимально кроссбраузерным, протестируйте свою работу во всех популярных браузерах: Google Chrome, Mozilla Firefox, Microsoft Edge, Safari. Поддержка IE11 не требуется, проверка кода в Safari от Apple может быть пропущена, если у вас нет такой возможности;
- В проекте должен присутствовать файл
.gitignore
с включёнными каталогамиnode_modules
иdist
. В репозитории не следует хранить npm-пакеты и собранную сборку проекта, только исходники.
После успешной сдачи учебного проекта вам будет предложено финальное испытание — самостоятельно выполнить личный проект в соответствии с предоставленным дизайном и критериями качества. Успешное завершение данного испытания даст вам возможность трудоустройства в нашей компании.