Animation on display block css

So, you’d like to animate the display property

The CSS Working Group gave that a thumbs-up a couple weeks ago. The super-duper conceptual proposal being that we can animate or transition from, say, display: block to display: none . It’s a bit of a brain-twister to reason about because setting display: none on an element cancels animations. And adding it restarts animations. Per the spec:

Setting the display property to none will terminate any running animation applied to the element and its descendants. If an element has a display of none, updating display to a value other than none will start all animations applied to the element by the animation-name property, as well as all animations applied to descendants with display other than none .

That circular behavior is what makes the concept seemingly dead on arrival. But if @keyframes supported any display value other than none , then there’s no way for none to cancel or restart things. That gives non- none values priority, allowing none to do its thing only after the animation or transition has completed. Miriam’s toot (this is what we’re really calling these, right?) explains how this might work: We’re not exactly interpolating between, say, block and none , but allowing block to stay intact until the time things stop moving and it’s safe to apply none . These are keywords, so there are no explicit values between the two. As such, this remains a discrete animation. We’re toggling between two values once that animation is complete. This is the Robert Flack’s example pulled straight from the discussion:

@keyframes slideaway < from < display: block; >to < transform: translateY(40px); opacity: 0;>> .hide

This is a helpful example because it shows how the first frame sets the element to display: block , which is given priority over the underlying display: none as a non- none value. That allows the animation to run and finish without none cancelling or resetting it in the process since it only resolves after the animation. This is the example Miriam referenced on Mastodon:

We’re dealing with a transition this time. The underlying display value is set to none before anything happens, so it’s completely out of the document flow. Now, if we were to transition this on hover, maybe like this:

…then the element should theoretically fade in at 200ms . Again, we’re toggling between display values, but block is given priority so the transition isn’t cancelled up front and is actually applied after opacity finishes its transition. At least that’s how my mind is reading into it. I’m glad there are super smart people thinking these things through because I imagine there’s a ton to sort out. Like, what happens if multiple animations are assigned to an element — will none reset or cancel any of those? I’m sure everything from infinite animations, reversed directions, and all sorts of other things will be addressed in time. But what a super cool first step!

Источник

Animating from “display: block” to “display: none”

CodeinWP CodeinWP

Animating display: block to display: none

As you might already know, CSS transitions and animations allow you to animate a specific set of CSS properties. One of the properties that cannot be animated is the display property.

Читайте также:  My location java application

It would be great if you could do it, but it’s not currently possible and I’m guessing it never will be (e.g. how would you animate to “display: table”?). But there are ways to work around it, and I’ll present one way here.

Why the Need to Animate “display”?

The need to animate the display property comes from wanting to solve the following problem:

  • You want to make an element gradually disappear visually from the page.
  • You don’t want that element to take up space after it has disappeared (i.e., you want the disappearance to cause reflow).
  • You want to use CSS for the animation, not a library.

For this reason, animating opacity to zero is simply not enough because an element with zero opacity still occupies the same space on the page.

Let’s look at how you might attempt to solve this problem, step by step.

Use Opacity and Display

The first thing you might think of doing is using both the opacity property and the display property. The HTML might look like this:

And the CSS might look like this:

Notice I have display: none and opacity: 0 on my “hidden” class. If you toggle this “hidden” class using JavaScript, you might have code that looks like this:

let box = document.getElementById('box'), btn = document.querySelector('button'); btn.addEventListener('click', function () < box.classList.toggle('hidden'); >, false);

But if you do that, you will not see the transition (defined in the .box declaration block) take effect. Instead you’ll see this :

Click the ‘toggle visibility’ button repeatedly and you’ll see the box disappear and appear suddenly, with no transition.

To fix this, you might try to separate the display property from opacity in your CSS:

Then you could toggle both classes:

var box = $('#box'); $('button').on('click', function () < box.toggleClass('visuallyhidden'); box.toggleClass('hidden'); >);

But this won’t work, as shown in the demo below:

What we want is for the element to disappear visually, then be removed from the page after it finishes disappearing visually, in a manner similar to a callback function.

(As a side point here, even if you combined opacity: 0 with visibility: hidden , it would animate just fine but the element would still occupy space on the page after it disappears, so that won’t work either.)

Why Doesn’t This Work?

Before getting to my solution, I’ll just explain why you can’t do this by just changing the classes one after the other. First, if you’re adding classes like in the examples above, even if the transition worked, you’d have to set up a separate section for removing the classes and reverse how that’s done (i.e. if the box starts out hidden you have to first set it to display: block , then change the opacity).

But that’s beside the point, because it doesn’t work anyhow. JavaScript executes one line after the other, but it doesn’t wait for all things associated with one line to be finished before executing the next line. (In other words, if you execute an animation or other asynchronous event on line 1, line 2 will proceed even if the animation isn’t done).

What’s happening is that the ‘opacity’ is attempting to animate immediately, and even if for a fraction of a millisecond it does start to animate, you won’t see it because the display: none part will take effect just as quickly.

Читайте также:  Use reference in java

We can sum up the problem we want to solve as follows:

  • When the element is visible, first animate the opacity, then, when that’s finished, make it display: none .
  • When the element is invisible, first make it display: block , then (while it’s still visually hidden, but existing on the page), animate the opacity.

A Possible Solution

There are probably other ways to do this, and I’d be glad to hear how you’d solve this problem. But here is my solution.

The CSS is the same (with the two ‘hidden’ classes still separated), but the JavaScript will look like this:

let box = document.getElementById('box'), btn = document.querySelector('button'); btn.addEventListener('click', function () < if (box.classList.contains('hidden')) < box.classList.remove('hidden'); setTimeout(function () < box.classList.remove('visuallyhidden'); >, 20); > else < box.classList.add('visuallyhidden'); box.addEventListener('transitionend', function(e) < box.classList.add('hidden'); >, < capture: false, once: true, passive: false >); > >, false);

Here’s a summary of what the code does when the box is visible:

  • Add the visuallyhidden class, which will animate it until it disappears.
  • At the same time that class is added, a single event handler is added using the options object in the addEventListener() method (a new feature with decent browser support), which tells the browser to wait for the transitionend event to occur once, then it stops looking.
  • The transitionend event fires when the opacity is done animating, and when this occurs the element is set to display: block .

Because you can’t detect a transitionend event on the display property, you have to use a different method for when the box is invisible:

  • First remove the hidden class, making it display: block while it’s still visually hidden.
  • While this is occuring, the script has executed a delay using setTimeout() , after which the opacity begins to animate.

The delay is very small (20 milliseconds), but because display: block occurs instantly, you don’t need much of a delay at all, just enough to allow the element to take its full place on the page before animating the opacity. You might have to mess around with the timing in some cases, possibly going down to as little as a single millisecond.

And in case you want to start with a box that’s hidden and make it appear, you just have to ensure that both the hidden and visuallyhidden classes are on the box when it starts. Here’s a demo:

If you don’t include both classes, the initial appearance won’t be animated.

How Would You Do It?

As mentioned, there are probably other ways to do this, or maybe there’s some improvement that could be made to my code.

Personally, I feel the use of setTimeout is a bit lame and hacky. But hey, it works, and I don’t think it’s going to cause any problems unless you had tons of similar animations on the page. But that would be another issue altogether.

There are a few possible solutions to this on StackOverflow, but I find most, if not all, of the proposed solutions don’t really solve the problem at hand.

Источник

Анимация от display: block до display: none

Отлично было бы это сделать, но на данный момент это невозможно и, думаю, никогда не станет реальностью (например, как анимировать до “display: table”?). Но есть возможность совершить обходной маневр, и один из них я здесь и опишу.

Читайте также:  Html как изучить быстро

Зачем анимировать “display”?

Анимировать свойство display требуется для решения следующей проблемы:

Нужно, чтобы элемент постепенно зрительно исчезал со страницы.

Вам нехочется, чтобы этот элемент занимал место после своего исчезновения (например, требуется, чтобы его исчезновение вызывало перезаливку).

Изучите Веб-вёрстку с нуля

Если вы мечтаете создавать сайты, но не знаете, с чего начать. Хотите глубоко погрузиться в основы веб-разработки, а не просто пройтись по верхам — этот курс для вас!

Нужно применять для анимации CSS, а не библиотеку.

По этой причине недостаточно просто анимировать opacity до нуля, так как элемент с нулевой непрозрачностью занимает то же самое место на странице. Давайте посмотрим, как шаг за шагом решить эту проблему.

Используйте Opacity и Display

Первое, о чем вы можете подумать – воспользоваться и свойством opacity, и display. Наш HTML будет выглядеть так:

Обратите внимание на то, что display: none и opacity: 0 присвоен класс “hidden”. Если переключать класс “hidden” с помощью jQuery, получится примерно такой код:

Но если так сделать, то мы не увидим эффекта перехода (определенного в блоке описаний .box). Вместо него мы увидим это (слегка отличающееся в Firefox по сравнению с Chrome/IE10):

Многократно нажмите кнопку ‘togglevisibility’ и увидите, как блок безо всяких переходов будет неожиданно исчезать и появляться. Чтобы это исправить, можно попробовать отделить в CSS свойство display от opacity:

Затем можно переключить оба класса, один за другим:

Помимо того, что требуется реверсировать эти две строки при появлении блока, это еще и не сработает, как видно здесь:

Нам нужно, чтобы элемент визуально исчезал, а затем удалялся со страницы по окончанию исчезновения идентично функции обратного вызова. (Кроме того, даже если мы скомбинируем opacity: 0 с visibility: hidden, то анимация получится хорошо, но элемент после своего исчезновения продолжит занимать место на странице, так что все это не сработает.)

Почему не работает?

До перехода к своему методу я просто объясню, почему невозможно ничего сделать, просто изменяя классы один за другим. Во-первых, если вы добавляете классы как в вышеприведенных примерах, и если переход даже сработал, то вам придется установить отдельный раздел для удаления классов и реверсирования (т.е. если блок сначала скрыт, вам придется установить его на display: block, а затем сменить непрозрачность).

Но это несущественно, потому что все равно не работает. JavaScript выполняет одну строку за другой, но не ждет, пока закончат выполняться все связанные с ней процессы, а переходит к выполнению следующей строки. (Другими словами, если в строке 1 вы выполняете анимацию или другое несинхронное событие, строка 2 будет исполняться, даже если анимация не выполнена).

Это происходит от того, что непрозрачность ‘opacity’ пытается анимироваться сразу же, и даже если на долю миллисекунды она действительно анимируется, вы этого не увидите, потому что display: none начнет действовать столь же быстро.
Можно резюмировать проблему, которую нам нужно решить, следующим образом:

Когда элемент виден, сначала анимируйте непрозрачность, а затем, когда это выполнено, сделайте его display: none.

Когда элемент невидим, сначала сделайте его display: block, затем (пока он еще визуально скрыт, но уже существует на странице), анимируйте непрозрачность.

Возможное решение

Вероятно, существуют другие способы это сделать, и я буду рад узнать, как вы бы решили эту проблему. Но вот мое мнение.
CSS тот же самый (с двумя все еще разделенными классами ‘hidden’), но jQuery будет выглядеть так:

Источник

Оцените статью