Будни разработчика
14.6K subscribers
1.36K photos
398 videos
8 files
2.28K links
Download Telegram
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
#статья дня

Когда пакет долго живёт, у него очень легко появляется один большой index.ts, который реэкспортит почти всё подряд.

В какой-то момент это начинает мешать: вроде бы импортируешь один маленький хелпер, а на практике инструменты идут через общий barrel-файл и поднимают гораздо больший граф модулей, чем реально нужен. На этом особенно быстро начинают болеть тесты и дев-среда, потому что Vitest и Vite очень чувствительны к размеру и связности module graph.

Статья Organize your library with subpath exports как раз про более аккуратный способ это организовать. Идея в том, чтобы не складывать весь публичный API в один вход, а объявлять несколько явных входов через exports в package.json. Тогда вместо условного import { bau, useWow } from 'mylib' можно сделать import { bau } from 'mylib/helpers' и import { useWow } from 'mylib/hooks'.

Снаружи это выглядит как импорт из подпапок, но на самом деле это не доступ внутрь пакета, а специально объявленные публичные entrypoint’ы.

За счёт этого API пакета становится понятнее, внутренности лучше инкапсулируются, а tooling меньше спотыкается о лишние реэкспорты и случайные зависимости. Хороший короткий разбор, если хочется быстро понять сам подход и зачем он нужен.

#vite #barrel #esm
👍13👎1🫡1
Будни разработчика
#заметка дня Модераторы Apple отклонили мой пульт, соответственно, не приняв его в магазин. Причина звучит обидно и стыдно: 4.3 Spam. И означать это может всё, что угодно: от того, что использованы чужие закопирайченные ассеты и до того, что я просто взял…
Да, кстати! Я же совсем забыл написать обновление по пульту и магазину 🙂

Как вы видите из сообщения, следующего за этим — модерацию я победил. И даже выпустил первую версию сразу же! Но в чат сразу не скидывал, ибо занялся не менее важной вещью — названием!

Как оказалось — ну, и ожидалось — пультов в магазине многие десятки. И моё до глупости банальное Smart Remote Plus тупо не искалось (кто бы мог подумать).

Пришлось начинать искать. Захотелось что-то короткое. И необычное. Финское, эстонское или карельское слово — подошло бы идеально. И понеслась...

Koti, Koda, Sora, Vire, Lumi — занято. Havu тоже не прокатил.

В какой-то момент наткнулся на Ruum — эстонское «комната», калька очевидна. На этом и остановился. Ruum Hub — идеально.

Итак, встречайте: Ruum Hub! Теперь шарить намного проще 🙂

https://apps.apple.com/fi/app/ruum-hub-smart-remote/id6761381793

Пока для iOS. Выделенная версия под macOS и на Android на подходе. Все, кто ставил из TestFlight — можете обновляться, я как раз починил интеграцию с последней webOS 25 и начал рабоду над LG NetCast. Google TV тоже на подходе.

Спасибо за поддержку!
14👍7
#статья дня

Злые Марсиане в очередной раз хвастаются!

Making your site visible to LLMs: 6 techniques that work, 8 that don't


Ладно, на самом деле — крайне забавный кейс. Заказчик сидел-сидел, пилил чота с Клодом, в итоге решился на заказную разработку. И ему выкинуло, что, мол, Злые Марсиане отлично подходят.

Как вам такое SEO, а? Сразу ссылка: https://evilmartians.com/chronicles/how-to-make-your-website-visible-to-llms

На самом деле, статья большая, с историческими экскурсами и подробностями обсуждений, но сводится всё к одному: LLM-ки любят простой текст и чёткие направления.

А кто-нибудь застал этот максимально дурацкий бред от SEO-оптимизаторов?

Помните же, как они ломали всю крутую семантику, не давали использовать заголовки, не давали прописывать strong, заставляя упихивать все стили в CSS и писать на дивах?

В моей карьере был случай, когда нас заставляли в каждую статью вносить грамматическую опечатку, просто чтобы поймать людей, ищущих с ошибками 🤦‍♂️

Да, Google и прочие в итоге, конечно, стали ранжировать нормальные проекты выше, но ущерб уже был нанесён.

А что же теперь? Как добиться от AI такой же эффективности как у марсиан?

А теперь заполняете llms.txt, вводите отдельные роуты на Markdown-файлы — и вы великолепны.

Зачем Markdown? Ну потому что все SEO потуги по добавлению в статьи смысла, которого нет, для LLM-ок являются просто HTML-мусором. А текст они любят.

Статью всё равно почитайте, там хорошо.

#llm #ai #seo
Please open Telegram to view this post
VIEW IN TELEGRAM
👍96
#инструмент дня

Наткнулся на шрифт Datatype.

Это вариативный шрифт, который превращает текст в… графики. Прямо через лигатуры. Пишешь что-то вроде:

{l:15,45,90,30,75,20,85,95} → получаешь линейный график
{b:30,70,50,90} → столбики
{p:65} → круговую диаграмму

То есть никакого SVG, canvas и прочего.

Сделано это через OpenType-лигатуры + вариативные оси. По сути, шрифт парсит жисон и подменяет символы на нужные глифы. Выглядит интересно.

Где это может быть полезно:
— быстрые прототипы графиков прямо в тексте
— документация
— демки и презентации

Минусы:
— копирование: вставится исходный текст, но не график (логично)
— доступность: скринридеры будут читать это как {l:15,45…}, а не как график (решаемо)
— кастомизация сильно ограничена

Хотя как концепт — очень круто.

Пощупать можно тут:
https://franktisellano.github.io/datatype/

Где используем, котаны?

#font #diagram
👍16
This media is not supported in your browser
VIEW IN TELEGRAM
#статья дня

Кажется странным, что сначала в браузерах (браузере?) появились переходы между страницами aka View Transitions, и только сейчас — между элементами.

В Chrome 147, наконец, добавили element-scoped view transitions.

До этого если хотелось анимировать, например, сортировку списка, приходилось запускать document.startViewTransition() — даже если менялся один маленький блок.

Выглядело это примерно так:

document.startViewTransition(() => {
list.sort(...)
render()
})


Теперь можно запустить переход прямо на контейнере списка:

listElement.startViewTransition(() => {
list.sort(...)
render()
})


И в этот момент браузер работает только с этим куском DOM.

На практике это означает, что можно спокойно:
— анимировать список
— параллельно обновить, например, сайдбар
— и одно не будет цеплять другое

Сплошные плюсы.

Собственно, статья:
https://developer.chrome.com/blog/element-scoped-view-transitions

Что ещё в Chrome 147:
https://developer.chrome.com/blog/new-in-chrome-147

#chrome #view #transitions
18
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
#такое дня

Кто хочет поорать на монитор?

На меня не смотрите, я уже поорал.

Итак, насколько хорошо ты понимаешь даты в JavaScript?

Кто сказал Temporal API? Выйди вон из класса, дедушки разговаривают.

Итак, вашему вниманию квиз на пограничные условия в JS Date API.

Вперёд, делитесь результатами: https://jsdate.wtf/

У меня всё очень плохо 🫠

#js #date #wtf #бородач
Please open Telegram to view this post
VIEW IN TELEGRAM
👍42
#статья дня

Висящие промисы как простой способ оборвать async-функцию


await new Promise(() => {})


Зачем так делать?

Отмена через throw ненадёжна — её легко случайно поймать в try/catch, и код поедет дальше.


try {
await handler()
} catch (e) {}


С висящим же промисом выполнение гарантированно останавливается.

Где это используется?

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


async function signup(user) {
await step("create-user", user)

if (!user.emailVerified) {
await new Promise(() => {}) // закончили здесь
}

await step("send-email", user)
}


Оркестратор сохраняет прогресс и потом запускает её заново, пропуская выполненные шаги.

Минусы:
— такой код легко сломать случайно: забытый await или лишний Promise — и функция зависнет навсегда
— трудно дебажить: нет ошибки, нет стека, просто «ничего не происходит»
— не подходит для обычного приложения без оркестратора (сам по себе это тупик)
— может путать других разработчиков: выглядит как баг, а не как намеренное поведение

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

А, ну да. Сама статья: https://www.inngest.com/blog/hanging-promises-for-control-flow

#js #promise #halt
👍5🫡2
#фишка дня

А вы знали, что в GitHub Markdown не надо списки нумеровать самому?

1. Раз
1. Два
1. Три


будет буквально преобразовано в

1. Раз
2. Два
3. Три


И не надо париться, когда редактируешь.

P. S. оказывается, есть такая штука, как mdlint, и она на самостоятельную нумерацию очень даже ругается.
🤩9👍31🫡1
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
👍6
#инструмент дня

Вот что происходит, когда компания годами игнорирует запросы сообщества и вместо этого штампует один AI-инструмент за другим.

Rebased — новый открытый графический Git-клиент, который быстро набирает обороты.

Все, кто работал с IDE от JetBrains, знают — их Git-инструменты долгое время считались одними из самых удобных. Особенно Diff.
Но пока рынок уходил в сторону AI-разработки, JetBrains топтались на месте — и многие пользователи начали искать альтернативы.

И вот появляется разработчик, который берет IntelliJ Community Edition (open source), вырезает оттуда всё, связанное с языками программирования, оставляет только Git — и собирает из этого отдельный продукт.

Так и появился Rebased.

Для тех, кто привык к экосистеме JetBrains — интерфейс будет знакомым.

В итоге:
• Полностью open source (Apache 2.0)
• Продвинутый Diff / Code Review (на базе JetBrains)
• Полноценные VCS-инструменты: Commit, Git Log, ветки
• Интерактивный rebase + визуальное решение конфликтов
• Полнотекстовый поиск
• Встроенный терминал (с вкладками)
• Нативная поддержка Git Worktree
• Те же хоткеи и UX, что в IntelliJ

Минус: потребляет больше памяти, чем другие клиенты. Но всё ещё заметно легче полноценной IDE.

На фоне быстрого развития agentic-разработки, удобный и привычный Git-клиент это очень важно, котаны.

GitHub: https://github.com/DetachHead/rebased

Скрины отсюда.

#git #ide #jetbrains
1🔥142👍2
#заметка дня

Ли Робинсон — разработчик и тренер в Cursor — поделился практическими советами о том, как выделиться среди сотен кандидатов при подаче на инженерную позицию.

Как сделать своё инженерное резюме заметным (глазами человека, который смотрит сотни резюме):

1. Резюме должно быть на одну страницу. Если нужно больше — добавьте ссылку на сайт. Не нужно по 10+ пунктов на каждую работу.

2. Вы сразу будете выделяться среди >90% кандидатов, если у вас есть персональный сайт с продуманным содержанием.

3. Если вы указываете свой X (Twitter), возможно, стоит почистить посты? Звучит очевидно, но люди публикуют всякое.

4. Обязательно добавьте GitHub. И, пожалуйста, без профиля в стиле MySpace с кучей бейджей и картинок — я хочу видеть код и ваши реальные навыки.

5. Адаптируйте отклик под компанию. Для стартапа курсы из университета менее важны. Для FAANG — могут помочь пройти ATS.

6. Удивительно, но многие резюме вообще не упоминают AI или агентов. Разработка меняется, и от вас ожидается понимание работы с AI. Это должно быть отражено в проектах и резюме.

7. Относитесь к LinkedIn серьёзно. Да, разработчики чаще сидят в X, но внутри компаний всё ещё пересылают именно LinkedIn.

8. Покажите свою индивидуальность: интересы, вкус, мышление. Книги, тексты, фильмы — всё, что раскрывает вас как человека. В конце концов, люди хотят работать с теми, кто им интересен и приятен.

9. Не используйте AI для написания резюме или сопроводительного письма. Это очень заметно, особенно в AI-компаниях. Можно использовать для идей, но писать — самому.

10. Не добавляйте фото в резюме. Лучше разместите его на внешних ссылках.

11. Качество важнее количества. Лучше 3 сильных проекта, чем 27 поверхностных AI-поделок.

Помните: рекрутеры просматривают сотни и тысячи откликов. Они не будут тратить 20 минут на каждый. Уберите лишнее и переходите к сути.

#resume #cv
👍8👎41
#инструмент дня

Надоело каждый раз выходить из уютной консоли и открывать caniuse.com, чтобы посмотреть, с каких браузеров поддерживаются сабгриды?

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

Вашему вниманию Bramus Van Damme и его caniuse-cli: https://www.npmjs.com/package/@bramus/caniuse-cli

$ caniuse viewport-units
$ caniuse "viewport units"
$ caniuse @property


Имеется автокомплит для zsh.

Ну, консольные маньяки, перепись!

P. S. Скилл для Клода есть же уже?)

#cli #caniuse #бородач
12
#такое дня

Когда в следующий раз будете ворчать на коллегу за PR в 200 строк — вспомните это: https://github.com/oven-sh/bun/pull/30412

Ментейнеры Bun, конечно, могут сколько угодно рассказывать нам о бессонных ночах в попытке отдебажить утечку памяти в Zig (будучи крупнейшим проектом на этом языке), но без этих ночей ничего бы не вышло.

Штош.

P. S. кстати, почитайте, что ответили авторы Zig о недавнем «ИИ-форке», который представили Bun. Там прям интересно.

#rust #zig
#фишка дня

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

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

Но это же можно исправить! Используя правило 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