Бесплатные уроки по HTML/CSS/JavaScript, лайфхаки для верстальщика и бесплатные дизайн-макеты для портфолио.
По рекламе — @yankovsky_ads
Купить рекламу напрямую https://telega.in/c/glo_academy
Post #2734
145
GL @glo_academy
const channel = new BroadcastChannel('auth');
// во вкладке, где нажали «Выйти»
channel.postMessage({ type: 'logout' });
// в остальных вкладках сайта
channel.onmessage = (e) => {
if (e.data.type === 'logout') redirect('/login');
};classList.add('loading'), потом add('error'), где-то забыли снять — и на элементе одновременно висят loading и completed. Какой стиль победит, решает порядок правил в файле. Вместо трёх классов держи состояние в одном data-атрибуте:<div class="order" data-state="loading">…</div>
order.dataset.state = 'completed';
.order[data-state="loading"] { opacity: 0.5; }
.order[data-state="error"] { border-color: red; }
.order[data-state="completed"] { border-color: green; }
dataset.state, а CSS цепляется за него селектором [data-state="…"]..cards {
display: grid;
grid-template-columns:
repeat(auto-fill, minmax(240px, 1fr));
gap: 16px;
}try {
const res = await fetch(url, {
signal: AbortSignal.timeout(5000)
});
const data = await res.json();
} catch (err) {
if (err.name === 'TimeoutError') {
// ответа нет 5 секунд
}
}/* одна строка */
.title {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
/* три строки */
.desc {
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
}
nowrap запрещает перенос, hidden прячет хвост, ellipsis дорисовывает многоточие. Несколько строк: -webkit-line-clamp задаёт, сколько оставить; соседние три строки обязательны..col {
animation: up linear both;
animation-timeline: view();
animation-range: entry 0% cover 100%;
}
.col:nth-child(2) { animation-name: down; }
@keyframes up { to { translate: 0 -30% } }
@keyframes down { to { translate: 0 30% } }view() привязывает анимацию к положению колонки на экране: проехала колонка — продвинулись кадры. animation-range задаёт участок: от появления снизу (entry 0%) до ухода за верхний край (cover 100%). В @keyframes крайние колонки едут на 30% высоты вверх, средняя — вниз.animation-timeline ставь после шорткода animation, иначе он его сбросит. Chrome 115+, Safari 26+, Firefox пока Nightly — оборачивай в @supports.node:zlib.import { ZipBuffer } from 'node:zlib';
import { readFileSync, writeFileSync } from 'node:fs';
const zip = new ZipBuffer(readFileSync('archive.zip'));
for (const [name, entry] of zip) console.log(name, entry.size);
await zip.add('readme.txt', Buffer.from('Привет'));
zip.delete('draft.txt');
writeFileSync('archive.zip', await zip.toBuffer());add кладёт файл, delete убирает, toBuffer собирает архив заново.ZipBuffer берёт записи по одной прямо из буфера, а ZipFile.stream() отдаёт запись потоком.maxSize ставишь предел на распакованный размер: архив на пару килобайт, разворачивающийся в гигабайты, дальше лимита не пойдёт.
<label>
Телефон
<input type="tel" inputmode="tel">
</label>
<label>
Индекс
<input type="text" inputmode="numeric">
</label>
inputmode.type говорит браузеру, какие данные в поле и как их проверять, а inputmode — только какую клавиатуру открыть на мобильном. Поэтому их ставят вместе: type="tel" inputmode="tel", и человек видит телефонную клавиатуру вместо букв. Ещё есть numeric, decimal, email, url и search.type="text" с inputmode="numeric": у type="number" сбоку стрелки-спиннеры, а ведущие нули он съедает — индекс 01234 станет 1234.
h1 {
text-wrap: balance;
}
text-wrap: balance заставляет браузер перебрать точки переноса и выбрать ту раскладку, где строки выходят примерно одной длины. Одинокое слово подтягивается наверх, а разметку трогать не нужно: поменяется текст — браузер пересчитает заново.
This post (sticker, poll or similar) has no web preview. Open in Telegram