Позиционирование элементов с помощью JS
CSS отлично справляется с позиционированием элементов, но иногда его не хватает. Учимся выбирать, когда нужен CSS, а когда — JS.
Время чтения: 11 мин
Открыть/закрыть навигацию по статье
- Кратко
- Когда использовать стили
- Когда использовать скрипты
- Как менять позиционирование на скриптах
- Изменять классы
- Изменять style
- Изменение margin или top / left / right / bottom
- Изменение transform
- Изменение кастомных свойств CSS
- Саша Беспоясов советует
Контрибьюторы:
Обновлено 16 ноября 2022
Кратко
Скопировать ссылку «Кратко» Скопировано
Элементы на странице можно позиционировать не только с помощью стилей, но и с помощью JavaScript. В этой статье мы рассмотрим ситуации, когда это оправдано и как таким позиционированием пользоваться.
Прежде чем мы приступим к непосредственно позиционированию, давайте определимся, зачем нам ещё один способ расставлять элементы, когда у нас уже есть CSS.
Когда использовать стили
Скопировать ссылку «Когда использовать стили» Скопировано
Используйте стили для позиционирования всегда, когда это возможно.
CSS — это инструмент, который специально был придуман для стилизации документов.
- Это работает в среднем быстрее.
- Это не собьёт с толку других разработчиков, которые будут читать ваш код.
- Это разделяет зоны ответственности между скриптами и стилями.
Когда использовать скрипты
Скопировать ссылку «Когда использовать скрипты» Скопировано
Используйте скрипты для позиционирования тогда, когда стилей не хватает.
CSS ограничен в обратной связи на действия пользователей на экране. В нём есть такие штуки как @keyframes , transition , :hover , :active , :focus и т. д., но этого не всегда достаточно.
Иногда нужно, чтобы в ответ на действия пользователя на странице происходили сложные преобразования или чтобы пользователи сами могли управлять анимациями на странице.
Такие случаи — это не просто стилизация документа, а скорее смесь из стилизации и программной логики. Чтобы решить такую задачу, нам нужны как инструменты стилизации (CSS), так и инструменты для программирования логики (JS).
Как менять позиционирование на скриптах
Скопировать ссылку «Как менять позиционирование на скриптах» Скопировано
Изменять положение элементов (как и любые стили элементов) на странице можно несколькими способами.
Изменять классы
Скопировать ссылку «Изменять классы» Скопировано
Допустим, мы хотим переместить элемент при клике на него в другое место. Для решения такой задачи нам вполне подойдёт способ с изменением класса у элемента.
.element /* Стили самого элемента. */> .element-initial /* Стили, определяющие начальное положение элемента на странице, например: */ transform: translateX(0px);> .element-final /* Стили, определяющие конечное положение, например: */ transform: translateX(50px);>.element /* Стили самого элемента. */ > .element-initial /* Стили, определяющие начальное положение элемента на странице, например: */ transform: translateX(0px); > .element-final /* Стили, определяющие конечное положение, например: */ transform: translateX(50px); >Элементу изначально заданы классы element element — initial , которые задают его стили, а также его начальное положение.
Теперь в ответ на действие пользователя (например, в ответ на клик), поменяем класс элемента, отвечающий за положение. Воспользуемся методом class List . toggle ( ) у элемента, чтобы добавить класс, если его нет на элементе, и убрать, если класс есть:
// Обрабатываем событие клика на элементе:element.addEventListener('click', () => element.classList.toggle('element-final') element.classList.toggle('element-initial')>)// Обрабатываем событие клика на элементе: element.addEventListener('click', () => element.classList.toggle('element-final') element.classList.toggle('element-initial') >)Тогда получим элемент, который меняет своё положение при клике на него:
Этот способ изменять стили элемента с помощью скриптов самый простой и чистый — все стили остаются описанными внутри CSS. Однако он не всегда подходит.
Использовать такой способ можно, когда мы заранее знаем, куда и откуда мы хотим переместить элемент, но не знаем момент, когда нам это понадобится.
Изменять style
Скопировать ссылку «Изменять style» Скопировано
Второй способ изменять положение элемента — менять атрибут style с помощью JS.
При работе со style следует помнить, что у этого атрибута высокая специфичность, из-за чего он будет перебивать основные стили элемента. Его следует использовать с осторожностью.
Он подойдёт в случае, когда мы мгновенно хотим отражать изменения на элементе, даже если не знаем, что и когда поменяется. Например, если мы хотим перемещать элемент мышкой на экране, нам может понадобиться менять его style .
Для изменения положения через style можно использовать разные свойства.
Изменение margin или top / left / right / bottom
Скопировать ссылку «Изменение margin или top / left / right / bottom» Скопировано
Первое, что приходит на ум — изменение соответствующих CSS-свойств типа margin или left / top / right / bottom .
Создадим элемент с классом element :
.element width: 50px; height: 50px; background: black; position: absolute;>.element width: 50px; height: 50px; background: black; position: absolute; >Теперь попробуем написать драг-н-дроп для мыши.
// Сперва создадим ссылку на этот элемент,// чтобы обрабатывать события на нём:const element = document.querySelector('.element') // Переменная dragging будет отвечать за состояние элемента.// Если его тащат, то переменная будет со значением true.// По умолчанию она false.let dragging = false // В переменных startX и startY мы будем держать координаты точки,// в которой находился элемент, когда мы начали его тащить мышью.let startX = 0let startY = 0 // При событии mousedown (когда на элемент нажимают мышью)// мы отмечаем dragging как true — значит, элемент начали тащить.element.addEventListener('mousedown', (e) => dragging = true // В значения для startX и startY мы помещаем положение курсора // через свойства события e.pageX и e.pageY. startX = e.pageX - Number.parseInt(element.style.left || 0) startY = e.pageY - Number.parseInt(element.style.top || 0) // Из положения курсора мы вычитаем отступы элемента, если они есть. // Вычитание отступов нам нужно, чтобы элемент «запоминал» // своё последнее положение, иначе мы всегда будем начинать тащить его // от начала экрана.>) // Далее мы обрабатываем событие перемещения мыши по body.// Мы наблюдаем именно за body, потому что хотим,// чтобы изменения работали на всей странице,// а не только внутри элемента element.document.body.addEventListener('mousemove', (e) => // Если элемент не тащат, то ничего не делаем. if (!dragging) return // Если тащат, то высчитываем новое положение, // вычитая начальное положение элемента из положения курсора. element.style.top = `$px` element.style.left = `$px`>) // Когда мы отпускаем мышь, мы отмечаем dragging как false.document.body.addEventListener('mouseup', () => dragging = false>)// Сперва создадим ссылку на этот элемент, // чтобы обрабатывать события на нём: const element = document.querySelector('.element') // Переменная dragging будет отвечать за состояние элемента. // Если его тащат, то переменная будет со значением true. // По умолчанию она false. let dragging = false // В переменных startX и startY мы будем держать координаты точки, // в которой находился элемент, когда мы начали его тащить мышью. let startX = 0 let startY = 0 // При событии mousedown (когда на элемент нажимают мышью) // мы отмечаем dragging как true — значит, элемент начали тащить. element.addEventListener('mousedown', (e) => dragging = true // В значения для startX и startY мы помещаем положение курсора // через свойства события e.pageX и e.pageY. startX = e.pageX - Number.parseInt(element.style.left || 0) startY = e.pageY - Number.parseInt(element.style.top || 0) // Из положения курсора мы вычитаем отступы элемента, если они есть. // Вычитание отступов нам нужно, чтобы элемент «запоминал» // своё последнее положение, иначе мы всегда будем начинать тащить его // от начала экрана. >) // Далее мы обрабатываем событие перемещения мыши по body. // Мы наблюдаем именно за body, потому что хотим, // чтобы изменения работали на всей странице, // а не только внутри элемента element. document.body.addEventListener('mousemove', (e) => // Если элемент не тащат, то ничего не делаем. if (!dragging) return // Если тащат, то высчитываем новое положение, // вычитая начальное положение элемента из положения курсора. element.style.top = `$e.pageY - startY>px` element.style.left = `$e.pageX - startX>px` >) // Когда мы отпускаем мышь, мы отмечаем dragging как false. document.body.addEventListener('mouseup', () => dragging = false >)Тогда получится вот такой драг-н-дроп:
Это работает, но не очень эффективно, потому что изменения в этих свойствах заставляют браузер делать много лишней работы.
Мы можем сделать лучше.
Изменение transform
Скопировать ссылку «Изменение transform» Скопировано
Перепишем наш драг-н-дроп, меняя теперь значение свойства transform .
Основа кода останется той же, стили и разметка не поменяются вовсе. В скриптах мы слегка изменим определение положения элемента.
// . element.addEventListener('mousedown', (e) => dragging = true // В этот раз мы не сможем считать нужные нам значения напрямую. // Вместо этого нам потребуется вначале вычислить стиль элемента // через window.getComputedStyle(), а затем узнать значение // свойства transform. const style = window.getComputedStyle(element) // Мы могли бы просто считать значение style.transform, // но это бы нам не сильно помогло. // При обычном считывании мы бы получили нечто вроде: // matrix(1, 0, 0, 1, 27, 15); // // Это матрица афинных преобразований. // Её можно представить в виде: // matrix(scaleX, skewY, skewX, scaleY, translateX, translateY); // где: // - scaleX — масштабирование по горизонтали, // - scaleY — масштабирование по вертикали, // - skewX — перекос по горизонтали, // - skewY — перекос по вертикали, // - translateX — смещение по горизонтали, // - translateY — смещение по вертикали. // // Но даже учитывая, что у нас есть все необходимые числа, // работать с этим неудобно — это же просто строка. // // К счастью мы можем воспользоваться DOMMatrixReadOnly, // который преобразует эту матрицу в удобную для использования: const transform = new DOMMatrixReadOnly(style.transform) // Теперь мы можем воспользоваться свойствами, // которые содержат в себе значения translateX и translateY. const translateX = transform.m41 const translateY = transform.m42 // Дальше — как раньше, только вычитаем не top и left, // а translateX и translateY. startX = e.pageX - translateX startY = e.pageY - translateY>)// добавляем возможность отпустить элемент при отжатии клавишиdocument.body.addEventListener("mouseup", () => dragging = false;>);// . element.addEventListener('mousedown', (e) => dragging = true // В этот раз мы не сможем считать нужные нам значения напрямую. // Вместо этого нам потребуется вначале вычислить стиль элемента // через window.getComputedStyle(), а затем узнать значение // свойства transform. const style = window.getComputedStyle(element) // Мы могли бы просто считать значение style.transform, // но это бы нам не сильно помогло. // При обычном считывании мы бы получили нечто вроде: // matrix(1, 0, 0, 1, 27, 15); // // Это матрица афинных преобразований. // Её можно представить в виде: // matrix(scaleX, skewY, skewX, scaleY, translateX, translateY); // где: // - scaleX — масштабирование по горизонтали, // - scaleY — масштабирование по вертикали, // - skewX — перекос по горизонтали, // - skewY — перекос по вертикали, // - translateX — смещение по горизонтали, // - translateY — смещение по вертикали. // // Но даже учитывая, что у нас есть все необходимые числа, // работать с этим неудобно — это же просто строка. // // К счастью мы можем воспользоваться DOMMatrixReadOnly, // который преобразует эту матрицу в удобную для использования: const transform = new DOMMatrixReadOnly(style.transform) // Теперь мы можем воспользоваться свойствами, // которые содержат в себе значения translateX и translateY. const translateX = transform.m41 const translateY = transform.m42 // Дальше — как раньше, только вычитаем не top и left, // а translateX и translateY. startX = e.pageX - translateX startY = e.pageY - translateY >) // добавляем возможность отпустить элемент при отжатии клавиши document.body.addEventListener("mouseup", () => dragging = false; >);А также немного обновим изменение положения:
// . document.body.addEventListener('mousemove', (e) => if (!dragging) return const x = e.pageX - startX const y = e.pageY - startY // В этот раз мы можем объединить обновлённые координаты // в одну запись translate, которую потом // присвоим в качестве значения свойству transform. element.style.transform = `translate($px, $px)`>)// . document.body.addEventListener('mousemove', (e) => if (!dragging) return const x = e.pageX - startX const y = e.pageY - startY // В этот раз мы можем объединить обновлённые координаты // в одну запись translate, которую потом // присвоим в качестве значения свойству transform. element.style.transform = `translate($x>px, $y>px)` >)В итоге получим такой же драг-н-дроп, но работающий на transform .
Но мы можем ещё лучше
Изменение кастомных свойств CSS
Скопировать ссылку «Изменение кастомных свойств CSS» Скопировано
Сейчас код рабочий, но его трудно читать. Как минимум потому, что надо знать, как работает матрица преобразований и DOM Matrix Read Only .
Мы же можем не менять значение transform вовсе, а вместо этого менять значение CSS-переменных, чтобы обновлять положение элемента!
Первым делом определяем кастомные свойства CSS в стилях элемента:
.element width: 50px; height: 50px; background: black; position: absolute; /* В переменной --x мы будем держать значение координаты по горизонтали; в переменной --y — по вертикали. */ --x: 0px; --y: 0px; /* Укажем transform, значением которого передадим translate с указанными переменными. В итоге нам не придётся менять сам transform, мы сможем ограничиться лишь изменением значений переменных --x и --y. */ transform: translate(var(--x), var(--y));>.element width: 50px; height: 50px; background: black; position: absolute; /* В переменной --x мы будем держать значение координаты по горизонтали; в переменной --y — по вертикали. */ --x: 0px; --y: 0px; /* Укажем transform, значением которого передадим translate с указанными переменными. В итоге нам не придётся менять сам transform, мы сможем ограничиться лишь изменением значений переменных --x и --y. */ transform: translate(var(--x), var(--y)); >Теперь подправим скрипт, чтобы сперва считать значение этих переменных:
// . element.addEventListener('mousedown', (e) => dragging = true // Получаем стиль элемента: const style = window.getComputedStyle(element) // Считываем значение каждой переменной через getPropertyValue: const translateX = parseInt(style.getPropertyValue('--x')) const translateY = parseInt(style.getPropertyValue('--y')) // Дальше всё остаётся по-старому :–) startX = e.pageX - translateX startY = e.pageY - translateY>)// . element.addEventListener('mousedown', (e) => dragging = true // Получаем стиль элемента: const style = window.getComputedStyle(element) // Считываем значение каждой переменной через getPropertyValue: const translateX = parseInt(style.getPropertyValue('--x')) const translateY = parseInt(style.getPropertyValue('--y')) // Дальше всё остаётся по-старому :–) startX = e.pageX - translateX startY = e.pageY - translateY >)А теперь изменим обновление стилей:
// . document.body.addEventListener('mousemove', (e) => if (!dragging) return // Обратите внимание, насколько лаконичной стала запись. // Мы всего лишь указываем, какое значение должна // принять каждая из переменных: element.style.setProperty("--x", `$px`) element.style.setProperty("--y", `$px`)>)// . document.body.addEventListener('mousemove', (e) => if (!dragging) return // Обратите внимание, насколько лаконичной стала запись. // Мы всего лишь указываем, какое значение должна // принять каждая из переменных: element.style.setProperty("--x", `$e.pageX - startX>px`) element.style.setProperty("--y", `$e.pageY - startY>px`) >)В результате получаем такой же драг-н-дроп!
На практике
Скопировать ссылку «На практике» Скопировано
Как запускать CSS-анимацию при прокрутке страницы
В этом пошаговом руководстве будет рассмотрено создание CSS-анимации с нуля и её включение при скролле (прокрутке вверх-вниз) страницы, когда HTML-элемент находится в поле зрения – видимой части окна, с помощью Intersection Observer API.
Настройка CSS-анимации с помощью ключевых кадров
Начнем с создания CSS-анимации, которая определяется ключевыми кадрами @keyframes .
@keyframes wipe-enter < 0% < transform: scale(0, .025); >50% < transform: scale(1, .025); >>
Анимацию можно назвать как угодно, пусть будет wipe-enter . Здесь HTML-элемент будет увеличиваться в ширину, а затем в высоту.
После того, как определены ключевые кадры, можно использовать анимацию для элемента, установив свойству animation-name название ключевых кадров: wipe-enter . Кроме этого необходимо установить animation-duration – продолжительность анимации и animation-iteration-count – счетчик итераций, указывающий, сколько раз анимация должна воспроизводиться, например – бесконечно.
@media (prefers-reduced-motion: no-preference) < .square < animation-name: wipe-enter; animation-duration: 1s; animation-iteration-count: infinite; >>CSS-класс .square пусть будет заключён в медиа-запрос prefers-reduce-motion: no-preference . Это обеспечит запуск анимации только в том случае, если пользователь не ограничил её и не включил параметр «уменьшить движение» в своей операционной системе.
В этом примере будет анимирован HTML-элемент квадратной формы:
Для CSS-анимации можно использовать сокращённое написание свойства animation , например:
@media (prefers-reduced-motion: no-preference) < .square < animation: wipe-enter 1s infinite; >>Управление анимацией с помощью CSS-класса
Допустим, не нужно, чтобы анимация воспроизводилась сразу. Воспроизведением анимации можно управлять, добавляя HTML-элементу CSS-класс переключатель только анимации, который не используется для остальной стилизации элемента.
.square < width: 200px; height: 200px; background: #e62a52; // и т.д. >@media (prefers-reduced-motion: no-preference) < .square-animation < animation: wipe-enter 1s 1; >>CSS-анимация будет воспроизводиться, когда HTML-элементу будет добавлен CSS-класс .square-animation :
В этом примере CSS-анимация воспроизводится не каждый раз при нажатии на кнопку, а только тогда, когда HTML-элементу будет добавлен CSS-класс .square-animation .
Несмотря на то, что анимация должна показывать появление элемента, элемент отображается и до добавления класса .square-animation . Это сделано для того, чтобы при первой загрузке элемент был виден пользователю, даже если JavaScript заблокирован или не работает.
Добавление CSS-класса, когда элемент появляется при скролле (прокрутке страницы вверх-вниз)
В примере выше была реализована CSS-анимация, которая запускается при добавлении HTML-элементу CSS-класса. Вместо перехвата события нажатия кнопки, для добавления и удаления CSS-класса можно использовать несколько вариантов обнаружения состояния, когда элемент при скролле появляется в видимой части окна.
Вот три способа определить, когда элемент находится в видимой области окна:
- Использовать Intersection Observer API
- Измерять смещение элемента при скролле страницы
- Использовать стороннюю JavaScript-библиотеку, которая реализует №1 или №2
Для базовой анимации с запуском при скролле, оптимально использование Intersection Observer API, потому что он требует меньше кода, удобнее и лучше с точки зрения производительности.
API-интерфейс Intersection Observer позволяет отслеживать момент пересечения одного элемента с другим, и сообщает, когда это происходит. Этот способ идеально подходит для запуска CSS-анимации при скролле страницы. Всё, что нужно знать – когда HTML-элемент пересекается с окном просмотра. Если он пересекается, значит – находится в видимой области окна и в этот момент надо запустить CSS-анимацию.
Intersection Observer API можно рассматривать, как обычный слушатель событий, но с некоторыми дополнительными опциями. Вместо того, чтобы прикреплять прослушивание событий к HTML-элементу, надо заставить наблюдателя отслеживать элемент и его положение на странице.
Начнём с создания наблюдателя и заставим его отслеживать HTML-элемент:
// Создать наблюдателя const observer = new IntersectionObserver(entries => < // Заполним метод обратного вызова позже. >); // Сообщить наблюдателю, какие элементы следует отслеживать observer.observe(document.querySelector('.square'));По умолчанию корневым элементом, который будет проверяться на пересечение, является окно браузера, поэтому наблюдателю нужно только сообщить об анимируемом HTML-элементе.
Когда функция обратного вызова (callback) запускается, она возвращает массив записей из целевых (target) элементов, которые были запрошены, а также некоторую дополнительную информацию о них. В функцию всегда будет возвращаться массив, даже если наблюдение ведётся только за одним элементом, как здесь.
В функции обратного вызова можно перебрать массив записей, чтобы указать, что с ними нужно сделать. Каждая запись имеет свойство isIntersecting , которое может быть true или false . Если оно возвращает true , это означает, что элемент находится в видимой области окна (viewport).
entries.forEach(entry => < if (entry.isIntersecting) < // Элемент появился, // надо добавить CSS-класс для анимации >>);Собираем всё вместе. Обратите внимание, что entry – это объект, предоставленный наблюдателем, а entry.target – это фактический элемент, за которым который ведется наблюдение, поэтому именно ему нужно добавить CSS-класс для запуска анимации.
const observer = new IntersectionObserver(entries => < // перебор записей entries.forEach(entry => < // если элемент появился if (entry.isIntersecting) < // добавить ему CSS-класс entry.target.classList.add('square-animation'); >>); >); observer.observe(document.querySelector('.square'));Теперь, когда HTML-элемент пересекает границы окна браузера, ему будет добавлен CSS-класс, который будет воспроизводить анимацию.
Если нужно, чтобы анимация запускалась каждый раз, когда HTML-элемент входит в видимую область окна, необходимо удалять CSS-класс запуска анимации, когда он находится за пределами видимой области окна.
Если элемент при анимации изменяет размер или положение, браузеру может быть сложно решить, находится ли элемент в данный момент в области просмотра или нет. Лучше всего поместить анимируемый элемент в контейнер, который не изменяет размер или положение и использовать его для наблюдения за скролллом.
Теперь надо наблюдать за HTML-элементом c CSS-классом square-wrapper а класс для анимации применять к элементу с классом square , как и прежде. Когда элемент-оболочка находится за пределами видимой области, нужно удалять CSS-класс у элемента .square , чтобы анимация перезапускалась каждый раз, когда элемент появляется в окне при скролле.
const observer = new IntersectionObserver(entries => < entries.forEach(entry => < const square = entry.target.querySelector('.square'); if (entry.isIntersecting) < square.classList.add('square-animation'); return; // если класс добавлен, продолжать уже не надо >// перемещение завершено, теперь надо удалить класс square.classList.remove('square-animation'); >); >); observer.observe(document.querySelector('.square-wrapper'));Чтобы элемент-оболочку было видно, для примера, ему добавлена пунктирная рамка. Попробуйте прокрутить вверх и вниз документ в окне ниже:
Теперь – порядок! Добавляя и удаляя CSS-класс каждый раз, когда при скролле страницы HTML-элемент входит в область просмотра, запускается CSS-анимация.
Запуск CSS-transition при скролле
Если для анимации используется только один шаг и не требуется применение @keyframes , например, достаточно изменения прозрачности HTML-элемента от 0 до 1, можно использовать CSS-transition вместо CSS-animation.
Метод по сути тот же. Вместо определения ключевых кадров ( @keyframes ) для CSS-класса анимации указаны свойства для transition .
.square < width: 200px; height: 200px; background: #e62a52; border-radius: 8px; opacity: 0; transform: scale(1.2); >@media (prefers-reduced-motion: no-preference) < .square < transition: opacity 1.5s ease, transform 1.5s ease; >> .square-transition
Заставим HTML-элемент появляться, когда он перемещается в видимую область просмотра. Для этого в момент появления в окне при скролле ему надо добавить CSS-класс square-transition . Так пользователь, у которого заблокирован или не загружается JavaScript, должен всё-равно увидеть HTML-элемент в его окончательном состоянии.
Это особенно важно, поскольку анимация начинается с opacity: 0 . Если бы не было настройки CSS-класса square-transition и JavaScript не работал, пользователь вообще не увидел бы HTML-элемент! Но если эффект перехода заключается в том, чтобы что-то исчезло, наверное, это не понадобится делать.
При первом запуске JavaScript нужно удалить CSS-класс, чтобы затем, его можно было добавить обратно, когда действительно нужно запустить transition . Это должно быть сделано вне метода обработки наблюдения за скроллом, желательно в начале JavaScript. Вот полный код:
// Удалить CSS-класс square-transition const square = document.querySelector('.square'); square.classList.remove('square-transition'); // Добавить наблюдение за появлением элемента const observer = new IntersectionObserver(entries => < entries.forEach(entry => < if (entry.isIntersecting) < square.classList.add('square-transition'); return; >square.classList.remove('square-transition'); >); >); observer.observe(document.querySelector('.square-wrapper'));В этом примере CSS-transition запускается, когда элемент-оболочка при скролле появляется в окне. Если Javascript не запустился, элемент всё-равно будет виден.
Как видите, эту технику можно расширять разными способами, чтобы создать множество эффектов анимации.
Почему скрытые элеметны видно во время загрузки страницы?
Есть попап на странице. Изначально он скрыт с помощью свойств opacity: 0 и visibility: hidden.
Все отлично работало, пока я не заметил, что этот попап видно при загрузке страницы с чистым кэшем. Потом он конечно же принимает скрытое состояние.
Мне удалось заскринить этот момент:
Что смог отметить:
1) это происходит только когда сайт на сервере, на локалке этого нет;
2) единственный браузер, в котором этого нет это Firefox;
3) если прописать opacity: 0 и visibility: hidden в атрибуте style то все нормально;
4) если прописать в CSS display: block, то тоже не не будет этого эффекта;
5) все в порядке, если убрать все transition (с opacity и visibility)Ссылка: cl13271.tmweb.ru
Нажимайте много раз Ctrl + F5 и увидите скрытый попап. И при первом заходе тоже должны увидеть (если у вас не Firefox).Неприятная штука, как можно от нее избавится? Скинул свой сайт на тестирование и это сразу бросилось в глаза. Клиент конечно же тоже заметит это.
Вообще, стили же подключаются в head, а разметка попапа находится внизу документа и по сути попап изначально должен быть всегда скрыт, т. к. стили подгружаются раньше, чем попап.Разметка и стили, используемые мной:
Салат с вяленым мясом косулисыром качотта и ореховым соусомПриятный сыр качотта и ореховый соус в сочетании с вяленым мясом косули придется по вкусу как любителям дикого мяса, так и истинным гурманам.220 г.410 руб..popup < position: fixed; top: 0; left: 0; z-index: 99; width: 100%; height: 100%; display: flex; padding: 30px; overflow-y: auto; background-color: rgba(0, 0, 0, 0.8); opacity: 0; visibility: hidden; pointer-events: none; transition: opacity 0.4s ease-in-out, visibility 0.4s ease-in-out; >.popup.active < opacity: 1; visibility: visible; pointer-events: auto; >.popup__card < width: 980px; height: 464px; margin: auto; transform: translateY(-20%); transition: transform 0.4s ease-in-out; >.popup.active .popup__card
- Вопрос задан более двух лет назад
- 850 просмотров
20 комментариев
Простой 20 комментариев
Как отключить CSS transition до завершения загрузки страницы
При верстке очередного большого проекта, на некоторых страницах CSS трансформация для структурных элементов страницы иногда начиналась еще до завершения загрузки всей страницы. Сказать честно — смотреться плохо 🙁
Для исправления данного дефекта можно воспользоваться методом запрета.
Добавим тегу BODY стиль:
#transition_disabled
После того, как страница полностью загрузится — необходимо удалить запрет. Сделать это можно при помощи JS.
$("window").load(function() < $("body").removeAttr("id"); >);После этого мы получим нужную нам анимацию только в тех случаях, когда это действительно необходимо