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

Cотрудничество: @energy_c

РКН: https://clck.ru/3NJCKs
Download Telegram
Попалась супер интересная статья на Хабре: «Как я собрал сайт на 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
👍43🔥1
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🤝7🔥62
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
👍107🔥6
Получаем порядковый номер элемента прямо в 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
👩‍💻 Нативный раскрывающийся блок с контентом без JavaScript!

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

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


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

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

📣 Code Ready | #атрибут
Please open Telegram to view this post
VIEW IN TELEGRAM
14👍8🔥8
Разбираем HTMLDialogElement — нативная модель модальных интерфейсов в браузере!

Несмотря на большое количество UI-библиотек, модальные окна часто остаются одним из компонентов, где разработчики повторяют одну и ту же инфраструктуру: создание overlay, блокировку прокрутки, управление focus lifecycle, обработку Escape, восстановление фокуса и синхронизацию состояния компонента.

HTMLDialogElement решает эту задачу на уровне платформы. Элемент <dialog> является частью HTML Standard и предоставляет браузерную модель поведения для диалоговых интерфейсов без необходимости вручную воспроизводить базовую механику. Базовая структура:
<dialog id="confirmDialog">
<p>Удалить запись?</p>

<button value="cancel">
Отмена
</button>

<button value="confirm">
Удалить
</button>
</dialog>


После получения ссылки на элемент становится доступен полный API HTMLDialogElement:
const dialog = document.querySelector(
'#confirmDialog'
);


У элемента есть два принципиально разных режима открытия.show() переводит <dialog> в состояние отображения без модального поведения:
dialog.show();


Такой режим используется для немодальных сценариев, когда пользователь может продолжать взаимодействовать с остальным интерфейсом.

showModal() создаёт настоящий modal dialog:
dialog.showModal();


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

Это отличается от обычного display: block, поскольку модальное поведение реализуется самим браузером, а не JavaScript-кодом приложения. Закрытие выполняется через:
dialog.close();


При необходимости можно передать результат завершения операции:
dialog.close('confirmed');

console.log(
dialog.returnValue
);


returnValue позволяет отделить состояние интерфейса от бизнес-логики. Например, один компонент диалога может использоваться для подтверждения удаления, отмены действия или выбора варианта.

Для форм внутри <dialog> существует специальный механизм method="dialog":
<form method="dialog">
<button value="cancel">
Отмена
</button>

<button value="confirm">
Подтвердить
</button>
</form>


При отправке такой формы браузер автоматически закрывает диалог и записывает значение активной кнопки в returnValue. Состояние элемента доступно через стандартное свойство:
console.log(
dialog.open
);


Для интеграции с состоянием приложения используются события жизненного цикла. После закрытия:
dialog.addEventListener(
'close',
() => {
console.log(
dialog.returnValue
);
}
);


Попытка закрытия через Escape вызывает событие cancel:
dialog.addEventListener(
'cancel',
event => {
event.preventDefault();
}
);


Это позволяет реализовать сценарии, где пользователь должен явно подтвердить действие перед закрытием.

Визуальное оформление модального слоя также предусмотрено платформой:
dialog::backdrop {
background: rgb(0 0 0 / 0.5);
}


Главное преимущество <dialog> заключается в переносе части ответственности из прикладного кода в браузерный runtime: управление фокусом, modal top layer, клавиатурное взаимодействие и базовая интеграция с accessibility.

🔥 Для стандартных модальных сценариев HTMLDialogElement позволяет избежать реализации собственного modal framework. Дополнительная логика требуется только там, где интерфейс выходит за пределы поведения, предусмотренного HTML Standard.

📣 Code Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
15🔥9👍8
This media is not supported in your browser
VIEW IN TELEGRAM
👩‍💻 Выделяем элементы в фокусе и их родителей!

Псевдокласс :focus-within применяется к элементам, которые либо сами находятся в фокусе, либо имеют дочерние элементы в фокусе. Срабатывает, когда фокус получает сам элемент или любой из его потомков. Например, можно изменить оформление всей формы, когда пользователь перешёл в одно из её полей.

Примеры использования:
подсветить контейнер с <input> при вводе;
изменить рамку всей формы;
выделить пункт меню при фокусе на вложенной ссылке;
показать дополнительные элементы управления.


В отличие от :focus, который реагирует только на фокус самого элемента, :focus-within учитывает фокус и на всех элементах внутри него.

📣 Code Ready | #свойство
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13👍97
📱 Range API — работа с фрагментами DOM!

В этой шпаргалке собраны основные методы Range API для программной работы с диапазонами и фрагментами DOM. Здесь показано, как задавать начальную и конечную границы диапазона, выбирать узел целиком или только его содержимое, копировать и извлекать выбранные фрагменты, вставлять новые DOM-узлы в заданную позицию, а также получать текстовое содержимое диапазона.

📣 Code Ready | #шпора
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍137🔥5
✍️ Полезная статья недавно вышла на Хабре: «Мои любимые CSS-трюки для фронтендеров, которые не используют Tailwind»!

В этой статье:
• Узнаете, как удобнее стилизовать контент с помощью `:not()` и управлять специфичностью через CSS-слои;
• Научитесь увеличивать кликабельную область элементов без изменения их размеров;
• Разберёте полезные приёмы с CSS Grid ить контент с пом которые упрощают адаптивную вёрстку.

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


📣 Code Ready | #статья
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥12👍7🤝7
👩‍💻 Семантически выделяет математические выражения и переменные!

Тег <var> используется для семантического выделения переменных в математических выражениях, формулах, программном коде и технической документации.

Например, с его помощью можно обозначить:
переменную в формуле — x, y, r;
аргумент функции;
параметр программы или команды;
значение, которое пользователь должен подставить самостоятельно.


По умолчанию браузеры обычно отображают содержимое <var> курсивом, однако внешний вид можно изменить с помощью CSS.

<var> нужен не просто для визуального выделения текста. Он добавляет семантику, указывая, что конкретный фрагмент представляет переменную.

📣 Code Ready | #атрибут
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥15👍65🤝3
Правильный порядок фокуса в сложном Grid без перестановки DOM!

CSS Grid позволяет визуально переставлять элементы, но раньше это создавало неприятную проблему: пользователь видит один порядок, а при нажатии Tab фокус может идти по исходному DOM.

Теперь для этого появился reading-flow.

Для Grid можно заставить последовательную навигацию следовать визуальным строкам:
.cards {
reading-flow: grid-rows;
}


Для Flex есть отдельный режим:
.toolbar {
reading-flow: flex-visual;
}


А если нужен контролируемый порядок, контейнер переводится в source-order, после чего отдельным детям можно задавать reading-order.
.list {
reading-flow: source-order;
}

.featured {
reading-order: -1;
}


Это полезно в адаптивных интерфейсах, где Grid/Flex визуально меняет расположение карточек или контролов, но переписывать DOM только ради порядка клавиатурной навигации неудобно.

🔥 reading-flow решает проблему расхождения визуального порядка и последовательной навигации на уровне CSS.

📣 Code Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
16👍7🔥6
This media is not supported in your browser
VIEW IN TELEGRAM
✍️ Краткое руководство по HTML — основные теги и структура веб-страницы!

Здесь собраны основы HTML с понятными примерами: структура HTML-документа, работа с <head> и метатегами, HTML5-разметка, заголовки и текст, ссылки, изображения, таблицы и основные атрибуты элементов. В конце есть удобная таблица с популярными тегами и их назначением.

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

📣 Code Ready | #репозиторий
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥12👍75
Делаем «сквиркл»-углы нативно в CSS!

Обычный border-radius строит эллиптическое скругление. Но в интерфейсах часто нужны более плавные, «квадратные» скругления — squircle.

Раньше для точной формы приходилось использовать SVG, clip-path или маски.

Теперь форму угла можно менять отдельно от его радиуса:
.card {
corner-shape: squircle;
}


При этом border-radius всё ещё определяет область скругления — без ненулевого радиуса corner-shape визуально ничего не изменит.

Есть и другие формы:
.card {
corner-shape: bevel;
}


И даже вогнутые углы:
.card {
corner-shape: scoop;
}


Причём границы, фон, outline и тени следуют новой форме углов, а сами формы можно анимировать. Поддержка пока ограничена.

🔥 corner-shape позволяет делать squircle, bevel и вогнутые углы двумя строками CSS — без дополнительной разметки и SVG.

📣 Code Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1410🔥6
👩‍💻 Можно ли стилизовать субтитры к видео с помощью CSS?

Псевдоэлемент::cue позволяет стилизовать текст субтитров и других текстовых дорожек, отображаемых внутри элемента <video>. Эти дорожки подключаются с помощью тега <track>. С помощью ::cue вы можете менять цвет, размер шрифта, фон и другие свойства субтитров, чтобы сделать их более читаемыми или соответствующими дизайну вашего сайта.

Внутри ::cue разрешён ограниченный набор свойств:
background, background-*
color
шрифтовые свойства: font, font-*
outline, outline-*
ruby-position
text-combine-upright
text-decoration, text-decoration-*
text-shadow
visibility
white-space


Поддержка ::cue(<селектор>) может отличаться: в некоторых браузерах он недоступен. Всегда проверяйте поддержку для нужного браузера.

📣 Code Ready | #свойство
Please open Telegram to view this post
VIEW IN TELEGRAM
15👍10🔥6
requestAnimationFrame() — почему время выполнения js нельзя привязывать к фиксированной частоте кадров!

Браузер самостоятельно управляет процессом обновления изображения на экране. JavaScript выполняется через event loop и не синхронизирован напрямую с частотой обновления дисплея.

Поэтому анимации, построенные на фиксированных задержках, могут вести себя по-разному на разных устройствах. setTimeout() не является механизмом синхронизации с браузерным rendering pipeline:
let x = 0;

function animate() {
x += 5;

element.style.transform = `translateX(${x}px)`;

setTimeout(animate, 16);
}

animate();


Значение 16 миллисекунд не означает один кадр. Это только минимальная задержка перед следующим выполнением callback. На дисплее 60 Hz это примерно соответствует одному кадру (~16.67 ms), но на устройствах с частотой 120 Hz, 144 Hz и выше браузер не будет синхронизировать выполнение JavaScript с каждым обновлением экрана.

В результате скорость такой анимации зависит от количества вызовов JavaScript, а не от реально прошедшего времени. Для визуальных обновлений используется requestAnimationFrame():
let x = 0;

function animate() {
x += 5;

element.style.transform = `translateX(${x}px)`;

requestAnimationFrame(animate);
}

requestAnimationFrame(animate);


Браузер планирует callback перед следующим обновлением изображения. Это позволяет выполнять изменения визуального состояния внутри стандартного цикла рендеринга.

Но сама привязка к кадрам не делает анимацию корректной. Если браузер пропустит несколько кадров из-за нагрузки, изменение состояния будет зависеть от количества вызовов requestAnimationFrame(), а не от реального времени.

Для независимости от частоты кадров необходимо использовать timestamp, который передаёт requestAnimationFrame():
let startTime = null;

function animate(timestamp) {
if (startTime === null) {
startTime = timestamp;
}

const elapsed = timestamp - startTime;
const x = elapsed * 0.1;

element.style.transform = `translateX(${x}px)`;

requestAnimationFrame(animate);
}

requestAnimationFrame(animate);


Теперь положение элемента вычисляется через прошедшее время, а не через количество кадров. Такой подход сохраняет одинаковую скорость анимации независимо от того, работает устройство на 60 Hz, 120 Hz или другой частоте обновления.

При этом requestAnimationFrame() не отменяет особенности браузерного rendering pipeline. Например, чтение геометрии элемента сразу после изменения стилей может вызвать forced synchronous layout:
element.style.width = '500px';

const height = element.offsetHeight;


После изменения стиля браузеру необходимо получить актуальное значение layout. Поэтому он может выполнить синхронный перерасчёт перед возвратом значения. В больших интерфейсах такие операции внутри animation loop становятся причиной лишней нагрузки и снижения производительности.

Также необходимо управлять жизненным циклом запущенных анимаций. Если компонент удалён, а callback продолжает создавать новые кадры, приложение продолжает выполнять ненужную работу:
let frameId;
let running = true;

function animate() {
if (!running) return;

update();

frameId = requestAnimationFrame(animate);
}

frameId = requestAnimationFrame(animate);

// cleanup
running = false;
cancelAnimationFrame(frameId);


Кроме того, requestAnimationFrame() не делает любую анимацию автоматически дешёвой. Для оптимальной работы браузеру желательно избегать постоянных layout и paint операций. Свойства вроде transform и opacity чаще позволяют обновлять слой через compositor без полного перерасчёта страницы.

🔥 requestAnimationFrame() — это не просто более плавная альтернатива таймерам. Это механизм синхронизации JavaScript с браузерным циклом обновления изображения, который позволяет выполнять визуальные изменения в правильный момент, рассчитывать анимации через реальное время, учитывать разные частоты обновления экранов и избегать лишних операций при работе с интерфейсом.

📣 Code Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
11👍10🔥7