This media is not supported in your browser
VIEW IN TELEGRAM
tabular-nums должно быть дефолтом для любых чисел, которые обновляются (таймеры, счетчики, цены, проценты, счёт, live-данные и т.д.).Включить OpenType-фичу
tnum можно через CSS-свойство font-variant-numeric..tabular-nums {
font-variant-numeric: tabular-nums;
}@WebDev_Plus
👍1
Laravel Tip
Когда нужно обновить запись, но не трогать колонку
Без таймстампов. Без событий. Тихое, чистое обновление, когда оно реально нужно.
@WebDev_Plus
Когда нужно обновить запись, но не трогать колонку
updated_at, используй updateQuietly().Без таймстампов. Без событий. Тихое, чистое обновление, когда оно реально нужно.
@WebDev_Plus
Если ты веб-разработчик и используешь ИИ, поставь это!
Agent Skills от Addy Osmani (Google) для:
* Web Performance
* best practices
* доступности (a11y)
* технического SEO
Под React, Vue, Angular или что угодно.
Вот какие skills поставятся:
*
*
*
*
*
*
@WebDev_Plus
Agent Skills от Addy Osmani (Google) для:
* Web Performance
* best practices
* доступности (a11y)
* технического SEO
Под React, Vue, Angular или что угодно.
npx add-skill addyosmani/web-quality-skills
Вот какие skills поставятся:
*
web-quality-audit - полный аудит в стиле Lighthouse*
performance - загрузка и оптимизация*
core-web-vitals - LCP, INP, CLS*
accessibility - WCAG и навигация с клавиатуры*
seo - meta-теги и структура*
best-practices - безопасность и стандарты@WebDev_Plus
❤4
This media is not supported in your browser
VIEW IN TELEGRAM
autofill у инпутов по умолчанию выглядит стремно: эта заливка фона ломает аккуратные дизайн-системы, особенно в темной теме.Пофиксил чисто CSS-хакам через inset-shadow:
autofill:shadow-[inset_0_0_0px_1000px_var(--color-background)]Чтобы принудительно поставить нужный фон и убрать нативный синий.
https://micro.bossadizenith.me/writing/taming-chromes-autofill
@WebDev_Plus
👍4
Angular совет дня: твое приложение ходит в несколько API, но интерсепторы не могут понять, к какому из них относится запрос!?
Оберни. Отфильтруй. Готово
@WebDev_Plus
Оберни. Отфильтруй. Готово
@WebDev_Plus
👍1
Это самый простой способ переключаться между режимами Dark, Light и System.
Просто добавьте элемент с выбранным режимом
Может, это и не идеальный вариант, но это самый быстрый и простой способ!
@WebDev_Plus
Просто добавьте элемент с выбранным режимом
data-theme или удалите его из DOM, чтобы переключиться на System mode.Может, это и не идеальный вариант, но это самый быстрый и простой способ!
@WebDev_Plus
Модалки бесят.
Хочешь, чтобы они бесили чуть меньше?
Используй
Что это делает:
Ты скроллишь модалку, доходишь до её конца и продолжаешь крутить дальше.
И тут бах, начинает скроллиться страница под ней. Модалка всё ещё открыта, но позиция на странице сзади уже уехала.
Это называется scroll chaining. Это свойство как раз это и останавливает.
Как это работает:
Когда пользователь доходит до конца прокручиваемого элемента, а модалки для этого вообще идеальный кейс, скролл просто останавливается. Он не продолжает передаваться родителю по цепочке.
На мобилках заодно не триггерит pull-to-refresh.
Где использовать:
• модалки и диалоги
• сайдбары и навигационные меню
• фиксированные контейнеры с
• мобильные карусели
Поддержка браузеров: 95%
Одна строка CSS.
Модалки всё ещё бесят, но уже чуть меньше😄
@WebDev_Plus
Хочешь, чтобы они бесили чуть меньше?
Используй
overscroll-behavior: contain;Что это делает:
Ты скроллишь модалку, доходишь до её конца и продолжаешь крутить дальше.
И тут бах, начинает скроллиться страница под ней. Модалка всё ещё открыта, но позиция на странице сзади уже уехала.
Это называется scroll chaining. Это свойство как раз это и останавливает.
Как это работает:
Когда пользователь доходит до конца прокручиваемого элемента, а модалки для этого вообще идеальный кейс, скролл просто останавливается. Он не продолжает передаваться родителю по цепочке.
На мобилках заодно не триггерит pull-to-refresh.
Где использовать:
• модалки и диалоги
• сайдбары и навигационные меню
• фиксированные контейнеры с
overflow: scroll• мобильные карусели
Поддержка браузеров: 95%
Одна строка CSS.
Модалки всё ещё бесят, но уже чуть меньше
@WebDev_Plus
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
JavaScript использует лексическую область видимости.
Но знаешь ли ты, что такое lexical scope?
Лексическая область видимости означает, что область видимости переменной определяется тем, где она написана в коде, а не тем, откуда её вызвали.
Пример:
Здесь
Это и есть lexical scope: функция как бы "помнит" окружение, в котором была создана.
Ключевые моменты:
* лексическая область видимости статическая, то есть фиксируется в момент определения кода
* внутренние функции могут обращаться к переменным из внешних областей видимости
* это фундамент, на котором в JavaScript построены closures
@WebDev_Plus
Но знаешь ли ты, что такое lexical scope?
Лексическая область видимости означает, что область видимости переменной определяется тем, где она написана в коде, а не тем, откуда её вызвали.
Пример:
function outer() {
let x = 10;
function inner() {
console.log(x); // может обратиться к x из outer
}
inner();
}
outer();Здесь
inner() может получить доступ к x, потому что функция была объявлена внутри outer().Это и есть lexical scope: функция как бы "помнит" окружение, в котором была создана.
Ключевые моменты:
* лексическая область видимости статическая, то есть фиксируется в момент определения кода
* внутренние функции могут обращаться к переменным из внешних областей видимости
* это фундамент, на котором в JavaScript построены closures
@WebDev_Plus
Хватит писать
Чисто, читаемо, без зависимостей.
Подробнее 👇
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/groupBy
@WebDev_Plus
reduce() просто ради того, чтобы сгруппировать массив Object.groupBy() уже работает во всех основных браузерах и позволяет группировать элементы массива по любому ключу в одну строку.Чисто, читаемо, без зависимостей.
Подробнее 👇
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/groupBy
@WebDev_Plus
❤3👍2
Бывало такое, что
Простое решение:
Что это делает:
Добавляет дополнительный отступ сверху у заголовка.
Якорные ссылки продолжают работать, но заголовок оказывается ниже
Как использовать:
Если высота вашего хедера
Теперь, когда кто-то кликает по якорной ссылке, браузер прокручивает страницу до заголовка, но оставляет сверху
Заголовок отображается ниже хедера.
Дополнительный совет: если высота хедера меняется, например на мобильных устройствах, используйте CSS-переменные:
Поддержка браузеров: около
Одна строка CSS. И якорные ссылки наконец работают так, как этого ждут пользователи.
@WebDev_Plus
sticky header перекрывает заголовки, на которые ведут якорные ссылки?Простое решение:
scroll-margin-topЧто это делает:
Добавляет дополнительный отступ сверху у заголовка.
Якорные ссылки продолжают работать, но заголовок оказывается ниже
sticky header, так что хедер больше не перекрывает его часть.Как использовать:
Если высота вашего хедера
80px, добавьте это к заголовкам:scroll-margin-top: 80px;
Теперь, когда кто-то кликает по якорной ссылке, браузер прокручивает страницу до заголовка, но оставляет сверху
80px.Заголовок отображается ниже хедера.
Дополнительный совет: если высота хедера меняется, например на мобильных устройствах, используйте CSS-переменные:
scroll-margin-top: var(--header-height);
Поддержка браузеров: около
96%Одна строка CSS. И якорные ссылки наконец работают так, как этого ждут пользователи.
@WebDev_Plus
❤4
В JavaScript теперь есть немутабельные методы массивов
Больше не нужно писать
Подробнее👇
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toSorted
@WebDev_Plus
toSorted(), toReversed(), toSpliced() и with() возвращают новые массивы вместо того, чтобы изменять исходный.Больше не нужно писать
[...arr].sort(), чтобы избежать побочных эффектов.Подробнее
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toSorted
@WebDev_Plus
Please open Telegram to view this post
VIEW IN TELEGRAM
Нужно ли писать 5 media queries, чтобы шрифт выглядел нормально на разной ширине экрана?
На деле хватает одной строки CSS:
Как это работает:
Сразу задаются три значения: минимальный размер, предпочтительный (плавающий) размер и максимальный размер.
Браузер выбирает подходящее среднее значение, но при этом никогда не уходит ниже минимума и выше максимума.
Например:
*
*
*
Результат:
Текст масштабируется в зависимости от ширины экрана. Без breakpoints, без media queries. Просто плавная адаптивная типографика.
Где использовать:
* Заголовки, которым нужно масштабирование
* Основной текст в hero-секциях
* Любой текст, который должен подстраиваться под размер экрана
Поддержка в браузерах: около 95%
Одна функция.
И адаптивная типографика готова.
@WebDev_Plus
На деле хватает одной строки CSS:
font-size: clamp(1rem, 2vw + 0.5rem, 2rem);
Как это работает:
Сразу задаются три значения: минимальный размер, предпочтительный (плавающий) размер и максимальный размер.
Браузер выбирает подходящее среднее значение, но при этом никогда не уходит ниже минимума и выше максимума.
Например:
*
1rem = минимум (16px). Текст никогда не станет меньше 16px.*
2vw + 0.5rem = предпочтительный размер. Плавно масштабируется вместе с шириной вьюпорта.*
2rem = максимум (32px). Текст не станет больше 32px даже на огромных мониторах.Результат:
Текст масштабируется в зависимости от ширины экрана. Без breakpoints, без media queries. Просто плавная адаптивная типографика.
Где использовать:
* Заголовки, которым нужно масштабирование
* Основной текст в hero-секциях
* Любой текст, который должен подстраиваться под размер экрана
Поддержка в браузерах: около 95%
Одна функция.
И адаптивная типографика готова.
@WebDev_Plus
Laravel Tip
Хотите знать, как отработала ваша запланированная задача в полночь?
Тут вам повезло: вывод scheduled tasks можно без проблем сохранить или отправить по email
@WebDev_Plus
Хотите знать, как отработала ваша запланированная задача в полночь?
Тут вам повезло: вывод scheduled tasks можно без проблем сохранить или отправить по email
@WebDev_Plus
Создавать Promise с внешними 🧹
Больше не нужно заворачивать логику внутрь конструктора.
Подробнее тут
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers
@WebDev_Plus
resolve и reject стало чище Promise.withResolvers() возвращает объект вида { promise, resolve, reject }Больше не нужно заворачивать логику внутрь конструктора.
Подробнее тут
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers
@WebDev_Plus
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3
This media is not supported in your browser
VIEW IN TELEGRAM
Теперь, когда
Настраиваете фигуру, потом просто копируете сгенерированный код.
@WebDev_Plus
shape() поддерживается всеми основными браузерами, напоминаю: вы можете использовать этот онлайн‑генератор, чтобы создавать любые полигоны с закруглёнными углами: https://css-generators.com/polygon-shape/Настраиваете фигуру, потом просто копируете сгенерированный код.
@WebDev_Plus
❤1
Замечали, как вся страница сдвигается, когда вы открываете модальное окно?
Это не баг — это просто отсутствующее CSS-свойство.
Вот что происходит:
Вы открываете модалку.
Затем обычно отключаете прокрутку, добавляя
Прокрутка отключается, и скроллбар исчезает.
И тут — бум — страница сдвигается, например, на 15px влево, потому что контент расширяется и занимает место, где раньше был скроллбар.
В результате получается layout shift.
Чтобы это исправить, можно использовать
Что делает это свойство:
Оно резервирует место под скроллбар, даже когда он не отображается. Когда открывается модалка и скроллбар исчезает, пространство под него остаётся зарезервированным, поэтому никакого сдвига layout не происходит.
Как это использовать👇
Теперь, когда вы открываете модальное окно:
* скроллбар исчезает
* зарезервированное пространство остаётся
* layout остаётся стабильным
Важное замечание (!)
В MacOS вы можете не заметить этот эффект, пока явно не включите настройку “всегда показывать скроллбар”. По крайней мере, я заметил разницу только после этого.
Предполагаю, что для пользователей Windows/Linux это происходит чаще, чем для пользователей MacOS, но я не проверял, как это работает там.
Поддержка браузерами: ~93%
Одна строка CSS — и ваши модальные окна больше не выглядят сломанными.
@WebDev_Plus
Это не баг — это просто отсутствующее CSS-свойство.
Вот что происходит:
Вы открываете модалку.
Затем обычно отключаете прокрутку, добавляя
overflow: hidden к тегу body.Прокрутка отключается, и скроллбар исчезает.
И тут — бум — страница сдвигается, например, на 15px влево, потому что контент расширяется и занимает место, где раньше был скроллбар.
В результате получается layout shift.
Чтобы это исправить, можно использовать
scrollbar-gutter: stable.Что делает это свойство:
Оно резервирует место под скроллбар, даже когда он не отображается. Когда открывается модалка и скроллбар исчезает, пространство под него остаётся зарезервированным, поэтому никакого сдвига layout не происходит.
Как это использовать
body {
overflow-y: scroll;
scrollbar-gutter: stable;
}Теперь, когда вы открываете модальное окно:
* скроллбар исчезает
* зарезервированное пространство остаётся
* layout остаётся стабильным
Важное замечание (!)
В MacOS вы можете не заметить этот эффект, пока явно не включите настройку “всегда показывать скроллбар”. По крайней мере, я заметил разницу только после этого.
Предполагаю, что для пользователей Windows/Linux это происходит чаще, чем для пользователей MacOS, но я не проверял, как это работает там.
Поддержка браузерами: ~93%
Одна строка CSS — и ваши модальные окна больше не выглядят сломанными.
@WebDev_Plus
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3❤1
Одно CSS-свойство только что избавило от необходимости писать JavaScript для каждого FAQ-аккордеона, который вы когда-либо делали.
Серьёзно.
Это свойство —
Годами в CSS нельзя было анимировать переход от
Браузер просто не мог вычислить переход между числовым значением и ключевым словом.
Поэтому разработчики писали JavaScript, измеряли
Теперь это можно сделать одной строкой:
Что оно делает
Сообщает браузеру, что ему разрешено интерполировать между числовыми значениями и ключевыми словами вроде
Как это работает
Добавьте это свойство к элементу (часто к
Контент будет плавно раскрываться от
И всё. Без JavaScript.
Небольшое замечание про аккордеоны
Да, я знаю, что accordion-компоненты имеют довольно спорную репутацию в кругах UX и accessibility.
Но это отличный пример, чтобы показать, как работает
Поддержка браузерами
Пока поддержка не идеальная — около 70%.
- Chrome 129+
- Edge 129+
- Opera 115+✅
Firefox и Safari — пока нет.
Отдельная благодарность команде Chrome за внедрение этой возможности. Она решает проблему, которая существовала с момента появления CSS transitions.
@WebDev_Plus
Серьёзно.
Это свойство —
interpolate-size: allow-keywords.Годами в CSS нельзя было анимировать переход от
height: 0 к height: auto.Браузер просто не мог вычислить переход между числовым значением и ключевым словом.
Поэтому разработчики писали JavaScript, измеряли
scrollHeight, использовали requestAnimationFrame и подобные вещи.Теперь это можно сделать одной строкой:
interpolate-size: allow-keywords;
Что оно делает
Сообщает браузеру, что ему разрешено интерполировать между числовыми значениями и ключевыми словами вроде
auto, min-content, max-content и т.д.Как это работает
Добавьте это свойство к элементу (часто к
:root). Затем используйте обычные CSS-transition для height, и браузер сам обработает остальное.Контент будет плавно раскрываться от
0 до своей фактической высоты.И всё. Без JavaScript.
:root {
interpolate-size: allow-keywords;
}
.content {
height: 0;
overflow: clip;
transition: height 0.3s ease;
}
.content.is-open {
height: auto;
}Небольшое замечание про аккордеоны
Да, я знаю, что accordion-компоненты имеют довольно спорную репутацию в кругах UX и accessibility.
Но это отличный пример, чтобы показать, как работает
interpolate-size.Поддержка браузерами
Пока поддержка не идеальная — около 70%.
- Chrome 129+
- Edge 129+
- Opera 115+
Firefox и Safari — пока нет.
Отдельная благодарность команде Chrome за внедрение этой возможности. Она решает проблему, которая существовала с момента появления CSS transitions.
@WebDev_Plus
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4❤2
Node всегда был про I/O: стримы, буферы, сокеты, файлы. Но есть один пробел, который меня раздражал годами: нельзя виртуализировать файловую систему.
Нельзя импортировать модуль, который существует только в памяти. Нельзя собрать ассеты в Single Executable без патчинга половины стандартной библиотеки.
Теперь это меняется :
Аносируют две вещи:
node:vfs — виртуальная файловая система, которая появляется в core Node.js (PR #61478, ~14 000 строк в 66 файлах)
Вот в чём проблема. Каждый раз, когда нужно:
- собрать приложение в Single Executable
- запускать тесты без обращения к диску
- заизолировать файловый доступ арендатора (tenant)
- загружать сгенерированный ИИ код во время выполнения
нужен один и тот же примитив: виртуальная файловая система, которая интегрируется и с node:fs, и с резолвером модулей. Никто этого не делал.
Экосистема предлагала приближённые решения: memfs, unionfs, mock-fs. У всех одна и та же проблема: они патчат fs, но не резолвер модулей.
Код с вызовом
Два режима:
Mount mode: VFS активна только под заданным префиксом пути. Чистая изоляция.
Overlay mode: VFS проверяется первой для всех путей, затем происходит fallback на реальную файловую систему. Можно переопределить несколько конфигов и оставить остальное без изменений. Идеально для тестирования.
Почему это должно быть в core? Потому что userland-решения всегда компромисс:
- 960+ строк дублированной логики резолвинга модулей
- патчинг приватных API вроде
- глобальный патчинг fs, который ломается, если код заранее сохранил ссылки
- нативные модули не могут загружаться из памяти
- невозможно корректно очистить кэш модулей извне
Скажу честно, как это появилось. PR на 16 000 строк обычно занимает месяцы. Этот был сделан за рождественские праздники 2025 года, потому автор делал его с помощью Claude Code.
Он отдал ИИ рутину: все варианты методов fs, покрытие тестами и документацию. Сам сосредоточился на архитектуре, дизайне API и построчном ревью.
Когда Мальте Убль, CTO Vercel увидел PR, команда Vercel независимо вынесла тот же API в userland как node-vfs-polyfill.
Когда две команды независимо реализуют одно и то же — значит, дизайн получился удачным.
https://github.com/vercel-labs/node-vfs-polyfill
SqliteProvider: персистентная VFS на базе node:sqlite. Файлы сохраняются между перезапусками.
RealFSProvider: изолированный доступ к реальной файловой системе с встроенной защитой от path traversal. Больше не нужны хрупкие проверки через
@WebDev_Plus
Нельзя импортировать модуль, который существует только в памяти. Нельзя собрать ассеты в Single Executable без патчинга половины стандартной библиотеки.
Теперь это меняется :
Аносируют две вещи:
node:vfs — виртуальная файловая система, которая появляется в core Node.js (PR #61478, ~14 000 строк в 66 файлах)
@platformatic/vfs — userland-пакет, который можно использовать уже сейчас на Node.js 22+Вот в чём проблема. Каждый раз, когда нужно:
- собрать приложение в Single Executable
- запускать тесты без обращения к диску
- заизолировать файловый доступ арендатора (tenant)
- загружать сгенерированный ИИ код во время выполнения
нужен один и тот же примитив: виртуальная файловая система, которая интегрируется и с node:fs, и с резолвером модулей. Никто этого не делал.
Экосистема предлагала приближённые решения: memfs, unionfs, mock-fs. У всех одна и та же проблема: они патчат fs, но не резолвер модулей.
Код с вызовом
import('./config.json') полностью их обходит.Два режима:
Mount mode: VFS активна только под заданным префиксом пути. Чистая изоляция.
Overlay mode: VFS проверяется первой для всех путей, затем происходит fallback на реальную файловую систему. Можно переопределить несколько конфигов и оставить остальное без изменений. Идеально для тестирования.
Почему это должно быть в core? Потому что userland-решения всегда компромисс:
- 960+ строк дублированной логики резолвинга модулей
- патчинг приватных API вроде
Module._resolveFilename- глобальный патчинг fs, который ломается, если код заранее сохранил ссылки
- нативные модули не могут загружаться из памяти
- невозможно корректно очистить кэш модулей извне
Скажу честно, как это появилось. PR на 16 000 строк обычно занимает месяцы. Этот был сделан за рождественские праздники 2025 года, потому автор делал его с помощью Claude Code.
Он отдал ИИ рутину: все варианты методов fs, покрытие тестами и документацию. Сам сосредоточился на архитектуре, дизайне API и построчном ревью.
Когда Мальте Убль, CTO Vercel увидел PR, команда Vercel независимо вынесла тот же API в userland как node-vfs-polyfill.
Когда две команды независимо реализуют одно и то же — значит, дизайн получился удачным.
https://github.com/vercel-labs/node-vfs-polyfill
@platformatic/vfs поставляется с дополнительными провайдерами, которых нет в core:SqliteProvider: персистентная VFS на базе node:sqlite. Файлы сохраняются между перезапусками.
RealFSProvider: изолированный доступ к реальной файловой системе с встроенной защитой от path traversal. Больше не нужны хрупкие проверки через
path.resolve().@WebDev_Plus
✍2
This media is not supported in your browser
VIEW IN TELEGRAM
Создавай красивые карты для своего веб-сайта или приложения.
Бесплатно, без настройки и одной командой:
→ http://github.com/AnmolSaini16/mapcn
@WebDev_Plus
Бесплатно, без настройки и одной командой:
→ http://github.com/AnmolSaini16/mapcn
@WebDev_Plus
❤2