Файл (англ. file
) — определенное количество информации (в виде программы или данных), имеющее имя и хранящееся во внешней памяти компьютера.
Текстовый файл (англ. text file
) содержит текстовые данные (символы, составлящие слова, формулы и прочее).
Двоичный, бинарный файл (англ. binary file
) содержит последовательность байт (состоящих из бит), которая что-то может значить.
Обычно принято разделять файлы на текстовые и бинарные, но оба этих типа хранятся в памяти компьютера одинаково: как последовательность байт. Текстовый файл просто интерпретируется в текст, но на самом деле является частным случаем бинарного файла. На низком уровне кодировки и символы компьютером не воспринимаются: он понимает только нули и единицы.
Имя файла (англ. filename
) состоит из двух частей, разделенных точкой .
: название файла и расширение, тип файла (англ. extension
).
Например, Notes.pdf
, Browsers.md
, users.txt
.
Файловая система (англ. file system
) — система хранения файлов и организации каталогов (папок).
Примечание: в браузерах Webkit (Chrome, Safari) и Gecko (Mozilla) терминология немного отличается.
Далее будет рассматриваться версия Webkit с пометками о том, как это называется в Gecko.
Uniform Resource Locator (URL) — ссылка на веб-ресурс (документ, изображение и прочее), определяющая его расположение в компьютерной сети и способ его получения (зависит от протокола).
Адресная строка (address bar, URL bar) — элемент интерфейса веб-браузера, который отображает текущий URL и позволяет изменять его на любой другой.
Следующая схема URL описывает большинство случаев использования адресной строки.
protocol:[//hostname[:port]][/path][?query]
Допустим, пользователь ввёл URL и нажал Enter.
Лексема — последовательность допустимых символов языка, имеющая определённый смысл для транслятора.
Браузер принимает введённую пользователем строку и пытается понять, из чего она состоит — разбивает её на лексемы (за счёт наличия :
, //
, /
, ?
).
Примеры разбиения URL на лексемы:
- http://localhost:3000
http
- протокол,localhost
- hostname,3000
- порт - https://twitter.com/favicon.ico:
https
- протокол,twitter.com
- hostname,favicon.ico
- путь - https://github.com/Max-Starling?from=2018-12-01&to=2018-12-31
https
- протокол,github.com
- hostname,Max-Starling
- путь,from=2018-12-01&to=2018-12-31
- query.
При наличии в URL корректного hostname и отсутствии протокола, браузер подставляет нужный протокол самостоятельно (по умолчанию HTTP, HTTPS для сайтов).
Если отсутствует протокол и браузеру не удаётся найти корректный hostname в строке, то она воспринимается как поисковой запрос.
Например, если пользователь ввёл в адресную строку hello world
, то браузер с поисковиком Chrome по умолчанию перейдёт на https://www.google.com/search?q=hello%20world.
Domain Name System (DNS) — система доменных имён, которая хранит информацию о доменах по их именам.
Обычно её используют для получения IP-адреса по имени хоста.
Домен (domain) — узел в дереве имён, вместе со всеми дочерними (подчинёнными) ему узлами.
Доменное имя — символьное обозначение, зарегистрированное для сетевой адресации, в которой используется DNS.
Доменные имена в доменах отделяются точками. Разрешённые символы в доменном имени: a-z
, 0-9
, -
.
DNS имеет древовидную (иерархическую) структуру.
Например, система доменных имён из двух доменов subdomain.domain.com
и wikipedia.org
имеет вид:
На самом деле полный домен выглядит вот так wikipedia.org.
, cимвол .
в конце — корневой домен, org
— домен верхнего (первого) уровня, wikipedia
— домен второго уровня.
Поддомен (subdomain) — подчинённый домен.
domain.com
- поддомен домена com
, subdomain.domain.com
- поддомен домена domain.com
.
Сперва браузер проверяет локальный кэш DNS.
В случае отсутствия кэша, для поиска (lookup) браузер вызывает функцию gethostbyname
, которая работает по-разному в зависимости от операционной системы.
Функция gethostbyname
сперва проверяет локальный файл hosts
(текстовый файл, содержащий базу данных доменных имён и используемый для их трансляции в IP-адреса), содержимое которого задаётся администрартором компьютера.
/* файл hosts */
127.0.0.1 localhost
Если файл hosts
не содержит нужного домена, делается запрос к DNS-серверу, являющемуся частью настроенного стека протоколов (network stack).
Есть два популярных DNS-сервера: 1.1.1.1
— Cloudflare, 8.8.8.8
— Google), однако большинство людей используют DNS-сервер, предоставленный интернет-провайдером.
DNS-сервер может хранить IP-адрес домена в своём кэше, если недавно уже разрешал (resolve) его.
Если в кэше домена нет, то делается запрос к корневому DNS-сервер .
(система из множества серверов по всему миру, управляющая интернетом).
Корневой DNS-сервер не знает IP-адреса каждого домена в мире, но может перенаправить запрос на тот DNS-сервер, который может знать — сервер верхнего уровня.
Браузер выполняет DNS-запрос по протоколу UDP, являющимся транспортным протоколом без установки соединения (connectionless).
Байты (bytes) → Символы (characters) → Лексемы → Токены (tokens) → Узлы (nodes) → Объектная модель (object model)
Алгоритм обработки HTML-файла:
- Загрузка файла. Браузер загружает файл (обычно из сети или локальной файловой системы, т.е. с диска), закодированный какой-то кодировкой. В компьютерной памяти все файлы представляются байтами, поэтому при загрузке файла браузер получает поток байтов.
EF BB BF EF B9 A4 68 74 6D 6C EF B9 A5
- Распознавание кодировки. Сначала браузер пытается распознать кодировку. Он считывает первые три байта из потока в буфер и проверяет, являются ли они символом маркера последовательности байтов (Byte Order Mark,
U+FEFF
), который указывает кодировку. Если да, то оставшиеся символы расшифровываются с учётом этой кодировки, если нет, то браузер пытается распознать кодировку самостоятельно, в случае неудачи далее используется кодировка UTF-8.
0xEF 0xB9 0xA4 → U+FEFF → маркер кодировки UTF-8
- Преобразование байтов в символы (decoding). Браузер расшифровывает (decode) поток байтов (stream of bytes) в символы, опираясь на заданную кодировку (encoding). Подробнее об алгоритме декодирования можно прочитать здесь.
0xEF 0xB9 0xA4 → U+FE64 → "<"
0x68 → U+0068 → "h"
0x74 → U+0074 → "t"
0x6D → U+006D → "m"
0x6C → U+006C → "l"
0xEF 0xB9 0xA5 → U+FE65 → ">"
<html>
- Лексический анализ (lexing, tokenization). Браузер конвертирует последовательности символов в отдельные распознанные группы — лексемы, каждая из которых имеет определённый смысл. Затем лексемы преобразовываются в объекты — токены, имеющие определённые свойства и правила.
Пример разбиения HTML на лексемы: <div class="box"></div>
.
<
- начало тега, div
- название тега, class
- название атрибута, =
- символ, объединяющий атрибут и его значение, "
- начало значения атрибута, box
- значение атрибута, "
- конец значения атрибута, >
- конец тега, </
- начало закрывающего тега, div
- название тега, >
- конец тега.
- Построение объектной модели. На основании информации токенов и их последовательности выясняется, из каких элементов состоит HTML и как они расположены по отношению друг к другу. Первое позволяет представить html-элементы в виде объектов. Второе — в виде дочерних и родительских элементов одного дерева. Поскольку в качестве узлов, вершин (nodes) дерева берутся объекты, полученная модель называется объектной моделью.
Полученную модель называют объектной моделью документа (Document Object Model, DOM).
Этот алгоритм браузер проделывает каждый раз, когда нужно обработать HTML.
Теперь браузер загружает подключенные к HTML-документу ресурсы (делая к ним запросы): картинки, видео, иконки, шрифты, а также CSS.
<link rel="stylesheet" type="text/css" href="/styles.css"/>
Любой CSS, присутствующий в документе (загруженный файлом или встроенный в документ при помощи <style>
, style=""
), браузер обрабатывает по тому же алгоритму, что и HTML, однако до построения объектной модели происходит ещё два важных действия:
- каскад
- обработка значений.
Получившееся в результате работы алгоритма представление в виде дерева называется объектной моделью CSS (CSS Object Model, CSSOM).
Пример разбиения CSS на лексемы : .box { width: 40px; }
.
.
- начало селектора по классу, box
- название класса, {
- начало блока объявлений, width
- свойство, :
- символ, объединяющий свойство с его значением, 40px
- значение свойства, ;
- конец объявления, }
- конец блока объявлений.
В CSS многие стили применяются не только к самому элементу, но и к его потомкам.
Это называется наследованием: потомки наследуют свойства предка.
Именно поэтому CSS имеет древовидную структуру.
Значение при обработке проходит следующие этапы.
- Объявленное значение (Declared value) — значение, объявленное автором (author declaration), то есть разработчиком.
- Каскадное значение (Cascaded value) — значение, полученное в результате применения каскада. Если есть конфликтующие объявления, применяется более приоритетное из них и становится каскадным. Значение, заданное браузером (user-agent declaration), становится каскадным, если бъявленное значение отсутствует. Примеры браузерных значений: синий цвет и подчёркивание ссылок
<a>
. - Указанное значение (Specified value) — значение, заданное по умолчанию для свойства (initial value). Указанное значение используется, если каскадное значение отсутствует. Каждое свойство имеет указанное значение. Значение, заданное браузером не является значением по умолчанию. Пример значений по умолчанию: для
margin
иpadding
по умолчанию применяется0px
, для шрифтов —16px
, для цвета —#000
. Наследуемое значение также становится указанным (применяется, если объявленное и каскадное отсутствуют). Наследуется вычисленное значение (computed value) родительского элемента, а не объявленное. - Вычисленное значение (Computed value) — значение, переведённое из относительных единиц (relative) в абсолютные (absolute). Также на этом шаге происходит перевод таких значений, как
auto
,green
,bold
и других. - Используемое значение (Used value). CSS-движок использует отрисованный макет (rendered layout), чтобы понять, как следует поступить с оставшимися значениями, зависящими от макета (например,
vh
,vw
,%
). Используемое значение считается точно (с плавающей точкой). Например,359.6px
. - Фактическое значение (Actual value) — финальное значение, готовое для использования в макете. Вычисляется на этапе этапе рендеринга страницы. Используемое значение может быть значением с плавающей точкой. Браузер не может разделить пиксели, поэтому округляет значение до целого
360px
.
%
технически не является единицой измерения (unit).
Все величины переводятся в пиксели, поскольку страница состоит из них.
Относительное значение переводится в пиксели относительно вычисленного значения (computed value).
%
для шрифта (font) вычисляется относительно размера шрифта родительского элемента.
.parent {
font-size: 24px;
}
.child {
font-size: 150%; /* 36px */
}
%
дляwidth
,margin
,padding
вычисляются относительноwidth
родительского элемента,height
— относительноheight
родительского элемента,border
не вычисляется в процентах.
.parent {
width: 200px;
height: 100px;
border: 2px solid #000;
}
.child {
width: 80%; /* 160px (от ширины родителя) */
padding: 10%; /* 20px (от ширины родителя) */
margin-top: 50%; /* 100px (от ширины родителя) */
/* но */
height: 50%; /* 100px (от высоты родителя) */
border: 50% solid #000; /* 0px (не считается в процентах) */
}
em
для шрифта вычисляется относительноfont-size
родительского элемента.1em
=font-size
родителя.
.parent {
font-size: 16px;
}
.child {
font-size: 4em; /* 64px */
}
em
дляwidth
,height
,margin
,padding
вычисляется относительноfont-size
текущего элемента.
.parent {
font-size: 24px;
}
.child {
font-size: 16px;
height: 4em; /* 64px (от шрифта текущего элемента) */
padding: 1em; /* 16px (от шрифта текущего элемента) */
}
rem
для всех свойств вычисляется относительно корневого (root)font-size
. Браузер обычно по умолчанию задаёт корневойfont-size
в16px
. Корневым элементом являетсяhtml
.
.block {
width: 10rem; /* 160px */
font-size: 2rem; /* 32px */
}
vh
иvw
для всех свойств вычисляются относительно высоты и шириныviewport
соответственно.
.block {
width: 10vw; /* 160px */
font-size: 10vh; /* 32px */
}
JavaScript — блокирующий ресурс для отрисовки, поскольку может напрямую работать с DOM.
Если скрипт внешний, то файл сперва загружается, а потом запускается (evaluate).
<script src="/main.js"></script>
Если скрипт встроенный, то файл сразу запускается.
<script>console.log('Hi')</script>
Если скрипт как-то повлиял на объектные модели, то в них вносятся соответствующие изменения.
Деревья DOM и CSSOM вместе объединяются в дерево рендеринга (Render Tree).
Алгоритм построения дерева рендеринга
- На рассмотрение берутся вершины DOM.
- Из рассмотрения исключаются вершины, которые не видны на странице:
<head>
со своим содержимым,<script>
и прочие подобные. - Для каждой оставшейся вершины находятся соответствующие наборы правил в CSSOM.
- Из рассмотрения исключаются вершины, которые скрыты при помощи CSS: имеют объявление
dispalay: none
. - Каждая оставшейся вершина DOM вместе со своими наборами правил становится вершиной дерева рендеринга.
Вершина дерева рендеринга называется объектом рендеринга (Render Object).
В браузерах на движке Gecko дерево рендеринга может также называться деревом фреймов (Frame Tree), а вершина дерева - фреймом (frame) или боксом (box).
После построения дерева рендеринга браузер знает, какие объекты видны на странице и какие стили к ним нужно применить.
При рассчёте макета (Layout) вычисляются расположение элементов на экране и занимаемое ими место, то есть их геометрия.
В первую очередь проверяется вьюпорт.
Его значение берётся из соответствующего метатега, в случае его отсутствия браузером задаётся значение по умолчанию.
<meta name="viewport" content="width=device-width, initial-scale=1">
Значения высоты и ширины вьюпорта берутся как базовые, затем браузер обходит (traverse) дерево рендендеринга, начиная от его корня <html>
, вычисляя все значения элементов: часто значения дочерних элементов зависят от родительских.
Пусть ширина вьюпорта составляет 800px.
<body>
<div class="parent">
<div class="child"></div>
</div>
</body>
html {
width: 50%; /* 400px, 50% от viewport */
}
body {
width: 25%; /* 100px, 25% от html */
}
.parent {
width: 100vw; /* 800px, 100% от viewport */
}
.child {
width: 10%; /* 80px, 10% от parent */
}
После рассчёта макета каждый элемент на странице имеет свою блочную модель (box model), а все величины измерения переводятся в пиксели.
Прорисовка (Painting) – это процесс заполнения пикселей на экране.
Иногда этот процесс называют растеризацией, растрированием (rasterisation, rasterization).
Он подразумевает вывод текста, цветов, изображений, границ и теней, по сути – всех визуальных частей элементов. Прорисовка обычно выполняется на нескольких поверхностях, которые называются слоями.