Хватит использовать библиотеки для рейтингов. Я сделал компонент звездочного рейтинга только на CSS с поддержкой половинок звезд всего в 60 строк. Без JavaScript. Полностью доступный. С плавным hover.
Я посмотрел существующие pure-CSS решения и почти везде одни и те же проблемы.
Либо нет поддержки половинок, либо завязка на FontAwesome, либо дерганый и нестабильный hover.
В итоге я сделал свое решение, используя только radio input’ы, label’ы и SVG-маски.
Ключевая идея упирается в ограничение CSS:
он умеет выбирать только элементы, идущие после текущего (через ~).
А в рейтинге звезд нужно подсвечивать звезды до той, на которую навели курсор.
Решение простое: переворачиваем DOM и визуально отражаем его через
Порядок в DOM: 5★ → 0.5★
Визуальный порядок: 0.5★ → 5★
Теперь
Для половинок я разделил каждую звезду на два
Каждый label использует SVG-маску половинки звезды.
Почему маска, а не
У background-image нельзя динамически менять цвет заливки SVG.
А mask работает как трафарет — сквозь него просто просвечивает
В итоге hover — это просто смена цвета.
Простые селекторы. Никаких JS-обработчиков.
Отступы между звездами ломают UX hover’а — появляются «мертвые зоны», где ничего не подсвечивается.
Фикс такой: расширяем ширину label, но оставляем
Зазор виден визуально, но зона hover остается непрерывной.
Radio-кнопки визуально скрыты, но остаются в DOM.
Скринридеры видят:
* нормальные radio input’ы
* label’ы с aria-label вроде
* полноценную навигацию с клавиатуры
CSS-only — это не компромисс по доступности.
@WebDev_Plus
Я посмотрел существующие pure-CSS решения и почти везде одни и те же проблемы.
Либо нет поддержки половинок, либо завязка на FontAwesome, либо дерганый и нестабильный hover.
В итоге я сделал свое решение, используя только radio input’ы, label’ы и SVG-маски.
Ключевая идея упирается в ограничение CSS:
он умеет выбирать только элементы, идущие после текущего (через ~).
А в рейтинге звезд нужно подсвечивать звезды до той, на которую навели курсор.
Решение простое: переворачиваем DOM и визуально отражаем его через
flex-direction: row-reverse..star-rating {
display: inline-flex;
flex-direction: row-reverse;
justify-content: flex-end;
}Порядок в DOM: 5★ → 0.5★
Визуальный порядок: 0.5★ → 5★
Теперь
~ выбирает визуально предыдущие звезды.Для половинок я разделил каждую звезду на два
<label> — левую и правую половину.Каждый label использует SVG-маску половинки звезды.
nth-of-type(odd) — правая половинаnth-of-type(even) — левая половинаПочему маска, а не
background-image?У background-image нельзя динамически менять цвет заливки SVG.
А mask работает как трафарет — сквозь него просто просвечивает
background-color.В итоге hover — это просто смена цвета.
/* Подсветка при наведении */
label:hover,
label:hover ~ label {
background-color: goldenrod;
}
/* Подсветка выбранного */
input:checked ~ label {
background-color: gold;
}
Простые селекторы. Никаких JS-обработчиков.
Отступы между звездами ломают UX hover’а — появляются «мертвые зоны», где ничего не подсвечивается.
Фикс такой: расширяем ширину label, но оставляем
mask-size прежним.Зазор виден визуально, но зона hover остается непрерывной.
Radio-кнопки визуально скрыты, но остаются в DOM.
Скринридеры видят:
* нормальные radio input’ы
* label’ы с aria-label вроде
3 1/2 stars* полноценную навигацию с клавиатуры
CSS-only — это не компромисс по доступности.
@WebDev_Plus
1👍7
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
Однострочный приём в JavaScript, чтобы вытащить уникальные значения из массива объектов.
@WebDev_Plus
const products = [
{ product: "Laptop", category: "Electronics", price: 999, brand: "Dell" },
{ product: "Mouse", category: "Electronics", price: 25, brand: "Logitech" },
{ product: "Shirt", category: "Clothing", price: 29, brand: "Nike" },
{ product: "Sneakers", category: "Footwear", price: 89, brand: "Adidas" },
{ product: "Watch", category: "Accessories", price: 299, brand: "Fossil" },
{ product: "Jacket", category: "Clothing", price: 179, brand: "Columbia" },
];
// Получить уникальные категории
const categories = [...new Set(products.map((item) => item.category))];
console.log(categories);
// ВЫВОД: [ 'Electronics', 'Clothing', 'Footwear', 'Accessories' ]
@WebDev_Plus
👍5👎1🤔1
This media is not supported in your browser
VIEW IN TELEGRAM
Сгенерируй headless-бэкенд для e-commerce за считанные секунды 🤯
Есть open-source проект Storecraft, который позволяет быстро поднять полностью AI-управляемый бэкенд интернет-магазина. Ты сам выбираешь стек, базу данных и все необходимые компоненты.
@WebDev_Plus
Есть open-source проект Storecraft, который позволяет быстро поднять полностью AI-управляемый бэкенд интернет-магазина. Ты сам выбираешь стек, базу данных и все необходимые компоненты.
@WebDev_Plus
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1
This media is not supported in your browser
VIEW IN TELEGRAM
Нашёл ещё одну новую фронтенд-игрушку на GitHub. Штука называется Its Hover с лозунгом “Moves for Intent”, хотя по факту она просто слегка дерзко подёргивается, когда наводишь курсор. Забавно выглядит.
🔗 [https://github.com/itshover/itshover]
@WebDev_Plus
@WebDev_Plus
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3❤2😁1
This media is not supported in your browser
VIEW IN TELEGRAM
Страница, на которой вам шаг за шагом объясняют любой код
С визуальным руководством по выполнению.
Для Python, JavaScript, C, C++ и Java
→ http://pythontutor.com
@WebDev_Plus
С визуальным руководством по выполнению.
Для Python, JavaScript, C, C++ и Java
→ http://pythontutor.com
@WebDev_Plus
👍1
Крутой проект. Изучай что угодно с DeepTutor.
Это персонализированный учебный ассистент на базе ИИ.
Это далеко не просто чат-бот. Он помнит твой контекст, прогресс и подстраивается под твой стиль обучения.
И в довесок ко всему, проект с открытым исходным кодом: https://github.com/HKUDS/DeepTutor
@WebDev_Plus
Это персонализированный учебный ассистент на базе ИИ.
Это далеко не просто чат-бот. Он помнит твой контекст, прогресс и подстраивается под твой стиль обучения.
И в довесок ко всему, проект с открытым исходным кодом: https://github.com/HKUDS/DeepTutor
@WebDev_Plus
🔥2
Знал ли ты?
В Node.js есть встроенная утилита loadEnvFile.
Она делает ровно то же самое, что и dotenv, но без единой зависимости. По сути, это рантайм-эквивалент CLI-опции --env-file.
Вот как с её помощью можно воспроизвести порядок загрузки env-файлов, как это делает Next.js:
@WebDev_Plus
В Node.js есть встроенная утилита loadEnvFile.
Она делает ровно то же самое, что и dotenv, но без единой зависимости. По сути, это рантайм-эквивалент CLI-опции --env-file.
Вот как с её помощью можно воспроизвести порядок загрузки env-файлов, как это делает Next.js:
import { loadEnvFile } from 'node:process'
export function loadEnv() {
const nodeEnv = process.env.NODE_ENV || 'development'
// Load in order of precedence
const files = [
`.env.${nodeEnv}.local`,
nodeEnv === 'test' ? null : '.env.local',
`.env.${nodeEnv}`,
'.env',
].filter((file): file is string => !!file)
for (const file of files) {
try {
loadEnvFile(file)
break // Stop after the first successful load
} catch {}
}
}@WebDev_Plus
This media is not supported in your browser
VIEW IN TELEGRAM
пик JavaScript-безумия: если вызвать setInterval с таймаутом больше чем INT_MAX, вместо того чтобы кинуть ошибку (что было бы логично), setInterval молча начнет дергать твой колбэк каждую миллисекунду
@WebDev_Plus
@WebDev_Plus
This media is not supported in your browser
VIEW IN TELEGRAM
Открытый и самохостящийся скрин-рекордер для Mac и Windows с неограниченной бесплатной локальной записью, плавными эффектами зума, поддержкой веб-камеры, автоматическими субтитрами и полноценным видеоредактором. Что выберешь ты? Открытый исходный код ✌️
@WebDev_Plus
@WebDev_Plus
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4👏3
TypeScript умеет вытаскивать типы через indexed access — помогает не дублировать типы и не объявлять всё заново.
@WebDev_Plus
interface UserAPIResponse {
user: {
id: number;
name: string;
email: string;
roles: Array<{
name: string;
permissions: string[];
scope: {
resource: string;
actions: string[];
};
}>;
metadata: {
createdAt: string;
lastLogin: string;
};
};
}
// Extract types without redefining
type User = UserAPIResponse["user"];
// Extract Nested Object
type UserMetadata = UserAPIResponse["user"]["metadata"];
// Extract Array Element Type
type Role = UserAPIResponse["user"]["roles"][number];
// Extract from Nested Array
type Permission = Role["permissions"][number];
// OR (direct access)
type Permission2 = UserAPIResponse["user"]["roles"][number]["permissions"][number];
// Extract Nested Object from Nested Array
type RoleScope = UserAPIResponse["user"]["roles"][number]["scope"];
// OR (via Role type)
type RoleScope2 = Role["scope"];@WebDev_Plus
👍3❤1🔥1😁1
This media is not supported in your browser
VIEW IN TELEGRAM
Только что вышла версия 1.4.0 расширения Laravel для VS Code, и в ней подъехала очень приятная штука:
теперь artisan:make можно запускать прямо из Command Palette.
Меньше переключений контекста, быстрее навигация и генерация — просто вызываешь палитру и создаёшь нужный класс/модель/контроллер на месте.
@WebDev_Plus
теперь artisan:make можно запускать прямо из Command Palette.
Меньше переключений контекста, быстрее навигация и генерация — просто вызываешь палитру и создаёшь нужный класс/модель/контроллер на месте.
@WebDev_Plus
❤5
JavaScript Proxy сильно выручает, когда нужно ловить обновления стейта.
@WebDev_Plus
// Building a reactive store with Proxy
const createReactiveStore = (data, onChange) => {
return new Proxy(data, {
set(target, key, value) {
const oldValue = target[key];
target[key] = value;
onChange(key, value, oldValue);
return true;
},
});
};
// Usage
const state = createReactiveStore(
{ count: 0, status: 'idle', isOnline: false },
(key, newVal, oldVal) => {
console.log(`🔁 ${key}: ${oldVal} -> ${newVal}`);
// You can handle business logic or UI updates here
}
);
state.count = 5; // 🔁 count: 0 -> 5
state.status = 'loading'; // 🔁 status: idle -> loading
state.isOnline = true; // 🔁 isOnline: false -> true
state.status = 'error'; // 🔁 status: loading -> error
state.count++; // 🔁 count: 5 -> 6
@WebDev_Plus
👍2👏2❤1🔥1
This media is not supported in your browser
VIEW IN TELEGRAM
Пошаговые уроки с практическими примерами охватывают ключевые темы: от базовой структуры страницы и стилей до flexbox и адаптивного дизайна, что делает его идеальной отправной точкой для тех, кто хочет уверенно войти в мир веб-разработки ☀️
@WebDev_Plus
@WebDev_Plus
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1😁1
Невозможно распарсить HTML регулярками.
Из этого родился самый известный пост на StackOverflow.
Регулярные выражения это грамматика третьего типа по Хомскому. Идеально для линейных паттернов, но без способности считать.
HTML это грамматика второго типа. Другими словами, там есть вложенность. Чтобы сопоставить закрывающий div, нужно знать сколько открывающих div было до этого.
Поэтому идея соблазнительная, но технически регексы не способны корректно парсить HTML. Ты начнешь хитрить и все равно наломаешь дров.
Но вам действительно стоит прочитать оригинал поста, он очень смешной и на данный момент является известной частью истории Интернета:
https://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags
@WebDev_Plus
Из этого родился самый известный пост на StackOverflow.
Регулярные выражения это грамматика третьего типа по Хомскому. Идеально для линейных паттернов, но без способности считать.
HTML это грамматика второго типа. Другими словами, там есть вложенность. Чтобы сопоставить закрывающий div, нужно знать сколько открывающих div было до этого.
Поэтому идея соблазнительная, но технически регексы не способны корректно парсить HTML. Ты начнешь хитрить и все равно наломаешь дров.
Но вам действительно стоит прочитать оригинал поста, он очень смешной и на данный момент является известной частью истории Интернета:
https://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags
@WebDev_Plus
❤3
Система управления SSL-сертификатами с поддержкой multi-DNS и REST API
https://github.com/fabriziosalmi/certmate
@WebDev_Plus
https://github.com/fabriziosalmi/certmate
@WebDev_Plus
❤1
This media is not supported in your browser
VIEW IN TELEGRAM
Chrome DevTools теперь умеет тормозить сеть на уровне конкретных запросов.
Этого давно хотели. Теперь можно эмулировать медленные сетевые условия не для всей страницы целиком, а для отдельных запросов.
Это удобно для проверки как приложение ведет себя если, скажем, отваливается или долго грузится конкретный ресурс — картинка, скрипт или API вызов.
@WebDev_Plus
Этого давно хотели. Теперь можно эмулировать медленные сетевые условия не для всей страницы целиком, а для отдельных запросов.
Это удобно для проверки как приложение ведет себя если, скажем, отваливается или долго грузится конкретный ресурс — картинка, скрипт или API вызов.
@WebDev_Plus
❤4
This media is not supported in your browser
VIEW IN TELEGRAM
Вам сложно создавать дизайны для ваших веб-сайтов или приложений?
Google запустил Stitch, который генерирует пользовательский интерфейс с помощью искусственного интеллекта.
Он бесплатный, а результат впечатляет
@WebDev_Plus
Google запустил Stitch, который генерирует пользовательский интерфейс с помощью искусственного интеллекта.
Он бесплатный, а результат впечатляет
@WebDev_Plus
🔥2👎1
Забавный факт про JavaScript: если передать строку с числом в конструктор Date, получится вполне безумный результат
@WebDev_Plus
new Date("0") дает Jan 1, 2000
new Date("1") дает Jan 1, 2001 (+1 год, ок...)
new Date("2") дает Feb 1, 2001 (+1 месяц, ??????)@WebDev_Plus
😁4