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

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

Реклама на бирже: https://telega.in/channels/code_ready/card

РКН: https://clck.ru/3NJCKs
Download Telegram
Как избежать потери изменений при обновлении данных через API?

При редактировании данных пользователь может отправить несколько запросов подряд. Если сервер обрабатывает их независимо, более старый запрос иногда завершается позже нового и перезаписывает актуальное состояние.

Например, два запроса изменяют название документа:
fetch('/api/document/1', {
method: 'PATCH',
body: JSON.stringify({ title: 'Draft' })
});

fetch('/api/document/1', {
method: 'PATCH',
body: JSON.stringify({ title: 'Final' })
});


Порядок отправки запросов не гарантирует порядок их применения на сервере. Поэтому итоговое название может оказаться Draft, хотя пользователь последним указал Final.

Один из способов предотвратить перезапись изменений устаревшими данными — оптимистическая блокировка через версионирование данных. Сервер возвращает документ вместе с его версией:
{
"id": 1,
"title": "Draft",
"version": 5
}


При обновлении клиент передаёт версию, на основе которой редактировал документ:
const response = await fetch('/api/document/1', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
title: 'Final',
version: 5
})
});


На бэкенд обновление выполняется только при совпадении версии. Например, в sql:
UPDATE documents
SET title = 'Final',
version = version + 1
WHERE id = 1
AND version = 5;


Если запись уже была изменена другим запросом, условие version = 5 не выполнится и количество обновлённых строк будет равно нулю. Такой же результат возможен, если документ не существует.

В таком случае бэкенд проверяет количество обновлённых строк и может вернуть 409 Conflict при несовпадении версии или 404 Not Found, если документ отсутствует. Фронтенд при конфликте может предложить пользователю обновить данные или разрешить конфликт:
if (response.status === 409) {
throw new Error(
'Документ был изменён. Обновите данные.'
);
}


🔥 Главное преимущество подхода — атомарная проверка версии и обновление записи в базе данных. Это предотвращает незаметную перезапись изменений, но не гарантирует применение последнего отправленного запроса.

📣 Code Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥8❤7
This media is not supported in your browser
VIEW IN TELEGRAM
😎 FrontEnd_rus — полноценный русскоязычный курс по HTML, CSS и JavaScript!

В репозитории собраны учебные материалы, примеры кода и практические задания: от создания адаптивных страниц и работы со стилями до асинхронных запросов и взаимодействия с API. Обучение построено вокруг практики — по итогам модулей можно создать многостраничный сайт и интерактивное веб-приложение. Дополнительно есть руководства по Git, Linux, настройке VS Code и рабочего окружения.

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


📣 Code Ready | #репозиторий
Please open Telegram to view this post
VIEW IN TELEGRAM
❤13👍8🔥7🤝1
CSS @container style() — проверяй состояние компонента без дополнительных классов!

Обычные контейнерные запросы проверяют размер контейнера. Но CSS умеет проверять и значения его свойств — через style().

Это полезно, когда оформление вложенных элементов зависит от настройки родительского компонента.
Например, карточка может иметь два варианта оформления.
<article class="card" style="--variant: compact">
<h3 class="card__title">Название</h3>
<p class="card__description">Описание</p>
</article>


Задаём значение по умолчанию через CSS-переменную.
.card {
--variant: default;
}


А теперь меняем оформление вложенных элементов в зависимости от её значения.
@container style(--variant: compact) {
.card__description {
display: none;
}

.card__title {
font-size: 14px;
}
}


Здесь не нужен container-type: для проверки CSS-переменной достаточно обычного родительского элемента.

Можно комбинировать несколько условий.
@container style(--variant: compact) {
.card__title {
line-height: 1.2;
}
}


Запрос проверяет стили предка, а не самого элемента, к которому применяется правило; также поддержка style() для произвольных CSS-свойств пока отличается от поддержки проверки CSS-переменных.

🔥 @container style() позволяет передавать состояние оформления вложенным элементам через CSS-переменные, не создавая отдельные классы для каждого варианта компонента.

📣 Code Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
❤14👍8🤝4🔥2
👩‍💻 Адаптивная карточка без media queries и JS!

Обычно для адаптивной вёрстки приходится прописывать брейкпоинты и вручную управлять количеством колонок. Но CSS Grid умеет самостоятельно перестраивать элементы в зависимости от доступного пространства — буквально одной строкой.

Как работает:
• repeat(auto-fit, ...) автоматически подбирает количество колонок, которые помещаются в контейнере;

• minmax() задаёт минимальную и максимальную ширину каждой колонки;

• min(100%, 260px) не даёт колонке выйти за пределы узкого контейнера;

• 1fr распределяет оставшееся пространство между колонками.


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

📣 Code Ready | #фишка
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍16❤7🔥7
📱 HTML Constraint Validation API: валидация форм!

В этом посте собраны основные методы и свойства HTML Constraint Validation API для проверки корректности данных в формах. Рассмотрены программная проверка полей, отображение ошибок, установка пользовательских сообщений, контроль обязательных значений, проверка формата и шаблонов, а также ограничений диапазона и шага.

📣 Code Ready | #шпора
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11👍8❤6🤝1
display: contents — убираем обёртку из CSS-раскладки!

Представим каталог, в котором карточки разбиты на группы. Обёртки нужны для структуры компонентов, но все товары должны находиться в одной сетке.
<div class="product-list">
<div class="product-group">
<article>Товар 1</article>
<article>Товар 2</article>
</div>

<div class="product-group">
<article>Товар 3</article>
</div>
</div>


Если применить Grid к .product-list, элементами сетки станут две группы, а не три карточки.
.product-list {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 16px;
}


Чтобы карточки участвовали в общей сетке, необязательно менять HTML. Достаточно убрать коробку обёртки из CSS-раскладки.
.product-group {
display: contents;
}


Теперь карточки становятся элементами сетки .product-list, хотя их родительские обёртки по-прежнему существуют в DOM.

Тот же приём работает и с Flexbox.
.toolbar {
display: flex;
gap: 12px;
}

.toolbar-group {
display: contents;
}


Важно: элемент с display: contents теряет собственную коробку, поэтому его фон, границы и отступы не отображаются как у обычного блока; для семантически важных обёрток также стоит проверять доступность.

🔥 display: contents позволяет сохранить структуру компонентов и при этом не усложнять CSS-раскладку лишними контейнерами.

📣 Code Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
❤14🔥8👍5
📱 HTML-атрибуты — получение, изменение, удаление и проверка атрибутов элементов!

Шпаргалка по работе с HTML-атрибутами через JavaScript: чтение значений с getAttribute(), добавление и обновление через setAttribute(), удаление с removeAttribute(), проверка наличия через hasAttribute() и переключение с toggleAttribute(). Также рассмотрены получение списка атрибутов через getAttributeNames(), работа с data-атрибутами через dataset и доступ к коллекции attributes.

📣 Code Ready | #шпора
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥12👍8❤7
Почему удалённый DOM-элемент может продолжать получать события?

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

Рассмотрим простой пример:
const button = document.querySelector('.action');

button.addEventListener('click', () => {
console.log('Clicked');
});

button.remove();


После remove() кнопка исчезает из документа, но сам объект button продолжает существовать, поскольку на него осталась ссылка.

Более того, обработчик всё ещё можно вызвать:
button.click(); // Clicked


Метод remove() отсоединяет элемент от DOM-дерева, но не уничтожает объект и не удаляет зарегистрированные на нём обработчики.

Это особенно интересно при использовании делегирования событий. Допустим, обработчик зарегистрирован на document:
document.addEventListener('click', (event) => {
console.log(event.target);
});


После удаления кнопки её программный click() уже не дойдёт до document:
button.remove();
button.click();


Причина в изменении пути распространения события. Отсоединённый элемент больше не имеет цепочки предков, ведущей к document.

Но если повторно добавить ту же кнопку в документ, её собственный обработчик продолжит работать:
document.body.append(button);

button.click(); // Clicked


При этом вызов снова достигнет обработчика на document, поскольку элемент вернулся в дерево. Здесь важно различать удаление элемента из документа и освобождение памяти.

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

🔥 element.remove() изменяет структуру DOM, а не жизненный цикл js-объекта. Удалённые элементы сохраняют свои обработчики, пока остаются достижимыми. Поэтому при диагностике утечек памяти нужно искать удерживающие ссылки, а не просто подсчитывать количество удалённых DOM-узлов.

📣 Code Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥14👍9❤7
This media is not supported in your browser
VIEW IN TELEGRAM
✍️ React Total — большая подборка материалов для изучения React!

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

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


📣 Code Ready | #репозиторий
Please open Telegram to view this post
VIEW IN TELEGRAM
❤16🔥7👍5🤝2👎1
😍 Наглядный гайд на Хабре: «CSS Anchor Positioning в картинках»!

В этой статье:
• Узнаете, как привязывать элементы друг к другу с помощью anchor-name, position-anchor и position-area;
• Разберётесь, как точно управлять расположением элементов через функцию anchor(), даже если они находятся в разных контейнерах;
• Посмотрите, как создавать адаптивные соединительные линии, схемы и цепочки элементов без JavaScript для расчёта координат.

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


📣 Code Ready | #статья
Please open Telegram to view this post
VIEW IN TELEGRAM
❤10👍6🔥4
Как уменьшить скачки текста при загрузке шрифтов без JS?

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

Обычно подключение выглядит так:
@font-face {
font-family: "Inter";
src: url("/fonts/inter.woff2") format("woff2");
font-display: swap;
}


font-display: swap позволяет быстро показать текст, но не устраняет разницу между основным и запасным шрифтом.

Для этого можно создать отдельное начертание запасного шрифта с откорректированными метриками.
@font-face {
font-family: "Inter Fallback";
src: local("Arial");
size-adjust: 105%;
}


size-adjust масштабирует глифы и метрики запасного шрифта. Значение 105% здесь условное: его нужно рассчитывать под конкретную пару шрифтов.

Теперь указываем оба семейства.
body {
font-family: "Inter", "Inter Fallback", sans-serif;
}


А для более точной подгонки существуют дополнительные дескрипторы.
@font-face {
font-family: "Inter Fallback";
src: local("Arial");
size-adjust: 105%;
ascent-override: 90%;
descent-override: 22%;
line-gap-override: 0%;
}


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

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

🔥 Правильно настроенный запасной шрифт помогает снизить CLS без отказа от font-display: swap и без дополнительных скриптов.

📣 Code Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
❤16👍8🔥4
👩‍💻 CSS, который сам подсвечивает ошибки в HTML!

При разработке легко пропустить изображение без alt, кнопку без type или ссылку-заглушку. Вместо того чтобы искать такие проблемы вручную, можно заставить CSS выделять подозрительные элементы прямо на странице.

Как работает:
• img:not([alt]) находит изображения без атрибута alt;

• button:not([type]) подсвечивает кнопки без явно указанного типа;

• a[href="#"] и a:not([href]) помогают обнаружить ссылки-заглушки и элементы без адреса;

• outline выделяет найденные элементы, не влияя на размеры и расположение блоков.


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

📣 Code Ready | #фишка
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥16👍10❤6