Проверяй возможности браузера прямо в CSS!
Многие делают такие проверки через JavaScript:
Но CSS уже давно умеет сам проверять поддержку возможностей.
Это особенно полезно при постепенном внедрении новых CSS API.
Например, можно безопасно добавить современные возможности:
Старые браузеры просто проигнорируют этот блок.
Для больших проектов это позволяет мигрировать постепенно.
🔥
📣 Code Ready | #совет
Многие делают такие проверки через 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-проверок и не ломать поддержку старых браузеров.Please open Telegram to view this post
VIEW IN TELEGRAM
🔥15👍8❤5🤝1
:user-valid и :user-invalid — псевдоклассы, которые совпадают с элементами форм по их валидности, но только после того, как пользователь изменил значение поля (элемент стал «грязным»). Это позволяет показывать обратную связь не сразу при загрузке страницы, а лишь после действия пользователя.Как они работают:
• :user-valid — пользователь ввёл корректное значение;
• :user-invalid — введённые данные не прошли валидацию.
Главное преимущество — форма не показывает ошибку сразу при загрузке страницы. Это удобно для более аккуратной UX-валидации без JavaScript.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍16🤝9❤6
This media is not supported in your browser
VIEW IN TELEGRAM
Это онлайн-справочник, где собраны материалы по Frontend: HTML, CSS, JavaScript, TypeScript, React и другим технологиям. Документация построена по темам, что позволяет последовательно изучать материал или быстро находить нужную информацию во время разработки.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤14👍5🔥5
TreeWalker — последовательный обход DOM без создания промежуточной коллекции!
При обходе DOM часто используют рекурсию или
DOM API предоставляет интерфейс
Обход начинается с потомков переданного корневого узла, поэтому сам
Фильтр вызывается для узлов во время обхода, поэтому отдельная коллекция найденных элементов не создаётся.
Например, можно найти первый элемент с атрибутом
В отличие от
При этом
🔥
📣 Code Ready | #практика
При обходе 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 и библиотек, которым требуется последовательный обход дерева с полным контролем над процессом навигации.Please open Telegram to view this post
VIEW IN TELEGRAM
🔥15❤6👍6
This media is not supported in your browser
VIEW IN TELEGRAM
Материал начинается с основ JavaScript и постепенно переходит к компонентам, JSX, хукам, формам и роутингу. Дальше разбираются TanStack Query, Redux Toolkit и Zustand, TypeScript, тестирование, безопасность, оптимизация производительности, архитектурные паттерны, Next.js, SSR и React Server Components. Получается полноценный маршрут от основ React до разработки и архитектуры крупных приложений.
Оставляю ссылочку: GitHub
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12❤10🔥7
Храним собственные данные прямо в HTML с помощью data-*!
Дата-атрибут — это пользовательский атрибут на HTML-элементе, название которого начинается с
После data- указывается произвольное имя, описывающее значение:
• data-id — идентификатор объекта;
• data-theme — тема оформления;
• data-status — состояние элемента;
• data-user-id — идентификатор пользователя.
📣 Code Ready | #атрибут
Дата-атрибут — это пользовательский атрибут на HTML-элементе, название которого начинается с
data-. Это встроенная возможность стандарта HTML5. В дата-атрибутах можно хранить дополнительную информацию в стандартных HTML-элементах и работать с этой информацией в JS при помощи собственного API.После data- указывается произвольное имя, описывающее значение:
• data-id — идентификатор объекта;
• data-theme — тема оформления;
• data-status — состояние элемента;
• data-user-id — идентификатор пользователя.
data-* полезен, когда элементу нужно передать дополнительные данные для поведения интерфейса, не отображая их пользователю.Please open Telegram to view this post
VIEW IN TELEGRAM
👍14❤11🔥7
В этой шпаргалке собраны основные методы и свойства Intersection Observer API для асинхронного отслеживания пересечения элементов с viewport или заданным root. Здесь показано, как подключать и отключать наблюдение, определять факт и степень пересечения, получать геометрию элемента, области пересечения и root, а также применять observer для lazy loading, аналитики и UI-эффектов.Please open Telegram to view this post
VIEW IN TELEGRAM
👍14❤6🤝6🔥3
This media is not supported in your browser
VIEW IN TELEGRAM
Атрибут
for используется у тега <label> и указывает, к какому элементу формы относится подпись.А ещё не каждый элемент подойдёт для связи, годятся только из категории «связываемых»:
• <button>;
• <input>;
• <meter>;
• <progress>;
• <select>;
• <textarea>;
• И даже сам <output>.
Кроме удобства, правильная связка
<label for="..."> улучшает доступность формы, поскольку вспомогательные технологии могут определить, какая подпись относится к конкретному полю.Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🔥6❤3
innerText vs textContent — как обычное чтение DOM может заставить браузер пересчитать layout!
DOM хранит структуру документа отдельно от того, как эта структура отображается пользователю.
Именно поэтому простое чтение свойства иногда может быть дорогой операцией:
После изменения стиля браузер помечает компоновку как устаревшую. Если следующая операция требует данных о визуальном состоянии страницы, браузеру может потребоваться немедленно выполнить перерасчёт. Это называется принудительным синхронным перерасчётом layout.
Похожий механизм работает с другими свойствами, зависящими от текущей геометрии страницы:
К этой же категории относятся
Проблема обычно появляется не из-за одного вызова, а из-за постоянного смешивания операций записи и чтения:
В таком случае браузер может постоянно выполнять цикл: запись — устаревшая компоновка — чтение — расчёт компоновки.
Это приводит к частым лишним перерасчётам компоновки (layout thrashing). Гораздо эффективнее разделять изменение состояния и чтение данных:
Важно понимать:
Если нужно получить данные из DOM, обычно достаточно
🔥 Разница между ними не только в возвращаемой строке.
📣 Code Ready | #практика
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 — с моделью отображения. В производительных интерфейсах это различие может определить, будет ли чтение обычным получением текстового содержимого или причиной перерасчёта компоновки.Please open Telegram to view this post
VIEW IN TELEGRAM
❤17👍8🔥4
Попалась супер интересная статья на Хабре: «Как я собрал сайт на 30 000 SEO-страниц за месяц»!
В этой статье:
📣 Code Ready | #статья
В этой статье:
• Показывается, как в одиночку с помощью Claude и GPT за месяц собрать полноценный веб-проект почти без ручного написания кода;• Разбирается архитектура на Astro со статической генерацией, серверным поиском, PWA и сборкой десятков тысяч лёгких страниц;• Рассказывается, как построить и отладить автоматический конвейер наполнения, который после настройки генерирует около 14 000 страниц в неделю;🔊 Продолжайте читать на Habr!
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥12❤5👍5
Что фронтенд может, а что не может, когда лёг хостинг
Недавно натыкался на новость — у одного из хостеров случился короткий сбой на уровне энергоснабжения дата-центра. Задело часть их инфраструктуры и клиентские сервисы. Восстановили быстро, но ЛК и часть сайтов на их хостинге минут на 40 ушли в недоступность.
В этот момент пользователь видит именно фронт. И самое неприятное — ты физически не можешь повлиять на ситуацию. Весь стек упирается в то, что происходит на площадке, которую ты даже и не видел никогда.
Такие истории — повод присмотреться к площадкам с продуманной инфраструктурой, а не разбираться постфактум. В рамках своих задач недавно зацепился за ЦОД Московского кластера видеоигр и анимации.
По питанию там два независимых ввода, ИБП, умные PDU. Охлаждение с изоляцией горячих/холодных коридоров. Сеть и хранение тоже задублированы — резервирование коммутаторов, диски арендных серверов в RAID-массивах. По площадке — 21 стойка, до 20 кВт на каждую, SLA 99,95%. Из железа — GPU-серверы (RTX Ada, H100). Там же и колокейшн от юнита за 4 000 р/мес до стойки 42U от 105 000 р/мес.
Кому интересно, вот страница ЦОДа с характеристиками. Я, например, после всех историй со сбоями начал смотреть на дата-центры иначе.
А если площадка все-таки легла, в ход идут инструменты фронта:
Все остальное зависит от того, что происходит на стороне инфраструктуры.
📣 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.
Все остальное зависит от того, что происходит на стороне инфраструктуры.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Element.toggleAttribute() — нативное переключение DOM-атрибутов!
В DOM многие состояния элементов представлены через наличие или отсутствие атрибутов:
До появления
Если атрибут отсутствует — он будет добавлен. При повторном вызове — удалён.
Для boolean HTML-атрибутов важно учитывать, что браузер анализирует сам факт присутствия атрибута, а не его значение.
а также
имеют одинаковое поведение.
Метод возвращает
Дополнительно
Этот вариант удобен при синхронизации DOM с состоянием приложения, когда итоговое значение уже вычислено:
После выполнения:
На практике метод используется для управления простыми состояниями интерфейса: переключение видимости элементов, изменение доступности контролов, управление режимами компонентов и другие сценарии, где состояние выражается наличием атрибута.
Например, управление видимостью через стандартный атрибут
🔥
📣 Code Ready | #практика
В 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-состояниями более лаконичной и предсказуемой. Поддерживается всеми современными браузерами.Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🤝6🔥5
This media is not supported in your browser
VIEW IN TELEGRAM
Здесь собраны учебники, справочники, курсы и полезные сервисы по HTML, CSS, JavaScript, TypeScript, React, Next.js, Node.js и SQL. Есть отдельные подборки для изучения Flexbox и Grid, тренировки задач на Codewars и LeetCode, подготовки к собеседованиям, работы с GitHub, размещения проектов и использования AI-инструментов в разработке.
Оставляю ссылочку: GitHub📱
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10❤6🔥6
This media is not supported in your browser
VIEW IN TELEGRAM
Очнись, нас готовят к цифровому ГУЛАГу
Уже в десятках регионов России отключают мобильный интернет (даже когда нет атак БПЛА), тестируют «белые списки» и замедляют Телегу.
90% людей тупо смотрят на уплывающий корабль свободного Интернета. Люди поумнее готовятся к новой реальности и читают «Пакет Безопасности».
Здесь дают самые свежие связки для приватности: приложения и утилиты на случай вайтлистов, прокси, браузеры, сервисы — чего тут только нет.
Без шуток, сейчас это один из самых полезных каналов в Телеге. Надеемся на лучшее, но к чему нужно готовиться — вы и сами понимаете: @package_security
Уже в десятках регионов России отключают мобильный интернет (даже когда нет атак БПЛА), тестируют «белые списки» и замедляют Телегу.
90% людей тупо смотрят на уплывающий корабль свободного Интернета. Люди поумнее готовятся к новой реальности и читают «Пакет Безопасности».
Здесь дают самые свежие связки для приватности: приложения и утилиты на случай вайтлистов, прокси, браузеры, сервисы — чего тут только нет.
Без шуток, сейчас это один из самых полезных каналов в Телеге. Надеемся на лучшее, но к чему нужно готовиться — вы и сами понимаете: @package_security
👎5🔥1
Получаем порядковый номер элемента прямо в CSS!
Для каскадной анимации списка часто приходится передавать индекс из JavaScript или прописывать
В CSS появились функции
Поэтому задержку от
Добавили десятый элемент — ничего менять не нужно. Его индекс вычислится из DOM автоматически.
Общее количество элементов тоже доступно прямо в выражении:
Это можно использовать для stagger-анимаций, распределения элементов и вычислений, которые раньше требовали
🔥 Функции учитывают все соседние элементы одного родителя, а не только элементы с классом
📣 Code Ready | #совет
Для каскадной анимации списка часто приходится передавать индекс из 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. Поддержка пока ограничена, поэтому перед использованием нужно проверить целевые браузеры.Please open Telegram to view this post
VIEW IN TELEGRAM
❤13🔥8👍6🤝2