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

Автор: @energy_it

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

Реклама на бирже: https://telega.in/c/code_ready
Download Telegram
🧐 Крутая статья недавно вышла на Хабре: «Как я собрал кубик Рубика в браузере на чистом Canvas»!

В этой статье:
• Пошагово показывается создание собственного симулятора кубика Рубика на JS и Canvas;
• Разбирается работа с 3D-проекцией, изометрией и ручным рендерингом объектов;
• Объясняется, как хранить состояние куба и реализовывать алгоритмы поворотов;
• Демонстрируются проблемы Canvas-рендеринга, сортировки граней и псевдо-3D.


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


📣 Code Ready | #статья
Please open Telegram to view this post
VIEW IN TELEGRAM
👍146🤝3
This media is not supported in your browser
VIEW IN TELEGRAM
👩‍💻 Нужно быстро обернуть текст или элемент в HTML-тег?

Htmltagwrap —
позволяет выделить любой фрагмент и за секунду обернуть его в нужный тег: div, span, section и любой другой, без ручного написания. Особенно удобно при верстке, работе с JSX и быстром редактировании разметки.

📣 Code Ready | #vscode
Please open Telegram to view this post
VIEW IN TELEGRAM
👍158🔥6
Почему scroll иногда внезапно прыгает сам по себе?

Добавляешь новый контент сверху и браузер внезапно меняет scroll-position. Особенно часто это ломает chat, infinite-feed и lazy-load layout.

Обычно проблема появляется при:
prepend,
lazy-image,
dynamic-content


Браузер пытается помочь и автоматически удерживает пользователя на прежнем месте через scroll anchoring.

Но в динамических интерфейсах это часто создаёт хаос.
.chat {
overflow-anchor: none;
}


Теперь браузер перестаёт вмешиваться в scroll-position контейнера.

Особенно полезно для:
chat,
feed,
virtual-list,
infinite-scroll


Где контент постоянно догружается или меняется.

Можно отключать anchoring точечно даже у отдельных элементов.
.loader {
overflow-anchor: none;
}


Например у skeleton, lazy-image или рекламных блоков.

🔥 overflow-anchor: none убирает один из scroll-багов в динамических интерфейсах.

📣 Code Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
14👍7🔥6
📂 Напоминалка для работы браузера и сети!

Например, когда вводишь google.com, браузер сначала ищет IP-адрес через DNS, затем устанавливает TCP/TLS-соединение, отправляет HTTPS-запрос и только после этого начинает рендерить страницу.

На картинке — полный путь от ввода URL до отображения сайта.

Сохрани, чтобы быстро освежить в памяти, как работает Web под капотом!

📣 Code Ready | #ресурс
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥146👍5
DocumentFragment: как делать пакетные DOM-вставки аккуратнее!

Когда элементы добавляются в DOM по одному, браузеру приходится постоянно обновлять структуру документа. На небольших объёмах это почти незаметно, но при рендере больших списков или сложных интерфейсов такие операции могут начать стоить дороже. Для таких случаев в DOM API есть DocumentFragment.

Создаём fragment:
const fragment = document.createDocumentFragment();


Это временный контейнер, который существует вне основного DOM-дерева. Пока элементы находятся внутри fragment — они не участвуют в рендеринге страницы. Можно спокойно собрать структуру в памяти, а потом вставить всё одной операцией. Пример — массовое добавление элементов:
const fragment = document.createDocumentFragment();

for (let i = 0; i < 1000; i++) {
const li = document.createElement('li');

li.textContent = `Item ${i}`;

fragment.appendChild(li);
}

document
.querySelector('.list')
.appendChild(fragment);


Здесь элементы сначала собираются внутри fragment, а затем одной вставкой попадают в основной DOM. Такой подход уменьшает количество промежуточных вставок в live DOM и делает массовый рендер более предсказуемым. Пример через append():
const fragment = document.createDocumentFragment();

users.forEach(user => {
const item = document.createElement('div');

item.className = 'user';
item.textContent = user.name;

fragment.append(item);
});

container.append(fragment);


append() тоже работает с DocumentFragment. По смыслу разницы почти нет — append() просто современнее и удобнее. Плюс он умеет принимать строки и несколько узлов сразу.

Пример с переносом существующих элементов:
const fragment = document.createDocumentFragment();

document
.querySelectorAll('.item')
.forEach(el => {
fragment.appendChild(el);
});

newContainer.appendChild(fragment);


Здесь элементы не копируются, appendChild() физически переносит DOM-узлы в новый контейнер. Один и тот же элемент не может одновременно находиться в двух местах дерева.

Ещё один частый кейс — работа с template:
const template = document.querySelector('#card');

const fragment = document.createDocumentFragment();

data.forEach(item => {
const cardFragment = template.content
.cloneNode(true);

cardFragment
.querySelector('.title')
.textContent = item.title;

fragment.appendChild(cardFragment);
});

container.appendChild(fragment);


template.content уже является DocumentFragment, поэтому cloneNode(true) возвращает готовый набор DOM-узлов, который удобно изменять перед вставкой.

И ещё один момент:
const fragment = document.createDocumentFragment();

fragment.appendChild(
document.createElement('div')
);

container.appendChild(fragment);

console.log(fragment.childNodes.length); // 0


После вставки содержимое fragment переносится в DOM, а сам fragment остаётся пустым. По сути это временный контейнер для группы узлов.

Важно понимать, что DocumentFragment — не полноценный HTML-элемент:
console.log(
fragment instanceof HTMLElement
); // false


🔥 У него нет собственного layout, стилей или визуального отображения. Но при больших объёмах DOM, сложных компонентах или частых обновлениях интерфейса DocumentFragment всё ещё остаётся удобным способом собрать структуру отдельно от основного DOM и вставить её одним действием.

📣 Code Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12🔥75
This media is not supported in your browser
VIEW IN TELEGRAM
❤️ Web Links — огромная подборка ресурсов по JavaScript и веб-разработке!

На сайте собрана большая коллекция полезных ссылок для разработчиков: учебники, документация, статьи, блоги, инструменты, библиотеки и сервисы по JavaScript, HTML, CSS, React, Node.js и другим технологиям веб-разработки. Всё удобно структурировано по категориям, что позволяет быстро находить нужные материалы для изучения или работы.

📌 Оставляю ссылочку: vallek.github.io

📣 Code Ready | #сайт
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11🤝75
👩‍💻 Эффект проявления изображения!

Через CSS Mask можно создавать интересные эффекты, управляя тем, какие части элемента будут видимы.

Как работает:
mask создаёт альфа-маску поверх изображения;

браузер отображает только разрешённые области;

mask-position двигает маску без изменения размеров элемента;

одновременно можно комбинировать эффект с фильтрами и анимациями.


🔥 Приём отлично подходит для галерей, карточек товаров, портфолио и интерактивных превью изображений.

📣 Code Ready | #фишка
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥20👍7🤝5👎2
This media is not supported in your browser
VIEW IN TELEGRAM
💅 dmitry-osin — шпаргалка по CSS на русском языке!

Очень полезный материал для frontend-разработчиков и всех, кто работает с вёрсткой. Здесь собрана все по CSS — от базовых селекторов и блочной модели до Flexbox, Grid, анимаций, адаптива и современных возможностей CSS. Особенно удобно, что всё структурировано и написано простым языком с примерами.

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


📣 Code Ready | #репозиторий
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥137👍7
Как убрать лишние классы для пустых блоков?

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

Если данных нет — элемент остаётся пустым, но продолжает занимать место.

Обычно это решают через JS или условный рендеринг.
.error {
display: none;
}


А потом отдельно добавляют класс при появлении контента.

Но CSS умеет определять пустые элементы самостоятельно.
.error:empty {
display: none;
}


Теперь блок автоматически скрывается, если внутри ничего нет.

Можно делать и обратную логику.
.card:not(:empty) {
padding: 16px;
}


Отступы появятся только тогда, когда внутри действительно есть контент.

Особенно удобно для:
error,
hint,
description,
badge


Где содержимое может появляться динамически.

🔥 :empty позволяет убрать лишние классы и часть условной логики прямо средствами CSS.

📣 Code Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥20👍12🤝81
📂 Напоминалка для работы с JavaScript DOM!

Например, querySelector() помогает быстро находить элементы на странице, addEventListener() обрабатывать события пользователя, а createElement() динамически создавать новый контент.

На картинке — основные DOM-методы и свойства: поиск элементов, работа с содержимым, атрибутами, классами, событиями и управление структурой документа.

Сохрани, чтобы не потерять!

📣 Code Ready | #ресурс
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥145👍5
Разбираемся зачем нужен event.currentTarget!

При работе с событиями многие используют event.target и не задумываются, что это не всегда тот элемент, на который был повешен обработчик.

Например:
<button class="btn">
<span>Сохранить</span>
</button>


Повесим обработчик на кнопку:
button.addEventListener('click', (event) => {
console.log(event.target);
});


Если кликнуть по тексту внутри span, то в консоль попадёт именно span, а не button.

Потому что event.target всегда указывает на элемент, который стал источником события.

Теперь выведем имя тега:
button.addEventListener('click', (event) => {
console.log(event.target.tagName);
});


Клик по кнопке даст такой результат: BUTTON. А клик по тексту внутри span даст: SPAN.

Из-за этого иногда появляются неожиданные баги:
button.addEventListener('click', (event) => {
event.target.disabled = true;
});


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

В таких ситуациях обычно нужен event.currentTarget:
button.addEventListener('click', (event) => {
console.log(event.currentTarget);
});


currentTarget всегда содержит элемент, на котором сейчас выполняется обработчик.

То есть:
button.addEventListener('click', (event) => {
console.log(event.target);
console.log(event.currentTarget);
});


При клике по span первым будет исходный элемент события:
event.target — span


А вторым — элемент, на котором выполняется обработчик:
event.currentTarget — button


Особенно хорошо разница видна при делегировании событий:
list.addEventListener('click', (event) => {
console.log(event.target);
console.log(event.currentTarget);
});


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

Ещё один момент: currentTarget существует только во время обработки события.
const saved = event.currentTarget;


После завершения обработки значение event.currentTarget становится null. Поэтому если ссылка нужна позже — её стоит сохранить заранее.

🔥 Простое правило: target отвечает на вопрос «какой элемент стал источником события», а currentTarget — «на каком элементе сейчас выполняется обработчик». Понимание этой разницы помогает избежать множества мелких ошибок при работе с DOM-событиями.

📣 Code Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥14👍98
This media is not supported in your browser
VIEW IN TELEGRAM
💅 Frontend Stuff — коллекция полезных ресурсов для frontend-разработчиков!

На сайте собрана большая база материалов для JavaScript-разработчиков: статьи, библиотеки, фреймворки, инструменты, полезные сервисы и обучающие ресурсы. От базовых инструментов до React, Vue, Node.js и др. Отличный ресурс для веб-разработчиков, которые хотят ускорить работу или найти новые инструменты.

📌 Оставляю ссылочку: frontend-stuff.com

📣 Code Ready | #сайт
Please open Telegram to view this post
VIEW IN TELEGRAM
👍137🤝7
✍️ Нашёл полезную статью на Хабре про современные возможности CSS, которые позволяют избавиться от старых костылей и писать код проще!

В этой статье:
• Показано, как решить проблему прыгающего контента через scrollbar-gutter;
• Разбираются современные CSS-возможности: system-ui, light-dark(), margin-inline и align-content;
• Объясняется, как сделать код чище, короче и удобнее для поддержки без лишних Flexbox и Grid-конструкций.

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


📣 Code Ready | #статья
Please open Telegram to view this post
VIEW IN TELEGRAM
13👍8🔥5
AI-инструменты можно любить и ненавидеть, но работать без них в IT уже практически невозможно 🤩

Коллеги из AvitoTech 11 июля зовут в их офис на Лесной на AI Hardcore Day. Приглашают тех, кто каждый день сталкивается с AI в работе и даже пишет своих AI-агентов. Обещают доклады и нетворкинг-сессию на террасе после — и всё это без записи.

💫 Среди тем:
— Spec-Driven Development: теория, инструменты, практика.
— Разработка и тестирование MCP для внутренних агентных систем аналитики.
— Выпрямляем руки агентов: как сделать MCP удобными и действительно полезными.
— Атаки на GenAI-агентов: OWASP на практике.

Регистрация тут!
Please open Telegram to view this post
VIEW IN TELEGRAM
👎1
Маленькая UI-деталь, которая влияет на восприятие интерфейса!

Часто бывает: кликаешь по button, tab, dropdown-item или card-action и выделяется текст.

Интерфейс сразу выглядит менее качественным.
.button {
user-select: none;
}


Теперь текст внутри элемента нельзя случайно выделить мышью или тапом.

Это особенно полезно для интерактивных элементов.
button,
.tab,
.badge {
user-select: none;
}


Но важно не применять это глобально.
body {
user-select: none;
}


Так можно сломать UX: пользователь не сможет копировать текст.

Используй только там, где выделение реально не нужно.
button,
.control,
.action


Это маленькая деталь, но она заметно улучшает UI.

🔥 user-select: none — простой способ сделать интерфейс визуально чище и приятнее.

📣 Code Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
👍16🤝75
This media is not supported in your browser
VIEW IN TELEGRAM
😍 dreamDevTeamx — большая шпаргалка для фронтенд разработчиков!

Годный репозиторий, в котором собрано много практической информации по разным направлениям разработки. Это база знаний, к которой удобно возвращаться во время обучения, работы или подготовки к собеседованиям. Материал ориентирован именно на практику.

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


📣 Code Ready | #репозиторий
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥43🤝1
Сидеть и работать в корпорации — страшно, жизнь-то мимо проходит. Уходить строить бизнес — страшно, а вдруг прогорит. Один из вариантов — разрабатывать свой пет-проект по вечерам. Многие успешные компании, например, Twitter, создавались именно так. Это не значит, что ваш проект обязательно заработает миллиарды, но заработать больше, чем в найме, и получить ценный опыт — вполне реально.

Перед началом разработки появляется множество вопросов, например:

• Как выбрать идею для пет-проекта?
• Что нужно знать про маркетинг
• Как запуститься и довести до первых продаж не имея бюджета на рекламу?

В телеграм-канале «Твой пет проект», Михаил Табунов делится своим опытом с разработчиками и менеджерами.

Он рассказывает, где искать идею для нового проекта, что нужно знать о маркетинге, как запустить стартап и привлечь первых 10 клиентов, а также о многих других важных вещах.

Подписывайтесь на «Твой пет проект», получайте пользу от практиков рынка!
https://t.me/+8Frwa03ciVlhNTky
👎2
Почему querySelectorAll() не обновляется автоматически?

Иногда кажется, что результат querySelectorAll() как-то привязан к DOM и должен сам обновляться при изменениях на странице. Но это не так — он возвращает фиксированный снимок на момент вызова.
const items = document.querySelectorAll('.item');

console.log(items.length); // 3

document.body.insertAdjacentHTML(
'beforeend',
'<div class="item"></div>'
);

console.log(items.length); // всё ещё 3


После этого items никак не пересчитывается. Это просто сохранённый результат поиска, а не живая коллекция.

Если нужен актуальный список — придётся заново выполнить запрос:
let items = document.querySelectorAll('.item');

document.body.insertAdjacentHTML(
'beforeend',
'<div class="item"></div>'
);

items = document.querySelectorAll('.item');

console.log(items.length); // 4


Из-за этого иногда появляются простые, но неприятные ошибки в динамическом UI. Например, когда элементы добавляются позже, а список уже был сохранён заранее:
const buttons = document.querySelectorAll('.btn');

addNewButton();

// новый элемент сюда уже не попадёт
buttons.forEach(bindHandler);


Человек ожидает, что обработчик навесится на всё, но фактически работает только с тем, что существовало в момент запроса.

Есть и другой вариант поведения — живые коллекции. Например:
const items = document.getElementsByClassName('item');

console.log(items.length); // 3

document.body.insertAdjacentHTML(
'beforeend',
'<div class="item"></div>'
);

console.log(items.length); // 4


Такие коллекции действительно меняются вместе с DOM. К ним относятся getElementsByClassName, getElementsByTagName и element.children. Разница простая: querySelectorAll даёт снимок, а getElementsBy* держат связь с DOM.

При этом NodeList, который возвращает querySelectorAll, можно спокойно перебирать как массив:
const items = document.querySelectorAll('.item');

items.forEach(item => {
console.log(item);
});


Но это всё ещё не массив:
Array.isArray(items); // false


Если нужны методы массива — его нужно явно преобразовать:
const items = [...document.querySelectorAll('.item')];


🔥 На практике querySelectorAll используют чаще именно из-за предсказуемости. Он не меняется сам по себе, и это как раз удобно в реальных приложениях. Для динамики обычно либо делают повторный запрос, либо уходят в делегирование событий.

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