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

Автор: @energy_c

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

Реклама на бирже: https://telega.in/c/code_ready
Download Telegram
This media is not supported in your browser
VIEW IN TELEGRAM
🤔 HTML5Book — большой учебник по HTML, CSS и JavaScript!

На сайте собрана большая база материалов по веб-разработке: подробные уроки по HTML5, CSS3, JavaScript и jQuery, а также удобные справочники по HTML- и CSS-свойствам. Здесь можно найти разбор тегов, форм, анимаций, Flexbox, Grid, DOM и других ключевых технологий фронтенда. Большое количество практических примеров, готовых решений и UI-эффектов для интерфейсов.

📌 Оставляю ссылочку: html5book.ru

📣 Code Ready | #сайт
Please open Telegram to view this post
VIEW IN TELEGRAM
11👍5🔥3
Date.parse() и неочевидные проблемы при работе с датами!

При работе с датами в JavaScript часто используют Date.parse() или new Date(), чтобы преобразовать строковое значение в дату или получить timestamp. При этом важно понимать, какое значение хранится в системе: календарная дата, локальное время или конкретный момент времени.

Ошибки обычно появляются, когда эти разные сценарии начинают обрабатываться одинаково. Например:
const timestamp = Date.parse(
'2024-01-15T10:30:00Z'
);

console.log(timestamp);


JavaScript возвращает количество миллисекунд от 1 января 1970 года UTC.
Проблемы возникают, когда в Date.parse() передают даты в произвольном формате:
Date.parse('01/15/2024');

Date.parse('15.01.2024');

Date.parse('2024/01/15');


Такие форматы не являются надёжным контрактом между системами. Их обработка может отличаться в зависимости от окружения и реализации JavaScript. Например:
Date.parse('01/02/2024');


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

Поэтому при обмене датами между backend и frontend обычно используют ISO 8601 с явным указанием времени и часового пояса:
new Date(
'2024-01-15T10:30:00Z'
);


Здесь описан конкретный момент времени. Указаны дата, время и часовой пояс (UTC), поэтому значение будет одинаково интерпретироваться независимо от локального времени пользователя.

Отдельная проблема возникает при работе с датами без времени. Например:
const date = new Date(
'2024-01-15'
);

console.log(date);


Строка 2024-01-15 в JavaScript интерпретируется как UTC-дата:
2024-01-15T00:00:00.000Z


После этого значение преобразуется в локальный часовой пояс пользователя. В часовом поясе UTC+3 пользователь увидит:
15.01.2024 03:00


А в UTC-5:
14.01.2024 19:00


Само значение времени остаётся одинаковым, но календарная дата при отображении может измениться. Именно здесь часто возникает ошибка в модели данных.

Например, сервер возвращает дату рождения пользователя:
{
"birthday": "2000-01-15"
}


На frontend создаётся объект Date:
const birthday = new Date(
user.birthday
);

birthday.toLocaleDateString('ru-RU');


Разработчик ожидает получить: 15.01.2000. Но пользователь в другом часовом поясе может увидеть: 14.01.2000. Причина в том, что дата рождения — это календарное значение. Она не зависит от часов, минут и часового пояса.

Объект Date в JavaScript используется для работы с конкретным моментом времени, поэтому при преобразовании строк учитывается часовой пояс. Для временных событий лучше использовать полный ISO-формат:
const createdAt = new Date(
'2024-01-15T14:30:00Z'
);


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

А вот календарные значения, например дату рождения или дату окончания периода, не всегда стоит преобразовывать в Date. В таких случаях безопаснее работать с исходным значением:
const [year, month, day] =
'2000-01-15'.split('-');

const formattedDate =
`${day}.${month}.${year}`;


Так значение останется календарной датой и не будет изменено из-за часового пояса.

Также стоит учитывать, что Date.parse() не выбрасывает исключение при невозможности распознать дату:
const result = Date.parse(
'invalid-date'
);

console.log(result);


Результат: NaN. Поэтому такие значения необходимо проверять:
const timestamp = Date.parse(value);

if (Number.isNaN(timestamp)) {
throw new Error(
'Invalid date'
);
}


Основная проблема при работе с датами в JavaScript связана не с самим Date.parse(). Проблемы появляются, когда смешиваются разные типы данных: календарные даты, локальное время и конкретные моменты времени.

🔥 Перед использованием Date важно определить, что именно хранится в данных: дата, время события или значение, которое зависит от часового пояса. Только после этого стоит выбирать способ представления и обработки.

📣 Code Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
14👍7🔥6
Как создавать независимые компоненты без конфликтов CSS-переменных?

В больших проектах часто используют глобальные переменные:
:root {
--color: blue;
}


Но потом один компонент случайно меняет значение, и стили начинают влиять друг на друга.

CSS позволяет делать локальные токены прямо внутри компонента.
.card {
--color: #222;
color: var(--color);
}


Теперь переменная действует только внутри .card и его потомков.

Можно создавать полностью изолированные темы компонентов.
.dark-card {
--bg: #111;
--text: white;
}


Внутренние элементы автоматически получают эти значения:
.title {
color: var(--text);
}


Без дополнительных классов и дублирования.

Особенно удобно для:
.theme,
.component,
.widget


где каждый блок должен иметь свои настройки.

🔥 Локальные CSS custom properties позволяют строить компонентные дизайн-системы без огромного количества модификаторов и переопределений.

📣 Code Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥4🤝3
Intersection Observer — отслеживаем появление элементов в области видимости!

Эффективная альтернатива scroll-событиям. Используется для ленивой загрузки, анимаций и инфинит-скролла.

Инициализируем наблюдатель:
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('visible');
}
});
});


Подключаем наблюдение:
document.querySelectorAll('.anim').forEach((el) => {
observer.observe(el);
});


Стили для появления:
.anim { opacity: 0; transform: translateY(30px); transition: 0.4s ease; }
.visible { opacity: 1; transform: none; }


🔥
Простая и масштабируемая практика, которую используют в продакшене: YouTube, Medium, e-commerce.

📣 Code Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥108👍7
This media is not supported in your browser
VIEW IN TELEGRAM
✍️ Frontend Handbook — большая база знаний по frontend-разработке!

Здесь собраны статьи, документация, шпаргалки, инструменты и другие ресурсы по HTML, CSS, JavaScript, TypeScript, React и многим другим технологиям. Особенно удобно, что информация хорошо структурирована, поэтому можно быстро найти нужную тему.

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

📣 Code Ready | #репозиторий
Please open Telegram to view this post
VIEW IN TELEGRAM
12🔥7🤝4
👩‍💻 Группируем заголовок и обычный текст!

Тег <hgroup> объединяет основной заголовок страницы или раздела с дополнительным текстом, который его сопровождает — например, подзаголовком или кратким описанием.

Чаще всего внутри <hgroup> размещают:
• один из заголовков <h1>–<h6>;

• дополнительные элементы текста, например <p> с пояснением.


Он помогает логически связать несколько элементов заголовка, сохраняя структуру документа более понятной для браузеров и вспомогательных технологий. Не используйте <hgroup>, если вы хотите показать два независимых заголовка, — лучше оформить это через <section> или <article>

📣 Code Ready | #атрибут
Please open Telegram to view this post
VIEW IN TELEGRAM
16👍6🤝4
Опа, тут бывший сеньор одного из IT-отделов Яндекса Игорь Никитин выкатил целый канал про Python — и это лучшее, что есть в рунете по теме.

Качественные гайды. Советы от известных прогеров. Тематические мемасы. Короче, ничего лишнего.

Хватит душить питона, учись его кодить: https://t.me/+IzIPzvoa7p40ZTUy 🐍
👎8
CSS.escape() — экранирование динамических значений для CSS-селекторов!

При работе с DOM часто приходится искать элементы по динамическим значениям: id, class, значениям атрибутов. И здесь есть один важный момент: querySelector() и querySelectorAll() принимают не просто строки, а полноценные CSS-селекторы.

Поэтому если часть селектора формируется динамически, нужно учитывать правила синтаксиса CSS. Например:
const id = "user:123";

const element = document.querySelector(
`#${id}`
);


После подстановки браузер получает:
#user:123


На первый взгляд кажется, что мы ищем элемент с id="user:123".

Но для CSS символ : имеет специальное значение. Он используется для псевдоклассов:
:hover
:focus
:checked


Поэтому CSS-парсер воспринимает : не как часть значения, а как элемент синтаксиса селектора.

Для таких случаев существует стандартный метод CSS.escape():
const id = "user:123";

const element = document.querySelector(
`#${CSS.escape(id)}`
);


Теперь значение будет преобразовано в корректный CSS-идентификатор:
#user\:123


Браузер понимает, что : является частью значения, а не специальной конструкцией CSS. Такая проблема возникает не только с двоеточием.

CSS имеет множество специальных символов, которые могут изменить смысл селектора:
const id = "product.item#42";

const element = document.querySelector(
`#${CSS.escape(id)}`
);


Без экранирования символы ., # и другие будут интерпретироваться как часть CSS-селектора.

То же самое относится к динамическим классам:
const className = "theme:dark";

const element = document.querySelector(
`.${CSS.escape(className)}`
);


CSS.escape() работает согласно правилам CSS-идентификаторов и возвращает строку, которую можно использовать внутри селектора:
CSS.escape("hello world");
// "hello\ world"

CSS.escape("item.value");
// "item\.value"

CSS.escape("a:b");
// "a\:b"


До появления этого метода часто использовали ручное экранирование:
value.replace(/:/g, "\\:");


Но такой подход быстро становится неудобным. CSS имеет много специальных случаев: разные символы, пробелы, цифры в начале идентификаторов и другие правила. CSS.escape() переносит эту логику на стандартный API браузера.

Использовать его стоит в местах, где динамическое значение становится частью CSS-селектора:
document.querySelector()

document.querySelectorAll()

element.matches()

element.closest()


Важный момент: CSS.escape() не является механизмом защиты данных.

Он решает только задачу корректного экранирования значения для CSS-селектора. Например:
element.innerHTML = value;


— это уже другая область: HTML и потенциальные XSS-риски. Там используются другие механизмы защиты. Если вы работаете с динамическими id, классами или значениями, которые приходят извне (например, из API), CSS.escape() помогает избежать ошибок парсинга и сохранить ожидаемое поведение DOM API.

🔥 CSS.escape() — хороший способ подготовить динамические значения перед использованием внутри CSS-селекторов.

📣 Code Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥12👍6🤝42
👩‍💻 Можно ли стилизовать текст, к которому пользователь перешёл по ссылке?

::target-text — псевдоэлемент, который применяется к тексту, найденному через текстовый фрагмент в URL вида #:~:text=.... Он позволяет задать стили выделения, которые браузер покажет после перехода по такой ссылке.

Примеры использования:
• изменить фон выделенного текста;

• добавить собственный цвет текста;

• настроить контрастное выделение вместо стандартного.


Стандартные якоря #id подсвечивают целевой элемент. Текстовые фрагменты #:~:text=... указывают на конкретную строку текста. ::target-text позволяет настраивать стиль этого автоматического выделения (обычно это жёлтая подсветка от браузера), чтобы он соответствовал дизайну.

📣 Code Ready | #свойство
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥43
🔥 Глобальное обновление программ CyberYozh Academy
3 новых уровня для вашей карьеры


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

⚡️Выбирайте свой трек:
🟢 УРОВЕНЬ 1: Новичкам - Инженер по информационной безопасности
Трек для тех, кто готов освоить одну из самых высокооплачиваемых и востребованных профессий в IT с полного нуля, без воды и иллюзий.
Длительность: 11 месяцев
Итог: Диплом установленного образца + помощь с трудоустройством
Стоимость: от 5 015 ₽/мес


🟡УРОВЕНЬ 2: Специализация - Специалист по OSINT
Полное погружение в конкретную специальность. Идеально для студентов, у которых уже есть базовые знания в ИБ, и которым нужно стать профи в узкой нише.
Длительность: 9 месяцев
Итог: Удостоверение + помощь с трудоустройством
Стоимость: от 4 763 ₽/мес


🟥УРОВЕНЬ 3: Повышение квалификации - Пентест внутренней инфраструктуры: Active Directory
Курсы для действующих специалистов в сфере ИБ, которым необходимо расширить свой боевой арсенал и пробить карьерный потолок.
Длительность: 6 месяцев
Итог: Удостоверение + подготовка к сертификации
Стоимость: от 5 821 ₽/мес


Неважно, делаете ли вы первые шаги или уже давно работаете - у нас есть инструменты, чтобы кратно усилить ваши скиллы.

👉 Подобрать программу и записаться на курс: @cyacademy_support 🦔
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Intl.ListFormat: форматируем списки с учётом языка пользователя!

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

Самый простой вариант — использовать join():
const users = [
'Alex',
'Maria',
'John'
];

users.join(', ');


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

Если приложение поддерживает несколько языков, обычно появляются ручные проверки:
if (locale === 'en') {
// добавить and
}

if (locale === 'ru') {
// добавить и
}


Поддерживать такую логику сложно, поэтому для подобных задач в JavaScript существует стандартный API Intl.ListFormat.

Создаём форматтер и передаём нужную локаль:
const formatter =
new Intl.ListFormat('ru');

formatter.format([
'JavaScript',
'TypeScript',
'Python'
]);


Результат: JavaScript, TypeScript и Python.

При изменении локали правила форматирования изменятся автоматически:
const formatter =
new Intl.ListFormat('en');

formatter.format([
'JavaScript',
'TypeScript',
'Python'
]);


Результат: JavaScript, TypeScript, and Python.

Intl.ListFormat использует встроенные правила локализации JavaScript, поэтому не нужно самостоятельно реализовывать союзы, разделители и особенности разных языков.

Кроме обычного перечисления можно форматировать варианты выбора. Например, когда пользователь выбирает один из способов оплаты:
const formatter =
new Intl.ListFormat(
'ru',
{
type: 'disjunction'
}
);

formatter.format([
'Карта',
'PayPal',
'Перевод'
]);


Результат: Карта, PayPal или Перевод.

По умолчанию используется conjunction — обычное перечисление через союз "и". Значение disjunction используется для альтернатив через "или".

Также важно понимать, что Intl.ListFormat не изменяет исходные данные. Он только создаёт новую строку:
const tags = [
'Frontend',
'Backend',
'DevOps'
];

const text =
new Intl.ListFormat('ru')
.format(tags);


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

🔥 Intl.ListFormat позволяет использовать стандартные правила локализации JavaScript вместо ручной сборки строк через join() и множества условий для разных языков.

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