Code Ready | Frontend


Kanal geosi va tili: Rossiya, Ruscha


Авторский канал по Frontend разработке.
Ресурсы, гайды, задачи, шпаргалки.
Информация ежедневно пополняется!
Автор: @energy_c
РКН: https://clck.ru/3NJCKs
Реклама на бирже: https://telega.in/c/code_ready

Зарегистрирован в РКН
Связанные каналы  |  Похожие каналы

Kanal geosi va tili
Rossiya, Ruscha
Statistika
Postlar filtri


Если вы уже используете ChatGPT, Claude или Cursor в разработке, но всё равно большую часть работы делаете руками — вы используете ИИ далеко не на максимум.

25 августа Хекслет проведёт бесплатный воркшоп, где покажут, как встроить AI-агента непосредственно в процесс разработки.

За 2 часа на реальном репозитории:
— настроите контекст проекта и AGENTS.md;
— дадите агенту задачу от issue до готового кода;
— подключите тесты и CI;
— автоматизируете code review;
— подключите RAG и MCP для работы с документацией, тикетами и API.

В результате — не набор промптов, а готовый процесс работы с AI-агентом.

25 августа, 19:00
Бесплатно.

👉 Записаться на вебинар



#реклама
О рекламодателе


👩‍💻 Нативный раскрывающийся блок с контентом без JavaScript!

Теги и позволяют создавать интерактивные блоки, содержимое которых пользователь может раскрывать и скрывать прямо средствами HTML.

Каждый из тегов выполняет свою роль:
— содержит скрываемый и раскрываемый контент;
— задаёт видимый заголовок, по которому можно кликнуть для переключения состояния блока.


По умолчанию содержимое скрыто. Если добавить атрибут open, блок будет изначально раскрыт. Такая конструкция отлично подходит для FAQ, дополнительной информации, настроек, примечаний и других элементов интерфейса, которые не нужно постоянно держать на экране.

При этом базовое раскрытие и сворачивание работает без единой строки JS.

📣 Code Ready | #атрибут


Получаем порядковый номер элемента прямо в CSS!

Для каскадной анимации списка часто приходится передавать индекс из JavaScript или прописывать :nth-child() для каждого элемента.


В CSS появились функции sibling-index() и sibling-count(): первая возвращает позицию элемента среди всех дочерних элементов родителя, начиная с 1, вторая — их общее количество.

Поэтому задержку от 0ms можно вычислить автоматически:
.item {
animation-delay: calc((sibling-index() - 1) * 80ms);
}

Добавили десятый элемент — ничего менять не нужно. Его индекс вычислится из DOM автоматически.

Общее количество элементов тоже доступно прямо в выражении:
.item {
--total: sibling-count();
}

Это можно использовать для stagger-анимаций, распределения элементов и вычислений, которые раньше требовали --i, :nth-child() или генерации CSS из JavaScript.

🔥 Функции учитывают все соседние элементы одного родителя, а не только элементы с классом .item. Поддержка пока ограничена, поэтому перед использованием нужно проверить целевые браузеры.

📣 Code Ready | #совет


🐱 Awesome Frontend Dev — большая подборка материалов и инструментов для frontend-разработчика!

Здесь собраны учебники, справочники, курсы и полезные сервисы по HTML, CSS, JavaScript, TypeScript, React, Next.js, Node.js и SQL. Есть отдельные подборки для изучения Flexbox и Grid, тренировки задач на Codewars и LeetCode, подготовки к собеседованиям, работы с GitHub, размещения проектов и использования AI-инструментов в разработке.

Оставляю ссылочку: GitHub 📱


📣 Code Ready | #репозиторий


Element.toggleAttribute() — нативное переключение DOM-атрибутов!

В DOM многие состояния элементов представлены через наличие или отсутствие атрибутов: disabled, hidden, required и пользовательские атрибуты состояния компонентов. Element.toggleAttribute() предоставляет нативный механизм для управления такими состояниями без ручной проверки текущего значения.

До появления toggleAttribute() подобные операции обычно реализовывались через отдельную проверку наличия атрибута и последующее добавление либо удаление:
const button = document.querySelector('button');

if (button.hasAttribute('disabled')) {
button.removeAttribute('disabled');
} else {
button.setAttribute('disabled', '');
}

Element.toggleAttribute() объединяет эту логику в один вызов. Метод проверяет текущее состояние атрибута и выполняет противоположное действие.
button.toggleAttribute('disabled');

Если атрибут отсутствует — он будет добавлен. При повторном вызове — удалён.

Для boolean HTML-атрибутов важно учитывать, что браузер анализирует сам факт присутствия атрибута, а не его значение.

Submit


а также

Submit


имеют одинаковое поведение.

Метод возвращает boolean, отражающий состояние атрибута после выполнения операции:
const isDisabled = button.toggleAttribute('disabled');

console.log(isDisabled); // true

Дополнительно toggleAttribute() поддерживает второй аргумент force, который позволяет явно задать требуемое состояние вместо переключения.
button.toggleAttribute('disabled', true); // добавить атрибут
button.toggleAttribute('disabled', false); // удалить атрибут

Этот вариант удобен при синхронизации DOM с состоянием приложения, когда итоговое значение уже вычислено:
input.toggleAttribute('required', isRequired);

toggleAttribute() работает с любыми валидными DOM-атрибутами, включая пользовательские флаги состояния компонентов:
const card = document.querySelector('.card');

card.toggleAttribute('data-selected');

После выполнения:


На практике метод используется для управления простыми состояниями интерфейса: переключение видимости элементов, изменение доступности контролов, управление режимами компонентов и другие сценарии, где состояние выражается наличием атрибута.

Например, управление видимостью через стандартный атрибут hidden:
const block = document.querySelector('.details');

block.toggleAttribute('hidden');

🔥 Element.toggleAttribute() определён в DOM Standard и предоставляет единый API для добавления и удаления атрибутов без необходимости вручную комбинировать hasAttribute(), setAttribute() и removeAttribute(). Полезный метод, который делает работу с DOM-состояниями более лаконичной и предсказуемой. Поддерживается всеми современными браузерами.

📣 Code Ready | #практика


Что фронтенд может, а что не может, когда лёг хостинг

Недавно натыкался на новость — у одного из хостеров случился короткий сбой на уровне энергоснабжения дата-центра. Задело часть их инфраструктуры и клиентские сервисы. Восстановили быстро, но ЛК и часть сайтов на их хостинге минут на 40 ушли в недоступность.

В этот момент пользователь видит именно фронт. И самое неприятное — ты физически не можешь повлиять на ситуацию. Весь стек упирается в то, что происходит на площадке, которую ты даже и не видел никогда.

Такие истории — повод присмотреться к площадкам с продуманной инфраструктурой, а не разбираться постфактум. В рамках своих задач недавно зацепился за ЦОД Московского кластера видеоигр и анимации.

По питанию там два независимых ввода, ИБП, умные PDU. Охлаждение с изоляцией горячих/холодных коридоров. Сеть и хранение тоже задублированы — резервирование коммутаторов, диски арендных серверов в RAID-массивах. По площадке — 21 стойка, до 20 кВт на каждую, SLA 99,95%. Из железа — GPU-серверы (RTX Ada, H100). Там же и колокейшн от юнита за 4 000 р/мес до стойки 42U от 105 000 р/мес.

Кому интересно, вот страница ЦОДа с характеристиками. Я, например, после всех историй со сбоями начал смотреть на дата-центры иначе.

А если площадка все-таки легла, в ход идут инструменты фронта:

offline-страница через Service Worker — только для тех, кто уже открывал сайт раньше и SW успел закешироваться; 

закешированные данные из localStorage/IndexedDB вместо пустого экрана — тоже нужен предыдущий визит; 

retry с backoff нужны не ради выживания в простой. Их цель — поберечь лежащий бэкенд и вовремя выдать вменяемую ошибку вместо бесконечной загрузки; 

статус-страница на отдельном хостинге/CDN.

Все остальное зависит от того, что происходит на стороне инфраструктуры.

📣 Code Ready


Попалась супер интересная статья на Хабре: «Как я собрал сайт на 30 000 SEO-страниц за месяц»!

В этой статье:
• Показывается, как в одиночку с помощью Claude и GPT за месяц собрать полноценный веб-проект почти без ручного написания кода;
• Разбирается архитектура на Astro со статической генерацией, серверным поиском, PWA и сборкой десятков тысяч лёгких страниц;
• Рассказывается, как построить и отладить автоматический конвейер наполнения, который после настройки генерирует около 14 000 страниц в неделю;

🔊 Продолжайте читать на Habr!


📣 Code Ready | #статья


innerText vs textContent — как обычное чтение DOM может заставить браузер пересчитать layout!

DOM хранит структуру документа отдельно от того, как эта структура отображается пользователю. textContent работает на уровне DOM-дерева. Он проходит по текстовым узлам и собирает содержимое без анализа CSS, размеров элементов или текущего состояния отображения.
const text = element.textContent;

innerText работает иначе. Чтобы вернуть текст в том виде, в котором его видит пользователь, браузеру необходимо учитывать CSS, видимость элементов, переносы строк и актуальное состояние компоновки.
const text = element.innerText;

Именно поэтому простое чтение свойства иногда может быть дорогой операцией:
element.style.width = '400px';

const text = element.innerText;

После изменения стиля браузер помечает компоновку как устаревшую. Если следующая операция требует данных о визуальном состоянии страницы, браузеру может потребоваться немедленно выполнить перерасчёт. Это называется принудительным синхронным перерасчётом layout.

Похожий механизм работает с другими свойствами, зависящими от текущей геометрии страницы:
element.style.width = '400px';

const width = element.offsetWidth;

К этой же категории относятся offsetHeight, getBoundingClientRect() и чтение некоторых свойств прокрутки (scrollTop, scrollHeight и другие).

Проблема обычно появляется не из-за одного вызова, а из-за постоянного смешивания операций записи и чтения:
elements.forEach(element => {
element.style.width = '400px';
console.log(element.innerText);
});

В таком случае браузер может постоянно выполнять цикл: запись — устаревшая компоновка — чтение — расчёт компоновки.

Это приводит к частым лишним перерасчётам компоновки (layout thrashing). Гораздо эффективнее разделять изменение состояния и чтение данных:
elements.forEach(element => {
element.style.width = '400px';
});

const values = elements.map(
element => element.innerText
);

Важно понимать: innerText не является медленным сам по себе. Если состояние компоновки уже актуально, чтение может быть дешёвым. Проблема возникает тогда, когда браузеру приходится синхронизировать DOM с текущим визуальным состоянием страницы.

Если нужно получить данные из DOM, обычно достаточно textContent. Если нужен текст именно в том виде, в котором его воспринимает пользователь, используется innerText.

🔥 Разница между ними не только в возвращаемой строке. textContent работает с моделью документа, а innerText — с моделью отображения. В производительных интерфейсах это различие может определить, будет ли чтение обычным получением текстового содержимого или причиной перерасчёта компоновки.

📣 Code Ready | #практика


👩‍💻 Связываем подпись с полем формы с помощью атрибута for!

Атрибут for используется у тега и указывает, к какому элементу формы относится подпись.

А ещё не каждый элемент подойдёт для связи, годятся только из категории «связываемых»:
;
;
;
;
;
;
И даже сам .


Кроме удобства, правильная связка улучшает доступность формы, поскольку вспомогательные технологии могут определить, какая подпись относится к конкретному полю.

📣 Code Ready | #атрибут


📱 Intersection Observer API — отслеживание видимости элементов!

В этой шпаргалке собраны основные методы и свойства Intersection Observer API для асинхронного отслеживания пересечения элементов с viewport или заданным root. Здесь показано, как подключать и отключать наблюдение, определять факт и степень пересечения, получать геометрию элемента, области пересечения и root, а также применять observer для lazy loading, аналитики и UI-эффектов.

📣 Code Ready | #шпора


Храним собственные данные прямо в HTML с помощью data-*!

Дата-атрибут — это пользовательский атрибут на HTML-элементе, название которого начинается с data-. Это встроенная возможность стандарта HTML5. В дата-атрибутах можно хранить дополнительную информацию в стандартных HTML-элементах и работать с этой информацией в JS при помощи собственного API.

После data- указывается произвольное имя, описывающее значение:
• data-id — идентификатор объекта;
• data-theme — тема оформления;
• data-status — состояние элемента;
• data-user-id — идентификатор пользователя.

data-* полезен, когда элементу нужно передать дополнительные данные для поведения интерфейса, не отображая их пользователю.

📣 Code Ready | #атрибут


✍️ React от нуля до архитектора — большое руководство по React-разработке!

Материал начинается с основ JavaScript и постепенно переходит к компонентам, JSX, хукам, формам и роутингу. Дальше разбираются TanStack Query, Redux Toolkit и Zustand, TypeScript, тестирование, безопасность, оптимизация производительности, архитектурные паттерны, Next.js, SSR и React Server Components. Получается полноценный маршрут от основ React до разработки и архитектуры крупных приложений.

Оставляю ссылочку: GitHub 📱

📣 Code Ready | #репозиторий


TreeWalker — последовательный обход DOM без создания промежуточной коллекции!

При обходе DOM часто используют рекурсию или querySelectorAll(). Это рабочие подходы, но они подходят не для всех задач: рекурсивный обход требует дополнительной логики, а querySelectorAll() сразу формирует статический NodeList со всеми найденными элементами.

DOM API предоставляет интерфейс TreeWalker, который позволяет последовательно обходить дерево документа и получать только нужные узлы по мере обхода. Например, создадим объект для обхода элементов:
{
const walker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_ELEMENT
);

let node;

while ((node = walker.nextNode())) {
console.log(node.tagName);
}
}

Обход начинается с потомков переданного корневого узла, поэтому сам document.body в цикл не попадёт.

TreeWalker поддерживает фильтрацию узлов. Например, можно возвращать только кнопки во время обхода дерева:
{
const walker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_ELEMENT,
{
acceptNode(node) {
return node.tagName === 'BUTTON'
? NodeFilter.FILTER_ACCEPT
: NodeFilter.FILTER_SKIP;
}
}
);

let node;

while ((node = walker.nextNode())) {
console.log(node);
}
}

Фильтр вызывается для узлов во время обхода, поэтому отдельная коллекция найденных элементов не создаётся.

FILTER_SKIP пропускает текущий узел, но продолжает обход его потомков. Если необходимо исключить всё поддерево целиком, используется FILTER_REJECT. TreeWalker также поддерживает навигацию в разных направлениях:
walker.parentNode();
walker.firstChild();
walker.lastChild();
walker.previousSibling();
walker.nextSibling();
walker.previousNode();
walker.nextNode();

Например, можно найти первый элемент с атрибутом data-error и сразу прокрутить страницу к нему:
{
const walker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_ELEMENT
);

let node;

while ((node = walker.nextNode())) {
if (node.hasAttribute('data-error')) {
node.scrollIntoView({
behavior: 'smooth',
block: 'center'
});

break;
}
}
}

В отличие от querySelectorAll(), TreeWalker не создаёт промежуточную коллекцию найденных элементов, а возвращает узлы по мере обхода дерева.

При этом TreeWalker не обязательно будет быстрее querySelectorAll() в каждом конкретном случае. Выбор зависит от задачи: для простого поиска по CSS-селектору обычно удобнее querySelector() или querySelectorAll(), а для управляемого последовательного обхода дерева — TreeWalker.

🔥 TreeWalker определён в DOM Standard и предоставляет низкоуровневый механизм навигации по DOM с возможностью фильтрации узлов во время обхода. Он подходит для реализации редакторов, инструментов анализа DOM и библиотек, которым требуется последовательный обход дерева с полным контролем над процессом навигации.

📣 Code Ready | #практика


😎 FrontSkill Docs — большая база знаний по Frontend-разработке!

Это онлайн-справочник, где собраны материалы по Frontend: HTML, CSS, JavaScript, TypeScript, React и другим технологиям. Документация построена по темам, что позволяет последовательно изучать материал или быстро находить нужную информацию во время разработки.

📌 Оставляю ссылочку: frontskill.ru

📣 Code Ready | #сайт


👩‍💻 Стилизуют элементы формы по валидности!

:user-valid и :user-invalid — псевдоклассы, которые совпадают с элементами форм по их валидности, но только после того, как пользователь изменил значение поля (элемент стал «грязным»). Это позволяет показывать обратную связь не сразу при загрузке страницы, а лишь после действия пользователя.

Как они работают:
:user-valid — пользователь ввёл корректное значение;
:user-invalid — введённые данные не прошли валидацию.

Главное преимущество — форма не показывает ошибку сразу при загрузке страницы. Это удобно для более аккуратной UX-валидации без JavaScript.

📣 Code Ready | #свойство


Проверяй возможности браузера прямо в CSS!

Многие делают такие проверки через JavaScript:
if ("container" in document.documentElement.style) {
// включаем новую логику
}

Но CSS уже давно умеет сам проверять поддержку возможностей.
@supports (display: grid) {
.layout {
display: grid;
}
}

Это особенно полезно при постепенном внедрении новых CSS API.

Например, можно безопасно добавить современные возможности:
@supports (interpolate-size: allow-keywords) {
.accordion {
interpolate-size: allow-keywords;
}
}

Старые браузеры просто проигнорируют этот блок.

Для больших проектов это позволяет мигрировать постепенно.
@supports not (selector(:has(*))) {
/* fallback */
}

🔥 @supports позволяет внедрять новые CSS-возможности без JS-проверок и не ломать поддержку старых браузеров.

📣 Code Ready | #совет


👩‍💻 Блок для видео, аудио и прочего контента!

Блок для вставки на страницу контента в сторонних форматах, которые браузер отображает с помощью плагинов. Чаще всего используется для видео- и аудиоконтента. Отображение вставленного контента будет зависеть от атрибутов тега , типа загружаемого контента и плагинов, установленных в браузере.

Атрибуты:
• src — ссылка на загружаемый контент;
• type — тип загружаемого контента в формате MIME. Тип указывать не обязательно, но желательно. Так браузер будет точно знать, какой плагин использовать для отображения контента;
• width — ширина в пикселях;
• height — высота в пикселях.

не заменяет универсальное решение для всех типов контента. Например, для видео лучше использовать , для аудио — , а для документов чаще применяют .

📣 Code Ready | #атрибут


Node.normalize(): восстановление нормализованной формы текстовых узлов в DOM!

После операций с Text, Range и точечной модификации DOM содержимое элемента может оказаться фрагментировано на несколько соседних текстовых узлов.
const container = document.createElement('div');
const text = document.createTextNode('Hello');

container.append(text);

const tail = text.splitText(2);

console.log([...container.childNodes].map(node => node.data));
// ['He', 'llo']

Для рендеринга это обычно не имеет значения:
console.log(container.textContent);
// Hello

Но для кода, который анализирует структуру дерева через childNodes, firstChild, nextSibling или хранит ссылки на конкретные Text-узлы, такая фрагментация уже существенна.

Метод Node.normalize() приводит всё поддерево узла к нормализованной форме:
container.normalize();

console.log(container.childNodes.length);
// 1

console.log(container.firstChild.data);
// Hello

Нормализация выполняется рекурсивно и гарантирует, что в обработанном поддереве: не останется пустых текстовых узлов; не останется соседних текстовых узлов без разделяющего их элемента, комментария или другого типа узла.

При объединении данные последующих Text-узлов добавляются к первому узлу группы, а сами последующие узлы удаляются из дерева.
console.log(tail.parentNode);
// null

Сохранённая ссылка tail при этом не становится невалидной: объект продолжает существовать, но больше не является частью DOM-дерева.

Важно и другое: normalize() не объединяет весь текст элемента в один узел, если между текстовыми узлами находятся другие узлы.
Hello DOM!

Здесь текст до и после  останется в разных Text-узлах и после нормализации.

Метод особенно полезен после splitText(), операций с Range и редакторских сценариев, где текстовые узлы регулярно разрезаются и склеиваются:
const paragraph = document.createElement('p');
const text = document.createTextNode('Hello world');

paragraph.replaceChildren(text);

text.splitText(5);

console.log(paragraph.childNodes.length);
// 2

paragraph.normalize();

console.log(paragraph.childNodes.length);
// 1

🔥 Node.normalize() не меняет текстовое содержимое элемента, но приводит его поддерево к нормализованной форме: без пустых и соседних текстовых узлов. Это полезно перед обходом DOM, сериализацией, сравнением структуры или выполнением алгоритмов, которые рассчитывают на предсказуемую организацию Text-узлов.

📣 Code Ready | #практика


Крутая статья недавно вышла на Хабре: «Заменяем JavaScript с помощью HTML и CSS»

В этой статье:
• использование `:has()` для управления состояниями компонентов;
• создание модальных окон и подсказок через Popover API;
• валидация форм с помощью встроенных возможностей браузера;
• стилизация сложных интерактивных состояний только средствами CSS.

🔊 Продолжайте читать на Habr!

📣 Code Ready | #статья


Почему CSS-переменные раньше не анимировались?

Многие пытаются сделать так:
.box {
transition: --angle .3s;
}

Но обычная CSS-переменная — это просто строка. Браузер не знает, как плавно перейти от 0deg к 180deg, поэтому анимация не работает.

Регистрируем переменную через @property.
@property --angle {
syntax: "";
}

Теперь браузер знает тип значения и умеет интерполировать его.

Остаётся использовать переменную как обычно.
.box {
transform: rotate(var(--angle));
}

И менять её значение.
.box:hover {
--angle: 180deg;
}

Теперь поворот происходит плавно без JS.

🔥 @property превращает CSS-переменные из обычных строк в типизированные значения, которые можно валидировать и анимировать.

📣 Code Ready | #совет

20 ta oxirgi post ko‘rsatilgan.