Будни разработчика
14.4K subscribers
1.31K photos
386 videos
8 files
2.2K links
Download Telegram
This media is not supported in your browser
VIEW IN TELEGRAM
#заметка дня

В чат прилетел вопрос: "Как добавить иконку в поле ввода так, чтобы она была видна только когда виден плейсхолдер и исчезла при вводе текста?"

Отвечаем: конечно же добавить её в контейнер label, а потом использовать псевдо-класс :placeholder-shown на поле ввода!

Он очень давно и хорошо поддерживается, так что почему бы и нет.

Оставим за пределами этого обсуждения тот факт, что плейсхолдеры не должны заменять реальные метки. Это всё равно уже стало де-факто стандартом индустрии... но постарайтесь так не делать.

И, конечно, пример:
https://codepen.io/alinaki/pen/xxMpgLK?editors=1100

Там заодно используются SVG-спрайты, потому что мне лениво подключать профессиональный аккаунт на кодпене и грузить туда картинки. Так что заодно можно посмотреть, как работать со спрайтами. Пригодится!

Всем бу, котаны!

#css #placeholder #svg #sprite #бородач
👍9
This media is not supported in your browser
VIEW IN TELEGRAM
#фишка дня

CSS anchor positioning aka якоря могут реально поменять то, как мы с вами реализуем интерфейсы, требующие графового представления: CJM, майндмапы, блок-схемы, пайплайны...

Темани Афиф недавно сделал пример, соединив круги стрелками и набросив немного JS для drag&drop: https://css-tip.com/connected-circles/

Потом немного улучшил: https://css-tip.com/connected-circles-2/

И пару дней назад пошёл ва-банк и представил буквально реализацию поиска кратчайшего пути в графе: https://css-tip.com/graph-theory/

Выглядит, конечно, весьма сложно. Но следующим шагом, видимо, будет транспиляция Mermaid в CSS... Зато самому алгоритм стрелок реализовывать не придётся! 😂️️️️️️

#css #anchor #graph
🫡9👍2🤩2
This media is not supported in your browser
VIEW IN TELEGRAM
#ссылка дня

Дамы и господа, мы зашли слишком далеко.

Нужна виртуалка на Intel, а у тебя мак? Не вопрос, давай напишем эмулятор на CSS!

Проект X86CSS — это эмулятор x86-ассемблера без JavaScript. Вообще. Всё состояние процессора — через CSS-переменные. Исполнение — через

«Процессорный цикл» — это просто тик анимации. Пять герц в эквиваленте.

ПЯТЬ. Не гигагерц, а герц.

Идея выросла из статьи The CPU Hack на dev.to: современные возможности CSS позволяют организовать пошаговое изменение состояния. Если состояние можно хранить, менять и пересчитывать, а изменения можно повторять — система становится тьюринг-полной.

Как это выглядит в упрощённом виде.

Тик процессора:


@property --ip {
syntax: "<integer>";
inherits: false;
initial-value: 0;
}

@property --tick {
syntax: "<integer>";
inherits: false;
initial-value: 0;
}

.cpu {
animation: clock 0.1s steps(1) infinite;
}

@keyframes clock {
to {
--tick: calc(var(--tick) + 1);
}
}

.cpu {
--ip: calc(var(--ip) + var(--tick));
}


Анимация создаёт шаг. На каждом шаге меняется состояние.
От состояния зависит, какие инструкции сработают дальше.

Ввод — тоже без JS. Например, зажатая кнопка:


.key:active ~ .cpu {
--running: 1;
}

.cpu {
--running: 0;
--ip: calc(var(--ip) + var(--running));
}


Пока кнопка нажата — переменная меняется и влияет на вычисления.

В реальном проекте вместо двух переменных — регистры, память, флаги и декодирование инструкций. Сотни их.

Практической пользы — ну, нет.

Но сам факт, что CSS можно довести до уровня полноценной вычислительной модели и запустить на нём x86 — выглядит как интересная точка в эволюции фронтенда.

Ах, да. Работает только на Chrome, потому что — какая внезапность — использует условный оператор (if), который появился совсем недавно. И вот это — это вполне себе имеет практическое применение.

Просто пойдите и поиграйте в это. Ощущения невероятные, хрен с ней, с применимостью на практике, честное слово. Это целый компьютер! Вы можете даже программы для него компилировать с C на x86asm. Буквально.

#css #cpu #x86 #hack
11🫡4👍3
#фишка дня

Многие недооценивают css variables, особенно при небольшой поддержке javascript.

Думали динамически можно изменять только цвет/типографику и что-то еще такое же очевидное?
А вот и нет, управлять можно даже текстом (ну ладно, еще немного математикой).

Идея для использования - динамический брендинг.
Задали название продукта/компании/клиента в одном свойстве --client-id и изменили один раз для шапки/подвала/сайдбара.

Пример кода показывает насколько это легко понять и использовать.
https://codepen.io/glebcha/pen/gbpwbob

#css #var #бородач
👍82
#событие дня

Я понятия не имею, как я пропустил! Итак, соревнование March MadCSS!

16 лучших фронтенд-разработчиков схлестнутся в жаркой битве по вёрстке интерфейсов.

Ну, я надеюсь, вам что-то говорят имена Josh Cameau, Wes Bos, Kyle Cook, Chris Coyier... если нет — очень зря!

Первый раунд был неделю назад и его можно посмотреть на YouTube: https://www.youtube.com/watch?v=nuxSFTjXrhI

А второй как раз будет сегодня.

И да, даже лучшие верстальщики мира гуглят, как выровнять текст.

Сайт ивента с турнирной таблицей и мерчом: https://madcss.com/

Смотрим?

#css #dev #battle
6👍1🤩1
#статья дня

Страница грузится 7 секунд.
Причина — один эмодзи ❤️

Иногда проблемы с производительностью оказываются совсем не там, где их ищешь. В статье Аллена Пайка «A Broken Heart» он разбирает случай, когда страница внезапно начала грузиться по 7 секунд, хотя сервер, сеть и JavaScript работали нормально. В профайлере оказалось, что почти всё время Safari тратит на layout — причём один проход занимал больше секунды.

Дальше — обычный путь: постепенно вырезать куски интерфейса и смотреть, когда станет быстрее. В какой-то момент выяснилось, что всё упирается в один эмодзи в кнопке. Убираешь его — всё работает мгновенно. Возвращаешь — снова тормоза.

Причина оказалась в том, как Safari работает со шрифтами. Если указать Noto Color Emoji как основной шрифт, он используется даже для обычного текста, хотя покрывает только эмодзи. Для всех остальных символов браузер каждый раз ищет подходящий fallback-шрифт. В процессе layout он пересчитывает размеры текста, переносы строк и позиции элементов, и делает это много раз подряд.

В норме такие пересчёты почти ничего не стоят, но в Safari здесь есть просадка, из-за которой всё резко замедляется. В итоге одна строка с emoji-шрифтом может увеличить время layout в десятки или даже сотни раз.

Минимальный пример:


<link href="https://fonts.googleapis.com/css2?family=Noto+Color+Emoji" rel="stylesheet">

<style>
body {
font-family: "Noto Color Emoji";
}
</style>

<button>Click ❤️</button>


Если не ставить emoji-шрифт основным, а оставить его только в конце списка как fallback, проблема исчезает. В оригинальной статье есть ещё детали про поиск причины и минимизацию примера — стоит почитать: https://allenpike.com/2026/a-broken-heart/

Ну и официальный issue: https://bugs.webkit.org/show_bug.cgi?id=305636

Потрясающая хрень, конечно. На пустом месте.

#css #emoji #svg #performance
1👍2413🫡1
#статья дня

А ну, сходу ответьте, чем отличается :has(:not()) от :not(:has())?

На самом деле, если тупо воспользоваться логикой английского языка — легко ошибиться.

Разработчики браузера для, простите, разработчиков —Polypane — ведут свой блог с разными мелкими фишками, и сегодня — вот такая, как раз об этом.

📌 :has(:not())

Выбирает элементы, которые содержат определённые дочерние элементы, но не содержащие другие.


.card:has(:not(img)) {
background: lightblue;
}


🔹 Выберет .card, если внутри есть любой элемент, кроме <img>.

📌 :not(:has())

Выбирает элементы, не содержащие определённый дочерний элемент.


.card:not(:has(img)) {
background: lightcoral;
}


🔹 Выберет .card, если внутри вообще нет <img>.

🏁 Итого:

:has(:not(img)) проверяет, есть ли что-то, кроме <img>.
:not(:has(img)) проверяет, что <img> вообще нет.

Ну а в статье всё то же самое, только чуть подробнее.

Не ошибайтесь, котаны.

#css #has #not #бородач
👍155
#видео дня

Оказывается, у блога Chrome for Developers есть свой собственный YouTube-канал: https://www.youtube.com/@ChromeDevs

Формат, правда, довольно странный. Основу канала составляют видео по 1-3 минуты, и нет, даже не все из них шортсы. Впрочем, есть и подкасты.

Ладно, это я к чему. Они выкатили очень пафосное видео о том, как в Pinterest пересмотрели свои методы создания CSS-каруселей и — как утверждается — избавились от кучи джаваскрипта, перейдя на нативные View Transitions и свежие API для скролла: https://youtu.be/oWJPu3yvfp8

Но, конечно, невозможно в две с половиной минуты уместить все идеи проекта. Потому действительная польза — в описании! А что там у нас?

А, собственно, ресурсы для повторения:

Доступные карусели → https://goo.gle/4aTpGtc
Карусели на CSShttps://goo.gle/3YuWhOv
Локальные View Transitions → https://goo.gle/3XuZMUX
View Transition API → https://goo.gle/3MzVngY

Другой вопрос, конечно, в том, что половина этих API толком недоступна не то что в других браузерах, а даже в самом Chrome без флага, это они аккуратно обходят стороной.

Впрочем, никого ещё обычный скролл и отсутствие переходов вместо красивых транзишенов не убивало.

#chrome #css #carousel
8
This media is not supported in your browser
VIEW IN TELEGRAM
#инструмент дня

Я искренне радуюсь способности разных людей создавать хайп вокруг своих продуктов. Умению создать продукт, попадающий в нерв миллионов людей. И сегодня такой продукт — Pretext от Шен Лу.

Собственно, заявка прям сильная: дать людям чёткий, быстрый и всеобъемлющий алгоритм подсчёта размерности текстовых нод на чистом TypeScript.

Как звучит, а?!

Зачем это нужно? Ну, яркий пример прямо на скриншоте: рассчитать, в каких местах разорвать текст, чтобы вставить туда фигуру. Или раскладка masonry. Или ASCII-арт. Или аккордионы с конкретным числом строк. Или редакторы текста. Примеров-то прям много: https://chenglou.me/pretext/

Правда — и вот проблема хайпа — подаётся это на потрясающем соусе вроде: «На CSS это сделать невозможно или очень сложно, все проблемы решены, никакого рефлоу, много лет этого никто не делал, мы прошли сквозь ад, пока писали это, никаких больше расчётов через DOM, работает с корейским и японскими языками» и так далее и тому подобное.

Я ни в коей мере не преуменьшаю объём работы и возможности библиотеки. Но...

Но даже если мы оставить за рамками то, что CSS в целом давно решает как минимум половину заявленных вещей и даже гораздо проще, вся красота решения лежит в стандартном методе canvas.measureText. Эта штука с нами чуть ли не с IE9 и — естественно — на ней писалось множество решений в последние лет 10. Так что половина заявлений о крутости библиотеки ну... как минимум, слишком сильная.

Главное — уметь попасть в нерв, да :)

Нас ждут еще множество удобных библиотек, реализующих всё и сразу, благодаря хорошей забытой идее и LLM.

Довольно злой пост получился, библиотека-то точно стоит вашего внимания. Просто посмотрите на это. Или это. Вдохновить людей — это тоже дорогого стоит.

#css #js #measureText #text
111
Media is too big
VIEW IN TELEGRAM
#codepen дня

Наткнулся на приятный и эффектный пример 3D-интерфейса — Painting Wheel.

Выглядит и ощущается как Three.js, но это CSS-преобразования.

По сути, берётся набор карточек и раскладывается по окружности. У каждой есть свой угол и одно и то же расстояние от центра. За счёт этого из обычного списка получается кольцо. Дальше вся сцена чуть наклоняется и добавляется перспектива.

JavaScript используется только чтобы поменять перспективу.

Ну а чтобы показать, что это всё совсем не запредельно сложно, я решил вытащить непосредственно реализацию кольца в отдельный кодпен: https://codepen.io/editor/alinaki/pen/019d2f65-9738-7ea5-a667-524ee1a68bef

Чтобы стало совсем понятно, я добавил панель управления: можете прощёлкать чекбоксы в верхнем правом углу и настроить любой аспект карусели.

Можно вообще сделать простую бесконечную прокрутку!

Из наворотов — только зум колесом, чтобы было проще рассматривать и понимать происходящее. Понятное дело, ваш ИИ-агент с лёгкостью вытащит код и из оригинального примера, но из упрощённого это делать сподручнее, не правда ли? :)

#css
6
#заметка дня

Чем отличаются auto-fit и auto-fill в гридах?

Отвечает Александр Друзь.

Функцию repeat используют чтобы не писать повторяющиеся определения колонок или строк. Помимо конкретного их числа, можно задать и автоматическое их заполнение при помощи пресловутых auto-fit и auto-fill, сравните на иллюстрации. Тут можно было бы и закончить :)

Так в чем же разница, словами? :)

При использовании repeat движок гридов создает столько колонок или строк, сколько вообще может уместиться в заданные рамки. Отличие fit от fill буквально в том, что fill задаст контенту минимально возможный размер, сохранив "фантомные", незаполненные, в примере, колонки. А fit — заполнит (впишет) контент, схлопнув те самые фантомные колонки.

В общем, всё довольно просто.

#css #grid #repeat #бородач
6👍3
This media is not supported in your browser
VIEW IN TELEGRAM
#фишка дня

В CSS есть ключевое слово safe, которое используется вместе со значениями выравнивания и не даёт контенту «вылезать» за границы контейнера. Если элемент не помещается при обычном выравнивании, браузер автоматически смещает его так, чтобы он оставался видимым.

Это удобно в адаптивных интерфейсах, где размеры могут меняться и важно не терять доступ к содержимому. safe работает с flexbox, grid и свойствами вроде align-items, justify-content и другими.

Простой пример:


.container {
display: flex;
justify-content: safe center;
}


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

Подробнее читать тут: https://iprodan.dev/l/safe-alignment/

#css #flex #safe
21
This media is not supported in your browser
VIEW IN TELEGRAM
#фишка дня

У скроллящегося сайдбара можно сделать fade по краям так, чтобы пункты меню как будто уходили под градиент сверху и снизу. И сделать это красиво.

Сразу пример со всем кодом и описанием: https://codepen.io/editor/alinaki/pen/019d954a-79e7-7e49-8653-181b0b67ad61

Для этого используется mask-image, а управляет всем scroll timeline: скролл контейнера становится прогрессом CSS-анимации. Дальше анимация меняет стопы градиента в маске, поэтому в начале верхний fade выключен, после начала прокрутки появляется, а в конце исчезает нижний.


@keyframes sidebar-fade-mask {
0% { --fade-top-end: 0%; --fade-bottom-start: 94%; --fade-bottom-end: 99%; }
8%, 92% { --fade-top-end: 6%; --fade-bottom-start: 94%; --fade-bottom-end: 99%; }
100% { --fade-top-end: 6%; --fade-bottom-start: 100%; --fade-bottom-end: 100%; }
}

.menu-scroll {
animation: sidebar-fade-mask auto linear both;
animation-timeline: scroll(self block);
mask-image: linear-gradient(
to bottom,
transparent 0%,
#000 var(--fade-top-end),
#000 var(--fade-bottom-start),
transparent var(--fade-bottom-end)
);
}


Важный момент в том, что здесь не двигается сам градиент и не меняется opacity списка. Меняются именно стопы градиента, и из-за этого fade ведёт себя как часть скролла, а не как отдельный декоративный слой.

Если хочется понять глубже, смотреть стоит в сторону animation-timeline, scroll-timeline и обзора scroll-driven animations.

Upd. добавил светлую тему, чтобы разница была виднее.

#css #scroll
👍203🤩2
#фишка дня

Надоело угадывать высоту строки, чтобы текст стал высотой ровно в прописную букву? Say no more!


line-height: 1cap;


И вы великолепны.

P. S. ещё более вы великолепны, если Safari версии больше 17.2 включительно.

#css #бородач
16
This media is not supported in your browser
VIEW IN TELEGRAM
#codepen дня

Ну что, кажется, настало то время, когда для стилизации радиокнопок и чекбоксов не нужно больше изгаляться с input:checked+i. Это освобождает мозг и руки для более приятных вещей.

Итак, смотрим на пример от Джона Кантнера: https://codepen.io/alinaki/pen/ExMXbqz

1. Для начала, обнуляем все браузерные стили и предположения браузера об внешнем виде радиокнопок вообще через appearance: none.

2. Я вам этого не говорил, но, технически, уже давно можно на поля ввода накладывать псевдоэлементы. Но не на select. Я всё хочу написать большой пост про реализацию select, пока вот так.

Благодаря этой возможности, собственно, можно стилизовать чекбокс как душе угодно: ::before, ::after, :checked::before, :checked::after... В целом, лично я бы обошёлся радиальным градиентом и одним псевдоэлементом.

3. Освободившиеся ресурсы мозга и тот факт, что теперь все элементы красиво вложены в label (как минимум, не нужны for и id), можно отправить на реализацию разных эффектов.

Например, проверить, есть ли лейбл с выделенным чекбоксом и подвинуть к нему рамку:


label:nth-of-type(2):has(input[type="radio"]:checked) ~ .selection {
transform: translateY(100%);
}


Обратите внимание, рамка — отдельный элемент, к ней обращаемся через селектор низлежащих соседей ~.

Не знаю, что меня больше впечатляет. Псевдоэлементы на полях ввода или :has.

И да, поддерживается везде.

#css #has #appearance #бородач
👍15
This media is not supported in your browser
VIEW IN TELEGRAM
#статья дня

Scroll-driven animations уже давно есть в Chrome, и за последний год вокруг них накопилось много примеров — у того же Bramus Van Damme были подробные демки с view-timeline и разными вариантами ranges. Теперь появился ещё один большой разбор от самого Джоша Комо: https://www.joshwcomeau.com/animation/scroll-driven-animations/

Как всегда, это интерактивная документация по animation-timeline.

Посмею себе напомнить ключевую идею процесса: прогресс анимации берётся не из времени (`animation-duration`), а из положения элемента относительно viewport или scroll-контейнера. В статье это сразу показывается на примере с progress bar, где значение анимации напрямую связано со скроллом страницы.

Дальше он последовательно вводит scroll-timeline и view-timeline. Первый вариант привязывается к прокрутке контейнера, второй — к тому, как конкретный элемент входит и выходит из viewport. Есть наглядные демо, где один и тот же @keyframes ведёт себя по-разному в зависимости от выбранного таймлайна.

Отдельно разбирается animation-range. На интерактивных примерах видно, как entry, exit, cover, contain влияют на диапазон, в котором проигрывается анимация.

Есть демонстрации с несколькими timeline’ами и синхронизацией анимаций, где один scroll-прогресс управляет сразу несколькими свойствами.

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

Документация: https://developer.mozilla.org/en-US/docs/Web/CSS/animation-timeline
Примеры от Google: https://developer.chrome.com/docs/css-ui/scroll-driven-animations/

Из нюансов — Safari всё ещё отстаёт: часть API отсутствует или работает неполно, так что без фоллбеков пока не обойтись.

#css #scroll
👍5
#фишка дня

Итак, все мы знаем, что при добавлении скроллбара (если этот скроллбар, конечно, виден) у нас происходит сдвиг по фазе полей справа.

Ну или слева, если вы араб.

Но это же можно исправить! Используя правило scrollbar-gutter: stable можно зарезервировать место под скроллбар, не прибегая к иным методам вроде overflow: scroll (который буквально этот самый скроллбар заранее покажет, даже если он не нужен).

Демо от Ахмада Шадида в его Defensive CSS: https://defensivecss.dev/tip/scrollbar-gutter/

Can I Use: https://caniuse.com/?search=scrollbar-gutter

Поддержка в Chrome и Firefox. В Safari пока только в TP, но на Apple-устройствах скроллбары, как правило, скрыты и отображаются поверх контента, не занимая места.

Выглядит это, правда, как дополнительный паддинг, но!

Есть интересное но в виде scrollbar-gutter: stable both-edges, которое зарезервирует место под скроллбар, и такое же — на другой стороне. Что, в целом, избавит нас от разных паддингов.

Раньше за похожее решение отвечало правило overflow: overlay, но его отменили в пользу gutter.

Лучше всего это работает, впрочем, для попапов. Мало кого волнует скроллбар на тексте, а вот прыгающий body при появлении модалки — это уже перебор.

#css #scrollbar #gutter #бородач
6👍2
This media is not supported in your browser
VIEW IN TELEGRAM
#заметка дня

А помните (конечно же помните!) как мы с вами обсуждали CSS Custom Highlight API для реализации подсветки кода?

Ну вот же, положила: https://xn--r1a.website/htmlshit/2715

Так вот, а почему бы не объединить подсветку CSS с поиском по тексту? Ну в самом деле, интересно же, как это реализовано, например, в текстовых редакторах или браузерах при поиске по странице. Хотя бы на минимальном уровне.

А реализовано это через, простите, обход дерева!

Алгориииииитмы

Ладно, нам не придётся самим писать обходчик, он уже имеется! Вот: https://developer.mozilla.org/en-US/docs/Web/API/Document/createTreeWalker

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

Ну в нашем случае всё просто: NodeFilter.SHOW_TEXT — ищем по текстовым нодам, словам.

Ну а дальше всё просто: проверяем регуляркой на совпадения и запускаем подсветку. Уж это за нас теперь может и браузер делать: https://codepen.io/alinaki/pen/zxvPbRJ

Да, теперь можно и ваших камтомных селектах красиво подсветить результат фильтрации.

Пользуемся, котаны.

#css #highlight #бородач
1👍62
This media is not supported in your browser
VIEW IN TELEGRAM
#фишка дня

Я не думал, что доживу, но, похоже, скоро можно будет вписывать текст в контейнер без хаков с vw/vh и даже без скриптов.

Сразу пример (нужны флаги! ниже): https://codepen.io/cssgrid/pen/emBZzPL

Фича называется text-fit. Это часть экспериментального CSS (обсуждается в рамках CSS Text / Sizing), и идея тут очевидна: вписать текст в контейнер.

Вот спека в процессе: https://drafts.csswg.org/css-text-4/#text-fit-property

Пока это всё работает только за флагом chrome://flags → Experimental Web Platform features.

Но уже хорошо же!

#css #text #fit
11🤩4
#статья дня

Кармен Ансио написал отличный материал про CSS-функцию linear(). Она появилась уже довольно давно, но в реальных проектах встречается редко — большинство по привычке ограничивается ease, ease-in-out и разными вариантами cubic-bezier().

Причина понятна: обычно linear() воспринимают как способ вручную задать несколько точек на кривой анимации. Не самый удобный инструмент и не очень понятно, зачем он вообще нужен.

Ансио показывает гораздо более интересный сценарий. Если заранее рассчитать движение какой-нибудь физической системы — например, пружины — то результат можно представить как последовательность значений и скормить её linear(). Браузер потом просто воспроизведёт эту траекторию.


.card {
transition:
transform 647ms
linear(
0, 0.04, 0.15, 0.30,
0.46, 0.59, 0.69,
0.75, 0.79, 0.80
/* ... */
);
}


Автор начинает с модели затухающей пружины, показывает уравнение, объясняет параметры системы и сопровождает всё это интерактивными примерами. Можно менять коэффициенты и сразу видеть, как меняется движение.

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

Короче, linear() — это вам не это.

Ссылка ещё раз: https://www.carmenansio.com/articles/spring-physics-css

#css #easing #spring #linear
👍7