Шпаргалка по CSS-селекторам: группировка через :is() и :where(), выбор связанных элементов с :has(), исключение через :not(), управление состояниями фокуса с :focus-visible и :focus-within(), определение пустых элементов через :empty и позиционная выборка с :nth-child(). Примеры охватывают специфичность, структуру DOM и стилизацию элементов в зависимости от их состояния.Please open Telegram to view this post
VIEW IN TELEGRAM
❤15🔥7🤝5👍1
overflow-anchor — управляем сохранением позиции прокрутки при изменении контента!
На страницах с динамическим контентом высота элементов может изменяться после рендеринга. Например, когда загружаются изображения, появляются сообщения или вставляются блоки выше текущей позиции пользователя.
Браузеры используют механизм scroll anchoring, который помогает сохранять видимую позицию при таких изменениях. Но иногда автоматическая компенсация прокрутки мешает логике интерфейса.
Рассмотрим контейнер с сообщениями:
Зададим ему ограниченную высоту и вертикальную прокрутку:
Если содержимое выше видимой области изменит размер, браузер может скорректировать
Для управления этим механизмом существует CSS-свойство
Значение
По умолчанию используется
В таком режиме элементы могут участвовать в выборе опорного узла, если это допускают условия алгоритма.
Чат, в котором новые сообщения добавляются в конец списка:
Если требуется самостоятельно управлять прокруткой, можно отключить scroll anchoring:
Например, после добавления сообщения можно прокрутить контейнер вниз:
Но если пользователь читает историю сообщений, принудительная прокрутка будет мешать.
Поэтому лучше проверять положение до добавления сообщения:
Теперь контейнер прокручивается вниз только тогда, когда пользователь уже находился рядом с нижней границей. Здесь
Если у родителя установлено
В данном случае
Также scroll anchoring не гарантирует компенсацию любых изменений. А поддержка
🔥
📣 Code Ready | #практика
На страницах с динамическим контентом высота элементов может изменяться после рендеринга. Например, когда загружаются изображения, появляются сообщения или вставляются блоки выше текущей позиции пользователя.
Браузеры используют механизм scroll anchoring, который помогает сохранять видимую позицию при таких изменениях. Но иногда автоматическая компенсация прокрутки мешает логике интерфейса.
Рассмотрим контейнер с сообщениями:
<div class="chat">
<div class="messages">
<!-- сообщения -->
</div>
</div>
Зададим ему ограниченную высоту и вертикальную прокрутку:
.chat {
height: 400px;
overflow-y: auto;
}Если содержимое выше видимой области изменит размер, браузер может скорректировать
scrollTop, чтобы сохранить положение опорного элемента.Для управления этим механизмом существует CSS-свойство
overflow-anchor:.chat {
overflow-anchor: none;
}Значение
none исключает контейнер и его потомков из выбора опорного элемента для scroll anchoring. При этом прокрутка продолжает работать, а размеры содержимого могут изменяться как обычно.По умолчанию используется
auto:.chat {
overflow-anchor: auto;
}В таком режиме элементы могут участвовать в выборе опорного узла, если это допускают условия алгоритма.
Чат, в котором новые сообщения добавляются в конец списка:
const chat = document.querySelector('.chat');
const messages = document.querySelector('.messages');
function appendMessage(text) {
const message = document.createElement('div');
message.textContent = text;
messages.append(message);
}Если требуется самостоятельно управлять прокруткой, можно отключить scroll anchoring:
.chat {
height: 400px;
overflow-y: auto;
overflow-anchor: none;
}Например, после добавления сообщения можно прокрутить контейнер вниз:
chat.scrollTop = chat.scrollHeight;
Но если пользователь читает историю сообщений, принудительная прокрутка будет мешать.
Поэтому лучше проверять положение до добавления сообщения:
function appendMessage(text) {
const distanceToBottom =
chat.scrollHeight -
chat.scrollTop -
chat.clientHeight;
const shouldScroll = distanceToBottom <= 20;
const message = document.createElement('div');
message.textContent = text;
messages.append(message);
if (shouldScroll) {
chat.scrollTop = chat.scrollHeight;
}
}Теперь контейнер прокручивается вниз только тогда, когда пользователь уже находился рядом с нижней границей. Здесь
overflow-anchor: none отключает автоматическую компенсацию, а js управляет необходимой позицией.Если у родителя установлено
overflow-anchor: none, потомки не могут повторно включить scroll anchoring:.container {
overflow-anchor: none;
}
.container .item {
overflow-anchor: auto;
}В данном случае
.item всё равно остаётся внутри исключённой области.Также scroll anchoring не гарантирует компенсацию любых изменений. А поддержка
overflow-anchor в Safari ограничена, поэтому для строго определённого поведения лучше использовать js.overflow-anchor позволяет управлять участием элементов в scroll anchoring. Свойство полезно для чатов, лент и динамических списков, где положение прокрутки контролируется логикой приложения.Please open Telegram to view this post
VIEW IN TELEGRAM
👍10❤8🔥4
This media is not supported in your browser
VIEW IN TELEGRAM
В репозитории собраны заметки по ключевым темам веб-разработки, которые помогают систематизировать знания и разобраться в вопросах, встречающихся на технических интервью. Удобно использовать для повторения теории, самопроверки и подготовки к собеседованию.
Оставляю ссылочку: GitHub📱
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12🔥6❤5🤝1
Обычный
:invalid подсвечивает ошибки даже в пустой форме, когда пользователь ещё ничего не вводил. Из-за этого приходится добавлять обработчики событий и отслеживать, какие поля уже были затронуты.Но у CSS есть более точный инструмент —
:user-invalid.Как работает:
• :user-invalid выбирает поле, которое не прошло проверку после взаимодействия пользователя;
• : неhas() позволяет родительскому контейнеру реагировать на состояние вложенного поля;
• :not(:placeholder-shown) здесь не нужен — браузер сам учитывает момент взаимодействия;
• :user-valid позволяет аналогично оформить корректно заполненные поля.
В результате можно показывать ошибки в нужный момент, не создавая отдельное JS-состояние для стилизации каждого поля.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12❤6🔥6
Как убрать скачки меню при наведении без фиксированной ширины?
В навигации при наведении текст становится жирным, его ширина увеличивается, а соседние пункты сдвигаются.
Часто это исправляют фиксированной шириной пунктов меню. Но такой подход плохо работает с переводами, динамическими названиями и адаптивной вёрсткой.
Есть более гибкий приём: заранее зарезервировать место под жирную версию текста.
Псевдоэлемент создаёт невидимую копию надписи с нужной толщиной шрифта. Несмотря на нулевую высоту, его ширина участвует в расчёте размера элемента.
Поэтому ссылка заранее занимает достаточно места для жирного текста. Остаётся добавить само состояние наведения.
Теперь изменение толщины шрифта не должно сдвигать соседние элементы, если жирная версия действительно шире обычной.
Важный нюанс: значение
🔥 Приём особенно полезен для горизонтальной навигации, вкладок и переключателей, где активный пункт выделяется жирным начертанием.
📣 Code Ready | #совет
В навигации при наведении текст становится жирным, его ширина увеличивается, а соседние пункты сдвигаются.
.nav-link:hover {
font-weight: 700;
}Часто это исправляют фиксированной шириной пунктов меню. Но такой подход плохо работает с переводами, динамическими названиями и адаптивной вёрсткой.
Есть более гибкий приём: заранее зарезервировать место под жирную версию текста.
<a class="nav-link" data-text="Каталог">
Каталог
</a>
.nav-link::before {
content: attr(data-text);
font-weight: 700;
display: block;
height: 0;
overflow: hidden;
visibility: hidden;
}Псевдоэлемент создаёт невидимую копию надписи с нужной толщиной шрифта. Несмотря на нулевую высоту, его ширина участвует в расчёте размера элемента.
Поэтому ссылка заранее занимает достаточно места для жирного текста. Остаётся добавить само состояние наведения.
.nav-link:is(:hover, :focus-visible) {
font-weight: 700;
}Теперь изменение толщины шрифта не должно сдвигать соседние элементы, если жирная версия действительно шире обычной.
Важный нюанс: значение
data-text нужно поддерживать в соответствии с видимым текстом. Для многострочных подписей и сложной типографики приём стоит проверять отдельно.Please open Telegram to view this post
VIEW IN TELEGRAM
🔥12👍10❤7🤝2
В этой статье:
• Узнаете, действительно ли переход с JavaScript на WebAssembly ускоряет Flutter-приложения;• Разберёте результаты 46 тестов производительности: от вычислений и работы с памятью до обработки данных и графики;• Посмотрите, в каких задачах выигрывает WASM, где быстрее JavaScript и как это влияет на плавность интерфейса.🔊 Продолжай читать на Habr!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9❤5🤝5👎1🔥1
Как избежать потери изменений при обновлении данных через API?
При редактировании данных пользователь может отправить несколько запросов подряд. Если сервер обрабатывает их независимо, более старый запрос иногда завершается позже нового и перезаписывает актуальное состояние.
Например, два запроса изменяют название документа:
Порядок отправки запросов не гарантирует порядок их применения на сервере. Поэтому итоговое название может оказаться
Один из способов предотвратить перезапись изменений устаревшими данными — оптимистическая блокировка через версионирование данных. Сервер возвращает документ вместе с его версией:
При обновлении клиент передаёт версию, на основе которой редактировал документ:
На бэкенд обновление выполняется только при совпадении версии. Например, в sql:
Если запись уже была изменена другим запросом, условие
В таком случае бэкенд проверяет количество обновлённых строк и может вернуть
🔥 Главное преимущество подхода — атомарная проверка версии и обновление записи в базе данных. Это предотвращает незаметную перезапись изменений, но не гарантирует применение последнего отправленного запроса.
📣 Code Ready | #практика
При редактировании данных пользователь может отправить несколько запросов подряд. Если сервер обрабатывает их независимо, более старый запрос иногда завершается позже нового и перезаписывает актуальное состояние.
Например, два запроса изменяют название документа:
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(
'Документ был изменён. Обновите данные.'
);
}Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥8❤7
This media is not supported in your browser
VIEW IN TELEGRAM
В репозитории собраны учебные материалы, примеры кода и практические задания: от создания адаптивных страниц и работы со стилями до асинхронных запросов и взаимодействия с API. Обучение построено вокруг практики — по итогам модулей можно создать многостраничный сайт и интерактивное веб-приложение. Дополнительно есть руководства по Git, Linux, настройке VS Code и рабочего окружения.
Оставляю ссылочку: GitHub📱
Please open Telegram to view this post
VIEW IN TELEGRAM
❤13👍8🔥7🤝1
CSS @container style() — проверяй состояние компонента без дополнительных классов!
Обычные контейнерные запросы проверяют размер контейнера. Но CSS умеет проверять и значения его свойств — через
Это полезно, когда оформление вложенных элементов зависит от настройки родительского компонента.
Например, карточка может иметь два варианта оформления.
Задаём значение по умолчанию через CSS-переменную.
А теперь меняем оформление вложенных элементов в зависимости от её значения.
Здесь не нужен
Можно комбинировать несколько условий.
Запрос проверяет стили предка, а не самого элемента, к которому применяется правило; также поддержка
🔥
📣 Code Ready | #совет
Обычные контейнерные запросы проверяют размер контейнера. Но 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-переменные, не создавая отдельные классы для каждого варианта компонента.Please open Telegram to view this post
VIEW IN TELEGRAM
❤14👍8🤝4🔥2
Обычно для адаптивной вёрстки приходится прописывать брейкпоинты и вручную управлять количеством колонок. Но CSS Grid умеет самостоятельно перестраивать элементы в зависимости от доступного пространства — буквально одной строкой.
Как работает:
• repeat(auto-fit, ...) автоматически подбирает количество колонок, которые помещаются в контейнере;
• minmax() задаёт минимальную и максимальную ширину каждой колонки;
• min(100%, 260px) не даёт колонке выйти за пределы узкого контейнера;
• 1fr распределяет оставшееся пространство между колонками.
В результате карточка сама переключается между горизонтальным и вертикальным расположением. Полезно для переиспользуемых компонентов, карточек товаров и интерфейсов с динамической шириной контейнера.
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 для проверки корректности данных в формах. Рассмотрены программная проверка полей, отображение ошибок, установка пользовательских сообщений, контроль обязательных значений, проверка формата и шаблонов, а также ограничений диапазона и шага.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-раскладки!
Представим каталог, в котором карточки разбиты на группы. Обёртки нужны для структуры компонентов, но все товары должны находиться в одной сетке.
Если применить Grid к
Чтобы карточки участвовали в общей сетке, необязательно менять HTML. Достаточно убрать коробку обёртки из CSS-раскладки.
Теперь карточки становятся элементами сетки
Тот же приём работает и с Flexbox.
Важно: элемент с
🔥
📣 Code Ready | #совет
Представим каталог, в котором карточки разбиты на группы. Обёртки нужны для структуры компонентов, но все товары должны находиться в одной сетке.
<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-раскладку лишними контейнерами.Please open Telegram to view this post
VIEW IN TELEGRAM
❤14🔥8👍5
Шпаргалка по работе с HTML-атрибутами через JavaScript: чтение значений с getAttribute(), добавление и обновление через setAttribute(), удаление с removeAttribute(), проверка наличия через hasAttribute() и переключение с toggleAttribute(). Также рассмотрены получение списка атрибутов через getAttributeNames(), работа с data-атрибутами через dataset и доступ к коллекции attributes.Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥12👍8❤7