CSS-сборщик CreepJS: вычисленные стили
Разберите сбор ключей CSSStyleDeclaration в CreepJS, нормализацию псевдонимов и отдельные запросы цветов и системных шрифтов.
BotBrowser Team
Нужна структурированная документация по теме Отпечатки?
Эта статья относится к редакционной библиотеке. Для пошаговой настройки, справки и постоянных обновлений переходите сразу в соответствующий раздел docs.
В CreepJS есть CSS-сборщик вычисленных стилей, отдельный от сборщика media queries. Зафиксированный
src/css/index.tsстроит список имен свойств, нормализует их псевдонимы, а затем отдельно читает системные цвета и общие ключевые слова шрифтов как вычисленные значения. BotBrowser документирует CSS-настройки профиля, но не утверждает, что реализует этот сторонний сборщик или предсказывает его результат. Список поддерживаемых имен не является списком наблюдавшихся значений и не устанавливает личность устройства.
TL;DR
- Зафиксированный сборщик читает имена, доступные в
CSSStyleDeclaration; он не вычисляет значение каждого названного свойства. - Он объединяет имена прототипа, перечисляемые собственные ключи и распознанные псевдонимы, затем удаляет дубликаты через
Set. - Системные цвета и общие ключевые слова системных шрифтов образуют отдельные запросы значений через
getComputedStyle(). - CreepJS отделяет этот модуль от проверок
@mediaиmatchMedia(), описанных в разборе каналов media query.
Содержание
- Входные данные сборщика
- Как формируется список ключей
- Проверка собственной страницы без выдуманной базы
- У нормализации псевдонимов есть пределы
- Системные цвета и шрифты: отдельные запросы
- Чего список ключей не показывает
- Практический вывод
Входные данные сборщика
Код вызывает getComputedStyle(document.body) и передает полученный CSSStyleDeclaration в computeStyle(). Этот объект служит источником имен доступных свойств, но сборщик не перебирает список, чтобы сохранить вычисленное значение каждого свойства. Если в keys есть color, это означает только, что интерфейс показывает это имя в данном окружении; оно не сообщает, какой цвет вычислен для элемента.
Сборщик также получает прототип декларации через Object.getPrototypeOf() и Object.getOwnPropertyNames(). Имена, принадлежащие самому прототипу, становятся еще одним входом списка. Руководство по CSS fingerprinting посвящено сбору через media query и загрузку ресурсов, а не списку свойств этой декларации.
Это не CSS-сборщик media query в CreepJS. Другой модуль проверяет предпочтения через канал пользовательских свойств @media и matchMedia(); его четырнадцать парных ключей отвечают не на тот же вопрос, что список имен вычисленных свойств.
Как формируется список ключей
Сначала код перебирает Object.keys(cssStyleDeclaration). Числовые ключи считаются индексированными записями: их значения являются именами свойств, поэтому сборщик добавляет значение, а не числовой индекс. Нечисловые ключи добавляются, если это не имена пользовательских свойств с префиксом --. Значение, похожее на токен пользовательского свойства, также исключается из индексированной ветви.
У многих CSS-свойств есть форма с дефисами и camelCase, например background-color и backgroundColor. Сборщик проверяет оператором in, существует ли соответствующая форма, и помечает ее, чтобы две записи не считались независимыми наблюдениями. При сокращении имени для поиска соответствия обрабатывается и начальный префиксный маркер.
Итоговый список объединяет имена прототипа, перечисляемые собственные имена и имена, выведенные из проверок соответствий. Set удаляет дубликаты. Поэтому показанное число описывает совмещенный список ключей для текущего окружения. Это не постоянное значение для всех версий и не означает, что каждое имя дает отдельное вычисленное значение.
| Источник | Что берет код | Что означает результат |
|---|---|---|
| Прототип | Object.getOwnPropertyNames(proto) | Имя, объявленное непосредственно на прототипе декларации |
| Собственные ключи | Object.keys(cssStyleDeclaration) | Перечисляемый собственный ключ; индексная запись превращается в имя свойства |
| Соответствующий псевдоним | Проверки in между формами с дефисами и camelCase | Связь написаний, чтобы не считать псевдонимы разными свойствами |
| Итоговый список | new Set([...]) | Уникальный список имен, а не карта значений |
Зафиксированный исходный код CSS-сборщика задает эти шаги. Справка CSSStyleDeclaration описывает объект, но не утверждает, что все браузеры перечисляют одинаковые имена.
Сборщик можно рассматривать как небольшой конвейер. Первый этап выбирает getComputedStyle(document.body) и прототип CSSStyleDeclaration. Второй строит имена из прототипа и собственных ключей, включая псевдонимы. Третий отдельно просит браузер разрешить системные цвета и общие шрифты. У этапов разные входы и формы результата; не объединяйте их в одно поле «CSS fingerprint».
| Этап | Операция источника | Форма результата | Полезный вопрос |
|---|---|---|---|
| Выбор декларации | getComputedStyle(document.body) | Объект декларации для body | Какой элемент и документ его создали? |
| Перечисление имен | Имена прототипа и Object.keys() | Уникальный массив keys | Изменился ли набор доступных имен? |
| Системные цвета | Задать ключевое слово и прочитать backgroundColor | Значение каждого слова в system.colors | Изменился ли разрешенный системный цвет? |
| Системные шрифты | Задать общий font, прочитать размер и семейство | Строка размера/семейства в system.fonts | Иначе ли разрешился системный shorthand шрифта? |
Это разделение полезно при сравнении версий браузера. Если изменился keys, сначала спросите, изменился ли набор имен, а не цвет отрисованного элемента. Новый псевдоним может изменить массив до удаления дублей; положение свойства в прототипе может повлиять на входной список; Set может скрыть одинаковые написания. И наоборот, список имен может не измениться, даже если вычисленный цвет изменился: он хранится отдельно в system.colors.
Сохраняйте иерархию отчета. CSS-объект содержит результат вычисленных стилей и результат системных стилей; интерфейс добавляет короткий hash и счетчик. Счетчик представляет собой сводку с потерями: она не сохраняет имена и значения, полученные отдельными запросами. Для сравнения храните исходные объекты целиком, а не переписывайте только число.
Проверка собственной страницы без выдуманной базы
На странице, которой вы управляете, эта консольная запись сохраняет категории отдельно. Это вспомогательное чтение, а не воспроизведение всех helper-функций CreepJS и не утверждение о данных другого сервиса:
const declaration = getComputedStyle(document.body);
const prototype = Object.getPrototypeOf(declaration);
const ownNames = Object.keys(declaration).map(key => {
const numeric = !Number.isNaN(Number(key));
return numeric ? declaration[key] : key;
});
const prototypeNames = Object.getOwnPropertyNames(prototype);
const inventory = [...new Set([...prototypeNames, ...ownNames])];
const selectedValues = Object.fromEntries(
['color', 'background-color', 'font-family', 'font-size'].map(name => [name, declaration.getPropertyValue(name)])
);
console.log({ inventory, selectedValues });
В примере выборка значений названа selectedValues; код не заявляет, что воспроизводит полную обработку псевдонимов. Он также не заменяет запросы CreepJS для системных цветов и шрифтов. В зафиксированном исходнике эти запросы создают или переиспользуют элемент, задают ключевое слово в inline-стиле, вызывают getComputedStyle() и читают конкретное поле. Перед интерпретацией укажите, какой элемент читался и менялся ли он.
Для сравнения записей отдельно храните версию браузера, origin страницы, выбранный элемент, время и точный объект. Сравнивайте список имен независимо от значений. Не сортируйте и не нормализуйте исходный объект до сохранения: можно стереть сведения о возвращенном представлении. Нормализованный вид допустим как производная копия, если исходник тоже сохранен.
Отсутствующее значение следует считать отдельным состоянием. Свойство может не поддерживаться, чтение может вернуть пустую строку, либо сборщик может завершиться до создания ожидаемого объекта. Это разные результаты. CSSOM определяет доступ и вычисление стилей, но запись должна уточнять, отсутствовало ли поле, было пустым или содержало значение. Так пропуск наблюдения не превращается в измеренный отрицательный результат.
У нормализации псевдонимов есть пределы
Проверки соответствий в источнике служат дедупликации, но не доказывают, что все написания CSS взаимозаменяемы в любом контексте. Код выводит соответствующую форму для имен с дефисами, учитывает начальный маркер префикса и создает дефисную форму из заглавных букв. Если соответствие есть в объекте декларации, оно помечается в propertiesInPrototypeChain; затем попадает в финальный список перед тем, как Set удалит точные дубликаты.
При сравнении есть два разных вопроса: считает ли этот сборщик две строки псевдонимами и дает ли чтение обеих форм на элементе одинаковый результат. Источник отвечает на первый вопрос при создании списка. Он не сохраняет сравнение значений для каждой пары. Не следует выводить проверку равенства значений только из того, что формы были нормализованы при перечислении.
Пользовательские свойства обрабатываются отдельно. Имена вида --... не добавляются обычной ветвью; некоторые похожие на токен пользовательского свойства значения исключаются из индексированного пути. Это фильтр именно данного источника. Он не доказывает, что пользовательское свойство недоступно через getPropertyValue(); поле keys не является полным дампом деклараций или таблиц стилей.
| Наблюдаемое изменение | Сначала проверьте | Не делайте вывод |
|---|---|---|
Счетчик keys изменился, обычные имена остались | Псевдонимы и перечисление прототипа | Что значение стиля изменилось в той же пропорции |
| Появилась новая форма с дефисом/camelCase | Преобразование имени и проверку in | Что значения обеих форм были измерены |
Изменился system.colors | Назначение ключевого слова и вычисленный backgroundColor | Что причиной обязательно была тема системы |
Изменился system.fonts | Общий shorthand font, размер и семейство | Что перечислены все установленные шрифты |
| CSS-отчет отсутствует или неполон | Обработку ошибок и путь отображения | Что браузер вернул пустой список |
Таблица представляет собой карту первичной диагностики, выведенную из зафиксированной реализации. Она показывает происхождение классов результата, но не диагностирует конкретную разницу без исходных объектов и метаданных окружения.
Системные цвета и шрифты: отдельные запросы
getSystemStyles() выполняет две группы вызовов. Для цветов Canvas, CanvasText, ButtonFace и Highlight временный элемент получает background-color, после чего читается getComputedStyle(el).backgroundColor. Для общих ключевых слов шрифта caption, icon, menu, message-box, small-caption и status-bar код задает shorthand font и записывает вычисленные fontSize и fontFamily.
Это наблюдения значений, в отличие от списка keys. Это и не парсер цветов: сборщик просит браузер разрешить системные ключевые слова и сохраняет полученную строку цвета. Справка о системных цветах CSS описывает категорию, а getComputedStyle() служит API для чтения вычисленного стиля.
Если элемент не передан, источник создает div, добавляет его в document.body, считывает стили и удаляет. Если элемент передан, используется он. Функция перехватывает ошибки и не возвращает результат системных стилей после сбоя, сообщая его через обработчик ошибок CreepJS. Поэтому отсутствие результата не означает измеренный пустой список.
Фиксированные списки показывают и то, чего сборщик не пытается измерять. Список цветов содержит Canvas, CanvasText, Field, FieldText, Highlight и WindowText; список шрифтов содержит общие ключевые слова, а не каталог установленных семейств. Результат отвечает, как браузер разрешил эти ключевые слова на выбранном элементе, но не какие шрифты установлены и не что вернул matchMedia().
Источник задает цвет как background-color: <keyword> !important, затем читает вычисленный фон. Для шрифта он задает shorthand font и соединяет вычисленные размер и семейство. Эти действия определяют измеряемую поверхность. Сравнительная запись должна сохранять ключевое слово, имя поля и возвращенную строку; иначе CanvasText → rgb(...) можно принять за прямое чтение цвета текста произвольной страницы.
Временное состояние DOM также имеет значение. Путь по умолчанию добавляет собственный div в body, читает стили и удаляет его. Это отличается от чтения элемента приложения, на который влияют классы, наследованные стили или inline-декларации. В источнике выбор элемента явный; воспроизведение не должно молча менять его, а затем приписывать разницу браузеру.
Чего список ключей не показывает
Список свойств не доказывает, что страница использовала свойство, что вернулось определенное значение или что удаленный детектор обработал отчет. Источник показывает записываемые имена и запрашиваемые системные стили. Сам по себе он не устанавливает оборудование, ОС или человека. Наличие имени само по себе является наблюдением поверхности API; для трактовки нужны версия браузера, контекст документа и реальные значения.
BotBrowser документирует CSS-настройки профиля в справке о согласованности CSS-сигналов, но не имитирует сборщик CreepJS и не гарантирует его результат. Возможности продукта и утверждения об исходнике CreepJS следует держать раздельно.
FAQ
keys содержит все вычисленные CSS-значения?
Нет. Это имена, собранные из ключей декларации и псевдонимов. Показанный код отдельно запрашивает только цвета и шрифты системы через getSystemStyles().
Зачем читать и объект, и его прототип?
Источник рассматривает перечисляемые собственные ключи и собственные имена прототипа как разные входы и затем объединяет их. Это показывает нормализацию сборщика, но не означает, что каждый вход является отдельным измерением браузера.
Это тот же сигнал, что matchMedia()?
Нет. src/css/index.ts читает имена деклараций и системные стили. src/cssmedia/index.ts проверяет предпочтения через CSS-правила и matchMedia(). Общее слово CSS не делает их одним сборщиком.
Может ли список идентифицировать устройство?
Нет. Имена описывают поверхность API, а результаты стилей представляют собой значения, разрешенные браузером. Ни то ни другое по отдельности не устанавливает физическое устройство или уникальную личность.
Источники
- Зафиксированный CSS-модуль CreepJS (
src/css/index.ts) - MDN:
Window.getComputedStyle() - MDN:
CSSStyleDeclaration - MDN: системные цвета CSS
- BotBrowser: согласованность CSS-сигналов
Практический вывод
Читайте CSS-отчет CreepJS как два вида данных: объединенный список имен свойств и отдельные вычисленные значения системных цветов и шрифтов. При сравнении сохраняйте эти категории раздельно, фиксируйте ревизию источника и храните реальные объекты вместо выводов по одному счетчику. Статья о каналах media queries описывает предпочтения, а материал о таблицах шрифтов CreepJS рассматривает другое поле отчета, а не вычисленные системные CSS-шрифты.
Эта статья входит в руководство: Что такое отпечаток браузера?
Похожие статьи
CreepJS: CSS-медиазапросы и два канала настройки
ОтпечаткиCSS-фингерпринтинг: как стили отслеживают вас
ОтпечаткиТаблицы шрифтов CreepJS: 51 имя и 14 вариантов возврата
ОтпечаткиОтчёт CreepJS WebRTC: происхождение полей
ОтпечаткиОтчёт CreepJS WebGL: контексты и сигналы
ОтпечаткиСигналы Math в CreepJS: источники полей
Выполните ту же проверку в BotBrowser
Загрузите профиль, сохраните внутри браузера те сигналы, о которых только что прочитали, и подтвердите результат на своей машине до раскатки.