- How to animate an element in display none in two steps
- The solution
- In this article:
- Problem we try to solve
- Step 1: animate during opening
- JS to show the modal
- CSS
- Step 2 : animate during closing
- JS
- CSS
- Animationend event
- Bonus : A little accessibility enhancement
- Button vs Link
- Don't play animation if user don't want animation.
- Как плавно скрыть элемент и после убрать его из дом дерева?
- Пять способов скрыть элемент с помощью CSS
- Свойство opacity
- Свойство visibility
- Свойство display
- Свойство position
- Свойство clip-path
How to animate an element in display none in two steps
Animate a hidden element is very simple now. We just need 2 CSS declaration and a bit of JavaScript to toggle the state open / close.
The solution
In this article:
- CSS :not pseudo-selector
- Single Source of truth
- animationend event
- Accessibility
Problem we try to solve
You have a hidden element with a hidden attribute. To provide a better UX, you want to animate this opening and closing state. But in CSS, display:none is like an interrupter; it can be «on» or «off» but animate between both state with a CSS transition is impossible.
Step 1: animate during opening
As you notice, I’m opting for a link instead of a button. Why ? Because my modal will still be accessible without JavaScript, thanks to the target CSS pseudo-class. I will focus on this point after.
JS to show the modal
modalButton.addEventListener("click", function (e) < e.preventDefault(); modal.hidden = false; >);
CSS
That’s it. ¯_(ツ)_/¯.
If you prefer relying on .hidden class (like in Tailwind), you can switch :not([hidden]) with :not(.hidden) . If you want both, the not pseudo-class accept multiple arguments separated by a comma : not([hidden], .hidden) . Anyway, our Modal appears with a shiny animation now :
Step 2 : animate during closing
The closing state is a little more tricky. If you set the hidden attribute to «true», you won’t be able to hide it smoothly. You need to add a temporary class like is-closing to play the closing animation and then, hide the element.
JS
modal.addEventListener("click", function (e) < // Omitted… if (hasClickedOutside || hasClickedCloseButton) < modal.classList.add("is-closing"); // Omitted…
CSS
Now our modal is closing smoothly, but it is not back to hidden state. You have to wait to the end of the animation to remove the .is-closing class and back to hidden="true" . With setTimeout ? You could, but you have a better option.
Animationend event
With a timeout , we have to declare a value at least equal to the animation duration, which can change.
If you can, you have to have a single source of truth : here, the animation duration declared in the CSS.
The animationend will wait to the end of the animation, then execute the function inside the listener.
modal.addEventListener("click", function (e) < const hasClickedOutside = !e.target.closest(".modal-main"); const hasClickedCloseButton = e.target.closest(".modal-close"); if (hasClickedOutside || hasClickedCloseButton) < modal.classList.add("is-closing"); modal.addEventListener( "animationend", function () < modal.hidden = true; modal.classList.remove("is-closing"); >, < once: true >); > >);
Once the event is completely done, you have to destroy it with the once: true option, as you don't need it anymore.
And voilà, you have the knowledge to animate any element hidden in the DOM.
Bonus : A little accessibility enhancement
Button vs Link
Without JS, the modal can still be open via its hash, and you can style the opened state with the :target pseudo class.
To close it, the user needs to back in your history. This is why I hide the .modal-close . It's not pertinent to show it if it can't do anything.
Don't play animation if user don't want animation.
For personal taste, medical reason or to solve a performance issue on their device, your users may not want any animation, and you have to respect their preferences. It would be a good idea to embed the following the rule as part of your CSS reset, if it's not already done.
@media (prefers-reduced-motion: reduce) < *, *::before, *::after < animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; >>
Как плавно скрыть элемент и после убрать его из дом дерева?
Добрый день.
Нужно плавно скрыть элемент и после убрать его из дом дерева, возможно ли это сделать только при помощи css(нужно, чтобы другие элементы заняли его место)? Или можно только поменять стили у элемента и потом с помощью setTimeout изменять ему св-во display?
Средствами css убрать из дом нельзя.
Можно скрыть из потока, но все связанные с этим свойства не анимируются.
А можно, например, сделать чтобы он не занимал места в потоке или придумать еще какие-нибудь костыли:
snippet
изменение дома происходит через JavaScript. Полностью удалить его из дома средствами CSS не получится. Просто скрыть можно
Видимо я немного некорректно задал вопрос.
Смотри, у меня есть какой-то элемент, я ему меняю opacity на 0, при этом добавляю св-во transition: opacity 1s, при определенных условиях он плавно исчезает, а можно ли посредством css и убрать его из потока рендера, чтобы на его место могли встать другие элементы?
shading, он у вас становится прозрачный, но все равно занимает место? Чтобы он "как-бы" исчез, используйте display: none . Тогда он перестанет занимать место на странице, и на его место сдвинутся другие элементы. Но в доме он все равно останется
Как я понял, ответ так и не был дан. С помощью CSS - никак, ведь CSS не могёт менять DOM-дерево.
С помощью JS - запросто, но уж точно не через setTimeout!
const item = document.querySelector('.item'); item.style.opacity = '0'; item.addEventListener('transitionend', function() );
Пояснение: цепляете нужный вам элемент, потом меняете ему прозрачность и прослушиваете событие transitionend по наступлению которого удаляете элемент из DOM (при этом это произойдет плавно и незаметно для пользователя).
PS: по поводу совместимости у 'transitionend' - все чикибамбони. Поддерживает даже IE10+
Пять способов скрыть элемент с помощью CSS
От автора: в CSS есть много различных способов сокрытия элементов. Можно установить opacity: 0, visibility: hidden, display: none или задать сверх большие значения при абсолютном позиционировании. Вы никогда не задумывались, зачем нужно столько много способов для одного и того же действия? Все методы почти не отличаются друг от друга, а существующие различия лишь указывают на то, какой из них и в каких обстоятельствах должен применяться. В этом уроке мы вам расскажем про мелкие отличия данных методов, на которые стоит обращать внимание.
Свойство opacity
С помощью свойства opacity задается прозрачность элемента. Данное свойство не изменяет границы элемента, т.е. если задать 0, то элемент будет скрыт только визуально. Элемент все так же будет занимать свое положение и пространство, влияя на расположение других элементов макета страницы. Кроме того, невидимый элемент будет отвечать на взаимодействие с ним.
Если вы хотите скрыть с помощью opacity элементы от скрин ридеров, то у вас это не получится. Элемент и весь его контент останутся видимыми для скрин ридеров, как и все остальные элементы на странице. То есть элемент ведет себя ровно так, как если бы он был видимым.
Онлайн курс по JavaScript
Научитесь создавать приложения со сложными интерфейсами
Это основной язык для современной веб-разработки — почти 100% сайтов работает на JavaScript. Освойте его с нуля всего за 4 месяца, и вы сможете зарабатывать от 70 000 рублей.
Также стоит отметить, что свойство поддается анимации, и с его помощью можно создавать поразительные эффекты. Элемент со свойством opacity меньшим 1задает новый контекст стека.
При наведении курсора на скрытый второй блок элемент плавно меняет свое состояние с полной прозрачности до полной непрозрачности. Блоку также задано свойство cursor: pointer, показывающее, что с ним можно взаимодействовать.
Свойство visibility
Следующее в нашем списке свойство visibility. Если установить значение hidden, то элемент будет скрыт. Как в случае со свойством opacity, скрытый с помощью данного свойства элемент не виден, но не стерт из макета страницы. Отличие от первого свойства в том, что данное свойство запрещает взаимодействовать со скрытым элементом. Также элемент будет скрыт от скрин ридеров.
Данное свойство также поддается анимации, можно менять первоначальное и конечное значения. Т.е. можно плавно анимировать свойство при помощи transition.
В демо ниже показана разница между visibility и opacity:
Обратите внимание на то, что дочерние элементы тега со свойством visibility: hidden могут быть видны, если им задать свойство visibility: visible. Проведите курсором внутри блока, но не доходя до цифры. Как видите, курсор не меняет свое значение на pointer. Также если кликнуть в этой области, то ничего не произойдет.
А вот тег
внутри захватывает все события мыши. При наведении курсора мыши на текст блок станет видимым и начнем также обрабатывать события.
Свойство display
Свойство display прячет элементы по-настоящему. Если установить элементу свойство display: none, то он не просто будет скрыт, не будет создана даже его блоковая модель. Данное свойство полностью скрывает элемент, будто его и не было. Также в таком случае с элементом нельзя никак взаимодействовать. Скрин ридерам будет не доступен контент скрытого элемента. Т.е. элемент как будто и не существовал.
Также будут скрыты все дочерние элементы. Свойство не поддается анимации, т.е. на него нельзя навесить плавные переходы.
Элемент остается доступным через DOM. Вы все так же можете манипулировать им, как и любым другим элементом.
Откройте вкладку CSS в демо ниже:
В коде видно, что у второго блока есть параграф, которому задано свойство display: block, но он все равно остается невидимым. В этом и есть разница между visibility: hidden и display: none. В первом случае если дочерним элементам задать свойство visibility: visible, то они станут видимыми. Во втором случае такой подход не работает. Все дочерние элементы остаются скрытыми независимо от их собственных значений свойства display.
Наведите пару раз курсор на первый блок. Событие hover выполняется? Если кликнуть на него, второй блок станет видимым. Счетчик во втором блоке должен показывать цифру, отличную от нуля. Блок скрыт от пользователя, но все еще доступен для взаимодействия через JS.
Свойство position
Представьте, что вам нужно создать такой элемент, чтобы с ним можно было взаимодействовать, но в то же время чтобы он не влиял на макет страницы. Ни одно из рассмотренных до сих пор свойств полностью не справлялось с этой задачей. В таком случае можно выдвинуть элемент за пределы видимой области. Элемент не будет влиять на макет, но останется доступным для взаимодействия. CSS код:
Демо ниже показывает работу абсолютного позиционирования. Принцип демо очень схож с предыдущим:
Основная задача тут это задать достаточно большие отрицательные значения свойств top и left, чтобы элемент ушел из видимой области просмотра. Плюс (или минус) в том, что при таком подходе контент внутри абсолютно спозиционированного элемента остается видимым для скрин ридеров. В принципе все логично, элемент просто отодвинут за пределы видимой области просмотра, чтобы пользователь не видел его.
Данную методику нельзя применять для сокрытия элементов, на которые можно поставить фокус. Курсор может перепрыгнуть непонятно куда, что может привести к непредсказуемым последствиям. Метод часто используется для создания пользовательских чекбоксов и радио кнопок.
Свойство clip-path
Еще один способ скрыть элемент – обрезать его. Раньше для этого было свойство clip. Оно устарело, и ему на смену появилось свойство clip-path.
Помните, что clip-path в демо ниже не полностью поддерживается в IE и Edge. Если использовать внешний SVG файл, поддержка становится еще более скудной (мы не стали использовать внешний файл). Для сокрытия элемента с помощью свойства clip-path используйте строку: