Code Ready | Frontend
21.6K subscribers
1.24K photos
531 videos
17 files
968 links
Авторский канал по Frontend разработке.
Ресурсы, гайды, задачи, шпаргалки.
Информация ежедневно пополняется!

Автор: @energy_c

РКН: https://clck.ru/3NJCKs

Реклама на бирже: https://telega.in/c/code_ready
Download Telegram
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 | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥156👍6
This media is not supported in your browser
VIEW IN TELEGRAM
✍️ React от нуля до архитектора — большое руководство по React-разработке!

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

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

📣 Code Ready | #репозиторий
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1210🔥7
Храним собственные данные прямо в HTML с помощью data-*!

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

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

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

📣 Code Ready | #атрибут
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1411🔥7
📱 Intersection Observer API — отслеживание видимости элементов!

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

📣 Code Ready | #шпора
Please open Telegram to view this post
VIEW IN TELEGRAM
👍146🤝6🔥3
This media is not supported in your browser
VIEW IN TELEGRAM
👩‍💻 Связываем подпись с полем формы с помощью атрибута for!

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

А ещё не каждый элемент подойдёт для связи, годятся только из категории «связываемых»:
<button>;
<input>;
<meter>;
<progress>;
<select>;
<textarea>;
И даже сам <output>.


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

📣 Code Ready | #атрибут
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🔥63
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 | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
17👍8🔥4
Попалась супер интересная статья на Хабре: «Как я собрал сайт на 30 000 SEO-страниц за месяц»!

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

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


📣 Code Ready | #статья
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥125👍5
Что фронтенд может, а что не может, когда лёг хостинг

Недавно натыкался на новость — у одного из хостеров случился короткий сбой на уровне энергоснабжения дата-центра. Задело часть их инфраструктуры и клиентские сервисы. Восстановили быстро, но ЛК и часть сайтов на их хостинге минут на 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
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
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-атрибутов важно учитывать, что браузер анализирует сам факт присутствия атрибута, а не его значение.
<button disabled>
Submit
</button>


а также
<button disabled="">
Submit
</button>


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

Метод возвращает 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');


После выполнения:
<div class="card" data-selected></div>


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

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

block.toggleAttribute('hidden');


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

📣 Code Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🤝6🔥5
This media is not supported in your browser
VIEW IN TELEGRAM
🐱 Awesome Frontend Dev — большая подборка материалов и инструментов для frontend-разработчика!

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

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


📣 Code Ready | #репозиторий
Please open Telegram to view this post
VIEW IN TELEGRAM
👍106🔥6
This media is not supported in your browser
VIEW IN TELEGRAM
Очнись, нас готовят к цифровому ГУЛАГу

Уже в десятках регионов России отключают мобильный интернет (даже когда нет атак БПЛА), тестируют «белые списки» и замедляют Телегу.

90% людей тупо смотрят на уплывающий корабль свободного Интернета. Люди поумнее готовятся к новой реальности и читают «Пакет Безопасности».

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

Без шуток, сейчас это один из самых полезных каналов в Телеге. Надеемся на лучшее, но к чему нужно готовиться — вы и сами понимаете: @package_security
👎5🔥1
Получаем порядковый номер элемента прямо в CSS!

Для каскадной анимации списка часто приходится передавать индекс из JavaScript или прописывать :nth-child() для каждого элемента.
<div style={{ "--i": index }} />


В 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 | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
13🔥8👍6🤝2