«Опять лагает»: где искать слабые места во фронтенде
Если сайт тормозит и работает не так быстро, как вам хотелось бы, ему нужен аудит — на это потребуется примерно 1 рабочий день.
Роман Игнатович, фронт-тимлид Далее, готов сэкономить эти бесценные 8 часов вашего рабочего времени. Он собрал чек-лист типичных ошибок во фронтенде, из-за которых всё лагает, с понятными способами их устранения.
Больше технических разборов кейсов, советов и вакансий для разработчиков — в канале Далее.
Подписывайтесь!
#реклама
О рекламодателе
Если сайт тормозит и работает не так быстро, как вам хотелось бы, ему нужен аудит — на это потребуется примерно 1 рабочий день.
Роман Игнатович, фронт-тимлид Далее, готов сэкономить эти бесценные 8 часов вашего рабочего времени. Он собрал чек-лист типичных ошибок во фронтенде, из-за которых всё лагает, с понятными способами их устранения.
Больше технических разборов кейсов, советов и вакансий для разработчиков — в канале Далее.
Подписывайтесь!
#реклама
О рекламодателе
🔥1
Автоматическое изменение высоты textarea — частая задача в формах, чатах и комментариях. Обычно для этого используют JavaScript, но современные браузеры уже умеют делать это нативно через CSS.
Как работает:
• field-sizing: content включает автоматический расчёт размеров поля;
• textarea начинает подстраиваться под объём текста;
• высота увеличивается по мере ввода;
• браузер сам рассчитывает размеры без JS-логики.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍26❤8🔥5
This media is not supported in your browser
VIEW IN TELEGRAM
Крутой материал для тех, кто изучает frontend или хочет быстро освежить базу по HTML. Здесь собрана действительно большая база — от структуры HTML-документа, тегов и атрибутов до форм, семантической вёрстки, мультимедиа, HTML5 API и accessibility.
Оставляю ссылочку: GitHub📱
Please open Telegram to view this post
VIEW IN TELEGRAM
1❤16👍7🔥6
Почему textarea часто ломает layout?
По умолчанию
Пользователь легко может растянуть её по ширине и сломать
Обычно никто это не контролирует.
Из-за этого форма начинает разъезжаться, особенно в боковых панелях, модальных окнах и узких контейнерах.
Лучше сразу ограничить направление
Теперь пользователь может увеличить высоту, но ширина
Если
Это особенно полезно для сложных форм.
🔥 Контроль
📣 Code Ready | #совет
По умолчанию
textarea можно тянуть во все стороны.Пользователь легко может растянуть её по ширине и сломать
grid, flex или весь form-layout.Обычно никто это не контролирует.
textarea {
resize: both;
}Из-за этого форма начинает разъезжаться, особенно в боковых панелях, модальных окнах и узких контейнерах.
Лучше сразу ограничить направление
resize.textarea {
resize: vertical;
}Теперь пользователь может увеличить высоту, но ширина
layout остаётся стабильной.Если
resize вообще не нужен:textarea {
resize: none;
}Это особенно полезно для сложных форм.
.modal textarea,
.sidebar textarea {
resize: vertical;
}
resize убирает неприятные layout-баги в формах и делает UI заметно стабильнее.Please open Telegram to view this post
VIEW IN TELEGRAM
1❤15👍8🔥4🤝2
Псевдокласс
:picture-in-picture в CSS применяется к видео, которое находится в режиме «картинка в картинке». Он позволяет стилизовать элемент <video>, когда пользователь вынес его в плавающее окно поверх других приложений или вкладок.Как это используется:
• изменение оформления видео в PiP-режиме;
• визуальная индикация активного режима воспроизведения;
• адаптация интерфейса под плавающее окно.
Комбинируйте с соседними селекторами (
~, +) и :has(), чтобы менять другие элементы интерфейса, пока видео в PiP.Please open Telegram to view this post
VIEW IN TELEGRAM
1❤14🔥8👍7
Почему innerHTML += иногда ведёт себя не так, как ожидаешь?
На первый взгляд это выглядит как самый простой способ что-то добавить в DOM — вроде бы просто дописал кусок HTML и всё. Но внутри браузер работает не так, и из-за этого появляются странные эффекты, когда вроде ничего особенного не сделал, а поведение страницы меняется.
По ощущениям просто добавили один
Упрощённо это примерно вот так:
И уже отсюда становится понятно, почему начинают вылезать побочные эффекты.
Допустим, у тебя есть кнопка с обработчиком:
После такого обновления DOM-поддерево контейнера заменяется новым. Визуально ты видишь тот же интерфейс, но старые узлы уничтожаются и создаются заново. Поэтому все обработчики событий, навешанные через
Та же история с ссылками на элементы:
И это особенно хорошо видно, когда начинаешь делать такие вещи в цикле:
Каждый раз браузер берёт текущее содержимое, сериализует его, парсит заново и пересоздаёт DOM внутри контейнера. На маленьких объёмах это почти незаметно, но когда элементов становится много — начинает сильно тормозить, потому что ты постоянно пересоздаёшь одно и то же дерево.
Поэтому в реальной практике так обычно не делают и используют более прямые DOM-методы.
Тут уже всё проще: создаёшь узел и просто добавляешь его в DOM, без пересборки контейнера.
Есть ещё вариант со строками, но без пересоздания всего содержимого:
Он вставляет кусок точечно в DOM, не пересоздавая существующие узлы, поэтому поведение стабильнее.
Если нужно добавить много элементов сразу, обычно используют
Тут всё собирается в памяти и вставляется одной операцией, без промежуточных пересборок и перерисовок.
🔥 Коротко, суть в том, что
📣 Code Ready | #практика
На первый взгляд это выглядит как самый простой способ что-то добавить в DOM — вроде бы просто дописал кусок HTML и всё. Но внутри браузер работает не так, и из-за этого появляются странные эффекты, когда вроде ничего особенного не сделал, а поведение страницы меняется.
const list = document.querySelector('.list');
list.innerHTML += `
<li>Новый элемент</li>
`;
По ощущениям просто добавили один
li, но на деле браузер не дописывает HTML внутрь DOM. Он делает иначе: берёт текущее содержимое, сериализует его в строку, добавляет новый кусок и затем заново парсит HTML, пересоздавая DOM-узлы внутри контейнера.Упрощённо это примерно вот так:
list.innerHTML = list.innerHTML + `
<li>Новый элемент</li>
`;
И уже отсюда становится понятно, почему начинают вылезать побочные эффекты.
Допустим, у тебя есть кнопка с обработчиком:
button.addEventListener('click', () => {
console.log('click');
});
container.innerHTML += `
<div>Новый блок</div>
`;
После такого обновления DOM-поддерево контейнера заменяется новым. Визуально ты видишь тот же интерфейс, но старые узлы уничтожаются и создаются заново. Поэтому все обработчики событий, навешанные через
addEventListener, на этих элементах теряются.Та же история с ссылками на элементы:
const item = document.querySelector('.item');
container.innerHTML += `
<div>Новый блок</div>
`;
console.log(item.isConnected); // false
item остаётся в переменной, но к текущему DOM он уже не привязан. Он существует как объект, но находится вне дерева документа, потому что был заменён старый поддерево контейнера.И это особенно хорошо видно, когда начинаешь делать такие вещи в цикле:
for (let i = 0; i < 1000; i++) {
list.innerHTML += `<li>${i}</li>`;
}
Каждый раз браузер берёт текущее содержимое, сериализует его, парсит заново и пересоздаёт DOM внутри контейнера. На маленьких объёмах это почти незаметно, но когда элементов становится много — начинает сильно тормозить, потому что ты постоянно пересоздаёшь одно и то же дерево.
Поэтому в реальной практике так обычно не делают и используют более прямые DOM-методы.
const li = document.createElement('li');
li.textContent = 'Новый элемент';
list.append(li);
Тут уже всё проще: создаёшь узел и просто добавляешь его в DOM, без пересборки контейнера.
Есть ещё вариант со строками, но без пересоздания всего содержимого:
list.insertAdjacentHTML(
'beforeend',
'<li>Новый элемент</li>'
);
Он вставляет кусок точечно в DOM, не пересоздавая существующие узлы, поэтому поведение стабильнее.
Если нужно добавить много элементов сразу, обычно используют
DocumentFragment, чтобы не дёргать DOM по сто раз:const fragment = document.createDocumentFragment();
for (let i = 0; i < 1000; i++) {
const li = document.createElement('li');
li.textContent = i;
fragment.appendChild(li);
}
list.appendChild(fragment);
Тут всё собирается в памяти и вставляется одной операцией, без промежуточных пересборок и перерисовок.
innerHTML += — это не добавить элемент, как это выглядит интуитивно. Это скорее пересобери мне весь контейнер заново через HTML-строку и вставь результат. Поэтому в живых интерфейсах он иногда ведёт себя неожиданно и может неприятно влиять и на логику, и на производительность.Please open Telegram to view this post
VIEW IN TELEGRAM
1❤15👍11🔥6
Привет! В этом гайде соберём аккордеон для часто задаваемых вопросов — лёгкий и доступный.
Ключевые моменты:
• HTML: семантическая разметка и aria-атрибуты для доступности.
• CSS: плавное открытие/закрытие блоков без прыжков.
• JavaScript: простой toggle и синхронизация с aria-expanded.
Полезный UI-паттерн, который улучшает читаемость и делает интерфейс чище.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤15👍6🤝5👎1🔥1
Генерируем UUID без библиотек!
Очень частая задача: создать уникальный id для пользователя, заказа, файла или любой сущности.
Раньше для этого почти всегда тянули библиотеки типа uuid.
Хотя в современном JavaScript это уже есть нативно.
Метод сразу возвращает криптографически стойкий UUID v4.
Результат выглядит так:
Подходит для случаев, где нужен уникальный идентификатор: id сущностей, ключи записей, request/session id, временные идентификаторы.
Для секретных токенов (reset password, API tokens) лучше использовать
В браузере работает в secure context — HTTPS или localhost.
🔥
📣 JS Ready | #совет
Очень частая задача: создать уникальный id для пользователя, заказа, файла или любой сущности.
Раньше для этого почти всегда тянули библиотеки типа uuid.
import { v4 as uuid } from 'uuid';Хотя в современном JavaScript это уже есть нативно.
crypto.randomUUID()
Метод сразу возвращает криптографически стойкий UUID v4.
const id = crypto.randomUUID();
Результат выглядит так:
36b8f84d-df4e-4d49-b662-bcde71a8764fПодходит для случаев, где нужен уникальный идентификатор: id сущностей, ключи записей, request/session id, временные идентификаторы.
Для секретных токенов (reset password, API tokens) лучше использовать
crypto.getRandomValues() или crypto.randomBytes().В браузере работает в secure context — HTTPS или localhost.
crypto.randomUUID() — простой способ получать уникальные id.Please open Telegram to view this post
VIEW IN TELEGRAM
1👍23🔥7❤5
Почему чтение offsetHeight иногда тормозит интерфейс?
На первый взгляд кажется, что получить высоту элемента — это самая обычная операция. Ты просто читаешь свойство и получаешь число. Но внутри браузера всё немного интереснее.
Например:
Кажется, что мы просто изменили ширину и прочитали высоту. Но есть нюанс. После изменения DOM или CSS браузер не обязан сразу пересчитывать размеры элементов. Наоборот, современные движки стараются откладывать такие вычисления, чтобы не делать лишнюю работу после каждого изменения.
Упрощённо это выглядит так:
Именно поэтому чтение некоторых свойств может заставить браузер синхронно обновить style и layout, если после изменений они ещё не актуальны.
Например:
Но важно понимать: сами по себе эти свойства не медленные. Если layout уже актуален, браузер просто вернёт готовое значение.
Проблемы обычно начинаются, когда чтение размеров смешивают с изменением стилей внутри цикла:
На десяти элементах ты, скорее всего, ничего не заметишь. Но если их сотни или тысячи, можно получить forced synchronous layout — ситуацию, когда JavaScript заставляет браузер выполнять дорогие вычисления прямо во время выполнения скрипта.
Особенно неприятно это становится в анимациях:
Если такой код выполняется каждый кадр, браузеру приходится постоянно переключаться между изменением стилей и пересчётом layout. В результате главный поток занят вычислениями, а пользователь начинает замечать рывки и пропуски кадров.
Поэтому один из самых простых приёмов — разделять запись и чтение. Вот так плохо:
Лучше будет так:
Так браузер сможет объединить изменения и выполнить один пересчёт вместо множества лишних. Для визуальных изменений также часто используют
🔥 Если коротко: проблема не в
📣 Code Ready | #практика
На первый взгляд кажется, что получить высоту элемента — это самая обычная операция. Ты просто читаешь свойство и получаешь число. Но внутри браузера всё немного интереснее.
Например:
const box = document.querySelector('.box');
box.style.width = '500px';
console.log(box.offsetHeight);
Кажется, что мы просто изменили ширину и прочитали высоту. Но есть нюанс. После изменения DOM или CSS браузер не обязан сразу пересчитывать размеры элементов. Наоборот, современные движки стараются откладывать такие вычисления, чтобы не делать лишнюю работу после каждого изменения.
Упрощённо это выглядит так:
box.style.width = '500px';
// браузер пока просто запомнил изменение
console.log(box.offsetHeight);
// здесь уже нужны реальные размеры,
// поэтому приходится пересчитать layout
Именно поэтому чтение некоторых свойств может заставить браузер синхронно обновить style и layout, если после изменений они ещё не актуальны.
Например:
element.offsetWidth;
element.offsetHeight;
element.clientWidth;
element.clientHeight;
element.scrollHeight;
element.getBoundingClientRect();
Но важно понимать: сами по себе эти свойства не медленные. Если layout уже актуален, браузер просто вернёт готовое значение.
Проблемы обычно начинаются, когда чтение размеров смешивают с изменением стилей внутри цикла:
const items = document.querySelectorAll('.item');
items.forEach(item => {
item.style.height = '100px';
console.log(item.offsetHeight);
});
На десяти элементах ты, скорее всего, ничего не заметишь. Но если их сотни или тысячи, можно получить forced synchronous layout — ситуацию, когда JavaScript заставляет браузер выполнять дорогие вычисления прямо во время выполнения скрипта.
Особенно неприятно это становится в анимациях:
function animate(elements) {
elements.forEach(element => {
element.style.width = '200px';
const height = element.offsetHeight;
element.style.height = `${height}px`;
});
}
Если такой код выполняется каждый кадр, браузеру приходится постоянно переключаться между изменением стилей и пересчётом layout. В результате главный поток занят вычислениями, а пользователь начинает замечать рывки и пропуски кадров.
Поэтому один из самых простых приёмов — разделять запись и чтение. Вот так плохо:
items.forEach(item => {
item.style.width = '200px';
console.log(item.offsetHeight);
});
Лучше будет так:
items.forEach(item => {
item.style.width = '200px';
});
items.forEach(item => {
console.log(item.offsetHeight);
});
Так браузер сможет объединить изменения и выполнить один пересчёт вместо множества лишних. Для визуальных изменений также часто используют
requestAnimationFrame, потому что он запускает код перед следующим циклом отрисовки браузера. Но сам по себе requestAnimationFrame не избавляет от layout thrashing. Если внутри его callback продолжать чередовать изменения DOM и чтение размеров, синхронные перерасчёты всё равно останутся.offsetHeight, а в том, когда ты его читаешь. После изменений DOM или CSS он может заставить браузер синхронно пересчитать layout. Именно чередование записей и чтений чаще всего становится причиной лишних тормозов.Please open Telegram to view this post
VIEW IN TELEGRAM
1👍15❤7🔥7
This media is not supported in your browser
VIEW IN TELEGRAM
Здесь собраны качественные статьи, инструменты, библиотеки и другие полезные ресурсы для работы со стилями. Особенно полезен тем, кто хочет лучше разобраться в современных возможностях CSS, быстрее находить решения для вёрстки и держать под рукой материалы. Хорошая база как для обучения, так и для повседневной разработки.
Оставляю ссылочку: GitHub📱
Please open Telegram to view this post
VIEW IN TELEGRAM
❤13👍8🤝5
This media is not supported in your browser
VIEW IN TELEGRAM
Так сказал мой друг из Африки, когда увидел этот стол)
Не знаю уж че за сетап, меня зовут Саша и качественную необычную мебель из натурального дерева я делаю уже больше 12-ти лет, столько же занимаюсь и темой здоровья.
Когда я услышал, что до 10% смертности связано с сидячим образом жизни, меня это поразило и я задался целью делать максимально функциональные и полезные рабочие пространства, ибо геморрой в 30 это конечно довольно нишево, но все же сомнительно 😂
Ну а собрать такой комплект под свои задачи и при этом сразу прикинуть цены вы можете в удобном Mini App конструкторе
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2👍2👎1🔥1