Совет по CSS 💡
Легко создайте полосатый прогресс-бар без использования сторонних библиотек 🤩
📲 Мы в MAX
👉 @frontend_1
Легко создайте полосатый прогресс-бар без использования сторонних библиотек 🤩
👉 @frontend_1
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7❤3
Перестаньте пихать всё в
Вижу это на каждом код-ревью. Джуны (и иногда уставшие мидлы) используют
🔴 Как делать не надо:
У вас есть
Почему это плохо?
1. Лишний рендер. Компонент рендерится, запускается эффект, обновляется стейт -> компонент рендерится снова.
2. Сложность отладки. Попробуйте отследить цепочку из 5 таких эффектов в большом компоненте.
🟢 Как надо (Derived State):
Вычисляйте значение прямо во время рендера.
Если вычисления тяжелые, используйте
💡 Правило большого пальца: Если вы можете вычислить что-то из уже имеющихся пропсов или стейта - не создавайте для этого новый стейт.
#react #bestpractices #performance
📲 Мы в MAX
👉 @frontend_1
useEffect. Серьезно.Вижу это на каждом код-ревью. Джуны (и иногда уставшие мидлы) используют
useEffect для синхронизации стейта. Это выстрел себе в ногу.🔴 Как делать не надо:
У вас есть
firstName и lastName, и вы создаете эффект, чтобы обновить fullName.
const [firstName, setFirstName] = useState('Alex');
const [lastName, setLastName] = useState('Dev');
const [fullName, setFullName] = useState('');
useEffect(() => {
setFullName(`${firstName} ${lastName}`);
}, [firstName, lastName]);
Почему это плохо?
1. Лишний рендер. Компонент рендерится, запускается эффект, обновляется стейт -> компонент рендерится снова.
2. Сложность отладки. Попробуйте отследить цепочку из 5 таких эффектов в большом компоненте.
🟢 Как надо (Derived State):
Вычисляйте значение прямо во время рендера.
const fullName = `${firstName} ${lastName}`;
Если вычисления тяжелые, используйте
useMemo. Но в 90% случаев вам не нужен ни эффект, ни стейт.💡 Правило большого пальца: Если вы можете вычислить что-то из уже имеющихся пропсов или стейта - не создавайте для этого новый стейт.
#react #bestpractices #performance
👉 @frontend_1
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤1👎1😁1
Знаете ли вы, что можно изменить метод формы в HTML-форме, указав атрибут
📲 Мы в MAX
👉 @frontend_1
formMethod на кнопке?👉 @frontend_1
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
💻SPA умеют почти все. А вот интерфейс, который живёт в реальном времени, без перезагрузок и костылей, обычно ломает даже уверенных фронтендеров.
📆На открытом вебинаре OTUS вы соберёте мини-биржу на Vue: поднимем локальный WebSocket-сервер с мок-данными, подключим подписку на стрим, выведем список валют, изменения цен и индикаторы роста/падения. Добавим живые графики (ApexCharts или Chart.js) и обновления.
Разберём архитектуру real-time интерфейсов: реактивные данные, управление соединением, обработка событий и потоков, обновления без перезагрузки. Покажем, как после урока заменить мок-источник на реальный WebSocket-поток.
👉Встречаемся 14 января в 20:00 МСК в преддверие старта курса «Vue.js-разработчик». Регистрация открыта: https://vk.cc/cTkUVz
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
📆На открытом вебинаре OTUS вы соберёте мини-биржу на Vue: поднимем локальный WebSocket-сервер с мок-данными, подключим подписку на стрим, выведем список валют, изменения цен и индикаторы роста/падения. Добавим живые графики (ApexCharts или Chart.js) и обновления.
Разберём архитектуру real-time интерфейсов: реактивные данные, управление соединением, обработка событий и потоков, обновления без перезагрузки. Покажем, как после урока заменить мок-источник на реальный WebSocket-поток.
👉Встречаемся 14 января в 20:00 МСК в преддверие старта курса «Vue.js-разработчик». Регистрация открыта: https://vk.cc/cTkUVz
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
👍1
🛡 TypeScript: Почему
Многие по привычке пишут так:
Это работает для валидации, но у этого подхода есть минус - Type Widening (расширение типов). Вы теряете точность выведенного типа в угоду соответствию интерфейсу.
Начиная с TS 4.9, оператор
В чем разница?
❌ Классический подход (потеря точности):
✅ Используем
Когда использовать?
Всегда, когда вы хотите проверить соответствие контракту (конфиги, темы, палитры цветов), но при этом хотите продолжать работать с конкретными значениями этого объекта, а не с его общим интерфейсом.
📲 Мы в MAX
👉 @frontend_1
satisfies круче обычного объявления типа?Многие по привычке пишут так:
const config: Config = { ... }.Это работает для валидации, но у этого подхода есть минус - Type Widening (расширение типов). Вы теряете точность выведенного типа в угоду соответствию интерфейсу.
Начиная с TS 4.9, оператор
satisfies решает эту проблему. Он проверяет, что объект соответствует типу, но сохраняет его точную структуру.В чем разница?
❌ Классический подход (потеря точности):
type Routes = Record<string, string | string[]>;
// Мы явно указали тип Routes
const nav: Routes = {
home: "/",
admin: ["/users", "/posts"]
};
// TS думает, что nav.home — это 'string | string[]'
// ОШИБКА: Property 'toUpperCase' does not exist on type 'string | string[]'
nav.home.toUpperCase();
✅ Используем
satisfies (сохраняем контекст):
const nav = {
home: "/",
admin: ["/users", "/posts"]
} satisfies Routes;
// Теперь TS знает:
// 1. nav соответствует Routes (опечатки не пропустит)
// 2. nav.home — это конкретно string
// 3. nav.admin — это конкретно string[]
// РАБОТАЕТ!
nav.home.toUpperCase();
nav.admin.map(path => path);
Когда использовать?
Всегда, когда вы хотите проверить соответствие контракту (конфиги, темы, палитры цветов), но при этом хотите продолжать работать с конкретными значениями этого объекта, а не с его общим интерфейсом.
👉 @frontend_1
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9❤1🔥1
Forwarded from Мобильная разработка #1
☠️ Баг, который вы не видите, а пользователи ненавидят
Представьте: пользователь заполнил длинную форму регистрации, свернул приложение, чтобы скопировать код из SMS, возвращается... а экран пустой. Данные исчезли. 🤬
Это System-initiated process death. Самая частая причина удаления приложения у пользователей и головная боль разработчиков.
Почему это происходит?
ОС (Android или iOS) всегда не хватает оперативной памяти. Когда ваше приложение уходит в фон, система может «тихо» убить его процесс, чтобы освободить ресурсы для активного окна (например, Камеры).
❌ Ошибка новичка:
«Я храню данные в
Реальность:
✅ Как делать правильно (Level Up):
🤖 Android:
Перестаньте полагаться только на поля класса. Используйте SavedStateHandle.
Это специальный механизм внутри ViewModel, который сохраняет небольшие кусочки данных (ID, поисковый запрос, ввод пользователя) в системный бандл. Система бережно восстановит его даже после смерти процесса.
Гуглить:
🍏 iOS (SwiftUI/UIKit):
В SwiftUI для простых данных (например, выбранная вкладка или текст) используйте обертку
Для сложных данных — сохраняйте их в локальную БД (CoreData/Realm/SwiftData) при каждом изменении, а не при закрытии экрана.
🛠 Как проверить себя (Челлендж на 5 минут):
Не верьте эмулятору. Проверьте свой текущий проект прямо сейчас:
1. Запустите приложение и введите данные в любое поле.
2. Сверните приложение (Home).
3. Android: В настройках разработчика включите опцию «Don't keep activities» (Не сохранять действия).
4. iOS: В Xcode нажмите Debug -> Simulate Memory Warning или остановите дебаг и запустите другое тяжелое приложение.
5. Вернитесь в свое приложение.
Если данные исчезли или случился краш, поздравляю, вы нашли критический баг. Время фиксить!
Знали про SavedStateHandle или по старинке сохраняли всё в базу данных? 👇
#android #ios #bugs #middle #architecture #обучение
👉 @developer_mobila
Представьте: пользователь заполнил длинную форму регистрации, свернул приложение, чтобы скопировать код из SMS, возвращается... а экран пустой. Данные исчезли. 🤬
Это System-initiated process death. Самая частая причина удаления приложения у пользователей и головная боль разработчиков.
Почему это происходит?
ОС (Android или iOS) всегда не хватает оперативной памяти. Когда ваше приложение уходит в фон, система может «тихо» убить его процесс, чтобы освободить ресурсы для активного окна (например, Камеры).
❌ Ошибка новичка:
«Я храню данные в
ViewModel (Android) или в переменной контроллера (iOS), они же живут долго!»Реальность:
ViewModel переживает поворот экрана, но умирает вместе с процессом. Синглтоны тоже сбрасываются.✅ Как делать правильно (Level Up):
🤖 Android:
Перестаньте полагаться только на поля класса. Используйте SavedStateHandle.
Это специальный механизм внутри ViewModel, который сохраняет небольшие кусочки данных (ID, поисковый запрос, ввод пользователя) в системный бандл. Система бережно восстановит его даже после смерти процесса.
Гуглить:
SavedStateHandle, Parcelable.🍏 iOS (SwiftUI/UIKit):
В SwiftUI для простых данных (например, выбранная вкладка или текст) используйте обертку
@SceneStorage. Она автоматически сохраняет и восстанавливает состояние.Для сложных данных — сохраняйте их в локальную БД (CoreData/Realm/SwiftData) при каждом изменении, а не при закрытии экрана.
🛠 Как проверить себя (Челлендж на 5 минут):
Не верьте эмулятору. Проверьте свой текущий проект прямо сейчас:
1. Запустите приложение и введите данные в любое поле.
2. Сверните приложение (Home).
3. Android: В настройках разработчика включите опцию «Don't keep activities» (Не сохранять действия).
4. iOS: В Xcode нажмите Debug -> Simulate Memory Warning или остановите дебаг и запустите другое тяжелое приложение.
5. Вернитесь в свое приложение.
Если данные исчезли или случился краш, поздравляю, вы нашли критический баг. Время фиксить!
Знали про SavedStateHandle или по старинке сохраняли всё в базу данных? 👇
#android #ios #bugs #middle #architecture #обучение
👉 @developer_mobila
👍7❤🔥1😍1
🎨 CSS
Мы привыкли называть
Вот два сценария, где
1. Контекстная стилизация (без BEM-модификаторов)
Раньше, чтобы изменить стили карточки в зависимости от контента (например, есть ли внутри картинка или бейдж), мы писали JS-проверку или добавляли класс
Теперь CSS сам смотрит внутрь:
2. Селектор «предыдущего соседа»
В CSS всегда можно было стилизовать элемент, идущий после (
Трюк: мы выбираем элемент, если за ним следует нужный нам сосед.
🔥Поддержка в браузерах уже отличная (Baseline 2023). Если вы всё еще пишете
📲 Мы в MAX
👉 @frontend_1
:has() - это легальный чит-код в версткеМы привыкли называть
:has() «селектором родителя», но это определение сильно преуменьшает его мощь. Это инструмент, который позволяет отказаться от JS и лишних классов-модификаторов для управления состоянием UI.Вот два сценария, где
:has() меняет правила игры:1. Контекстная стилизация (без BEM-модификаторов)
Раньше, чтобы изменить стили карточки в зависимости от контента (например, есть ли внутри картинка или бейдж), мы писали JS-проверку или добавляли класс
.card--with-image.Теперь CSS сам смотрит внутрь:
/* Если внутри карточки есть картинка -> меняем грид */
.card:has(img) {
grid-template-columns: 1fr 1fr;
}
/* Если внутри есть сообщение об ошибке -> красим бордер */
.form-group:has(.error-message) {
border-color: red;
background: #fff0f0;
}
2. Селектор «предыдущего соседа»
В CSS всегда можно было стилизовать элемент, идущий после (
h2 + p), но никогда - перед. С :has() это стало возможным.Трюк: мы выбираем элемент, если за ним следует нужный нам сосед.
/* Стилизуем h2, ТОЛЬКО если сразу за ним идет список ul */
h2:has(+ ul) {
margin-bottom: 0; /* Убираем отступ, чтобы "приклеить" к списку */
color: var(--primary);
}
🔥Поддержка в браузерах уже отличная (Baseline 2023). Если вы всё еще пишете
useEffect или вешаете классы просто чтобы поменять стиль родителя при фокусе инпута (:focus-within не всегда хватает) или наличии элемента - удаляйте лишний код и берите :has().👉 @frontend_1
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥5
This media is not supported in your browser
VIEW IN TELEGRAM
Советы по HTML 💡
Знаете ли вы, что с помощью элемента HTML <dialog> можно легко создать модал?
📲 Мы в MAX
👉 @frontend_1
Знаете ли вы, что с помощью элемента HTML <dialog> можно легко создать модал?
👉 @frontend_1
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤3
any - это ложь, которую вы говорите сами себеДавайте честно: когда у вас горят дедлайны, а TypeScript ругается на несовпадение типов, рука сама тянется написать
: any.«Я потом поправлю», - говорите вы.
Спойлер: не поправите.
Использование
any превращает ваш строгий TypeScript проект обратно в анархичный JavaScript, но с лишним этапом сборки. Вы просто отключаете компилятор.🔥 Почему это плохо:
Вы теряете автокомплит, рефакторинг становится русской рулеткой, а баг
undefined is not a function вернется к вам в самый неподходящий момент.🛡 Что делать вместо
any?1. Если вы реально не знаете, что прилетит:
Используйте
unknown. Это безопасный аналог any. Он скажет: "Я не знаю, что это, но я не дам тебе с этим работать, пока ты не проверишь тип".
// ❌ Плохо
const processData = (data: any) => {
data.toUpperCase(); // Может упасть, если data — число
}
// ✅ Хорошо
const processData = (data: unknown) => {
if (typeof data === 'string') {
data.toUpperCase(); // TS теперь знает, что это строка
}
}
2. Если лень описывать огромный ответ бэкенда:
Используйте утилиты для генерации типов из Swagger/OpenAPI. Не пишите интерфейсы руками, мы же не в каменном веке.
Уважайте свои нервы. Типизируйте нормально.
#typescript #cleancode #safety
📲 Мы в MAX
👉 @frontend_1
👍4❤2
🛑 Хватит проверять
Вы наверняка видели (или писали) такой код, чтобы избежать ошибки "Can't perform a React state update on an unmounted component":
Это «мусорный» код. Запрос все равно происходит, трафик тратится, промис висит в памяти.
Вместо ручных флагов используйте стандартный браузерный API - AbortController.
✅ Как сделать правильно:
🚀 Бонус-фича: Очистка Event Listeners
📲 Мы в MAX
👉 @frontend_1
isMounted в useEffectВы наверняка видели (или писали) такой код, чтобы избежать ошибки "Can't perform a React state update on an unmounted component":
// ❌ Антипаттерн
useEffect(() => {
let isMounted = true;
fetchData().then(data => {
if (isMounted) setState(data);
});
return () => { isMounted = false; };
}, []);
Это «мусорный» код. Запрос все равно происходит, трафик тратится, промис висит в памяти.
Вместо ручных флагов используйте стандартный браузерный API - AbortController.
✅ Как сделать правильно:
useEffect(() => {
const controller = new AbortController();
fetch('/api/data', { signal: controller.signal })
.then(res => res.json())
.then(setData)
.catch(err => {
// Важно: не считаем отмену запроса ошибкой
if (err.name !== 'AbortError') {
console.error(err);
}
});
// При размонтировании или перезапуске эффекта запрос реально отменится браузером
return () => controller.abort();
}, []);
🚀 Бонус-фича: Очистка Event Listeners
AbortController умеет удалять и слушатели событий. Больше не нужно выносить функцию-хендлер в отдельную переменную, чтобы передать её в removeEventListener.
const controller = new AbortController();
// Передаем signal в опции
window.addEventListener('resize', (e) => handleResize(e), {
signal: controller.signal
});
// Одним вызовом удаляем слушатель (или группу слушателей с одним сигналом)
controller.abort();
📲 Мы в MAX
👉 @frontend_1
👍5
🏗 Забудьте про
Мы годами писали сложные велосипеды для модальных окон или тянули тяжелые библиотеки. Главная боль кастомных решений - это accessibility (focus trap), закрытие по
HTML-элемент
Почему это Game Changer:
1. Top Layer API: При открытии через
2. Встроенная доступность: Браузер сам запирает фокус внутри окна (focus trap) и обрабатывает нажатие
3. Магия форм: Форма с
Пример (Минимум кода):
🎨 Как стилизовать фон?
Забудьте про создание отдельного
⚠️ Важный нюанс:
Не путайте методы.
▪️
▪️
📲 Мы в MAX
👉 @frontend_1
z-index: 9999: Нативный <dialog>Мы годами писали сложные велосипеды для модальных окон или тянули тяжелые библиотеки. Главная боль кастомных решений - это accessibility (focus trap), закрытие по
Esc и вечные войны с контекстом наложения (z-index).HTML-элемент
<dialog> теперь стабилен во всех браузерах и решает эти проблемы на уровне движка.Почему это Game Changer:
1. Top Layer API: При открытии через
.showModal(), элемент помещается в специальный «верхний слой» браузера. Ему плевать на overflow: hidden родителя или низкий z-index контейнера. Он всегда будет поверх всего.2. Встроенная доступность: Браузер сам запирает фокус внутри окна (focus trap) и обрабатывает нажатие
Esc.3. Магия форм: Форма с
method="dialog" закрывает модалку при сабмите без единой строчки JS-обработчика.Пример (Минимум кода):
<dialog id="confirmModal">
<form method="dialog">
<h3>Удалить продакшн?</h3>
<p>Это действие необратимо.</p>
<button value="cancel">Отмена</button>
<button value="confirm" autofocus>Да, удалить</button>
</form>
</dialog>
const modal = document.getElementById('confirmModal');
// 1. Открываем (добавляет backdrop и блокирует остальную страницу)
modal.showModal();
// 2. Слушаем закрытие
modal.addEventListener('close', () => {
if (modal.returnValue === 'confirm') {
runDeleteScript();
}
});
🎨 Как стилизовать фон?
Забудьте про создание отдельного
div для затемнения. Используйте псевдоэлемент:
dialog::backdrop {
background: rgb(0 0 0 / 0.5);
backdrop-filter: blur(4px); /* Красивое размытие фона */
}
⚠️ Важный нюанс:
Не путайте методы.
▪️
.show() - просто показывает элемент (позционирование absolute, страница скроллится).▪️
.showModal() - то, что вам нужно (Top Layer, fixed, блокировка фона).📲 Мы в MAX
👉 @frontend_1
🔥7👍4❤2🤷♂1
14 февраля встречаемся на главной фронтенд-конференции Яндекса — «Я 💛 Фронтенд»: ежегодное мероприятие для тех, кто создает современные интерфейсы. Присоединяйтесь офлайн в Москве или онлайн!
Что вас ждет?
📌 Доклады о применении веб-компонентов, использовании LLM, переходе от традиционной адаптивности к новому подходу, и о том, как встроенные модели меняют архитектуру веб-приложений
📌 Code in the Dark — баттл по верстке на HTML/CSS
📌 CSS арт-челлендж, интерактивная викторина по фронтенд-разработке и другие активности от команд Яндекса
А совсем скоро стартует Capture the Flag — фронтендерский турнир на скорость с наградами для победителей.
Регистрируемся на ивент здесь — там же будут появляться онлайн-активности.
Что вас ждет?
📌 Доклады о применении веб-компонентов, использовании LLM, переходе от традиционной адаптивности к новому подходу, и о том, как встроенные модели меняют архитектуру веб-приложений
📌 Code in the Dark — баттл по верстке на HTML/CSS
📌 CSS арт-челлендж, интерактивная викторина по фронтенд-разработке и другие активности от команд Яндекса
А совсем скоро стартует Capture the Flag — фронтендерский турнир на скорость с наградами для победителей.
Регистрируемся на ивент здесь — там же будут появляться онлайн-активности.
👍2❤1🔥1
🧬 Прощай,
Глубокое копирование объектов (Deep Copy) долго было болью в JS. Чтобы не копировать ссылки, мы либо тянули жирный
Проблема хака
1.
2.
3.
4. Циклические ссылки вызывают ошибку.
Теперь у нас есть нативный стандарт -
Как это работает:
⚠️ Важные ограничения:
Он выбросит ошибку
• Функции (методы объекта);
• DOM-элементы;
• Свойства прототипа (копируются только собственные свойства).
📲 Мы в MAX
👉 @frontend_1
JSON.parse(JSON.stringify())Глубокое копирование объектов (Deep Copy) долго было болью в JS. Чтобы не копировать ссылки, мы либо тянули жирный
lodash.cloneDeep, либо использовали популярный хак с JSON.Проблема хака
JSON.parse(JSON.stringify(obj)) в том, что он теряет данные:1.
Date превращается в строку.2.
Set и Map превращаются в пустые объекты {}.3.
undefined просто исчезает.4. Циклические ссылки вызывают ошибку.
Теперь у нас есть нативный стандарт -
structuredClone().Как это работает:
const original = {
title: "Dev Meeting",
date: new Date(),
members: new Set(['Alex', 'Sam']),
meta: undefined
};
// ❌ Старый хак
const jsonCopy = JSON.parse(JSON.stringify(original));
console.log(jsonCopy.date); // Строка "2023-10-...", а не объект Date
console.log(jsonCopy.members); // {}, данные потеряны
console.log(jsonCopy.meta); // Ключ исчез совсем
// ✅ structuredClone
const realCopy = structuredClone(original);
console.log(realCopy.date.getFullYear()); // Работает! Это всё ещё Date
console.log(realCopy.members.has('Alex')); // Работает! Это всё ещё Set
console.log(realCopy.meta); // undefined (на месте)
⚠️ Важные ограничения:
structuredClone предназначен для данных.Он выбросит ошибку
DataCloneError, если вы попытаетесь скопировать:• Функции (методы объекта);
• DOM-элементы;
• Свойства прототипа (копируются только собственные свойства).
📲 Мы в MAX
👉 @frontend_1
🔥6👍2🗿2💩1
📦 Нативная группировка:
Сколько раз в жизни вы писали
Задача: Сгруппировать продукты по категории.
🐢 Как мы делали раньше (Reduce):
🚀 Как это делается теперь:
🧠 Senior-нюанс:
Обычный
Если вам нужно сгруппировать данные, где ключом выступает объект (например, пользователь или конфиг), используйте
Итог: Еще одна причина перестать тащить utility-библиотеки в бандл.
📲 Мы в MAX
👉 @frontend_1
Object.groupByСколько раз в жизни вы писали
reduce для группировки массива объектов по какому-то полю? Или тянули для этого жирный lodash?Задача: Сгруппировать продукты по категории.
🐢 Как мы делали раньше (Reduce):
const inventory = [
{ name: "Asparagus", type: "vegetables" },
{ name: "Bananas", type: "fruit" },
{ name: "Goat", type: "meat" },
{ name: "Cherries", type: "fruit" },
];
// Читать сложно, легко ошибиться в мутации аккумулятора
const result = inventory.reduce((acc, item) => {
(acc[item.type] ||= []).push(item);
return acc;
}, {});
🚀 Как это делается теперь:
const result = Object.groupBy(inventory, ({ type }) => type);
/* Результат:
{
vegetables: [{ name: "Asparagus", ... }],
fruit: [{ name: "Bananas", ... }, { name: "Cherries", ... }],
meat: [{ name: "Goat", ... }]
}
*/
🧠 Senior-нюанс:
Map.groupByОбычный
Object.groupBy возвращает объект, где ключи всегда приводятся к строкам.Если вам нужно сгруппировать данные, где ключом выступает объект (например, пользователь или конфиг), используйте
Map.groupBy.
const restockOptions = { threshold: 10 };
const urgentOptions = { threshold: 0 };
// Группируем элементы по объектам-конфигам
const result = Map.groupBy(inventory, (item) => {
return item.quantity < 5 ? urgentOptions : restockOptions;
});
// Получаем доступ по ссылке на объект!
result.get(urgentOptions);
Итог: Еще одна причина перестать тащить utility-библиотеки в бандл.
📲 Мы в MAX
👉 @frontend_1
👍4
Как frontend-разработчику получить оффер в Big Tech?
Платят как джуну, а спрашивают как с лида 🙄 Зарплата не растёт, задачи скучные.
Пробуешь откликаться, но на резюме клюют только ноунейм компании, а на собесах валят на алгоритмах? При этом вокруг кто-то постоянно получает офферы в Яндекс или VK...
Стабильность с маленькой зп, или дестрой рынка и выход на максимальную? Синяя или красная таблетка, Нео?! 👾
В своем канале:
👉Разбираю самые популярные и каверзные вопросы на собесах
👉Рассказываю как пройти фильтр HR
👉Борюсь с убеждениями, которые мешают развиваться
👉Делюсь лайфхаками, например как аккуратно “пинговать” рекрутеров
Регулярно публикую полезные материалы:
▪️60 вопросов, которые точно помогут тебе на собеседовании.
▪️Подборка из 100+ каналов с вакансиями для разработчиков
▪️10 задротских вопросов про JavaScript, после которых ты усомнишься, что вообще знаешь JS. Часть 1
▪️Чек лист проверки своего резюме
Подписывайся, нас уже 4500 🤓: ссылка
Реклама, erid2W5zFK72PEp: ИП Галактионов Тихон Витальевич, ИНН 771618975809
Платят как джуну, а спрашивают как с лида 🙄 Зарплата не растёт, задачи скучные.
Пробуешь откликаться, но на резюме клюют только ноунейм компании, а на собесах валят на алгоритмах? При этом вокруг кто-то постоянно получает офферы в Яндекс или VK...
Стабильность с маленькой зп, или дестрой рынка и выход на максимальную? Синяя или красная таблетка, Нео?! 👾
Меня зовут Тихон, привет! Я — действующий Frontend-разработчик и ментор.
Помогаю устроиться на хорошие позиции в Big Tech и сопровождаю на испытательном сроке.
В своем канале:
👉Разбираю самые популярные и каверзные вопросы на собесах
👉Рассказываю как пройти фильтр HR
👉Борюсь с убеждениями, которые мешают развиваться
👉Делюсь лайфхаками, например как аккуратно “пинговать” рекрутеров
Регулярно публикую полезные материалы:
▪️60 вопросов, которые точно помогут тебе на собеседовании.
▪️Подборка из 100+ каналов с вакансиями для разработчиков
▪️10 задротских вопросов про JavaScript, после которых ты усомнишься, что вообще знаешь JS. Часть 1
▪️Чек лист проверки своего резюме
Подписывайся, нас уже 4500 🤓: ссылка
Реклама, erid2W5zFK72PEp: ИП Галактионов Тихон Витальевич, ИНН 771618975809
📐 Перестаньте верстать под экран:
Мы привыкли делать адаптив через
Представьте карточку товара. На десктопе в основной сетке она широкая, а в сайдбаре - узкая. Если вы используете
Раньше мы лечили это пропсами
В чем суть?
Компонент теперь смотрит не на ширину окна браузера (
Как использовать:
1. Обозначаем родителя как контейнер
Чтобы дочерние элементы могли "измерять" родителя, нужно явно включить этот режим.
2. Пишем стили для ребенка
Вместо
Вы создаете по-настоящему изолированный компонент.
Вы можете кинуть этот компонент в футер, в модалку, в грид на 3 колонки или на весь экран, он сам подстроится под выделенное ему место. Вам больше не нужно знать контекст, где компонент будет использоваться.
📲 Мы в MAX
👉 @frontend_1
@containerМы привыкли делать адаптив через
@media, опираясь на размер экрана. Но это ломает компонентный подход.Представьте карточку товара. На десктопе в основной сетке она широкая, а в сайдбаре - узкая. Если вы используете
@media (min-width: 1200px), то карточка в сайдбаре будет "думать", что места много, и развалится, хотя сам сайдбар узкий.Раньше мы лечили это пропсами
isSmall, variant="sidebar" или сложным CSS. Теперь есть нативное решение Container Queries.В чем суть?
Компонент теперь смотрит не на ширину окна браузера (
viewport), а на ширину своего родительского контейнера.Как использовать:
1. Обозначаем родителя как контейнер
Чтобы дочерние элементы могли "измерять" родителя, нужно явно включить этот режим.
.card-wrapper {
/* Включаем отслеживание изменения размера по горизонтали */
container-type: inline-size;
/* Опционально: даем имя, чтобы обращаться к конкретному контейнеру */
container-name: card-box;
}
2. Пишем стили для ребенка
Вместо
@media используем @container.
.card {
display: flex;
flex-direction: column;
}
/* Если РОДИТЕЛЬ (.card-wrapper) шире 400px */
@container card-box (min-width: 400px) {
.card {
flex-direction: row; /* Перестраиваем в горизонталь */
gap: 20px;
}
}
Вы создаете по-настоящему изолированный компонент.
Вы можете кинуть этот компонент в футер, в модалку, в грид на 3 колонки или на весь экран, он сам подстроится под выделенное ему место. Вам больше не нужно знать контекст, где компонент будет использоваться.
📲 Мы в MAX
👉 @frontend_1
👍12