Files
2026-10-20 12:58:34 +03:00

1268 lines
66 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Теоретические вопросы к лабораторной работе №1
Ответы на контрольные вопросы. Примеры по возможности взяты из собственной работы
(`index.html`, `script.js`) — так проще отвечать на защите.
---
## 1. Протокол HTTP
**HTTP** (HyperText Transfer Protocol) — прикладной текстовый протокол
клиент-серверного взаимодействия, работающий поверх TCP (порт 80) или TLS/TCP
(HTTPS, порт 443). Работает по схеме «запрос — ответ»: клиент всегда инициирует
обмен, сервер отвечает.
Ключевое свойство — **отсутствие состояния** (stateless). Сервер не обязан
помнить предыдущие запросы клиента; каждый запрос самодостаточен. Состояние
надстраивается сверху: cookies, сессии, токены, а на клиенте — `localStorage`
(как в этой работе).
Версии: HTTP/1.1 (текстовый, keep-alive соединения), HTTP/2 (бинарные кадры,
мультиплексирование нескольких запросов в одном соединении, сжатие заголовков
HPACK), HTTP/3 (поверх QUIC/UDP).
### Структура запроса
```
МЕТОД URI ВЕРСИЯ ← строка запроса (start line)
Заголовок: значение ← заголовки, по одному на строку
Заголовок: значение
← ПУСТАЯ строка — обязательный разделитель
тело запроса ← необязательно (есть у POST/PUT/PATCH)
```
Пример:
```http
POST /check-point HTTP/1.1
Host: se.ifmo.ru
Content-Type: application/x-www-form-urlencoded
Content-Length: 24
User-Agent: Mozilla/5.0
xval=1&yval=2.5&rval=3
```
### Структура ответа
```
ВЕРСИЯ КОД ПОЯСНЕНИЕ ← строка статуса
Заголовок: значение
← пустая строка
тело ответа
```
Пример:
```http
HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Content-Length: 1024
```
### Методы запросов
| Метод | Назначение | Безопасный | Идемпотентный | Тело |
|---|---|---|---|---|
| `GET` | Получить ресурс | да | да | нет |
| `POST` | Отправить данные, создать ресурс | нет | **нет** | да |
| `PUT` | Полностью заменить ресурс | нет | да | да |
| `PATCH` | Частично изменить ресурс | нет | нет | да |
| `DELETE` | Удалить ресурс | нет | да | необяз. |
| `HEAD` | Как GET, но только заголовки | да | да | нет |
| `OPTIONS` | Узнать поддерживаемые методы (CORS preflight) | да | да | нет |
| `TRACE` | Диагностика — вернуть запрос как есть | да | да | нет |
Два свойства, которые обязательно спросят:
- **Безопасный** (safe) — не изменяет состояние сервера, только читает.
- **Идемпотентный** — повторный одинаковый запрос даёт тот же результат.
`DELETE /point/5` можно послать трижды — точка всё равно одна удалённая.
А три `POST` создадут три записи, поэтому POST не идемпотентен — отсюда
предупреждение браузера «повторить отправку формы?» при обновлении страницы.
### Коды ответов сервера
Пять классов по первой цифре:
| Класс | Смысл |
|---|---|
| **1xx** | Информационные — запрос принят, обработка продолжается |
| **2xx** | Успех |
| **3xx** | Перенаправление |
| **4xx** | Ошибка клиента |
| **5xx** | Ошибка сервера |
Конкретные коды, которые нужно знать:
| Код | Название | Когда |
|---|---|---|
| 100 | Continue | Сервер готов принять тело |
| 101 | Switching Protocols | Переход на WebSocket |
| **200** | OK | Успех, тело содержит результат |
| 201 | Created | Ресурс создан (ответ на POST/PUT) |
| 204 | No Content | Успех, тела нет |
| 301 | Moved Permanently | Переехало навсегда, обновите ссылки |
| 302 | Found | Временное перенаправление |
| **304** | Not Modified | Ресурс не изменился, берите из кэша |
| 400 | Bad Request | Синтаксически некорректный запрос |
| **401** | Unauthorized | Не аутентифицирован (нужно войти) |
| **403** | Forbidden | Аутентифицирован, но нет прав |
| **404** | Not Found | Ресурс не найден |
| 405 | Method Not Allowed | Метод не поддерживается этим URI |
| 409 | Conflict | Конфликт состояния |
| 418 | I'm a teapot | Шутка из RFC 2324 |
| 422 | Unprocessable Entity | Синтаксис верен, но данные не прошли валидацию |
| 429 | Too Many Requests | Превышен лимит частоты |
| **500** | Internal Server Error | Необработанное исключение на сервере |
| 501 | Not Implemented | Метод не реализован |
| 502 | Bad Gateway | Прокси получил некорректный ответ от бэкенда |
| 503 | Service Unavailable | Сервер перегружен или на обслуживании |
| 504 | Gateway Timeout | Прокси не дождался ответа |
Разница 401 и 403 — частый вопрос: 401 «я тебя не знаю, представься»,
403 «я тебя знаю, но тебе сюда нельзя».
### Заголовки
Заголовки — это метаданные в формате `Имя: значение`. Имена
регистронезависимы. Делятся на четыре группы: общие, запроса, ответа и
сущности (описывающие тело).
**Заголовки запроса:**
| Заголовок | Смысл |
|---|---|
| `Host` | Домен — обязателен в HTTP/1.1, позволяет виртуальный хостинг |
| `User-Agent` | Клиент: браузер, ОС, версия |
| `Accept` | Какие MIME-типы клиент готов принять |
| `Accept-Language` | Предпочитаемые языки (`ru-RU,ru;q=0.9`) |
| `Accept-Encoding` | Поддерживаемое сжатие (`gzip, br`) |
| `Cookie` | Cookies, ранее установленные сервером |
| `Authorization` | Данные аутентификации (`Bearer <token>`) |
| `Referer` | Страница, с которой пришёл запрос |
| `If-Modified-Since` | Условный запрос — отдай, только если изменилось |
| `Content-Type` | Тип тела запроса |
| `Content-Length` | Длина тела в байтах |
| `Connection` | `keep-alive` / `close` |
| `Origin` | Источник запроса, используется в CORS |
**Заголовки ответа:**
| Заголовок | Смысл |
|---|---|
| `Content-Type` | MIME-тип и кодировка тела (`text/html; charset=UTF-8`) |
| `Content-Length` | Длина тела |
| `Content-Encoding` | Применённое сжатие |
| `Server` | ПО сервера (`nginx/1.24`) |
| `Set-Cookie` | Установить cookie у клиента |
| `Location` | Куда перенаправить (с кодами 3xx) |
| `Cache-Control` | Правила кэширования (`no-cache`, `max-age=3600`) |
| `ETag` | Версия-отпечаток ресурса для условных запросов |
| `Last-Modified` | Дата последнего изменения |
| `Access-Control-Allow-Origin` | CORS: кому разрешён кросс-доменный доступ |
| `Content-Disposition` | `attachment; filename="f.pdf"` — скачать как файл |
| `WWW-Authenticate` | Метод аутентификации (вместе с 401) |
> В данной работе HTTP-обмена фактически нет: страница статическая, а отправка
> формы перехватывается `e.preventDefault()`, и всё считается на клиенте.
> Браузер делает лишь GET-запросы за `index.html`, `script.js` и `assets/oscar.png`.
---
## 2. Язык разметки HTML
**HTML** (HyperText Markup Language) — язык **разметки**, а не
программирования: он описывает структуру и смысл документа, но не содержит
алгоритмов. Актуальная версия — HTML5 (living standard WHATWG).
### Особенности
- **Декларативность** — описывается *что* это, а не *как это сделать*.
- **Теговая структура** — элементы образуют дерево вложенности.
- **Устойчивость к ошибкам** — браузер не падает на некорректной разметке,
а исправляет её по стандартным правилам восстановления. В отличие от XHTML,
который требовал строгой валидности.
- **Семантичность** — HTML5 ввёл теги со смыслом (`<header>`, `<article>`,
`<nav>`), важные для SEO и программ чтения с экрана.
- **Регистронезависимость** имён тегов и атрибутов.
- **Разделение ответственности** — структура в HTML, оформление в CSS,
поведение в JS.
### Синтаксис элемента
```html
<тег атрибут="значение">содержимое</тег>
<img src="x.png" alt="описание"> <!-- одиночный (void) элемент -->
<!-- комментарий -->
```
Элементы делятся на **блочные** (`div`, `p`, `table` — занимают всю ширину,
начинаются с новой строки) и **строчные** (`span`, `a`, `b` — только по
содержимому). Это поведение по умолчанию, в CSS меняется через `display`.
### Основные теги
**Структура документа:**
| Тег | Назначение |
|---|---|
| `<!DOCTYPE html>` | Объявление типа документа, включает стандартный режим |
| `<html>` | Корневой элемент |
| `<head>` | Метаданные, не отображаются |
| `<body>` | Видимое содержимое |
| `<meta>` | Кодировка, viewport, описание |
| `<title>` | Заголовок окна/вкладки |
| `<link>` | Подключение внешних ресурсов (CSS, favicon) |
| `<style>` | Встроенные стили |
| `<script>` | JavaScript |
**Текст и блоки:** `<h1>`–`<h6>` (заголовки), `<p>`, `<br>`, `<hr>`,
`<b>`/`<strong>`, `<i>`/`<em>`, `<span>`, `<div>`, `<pre>`, `<code>`.
> `<b>` и `<i>` задают только начертание, `<strong>` и `<em>` несут смысл
> важности и акцента — их озвучивают скринридеры.
**Списки:** `<ul>` (маркированный), `<ol>` (нумерованный), `<li>` (элемент),
`<dl>`/`<dt>`/`<dd>` (список определений).
**Ссылки и медиа:** `<a>`, `<img>`, `<video>`, `<audio>`, `<canvas>`, `<svg>`,
`<iframe>`.
**Таблицы:** `<table>`, `<caption>`, `<thead>`, `<tbody>`, `<tfoot>`, `<tr>`,
`<th>` (ячейка-заголовок), `<td>` (ячейка данных).
**Формы:** `<form>`, `<input>`, `<textarea>`, `<select>`/`<option>`, `<button>`,
`<label>`, `<fieldset>`/`<legend>`.
**Семантические теги HTML5:** `<header>`, `<footer>`, `<nav>`, `<main>`,
`<section>`, `<article>`, `<aside>`, `<figure>`/`<figcaption>`.
### Атрибуты
**Глобальные** — применимы к любому тегу:
| Атрибут | Назначение |
|---|---|
| `id` | Уникальный идентификатор элемента на странице |
| `class` | Список классов через пробел, для CSS и JS |
| `style` | Инлайновые стили (нежелательно) |
| `title` | Всплывающая подсказка |
| `lang` | Язык содержимого |
| `hidden` | Скрыть элемент |
| `data-*` | Произвольные пользовательские данные |
| `tabindex` | Порядок обхода по Tab |
**Специфичные для тегов:**
- `<a href target rel>` — адрес, окно открытия, отношение
- `<img src alt width height>` — `alt` обязателен для доступности
- `<input type name value placeholder required disabled checked>`
- `<form action method enctype>`
- `<td colspan rowspan>`
- `<canvas width height>`
- `<script src defer async>`
**Пример из работы** — атрибут `data-val` на кнопках выбора R:
```html
<button type="button" class="r-button" data-val="3">3</button>
```
Читается из JS: `btn.getAttribute('data-val')`. Это стандартный способ привязать
данные к элементу, не нарушая валидность разметки.
---
## 3. Структура HTML-страницы и DOM
### Структура страницы
```html
<!DOCTYPE html> <!-- тип документа -->
<html lang="ru"> <!-- корень, язык -->
<head>
<meta charset="UTF-8"> <!-- кодировка — первой! -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Лабораторная работа №1</title>
<style> /* ... */ </style>
</head>
<body>
<!-- видимое содержимое -->
<script src="script.js"></script>
</body>
</html>
```
Почему именно так:
- `<!DOCTYPE html>` включает **стандартный режим** отображения. Без него
браузер уходит в quirks mode и имитирует баги старого IE.
- `<meta charset>` должен идти в первых 1024 байтах, иначе браузер начнёт
разбирать страницу в неверной кодировке и русский текст превратится в мусор.
- `<meta viewport>` обязателен для адаптивности на мобильных устройствах.
- `<script>` в конце `<body>` — чтобы к моменту выполнения весь DOM уже
существовал. Альтернатива — `<script defer>` в `<head>`.
### DOM (Document Object Model)
**DOM** — программный интерфейс документа: браузер разбирает (парсит) HTML и
строит в памяти **дерево объектов**, где каждый тег, текст, атрибут и
комментарий становится **узлом** (Node). Это дерево доступно из JavaScript для
чтения и изменения, причём изменения немедленно отражаются на экране.
Важно: DOM строится из HTML, но **не равен** ему. Браузер исправляет ошибки
разметки, достраивает пропущенные `<tbody>`, а JS может добавить узлы, которых
в исходном файле не было вовсе.
**Типы узлов:** `Document` (корень), `Element` (тег), `Text` (текст),
`Comment`, `Attr`, `DocumentFragment`.
Фрагмент дерева этой работы:
```
document
└── html
├── head
│ ├── meta, title
│ └── style
└── body
├── table#layout-table
│ └── tbody
│ ├── tr → td#header
│ ├── tr → td.canvas-cell → canvas#graphCanvas
│ │ td.content-cell → form#point-form → table → ...
│ └── tr → td.content-cell → table#results-table → tbody#results-body
├── img#oscar-easter-egg
└── script
```
### Работа с DOM из JavaScript
**Поиск узлов:**
```js
document.getElementById('graphCanvas'); // по id, один элемент
document.querySelector('.r-button'); // первый по CSS-селектору
document.querySelectorAll('input[name="xval"]'); // все по селектору
document.getElementsByClassName('r-button'); // живая коллекция
document.getElementsByTagName('td');
```
`querySelectorAll` возвращает **статический** `NodeList` — снимок на момент
вызова. `getElementsBy*` возвращают **живые** коллекции, которые сами
обновляются при изменении DOM.
**Навигация:** `parentNode`, `children`, `firstElementChild`,
`nextElementSibling`.
**Изменение:**
```js
el.textContent = 'текст'; // текст, безопасно
el.innerHTML = '<td>1</td>'; // парсится как HTML — риск XSS
el.setAttribute('data-x', '1');
el.classList.add('active');
el.style.color = 'red';
const tr = document.createElement('tr'); // создать узел
parent.appendChild(tr); // вставить
el.remove(); // удалить
```
**События** — третья функция DOM помимо структуры и изменения:
```js
el.addEventListener('click', (e) => { /* ... */ });
```
Событие проходит три фазы: **погружение** (capturing) от `document` к цели,
**цель** (target), **всплытие** (bubbling) обратно наверх. По умолчанию
обработчики срабатывают на всплытии. Отсюда приём **делегирования**: один
обработчик на родителе обслуживает все дочерние элементы, включая добавленные
позже.
**Пример из работы** — построение строк таблицы истории:
```js
function renderHistory() {
resultsBody.innerHTML = ''; // очистить поддерево
[...history].reverse().forEach(rec => {
const tr = document.createElement('tr'); // создать узел
tr.innerHTML = `<td>${rec.x}</td>...`; // заполнить
resultsBody.appendChild(tr); // вставить в дерево
});
}
```
Событие `DOMContentLoaded` означает «HTML разобран, дерево DOM построено»
(в отличие от `load`, который ждёт ещё и картинки со стилями). В работе на нём
выполняется первичная отрисовка:
```js
window.addEventListener('DOMContentLoaded', () => {
renderHistory();
drawGraph();
validateForm();
});
```
---
## 4. HTML-формы
**Форма** — набор элементов ввода, предназначенный для сбора данных
пользователя и их передачи обработчику (серверу или клиентскому скрипту).
### Тег `<form>` и его атрибуты
```html
<form action="/submit" method="post" enctype="multipart/form-data">
```
| Атрибут | Назначение |
|---|---|
| `action` | URL обработчика. Пустой или отсутствует — текущая страница |
| `method` | HTTP-метод: `get` (по умолчанию) или `post` |
| `enctype` | Кодирование тела при POST |
| `name` | Имя формы |
| `target` | Где открыть ответ (`_blank`, `_self`) |
| `novalidate` | Отключить встроенную браузерную валидацию |
| `autocomplete` | `on`/`off` — автозаполнение |
### Задание метода HTTP-запроса
Метод задаётся атрибутом `method`:
```html
<form method="get"> <!-- данные в URL -->
<form method="post"> <!-- данные в теле запроса -->
```
**`method="get"`** — данные формы кодируются в строку запроса URL:
```
GET /search?xval=1&yval=2.5&rval=3 HTTP/1.1
```
- Запрос виден в адресной строке, попадает в историю браузера и логи прокси.
- Длина URL ограничена (практически ~2000 символов).
- Можно сохранить в закладки и переслать ссылкой.
- Кэшируется, идемпотентен.
- **Применение:** поиск, фильтры, пагинация — всё, что только читает.
**`method="post"`** — данные передаются в теле запроса:
```
POST /submit HTTP/1.1
Content-Type: application/x-www-form-urlencoded
xval=1&yval=2.5&rval=3
```
- Данных может быть сколько угодно, включая файлы.
- В URL не видны (но **не зашифрованы** — защищает только HTTPS).
- Не кэшируется, не идемпотентен — обновление страницы вызывает
предупреждение о повторной отправке.
- **Применение:** регистрация, авторизация, создание и изменение данных.
Значения `enctype` для POST:
| Значение | Когда |
|---|---|
| `application/x-www-form-urlencoded` | По умолчанию, `key=value&key=value` |
| `multipart/form-data` | **Обязательно** при загрузке файлов |
| `text/plain` | Только для отладки |
Методы `PUT`/`DELETE` HTML-формами не поддерживаются — только через
JavaScript (`fetch`, `XMLHttpRequest`).
### Правила размещения форм на страницах
1. **Формы нельзя вкладывать друг в друга** — `<form>` внутри `<form>`
недопустим, браузер проигнорирует внутреннюю.
2. Форм на странице может быть несколько, но они независимы: отправляется
только та, в которой произошёл submit.
3. **Поля должны находиться внутри `<form>`**, иначе не попадут в отправку.
Исключение HTML5 — атрибут `form="id-формы"` позволяет связать поле,
лежащее вне формы.
4. **Передаются только поля с атрибутом `name`.** Поле без `name`
не отправляется, даже если заполнено. `id` для отправки не используется —
он нужен CSS и JS.
5. Поля с `disabled` не отправляются; с `readonly` — отправляются.
6. Невыбранные чекбоксы и радиокнопки не отправляются вообще (а не как пустое
значение) — обработчик должен считать отсутствие ключа ответом «нет».
7. Радиокнопки одной группы обязаны иметь **одинаковый `name`** — именно это
делает выбор взаимоисключающим.
8. `<form>` — блочный элемент; внутри таблицы его следует размещать целиком
внутри `<td>`, а не между `<tr>`, иначе разметка невалидна.
9. Каждое поле должно иметь `<label for="id">` — это и доступность
(скринридеры), и удобство (клик по подписи активирует поле).
10. Кнопка `<button>` внутри формы по умолчанию имеет `type="submit"`.
Чтобы кнопка не отправляла форму, нужен явный `type="button"`.
11. Клиентская валидация **не отменяет серверную**: любые проверки в браузере
обходятся через DevTools или прямым HTTP-запросом.
### Виды полей ввода
`<input>` различается атрибутом `type`:
| `type` | Описание |
|---|---|
| `text` | Однострочный текст |
| `password` | Текст со скрытыми символами |
| `number` | Число со счётчиком, атрибуты `min`, `max`, `step` |
| `email` | С встроенной проверкой формата |
| `tel`, `url` | Телефон, адрес |
| `search` | Поле поиска |
| `checkbox` | Флажок — независимый множественный выбор |
| `radio` | Радиокнопка — выбор одного из группы с общим `name` |
| `file` | Выбор файла, требует `enctype="multipart/form-data"` |
| `date`, `time`, `datetime-local`, `month`, `week` | Выбор даты и времени |
| `range` | Ползунок |
| `color` | Выбор цвета |
| `hidden` | Скрытое поле — не видно, но отправляется |
| `submit` | Кнопка отправки |
| `reset` | Кнопка сброса значений |
| `button` | Кнопка без действия по умолчанию |
| `image` | Кнопка-картинка |
Другие элементы ввода:
- `<textarea rows cols>` — многострочный текст
- `<select>` + `<option>` — выпадающий список; с `multiple` — множественный
выбор; `<optgroup>` группирует варианты
- `<button>` — кнопка с произвольным HTML внутри
- `<datalist>` — список подсказок для `input`
- `<output>`, `<progress>`, `<meter>` — вывод значений
**Атрибуты валидации HTML5:** `required`, `min`/`max`, `minlength`/`maxlength`,
`pattern` (регулярное выражение), `step`.
### Форма в данной работе
```html
<form id="point-form">
<!-- X: чекбоксы — множественный выбор -->
<input type="checkbox" name="xval" value="-2"> -2
...
<!-- Y: текстовое поле -->
<input type="text" id="y-input" name="yval" placeholder="-3 ... 5">
<!-- R: кнопки + скрытое поле -->
<button type="button" class="r-button" data-val="1">1</button>
<input type="hidden" id="r-hidden" name="rval" value="">
<button type="submit" id="submit-btn" disabled>Проверить попадание</button>
</form>
```
Разбор решений:
- Типы полей заданы вариантом: X — checkbox, Y — text, R — button.
- У `<form>` нет `action` и `method`, потому что отправка перехватывается
и обрабатывается на клиенте:
```js
form.addEventListener('submit', (e) => {
e.preventDefault(); // отменить стандартную отправку и перезагрузку
...
});
```
Без `preventDefault()` браузер выполнил бы GET на ту же страницу, и всё
состояние было бы потеряно.
- Кнопки R имеют `type="button"` — иначе каждое нажатие отправляло бы форму.
- Выбранный R хранится в `<input type="hidden">`: кнопки сами по себе значение
не хранят, а скрытое поле — штатный способ держать его в форме.
- Чекбоксы X дают **множественный выбор**, поэтому один submit порождает
столько записей, сколько галочек поставлено:
```js
checkboxes.forEach(cb => {
if (cb.checked) { history.push({...}); }
});
```
- `submitBtn.disabled = !isValid` — кнопка заблокирована, пока данные
некорректны, а сообщения выводятся в `<span class="error">` рядом с полем,
а не через `alert` (это прямо указано в списке частых ошибок).
---
## 5. Каскадные таблицы стилей (CSS)
**CSS** (Cascading Style Sheets) — язык описания внешнего вида документа.
Отделяет оформление от структуры: HTML отвечает за смысл, CSS — за вид.
### Способы подключения
1. **Внешний файл** — `<link rel="stylesheet" href="style.css">`;
кэшируется, переиспользуется между страницами.
2. **Встроенная таблица** — `<style>` в `<head>`. Используется в этой работе,
так как требование п.2 задания — «таблицы стилей должны располагаться
в самом веб-документе».
3. **Инлайновый стиль** — атрибут `style="..."` у тега. Нежелателен.
### Структура правила
```css
селектор {
свойство: значение; /* это объявление */
свойство: значение;
}
```
Селектор + блок объявлений = **правило**. Пример из работы:
```css
#header {
background-color: #eeeeee;
color: #000000;
padding: 10px;
text-align: center;
font-family: monospace;
font-size: 16px;
}
```
### Виды селекторов
| Вид | Синтаксис | Что выбирает |
|---|---|---|
| Универсальный | `*` | Все элементы |
| **Элемента (тега)** | `td` | Все `<td>` |
| **Класса** | `.r-button` | Все с `class="r-button"` |
| **Идентификатора** | `#header` | Элемент с `id="header"` |
| Атрибута | `input[type="text"]` | По наличию/значению атрибута |
| Группировка | `table, th, td` | Каждый из перечисленных |
**Комбинаторы** (отношения между элементами):
| Комбинатор | Синтаксис | Что выбирает |
|---|---|---|
| Вложенный (потомка) | `A B` | Все `B` внутри `A` на любой глубине |
| **Дочерний** | `A > B` | Только непосредственных детей `A` |
| Соседний | `A + B` | Первый `B` сразу после `A` |
| Последующий | `A ~ B` | Все `B` после `A` на том же уровне |
Разница потомка и дочернего — обязательный вопрос:
`#point-form td` выберет и `<td>` во вложенной таблице подсказок, а
`#point-form > table > tbody > tr > td` — только ячейки верхнего уровня.
**Псевдоклассы** — состояние элемента: `:hover`, `:focus`, `:active`,
`:visited`, `:checked`, `:disabled`, `:first-child`, `:last-child`,
`:nth-child(2n)`, `:not(.x)`.
**Псевдоэлементы** — виртуальные части: `::before`, `::after`,
`::first-line`, `::placeholder`.
### Особенности применения
- Классы — для стилей, повторяющихся у многих элементов. Основной рабочий
инструмент.
- Идентификаторы — для уникальных элементов. Злоупотреблять не стоит: высокая
специфичность мешает переопределению.
- Селекторы тегов — для базовых правил на весь документ (`body`, сброс
отступов).
- Чем короче и менее специфичен селектор, тем легче поддерживать код. Длинные
цепочки вроде `div#main table.data tbody tr td span` делают стили хрупкими.
- Браузер читает селекторы **справа налево**, поэтому последняя часть должна
быть как можно более конкретной.
Все четыре требуемых видов селекторов в работе присутствуют:
```css
body { ... } /* селектор элемента */
.content-cell { ... } /* селектор класса */
#layout-table { ... } /* селектор идентификатора */
#point-form label { ... } /* потомка */
td.canvas-cell > * { ... } /* дочерних элементов */
.content-cell[colspan="2"] > h3 { } /* атрибута + дочерний */
#point-form input[type="text"] { } /* тег + атрибут */
.r-button.active { ... } /* два класса на одном элементе */
```
### Приоритеты правил
Когда к одному элементу применимы несколько правил, конфликт решается
**каскадом** — по шагам, в строгом порядке:
**1. Происхождение и важность** (от низшего к высшему):
1. Стили браузера по умолчанию
2. Стили пользователя
3. Стили автора (`<style>`, `<link>`, `style=""`)
4. Стили автора с `!important`
5. Стили пользователя с `!important`
**2. Специфичность** — считается как тройка `(A, B, C)`:
| Разряд | Что считается | Вес |
|---|---|---|
| A | Идентификаторы `#id` | 100 |
| B | Классы, атрибуты, псевдоклассы | 10 |
| C | Теги и псевдоэлементы | 1 |
Инлайновый `style=""` стоит выше любого селектора (условно 1000),
`!important` — выше всего, кроме пользовательского `!important`.
Универсальный селектор `*` и `:not()` сами по себе веса не добавляют.
Примеры подсчёта:
| Селектор | Специфичность | Вес |
|---|---|---|
| `td` | 0,0,1 | 1 |
| `.content-cell` | 0,1,0 | 10 |
| `td.canvas-cell` | 0,1,1 | 11 |
| `.r-button.active` | 0,2,0 | 20 |
| `#point-form td` | 1,0,1 | 101 |
| `style="..."` | — | 1000 |
**3. Порядок следования** — при равной специфичности побеждает правило,
объявленное **позже**. Именно поэтому `.r-button.active` в работе написано
после `.r-button` — хотя здесь и специфичность выше.
### Наследование
Часть свойств передаётся от родителя к детям автоматически: `color`,
`font-family`, `font-size`, `font-weight`, `line-height`, `text-align`,
`visibility`. Не наследуются свойства блочной модели: `margin`, `padding`,
`border`, `background`, `width`, `height`.
Пример из работы — наследование и каскадирование:
```css
body {
font-family: Arial, sans-serif; /* наследуется всеми потомками */
color: #000000;
}
#header {
color: #000000; /* комментарий в коде: «Каскадирование» */
font-family: monospace; /* переопределяет унаследованный Arial */
}
#header span.variant {
color: #cc0000; /* переопределяет на уровень глубже */
}
```
`<b>` внутри `#header` получает monospace по наследству, а `span.variant`
перебивает цвет более специфичным правилом.
### Преимущества CSS перед атрибутом `style`
1. **Разделение ответственности** — структура отдельно, оформление отдельно.
HTML остаётся читаемым и семантичным.
2. **Переиспользование** — одно правило `.r-button` оформляет все пять кнопок.
С `style` пришлось бы дублировать код пять раз.
3. **Поддерживаемость** — чтобы изменить вид всех кнопок, правится одна строка,
а не N тегов. Меньше кода — меньше шансов пропустить место.
4. **Размер и кэширование** — внешний CSS-файл загружается один раз и
кэшируется для всех страниц сайта; инлайновые стили заново передаются
с каждой страницей.
5. **Каскад и наследование работают** — инлайновый стиль их фактически
отключает, он всегда главнее и не переопределяется ничем, кроме
`!important`.
6. **Полная функциональность** — через `style` невозможны псевдоклассы
(`:hover`, `:focus`), псевдоэлементы (`::before`), медиазапросы
(`@media`), анимации (`@keyframes`).
7. **Адаптивность** — медиазапросы для разных размеров экрана доступны только
в таблицах стилей.
8. **Доступность** — пользователь может подключить свою таблицу стилей
(крупный шрифт, высокий контраст); инлайновые стили её перебьют.
9. **Отладка** — DevTools показывает всю цепочку правил и причину победы
одного над другим.
---
## 6. LESS, Sass, SCSS
**Препроцессоры CSS** — надстройки над CSS, добавляющие возможности,
которых в самом CSS нет или не было: переменные, вложенность, миксины,
функции, арифметику. Код на препроцессоре **транслируется (компилируется)
в обычный CSS**.
### Зачем они появились
Чистый CSS долго не имел переменных, средств повторного использования и
структурирования. В больших проектах это приводило к дублированию, длинным
повторяющимся селекторам и трудно поддерживаемым файлам.
### Ключевые особенности (общие)
| Возможность | Описание |
|---|---|
| **Переменные** | Именованные значения: цвета, размеры, шрифты в одном месте |
| **Вложенность** | Селекторы внутри селекторов повторяют структуру HTML |
| **Миксины** | Переиспользуемые блоки объявлений, в т.ч. с параметрами |
| **Наследование** | `@extend` — один селектор перенимает правила другого |
| **Операции** | Арифметика: `10px * 2`, работа с цветами |
| **Функции** | Встроенные (`darken`, `lighten`) и свои |
| **Импорт** | Разбиение на файлы, объединяемые при компиляции без лишних HTTP-запросов |
| **Условия и циклы** | `@if`, `@for`, `@each` — у Sass/SCSS развиты сильнее |
### Sass и SCSS
**Sass** (Syntactically Awesome Style Sheets, 2006) — написан на Ruby,
сейчас реализация Dart Sass. Имеет **два синтаксиса**:
**Sass (indented, `.sass`)** — отступы вместо фигурных скобок, без точек
с запятой:
```sass
$primary: #3399FF
.button
background: $primary
padding: 5px 10px
```
**SCSS (Sassy CSS, `.scss`)** — синтаксис, надмножество CSS: любой валидный
CSS является валидным SCSS. Сейчас основной вариант.
```scss
$primary: #3399FF;
$padding: 5px;
@mixin button-base($bg) {
background-color: $bg;
padding: $padding ($padding * 2);
cursor: pointer;
}
.r-button {
@include button-base(#dddddd);
border: 1px solid #888888;
&.active { // & — ссылка на родительский селектор
@include button-base(#888888);
color: #ffffff;
}
&:hover { background-color: darken(#dddddd, 10%); }
}
```
Компилируется в:
```css
.r-button { background-color: #dddddd; padding: 5px 10px; cursor: pointer;
border: 1px solid #888888; }
.r-button.active { background-color: #888888; padding: 5px 10px;
cursor: pointer; color: #fff; }
.r-button:hover { background-color: #c4c4c4; }
```
**LESS** (Leaner Style Sheets, 2009) — написан на JavaScript, работает под
Node.js, может выполняться и в браузере. Синтаксис ближе к CSS; переменные
через `@`:
```less
@primary: #3399FF;
@padding: 5px;
.button-base(@bg) {
background-color: @bg;
padding: @padding (@padding * 2);
}
.r-button {
.button-base(#dddddd);
&.active { .button-base(#888888); color: #ffffff; }
}
```
### Сравнительная характеристика
| Критерий | Sass/SCSS | LESS |
|---|---|---|
| Год | 2006 | 2009 |
| Реализация | Dart (ранее Ruby) | JavaScript (Node.js) |
| Синтаксис переменных | `$var` | `@var` |
| Синтаксисы | Два: `.sass` и `.scss` | Один: `.less` |
| Миксины | `@mixin` / `@include` — явные | Любой класс может быть миксином |
| Логика | Полноценные `@if`, `@for`, `@each`, `@while`, свои функции | Ограниченная: guard-выражения, рекурсия |
| Модульность | `@use` / `@forward` — пространства имён | `@import` |
| Выполнение в браузере | Нет | Да (less.js, только для разработки) |
| Экосистема | Крупнее: Bootstrap 4+, Foundation | Bootstrap 3, Semantic UI |
| Порог входа | Чуть выше | Ниже |
**Коротко:** SCSS мощнее и является отраслевым стандартом; LESS проще и ближе
к чистому CSS. Конфликт `@` в LESS с директивами CSS (`@media`, `@import`) —
известное неудобство.
Существует также **Stylus** (гибкий синтаксис, необязательные скобки и
двоеточия) и **PostCSS** — не препроцессор, а инструмент преобразования CSS
плагинами (`autoprefixer`, `postcss-preset-env`).
### Совместимость с браузерами и трансляция
Это ключевой момент: **браузеры не понимают LESS, Sass и SCSS вообще**.
Браузер умеет только CSS. Поэтому исходники компилируются в обычный CSS
**до** отправки клиенту:
```
style.scss ──[компилятор]──► style.css ──► <link rel="stylesheet">
```
Отсюда следствия:
- **Совместимость с браузерами — стопроцентная**, потому что на выходе
получается обычный CSS. Препроцессор не создаёт проблем поддержки сам по
себе; ограничения задают только те CSS-свойства, которые вы используете.
- Вся обработка происходит на этапе сборки — **во время выполнения накладных
расходов нет**.
- Для отладки генерируются **source maps**: DevTools показывает строку
исходного `.scss`, а не скомпилированного `.css`.
Способы трансляции:
```bash
sass style.scss style.css # Dart Sass, разово
sass --watch src:dist # автоматически при изменениях
lessc style.less style.css # LESS
```
Также: сборщики (Webpack с `sass-loader`, Vite, Gulp), встроенная поддержка
в IDE, плагины фреймворков.
> **Современная оговорка.** Часть возможностей препроцессоров уже появилась
> в самом CSS: **кастомные свойства** (`--main-color: #333; color:
> var(--main-color)`) — они, в отличие от переменных препроцессора, живут во
> время выполнения и меняются из JS; функция `calc()`; **встроенная
> вложенность** селекторов (поддерживается современными браузерами с 2023 г.).
> Поэтому необходимость в препроцессорах снизилась, но миксины, циклы,
> модульность и функции по-прежнему остаются их преимуществом.
В данной работе препроцессоры не применяются: по заданию стили должны быть
в самом документе внутри `<style>`, объём невелик, и подключение сборки стало
бы «использованием микроскопа для забивания гвоздей».
---
## 7. Клиентские сценарии
**Клиентский сценарий** (client-side script) — программный код, который
передаётся вместе со страницей и выполняется **в браузере пользователя**, а не
на сервере. Противоположность — серверные сценарии (PHP, Java, Python),
исполняемые до отправки ответа.
### Особенности
**Сильные стороны:**
- **Мгновенная реакция** без обращения к серверу — нет задержки сети.
- **Снижение нагрузки на сервер и трафика** — вычисления переносятся на
устройство клиента.
- **Полный доступ к DOM и браузерным API** — можно менять страницу без
перезагрузки, рисовать на Canvas, читать геолокацию, хранить данные.
- **Интерактивность** — анимации, drag&drop, динамические интерфейсы, SPA.
**Ограничения и риски:**
- **Код полностью открыт пользователю.** Исходник виден в DevTools; минификация
лишь затрудняет чтение. Никаких секретов, ключей и паролей в клиентском коде
быть не может.
- **Клиентскую валидацию невозможно считать защитой.** Пользователь может
отключить JS, изменить код в DevTools или послать запрос напрямую через
`curl`. Поэтому **серверная валидация обязательна всегда** — клиентская нужна
лишь для удобства и скорости отклика.
- **Зависимость от среды** — разные браузеры, версии, устройства; нужны
полифиллы и транспиляция.
- **JS может быть отключён** — отсюда принцип постепенного улучшения
(progressive enhancement): базовая функциональность должна работать без JS.
- **Производительность ограничена устройством** клиента; тяжёлые вычисления
блокируют единственный поток и «подвешивают» интерфейс.
- **Безопасность** — уязвимости XSS, когда чужой скрипт исполняется в контексте
страницы.
### Сферы применения
| Сфера | Примеры |
|---|---|
| Валидация форм | Проверка значений до отправки |
| Динамический интерфейс | Табы, модальные окна, аккордеоны, подсказки |
| Асинхронный обмен данными | AJAX, `fetch` — обновление части страницы |
| Графика и визуализация | Canvas, SVG, WebGL, графики и диаграммы |
| Анимация | Переходы, эффекты, параллакс |
| Локальное хранение | `localStorage`, `sessionStorage`, IndexedDB |
| SPA и фреймворки | React, Vue, Angular |
| Работа с медиа | Плееры, обработка изображений |
| Реальное время | WebSocket, чаты, уведомления |
| Устройство пользователя | Геолокация, камера, датчики, уведомления |
| Офлайн-режим | Service Workers, PWA |
| Аналитика | Сбор поведенческих метрик |
### Язык JavaScript
**JavaScript** — высокоуровневый, динамический, интерпретируемый язык
программирования. Создан Бренданом Айком в Netscape в 1995 году за десять
дней; изначально назывался Mocha, затем LiveScript. Имя «JavaScript» —
маркетинговый ход: **к языку Java отношения не имеет**.
Стандартизован как **ECMAScript** (ECMA-262). JavaScript — его наиболее
известная реализация.
**Характеристики языка:**
| Свойство | Пояснение |
|---|---|
| Динамическая типизация | Тип определяется во время выполнения, переменная может менять тип |
| Слабая типизация | Автоматическое приведение типов (`'2' == 2` → `true`) |
| Интерпретируемый + JIT | Движки (V8, SpiderMonkey, JavaScriptCore) компилируют «на лету» |
| Многопарадигменный | Императивный, объектно-ориентированный, функциональный |
| Прототипное наследование | Объекты наследуют от объектов, а не от классов; `class` — синтаксический сахар |
| Функции — объекты первого класса | Передаются как аргументы, возвращаются, замыкания |
| Однопоточность | Один поток выполнения, event loop, асинхронность без блокировки |
| Автоматическая сборка мусора | Память освобождается автоматически |
**Где исполняется:** браузер (основная среда), сервер (Node.js, Deno, Bun),
мобильные приложения (React Native), десктоп (Electron), встраиваемые системы.
**Пример из данной работы.** Все три характерные сферы клиентских сценариев
задействованы:
```js
// 1. Валидация ввода без обращения к серверу
function validateY(showErrors = false) {
const valStr = yInput.value.trim().replace(',', '.');
if (valStr === '') { /* сообщение об ошибке */ return false; }
const y = Number(valStr);
if (isNaN(y)) { return false; }
if (y < -3 || y > 5) { return false; }
return true;
}
// 2. Графика на Canvas
ctx.arc(center, center, R_PIXELS, -Math.PI / 2, 0, false);
// 3. Локальное хранение между перезагрузками
localStorage.setItem(STORAGE_KEY, JSON.stringify(history));
```
Показательно, что данные из `localStorage` в работе перепроверяются при
загрузке:
```js
history = rawData.filter(rec => {
if (![1, 2, 3, 4, 5].includes(rec.r)) return false;
...
});
```
Это иллюстрация главного ограничения клиентских сценариев: всё, что доступно
клиенту, — недоверенные данные, потому что пользователь может их изменить.
По той же причине в работе проверяются значения `data-val` у кнопок R и
`value` у чекбоксов — они редактируются через DevTools.
---
## 8. Версии ECMAScript. Возможности ES6 и ES7
**ECMAScript** — стандарт языка (спецификация ECMA-262), разрабатываемый
комитетом **TC39** организации ECMA International. JavaScript — реализация
этого стандарта.
### История версий
| Версия | Год | Главное |
|---|---|---|
| ES1 | 1997 | Первая редакция |
| ES2 | 1998 | Приведение к стандарту ISO |
| ES3 | 1999 | Регулярные выражения, `try/catch`, `do-while` |
| ES4 | — | **Отменена** из-за разногласий, слишком радикальна |
| ES5 | 2009 | `strict mode`, `JSON`, методы массивов (`forEach`, `map`, `filter`, `reduce`), геттеры/сеттеры, `Object.defineProperty` |
| ES5.1 | 2011 | Уточнения |
| **ES6 / ES2015** | 2015 | Крупнейшее обновление языка |
| **ES7 / ES2016** | 2016 | Маленький релиз, начало ежегодного цикла |
| ES2017 | 2017 | `async/await` |
| ES2018 | 2018 | Spread для объектов, `for await`, `Promise.finally` |
| ES2019 | 2019 | `flat`, `trimStart/End`, необязательный параметр `catch` |
| ES2020 | 2020 | `?.`, `??`, `BigInt`, `Promise.allSettled`, динамический `import()` |
| ES2021 | 2021 | `replaceAll`, `??=`, `Promise.any`, числовые разделители |
| ES2022 | 2022 | Top-level `await`, приватные поля `#`, `at()`, `Object.hasOwn` |
| ES2023 | 2023 | `findLast`, неразрушающие методы массивов (`toSorted`, `with`) |
| ES2024–2025 | | `Object.groupBy`, `Promise.withResolvers`, `Array.fromAsync` и др. |
С 2015 года версии выпускаются **ежегодно** и называются по году. Отсюда
практика называть «современный JS» не версией, а годом.
### ES6 (ES2015) — ключевые возможности
**1. `let` и `const` — блочная область видимости**
```js
let x = 1; // можно переприсвоить
const y = 2; // нельзя (но содержимое объекта меняется)
```
До ES6 был только `var` с областью видимости на всю функцию и всплытием
(hoisting), что порождало классический баг с замыканиями в цикле.
**2. Стрелочные функции**
```js
const sum = (a, b) => a + b;
rButtons.forEach(btn => btn.classList.remove('active'));
```
Короткий синтаксис, неявный `return` без фигурных скобок, и главное —
**не имеют своего `this`**, а берут его из окружающего контекста. Это убрало
необходимость в `var self = this` и `.bind(this)`.
**3. Шаблонные строки (template literals)**
```js
tr.innerHTML = `<td>${rec.x}</td><td>${rec.y}</td>`;
```
Обратные кавычки, подстановка `${выражение}`, многострочность.
**4. Деструктуризация**
```js
const { x, y, r } = rec; // из объекта
const [first, second] = arr; // из массива
const { x: coordX = 0 } = rec; // переименование и значение по умолчанию
```
**5. Параметры по умолчанию, rest и spread**
```js
function validateY(showErrors = false) { } // default
function sum(...nums) { } // rest — собрать в массив
const copy = [...history]; // spread — развернуть
Math.max(...arr);
```
**6. Классы** — синтаксический сахар над прототипами
```js
class Point {
constructor(x, y) { this.x = x; this.y = y; }
hit(r) { return this.x ** 2 + this.y ** 2 <= r ** 2; }
static zero() { return new Point(0, 0); }
}
class Marked extends Point { /* super(), переопределение */ }
```
**7. Промисы** — работа с асинхронностью без «callback hell»
```js
fetch('/api/points')
.then(res => res.json())
.then(data => render(data))
.catch(err => console.error(err));
```
**8. Модули**
```js
export function checkHit(x, y, r) { } // module.js
import { checkHit } from './module.js';
```
Штатное разделение кода на файлы на уровне языка.
**9. Новые структуры данных:** `Map` (ключи любого типа), `Set` (уникальные
значения), `WeakMap`, `WeakSet`.
**10. Итераторы, `for...of` и генераторы**
```js
for (const rec of history) { } // по значениям (vs for...in — по ключам)
function* gen() { yield 1; yield 2; } // генератор
```
**11. Новые методы:** `Array.from`, `Array.of`, `find`, `findIndex`, `fill`,
`Object.assign`, `String.prototype.includes`/`startsWith`/`endsWith`/`repeat`,
`Number.isNaN`, `Number.isInteger`.
**12. Прочее:** краткая запись свойств объекта (`{ x, y }` вместо
`{ x: x, y: y }`), вычисляемые имена свойств (`{ [key]: value }`), символы
(`Symbol`), `Proxy` и `Reflect`, оператор `**` (возведение в степень —
формально ES7), хвостовая рекурсия.
### ES7 (ES2016) — две возможности
ES2016 намеренно сделали маленьким, чтобы перейти к предсказуемому
ежегодному циклу вместо редких гигантских релизов.
**1. Оператор возведения в степень `**`**
```js
2 ** 10 // 1024 — вместо Math.pow(2, 10)
x ** 2 + y ** 2 <= r ** 2
```
Именно в это преобразуется пользовательский ввод в данной работе:
```js
.replace(/\^/g, '**'); // x^2 → x**2
```
**2. `Array.prototype.includes`**
```js
[1, 2, 3, 4, 5].includes(3); // true
[NaN].includes(NaN); // true — а indexOf даёт -1!
```
Удобнее и честнее, чем `arr.indexOf(x) !== -1`: возвращает булево значение и
корректно находит `NaN`. Применяется в работе для проверки допустимых значений:
```js
if (![1, 2, 3, 4, 5].includes(rec.r)) return false;
if (![-2, -1.5, -1, -0.5, 0, 0.5, 1, 1.5, 2].includes(rec.x)) return false;
```
### Коротко о последующих версиях
- **ES2017:** `async/await` — асинхронный код в синхронном стиле;
`Object.values`, `Object.entries`, `padStart`/`padEnd`.
- **ES2020:** опциональная цепочка `obj?.a?.b` и нулевое слияние
`a ?? b` — обе конструкции сильно сократили защитные проверки.
- **ES2022:** приватные поля классов `#field`, `at(-1)`.
### Совместимость и транспиляция
Браузеры поддерживают разные версии стандарта. Решения:
- **Транспиляция** (Babel, TypeScript, SWC) — современный код
переписывается в ES5 для старых браузеров.
- **Полифиллы** (core-js) — реализация отсутствующих методов на старом JS.
- **Browserslist** — настройка целевых браузеров, по которой сборщик решает,
что преобразовывать.
- Таблицы поддержки: caniuse.com, compat-table.
В данной работе используются ES6+ конструкции (`const`/`let`, стрелочные
функции, шаблонные строки, spread, параметры по умолчанию) и ES7
(`includes`, `**`). Транспиляция не нужна: все современные браузеры
поддерживают их нативно, а сборка усложнила бы проект без выгоды.
---
## Краткая шпаргалка для защиты
| Вопрос | Ответ одной фразой |
|---|---|
| HTTP stateless? | Да, сервер не помнит клиента; состояние — через cookies/сессии/токены |
| GET vs POST | GET — данные в URL, кэшируется, идемпотентен, для чтения; POST — в теле, для изменений |
| 401 vs 403 | 401 — не представился; 403 — представился, но нет прав |
| Идемпотентность | Повтор запроса даёт тот же результат; POST — не идемпотентен |
| HTML — язык программирования? | Нет, язык разметки: описывает структуру, не алгоритмы |
| Зачем DOCTYPE | Включает стандартный режим вместо quirks mode |
| DOM | Дерево объектов документа в памяти браузера, доступное из JS |
| `textContent` vs `innerHTML` | Первый вставляет текст, второй парсит HTML — риск XSS |
| Почему `<script>` в конце body | Чтобы DOM был построен; альтернатива — `defer` |
| Какие поля отправляются | Только с атрибутом `name` и без `disabled` |
| Можно ли вложить формы | Нет |
| Приоритет CSS | Важность → специфичность (id=100, класс=10, тег=1) → порядок |
| `A B` vs `A > B` | Все потомки на любой глубине vs только прямые дети |
| Что не наследуется | Блочная модель: margin, padding, border, background, width |
| Зачем CSS вместо style="" | Переиспользование, каскад, псевдоклассы, медиазапросы, кэширование |
| Понимает ли браузер SCSS | Нет, компилируется в CSS до отправки; совместимость 100% |
| Sass vs LESS | `$` vs `@`; Dart vs JS; у Sass сильнее логика и модульность |
| Достаточно ли клиентской валидации | Нет, обходится через DevTools; серверная обязательна |
| ES6 год и главное | 2015; `let`/`const`, стрелочные, классы, промисы, модули, деструктуризация |
| ES7 что добавил | `**` и `Array.prototype.includes` |