🔥 Трюк с :has() в CSS — как маленький хак улучшает UX
Селектор :has() поддерживается во всех современных браузерах. Его часто называют «селектором родителя», но он куда мощнее.
Вот пример, как улучшить UX форм без JS 👇
form:has(input:invalid) button[type="submit"] {
opacity: 0.5;
pointer-events: none;
}
📌 Что делает:
Если в форме есть невалидный input, сабмит-кнопка становится неактивной.
💡 Применения :has():
- Показывать/прятать элементы в зависимости от вложенности;
- Делать UI реактивным без JS;
- Улучшать доступность форм и состояний.
✅ Минимализм, UX и современный CSS — в одном трюке. Попробуй!
CodeBase | Frontend | #CSS
Селектор :has() поддерживается во всех современных браузерах. Его часто называют «селектором родителя», но он куда мощнее.
Вот пример, как улучшить UX форм без JS 👇
form:has(input:invalid) button[type="submit"] {
opacity: 0.5;
pointer-events: none;
}
📌 Что делает:
Если в форме есть невалидный input, сабмит-кнопка становится неактивной.
💡 Применения :has():
- Показывать/прятать элементы в зависимости от вложенности;
- Делать UI реактивным без JS;
- Улучшать доступность форм и состояний.
✅ Минимализм, UX и современный CSS — в одном трюке. Попробуй!
CodeBase | Frontend | #CSS
❤2
🎯 CSS tip: как избавиться от :last-child и упростить отступы
Когда нужно задать отступ между элементами, но не последнему, часто пишут:
.item:not(:last-child) {
margin-bottom: 16px;
}
Но есть современный способ без селекторов и костылей 👇
✅ Используй gap с flex или grid:
.container {
display: flex;
flex-direction: column;
gap: 16px;
}
📌 Преимущества:
– Нет нужды в :last-child
– Чище HTML и CSS
– Работает одинаково в любом направлении (row, column)
– Поддерживается во всех современных браузерах
Итог: если ты всё ещё пишешь :not(:last-child) — пришло время обновить подход.
CodeBase | Frontend | #CSS
Когда нужно задать отступ между элементами, но не последнему, часто пишут:
.item:not(:last-child) {
margin-bottom: 16px;
}
Но есть современный способ без селекторов и костылей 👇
✅ Используй gap с flex или grid:
.container {
display: flex;
flex-direction: column;
gap: 16px;
}
📌 Преимущества:
– Нет нужды в :last-child
– Чище HTML и CSS
– Работает одинаково в любом направлении (row, column)
– Поддерживается во всех современных браузерах
Итог: если ты всё ещё пишешь :not(:last-child) — пришло время обновить подход.
CodeBase | Frontend | #CSS
❤2👍2🔥1
🔥 Быстрое сравнение объектов в JS без глубоких сравнений
Иногда не нужен deep equal, а просто надо понять: два объекта точно одинаковы по содержимому?
Вот простой, но мощный трюк на базе JSON.stringify():
const isEqual = (a: object, b: object) =>
JSON.stringify(a) === JSON.stringify(b);
📌 Подходит для:
* Простых объектов без методов и undefined;
* Сравнения кеша/props в memo;
* Быстрой проверки изменений формы.
⚠️ Не подходит:
* Для вложенных объектов с разным порядком ключей ({a:1,b:2} !== {b:2,a:1});
* Когда есть Date, Map, Set, функции, undefined, symbol.
🧠 Альтернатива:
Если важен порядок и типы — используй lodash.isEqual.
👉 Пример использования:
if (!isEqual(prevForm, currentForm)) {
saveChanges();
}
⚡ Просто. Эффективно. Для 80% кейсов — 🔥
CodeBase | Frontend | #JS
Иногда не нужен deep equal, а просто надо понять: два объекта точно одинаковы по содержимому?
Вот простой, но мощный трюк на базе JSON.stringify():
const isEqual = (a: object, b: object) =>
JSON.stringify(a) === JSON.stringify(b);
📌 Подходит для:
* Простых объектов без методов и undefined;
* Сравнения кеша/props в memo;
* Быстрой проверки изменений формы.
⚠️ Не подходит:
* Для вложенных объектов с разным порядком ключей ({a:1,b:2} !== {b:2,a:1});
* Когда есть Date, Map, Set, функции, undefined, symbol.
🧠 Альтернатива:
Если важен порядок и типы — используй lodash.isEqual.
👉 Пример использования:
if (!isEqual(prevForm, currentForm)) {
saveChanges();
}
⚡ Просто. Эффективно. Для 80% кейсов — 🔥
CodeBase | Frontend | #JS
🔥1
This media is not supported in your browser
VIEW IN TELEGRAM
Всплывающие скроллеры изображений с анимацией, управляемой прокруткой CSS 🤙
.pop {
view-timeline-name: --pop;
}
img {
animation: slide both;
animation-timeline: --pop;
animation-range: entry 100% cover 50%;
}
.skateboarder {
--x: 0;
--y: -45%;
}
@ keyframes slide {
to { translate: var(--x) var(--y); }
}
https://codepen.io/jh3y/pen/abPgrGR
CodeBase | Frontend | #CSS
.pop {
view-timeline-name: --pop;
}
img {
animation: slide both;
animation-timeline: --pop;
animation-range: entry 100% cover 50%;
}
.skateboarder {
--x: 0;
--y: -45%;
}
@ keyframes slide {
to { translate: var(--x) var(--y); }
}
https://codepen.io/jh3y/pen/abPgrGR
CodeBase | Frontend | #CSS
👍2
💡 Scroll-snap-type
Позволяет создавать плавные, контролируемые прокрутки с «привязкой» к определённым позициям.
🔘 Используется для каруселей, слайдеров и списков.
Зачем это нужно:
➡️ Сделать UX удобным и предсказуемым.
➡️ Избавиться от костылей на JS.
CodeBase | Frontend | #JS
Позволяет создавать плавные, контролируемые прокрутки с «привязкой» к определённым позициям.
.container {
scroll-snap-type: x mandatory;
}
.item {
scroll-snap-align: start;
}🔘 Используется для каруселей, слайдеров и списков.
Зачем это нужно:
➡️ Сделать UX удобным и предсказуемым.
➡️ Избавиться от костылей на JS.
CodeBase | Frontend | #JS
👍1
Прокачать навыки вёрстки и фронтенда можно в телеграм!
В этом канале опытный верстальщик делится структурированными уроками и различными материалами по HTML, CSS, JS, а также советами по заработку на фрилансе.
Канал будет полезен:
1. начинающим и опытным верстальщикам
2. программистам
3. веб-дизайнерам
Научиться и зарабатывать на верстке:
@free_html_lessons
В этом канале опытный верстальщик делится структурированными уроками и различными материалами по HTML, CSS, JS, а также советами по заработку на фрилансе.
Канал будет полезен:
1. начинающим и опытным верстальщикам
2. программистам
3. веб-дизайнерам
Научиться и зарабатывать на верстке:
@free_html_lessons
🔥1
CSS совет 💡
Возможно, ты не знал об этом новом и самом простом способе вертикально центрировать контент в блочном макете.
CodeBase | Frontend | #CSS
Возможно, ты не знал об этом новом и самом простом способе вертикально центрировать контент в блочном макете.
CodeBase | Frontend | #CSS
👍6
🔥 Трюк с :has() в CSS: "Родительская магия"
Селектор :has() наконец стабильно работает во всех современных браузерах. Это открывает мощные возможности — реакция родителя на состояние потомка без JS!
Пример: подсветить div, если внутри есть заполненный input:
div:has(input:valid) {
border: 2px solid green;
}
Или показать ошибку, если инпут невалиден:
form:has(input:invalid) .error-message {
display: block;
}
📌 Зачем это нужно:
- 💡 Упрощает логику UI без JS
- 🚫 Убирает необходимость в лишних классах и хендлерах
- 💪 Делает компоненты декларативнее и чище
Проверить поддержку: https://caniuse.com/css-has
CodeBase | Frontend | #CSS
Селектор :has() наконец стабильно работает во всех современных браузерах. Это открывает мощные возможности — реакция родителя на состояние потомка без JS!
Пример: подсветить div, если внутри есть заполненный input:
div:has(input:valid) {
border: 2px solid green;
}
Или показать ошибку, если инпут невалиден:
form:has(input:invalid) .error-message {
display: block;
}
📌 Зачем это нужно:
- 💡 Упрощает логику UI без JS
- 🚫 Убирает необходимость в лишних классах и хендлерах
- 💪 Делает компоненты декларативнее и чище
Проверить поддержку: https://caniuse.com/css-has
CodeBase | Frontend | #CSS
👍2
📌 Подборка полезных функций, которые пригодятся продвинутым frontend-разработчикам при работе с UI, производительностью и архитектурой
1. Throttle
Контролирует частоту вызова функции, полезно для scroll/resize-событий.
function throttle(fn: Function, delay: number) {
let last = 0;
return (...args: any[]) => {
const now = Date.now();
if (now - last >= delay) {
last = now;
fn(...args);
}
};
}
2. Debounce
Откладывает выполнение функции до окончания серии вызовов.
function debounce(fn: Function, delay: number) {
let timeout: ReturnType<typeof setTimeout>;
return (...args: any[]) => {
clearTimeout(timeout);
timeout = setTimeout(() => fn(...args), delay);
};
}
3. Deep Clone (без structuredClone)
function deepClone<T>(obj: T): T {
return JSON.parse(JSON.stringify(obj));
}
Подходит для простых объектов, не содержащих функций, дат и т.п.
4. Safe Access (Optional Chaining + Fallback)
function get<T>(obj: any, path: string, fallback?: T): T {
return path.split('.').reduce((acc, key) => acc?.[key], obj) ?? fallback;
}
5. Wait (async delay)
function wait(ms: number) {
return new Promise(resolve => setTimeout(resolve, ms));
}
6. Generate UUID v4
function uuidv4() {
return crypto.randomUUID(); // нативно в современных браузерах
}
7. Copy to Clipboard
async function copyToClipboard(text: string) {
try {
await navigator.clipboard.writeText(text);
} catch {
const textarea = document.createElement('textarea');
textarea.value = text;
document.body.appendChild(textarea);
textarea.select();
document.execCommand('copy');
document.body.removeChild(textarea);
}
}
8. Detect Outside Click (для dropdown/modals)
function onClickOutside(element: HTMLElement, callback: () => void) {
function handler(event: MouseEvent) {
if (!element.contains(event.target as Node)) {
callback();
}
}
document.addEventListener('click', handler);
return () => document.removeEventListener('click', handler); // для очистки
}
9. Download File from Blob
function downloadBlob(blob: Blob, filename: string) {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
a.click();
URL.revokeObjectURL(url);
}
10. Dynamic Script Loader (например, для внешних SDK)
function loadScript(src: string): Promise<void> {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = src;
script.async = true;
script.onload = () => resolve();
script.onerror = () => reject(new Error(
document.head.appendChild(script);
});
}
CodeBase | Frontend | #JS
1. Throttle
Контролирует частоту вызова функции, полезно для scroll/resize-событий.
function throttle(fn: Function, delay: number) {
let last = 0;
return (...args: any[]) => {
const now = Date.now();
if (now - last >= delay) {
last = now;
fn(...args);
}
};
}
2. Debounce
Откладывает выполнение функции до окончания серии вызовов.
function debounce(fn: Function, delay: number) {
let timeout: ReturnType<typeof setTimeout>;
return (...args: any[]) => {
clearTimeout(timeout);
timeout = setTimeout(() => fn(...args), delay);
};
}
3. Deep Clone (без structuredClone)
function deepClone<T>(obj: T): T {
return JSON.parse(JSON.stringify(obj));
}
Подходит для простых объектов, не содержащих функций, дат и т.п.
4. Safe Access (Optional Chaining + Fallback)
function get<T>(obj: any, path: string, fallback?: T): T {
return path.split('.').reduce((acc, key) => acc?.[key], obj) ?? fallback;
}
5. Wait (async delay)
function wait(ms: number) {
return new Promise(resolve => setTimeout(resolve, ms));
}
6. Generate UUID v4
function uuidv4() {
return crypto.randomUUID(); // нативно в современных браузерах
}
7. Copy to Clipboard
async function copyToClipboard(text: string) {
try {
await navigator.clipboard.writeText(text);
} catch {
const textarea = document.createElement('textarea');
textarea.value = text;
document.body.appendChild(textarea);
textarea.select();
document.execCommand('copy');
document.body.removeChild(textarea);
}
}
8. Detect Outside Click (для dropdown/modals)
function onClickOutside(element: HTMLElement, callback: () => void) {
function handler(event: MouseEvent) {
if (!element.contains(event.target as Node)) {
callback();
}
}
document.addEventListener('click', handler);
return () => document.removeEventListener('click', handler); // для очистки
}
9. Download File from Blob
function downloadBlob(blob: Blob, filename: string) {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
a.click();
URL.revokeObjectURL(url);
}
10. Dynamic Script Loader (например, для внешних SDK)
function loadScript(src: string): Promise<void> {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = src;
script.async = true;
script.onload = () => resolve();
script.onerror = () => reject(new Error(
Failed to load ${src}));document.head.appendChild(script);
});
}
CodeBase | Frontend | #JS
❤2