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

Автор: @energy_c

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

Реклама на бирже: https://telega.in/c/code_ready
Download Telegram
✍️ Полезная статья недавно вышла на Хабре: «Мои любимые 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
🔥14👍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
15👍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
14👍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
👩‍💻 Показываем результат работы программы с помощью <samp>!

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

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


Важно не путать <samp> с <code>: <code> обозначает фрагмент программного кода, а <samp> — результат, который программа выводит пользователю.

📣 Code Ready | #атрибут
Please open Telegram to view this post
VIEW IN TELEGRAM
11👍8🔥5🤝1
👨‍💻 Интересная статья попалась на Хабре: «o2 game engine»!

В этой статье:
• Познакомитесь с компактным open-source движком для 2D/3D-игр на C++ и JavaScript;
• Разберёте его архитектуру, редактор, UI, физику, анимации и поддержку Windows, Linux, macOS, Android, iOS и Web;
• Узнаете, как в движок интегрирован ИИ, способный помогать создавать игровые механики и самостоятельно тестировать результат.

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


📣 Code Ready | #статья
Please open Telegram to view this post
VIEW IN TELEGRAM
👍107🔥3🤝1
7,2 млн рублей призового фонда и реальные задачи космической отрасли 🚀

В сентябре пройдет серия КосмоХакатонов для студентов, молодых ученых и специалистов.
Участникам предстоит за два дня разработать собственное решение, поработать с экспертами и представить проект жюри.

Участников ждут:
🛰 реальные задачи космической отрасли
👥 команды от 3 до 5 человек
💻 очный и онлайн-форматы
🧑‍💻 работа с экспертами и трекерами
🏆 финал в Москве

Первый КосмоХакатон стартует уже 4 сентября в Ростове-на-Дону.

Дальше серия продолжится в Красноярске, Нижнем Новгороде, Благовещенске и Санкт-Петербурге, а завершится финалом в Москве.

Участие бесплатное. Присоединиться могут студенты, аспиранты, молодые ученые и специалисты от 18 лет.
🔗 Зарегистрироваться: https://космохакатон.рф
dataset: работа с data-* без getAttribute() и setAttribute()!

HTML-атрибуты data-* позволяют хранить данные, непосредственно связанные с конкретным DOM-элементом. Для доступа к таким значениям DOM предоставляет стандартный API dataset.
<button
data-user-id="42"
data-action="delete"
>
Удалить
</button>


Свойство dataset возвращает объект DOMStringMap, через который можно читать значения data-* как свойства JavaScript-объекта.
const button = document.querySelector('button');

console.log(button.dataset.userId);
// "42"

console.log(button.dataset.action);
// "delete"


При формировании имени свойства префикс data- удаляется, а дефис перед строчной ASCII-буквой a-z удаляется, при этом следующая буква преобразуется в верхний регистр. Поэтому data-user-role становится dataset.userRole.
<div
id="user"
data-user-role="admin"
></div>


Это преобразование выполняется самим DOM API, поэтому обращаться к исходному имени атрибута вручную не требуется.
const user = document.querySelector('#user');

console.log(user.dataset.userRole);
// "admin"


dataset поддерживает не только чтение. Присваивание свойства изменяет соответствующий data-* атрибут элемента.
button.dataset.action = 'restore';

console.log(button.getAttribute('data-action'));
// "restore"


Если соответствующего data-* атрибута ещё нет, присваивание через dataset создаст его в DOM.
button.dataset.loading = 'true';

console.log(button.hasAttribute('data-loading'));
// true


Удаление свойства через оператор delete удаляет и соответствующий атрибут элемента.
delete button.dataset.loading;

console.log(button.hasAttribute('data-loading'));
// false


Важная особенность dataset: значения представлены строками. При присваивании числа, boolean и другие значения преобразуются в строковое представление.
button.dataset.userId = 42;
button.dataset.active = true;

console.log(button.dataset.userId);
// "42"

console.log(button.dataset.active);
// "true"

console.log(typeof button.dataset.userId);
// "string"


Если приложению нужен другой тип, преобразование следует выполнять явно. Это особенно важно для чисел и boolean-значений, поскольку строка "false" в JavaScript сама по себе является truthy.
const userId = Number(button.dataset.userId);
const isActive = button.dataset.active === 'true';


Один из практических сценариев для data-* — делегирование событий. При этом использовать event.target.dataset напрямую не всегда корректно: фактической целью события может оказаться вложенный span, svg или другой дочерний элемент.
<ul id="users">
<li>
<button data-user-id="42">
<span>Удалить</span>
</button>
</li>
</ul>


Для такого случая надёжнее найти ближайший подходящий элемент через closest() и дополнительно проверить, что он относится к нужному контейнеру.
const list = document.querySelector('#users');

list.addEventListener('click', event => {
const button =
event.target.closest('[data-user-id]');

if (!button || !list.contains(button)) {
return;
}

const userId =
Number(button.dataset.userId);

removeUser(userId);
});


dataset хорошо подходит для небольших объёмов метаданных, принадлежащих конкретному DOM-элементу: идентификаторов, режимов, состояний интерфейса и параметров поведения.

Для сложных объектов и полноценного состояния приложения data-* использовать не стоит — DOM в таком случае фактически превращается в хранилище состояния, для которого существуют более подходящие структуры данных.
button.dataset.userId = '42';
button.dataset.action = 'delete';
button.dataset.confirm = 'true';


🔥 dataset — стандартный DOM API поверх data-*, который делает работу с пользовательскими атрибутами короче и удобнее, но не обеспечивает типизацию их значений: значения dataset представлены строками и при необходимости требуют явного преобразования.

📣 Code Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
👍86🔥5
📱 Clipboard API — работа с буфером обмена!

В этой шпаргалке собраны основные методы Clipboard API для программной работы с буфером обмена. Здесь показано, как читать и записывать текстовые данные, работать с HTML, изображениями и другими поддерживаемыми MIME-типами, создавать ClipboardItem с несколькими представлениями данных, проверять поддержку форматов и извлекать содержимое нужного типа, а также использовать legacy-механизм копирования в качестве fallback.

📣 Code Ready | #шпора
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥54