2

I'm building an accessible accordion using a definition list. I have this working well, where the <dt> contains a <button> which when clicked toggles an aria-expanded from true/false and toggles a hidden attribute on the corresponding <dd>. There's other things going on for accessibility but that's the basics for the list and the show/hide.

The show/hide display of the dd is then controlled via a hidden attribute selector (in this case, this is coming from the bootstrap stylesheet):

[hidden] {
  display: none!important;
}

The show/hide functionality right now is a hard show/hide and I'm trying to add a nice animation via css transitions (this needs to work in IE11 where transitions are supported.)

I built a simple POC for the animation at http://jsfiddle.net/jokvqy6u/ which just toggles a show and hide class. This was just something I could quickly throw together and send out to our marketing team to illustrate the animation to get feedback on.

I thought I'd be able to just easily add hidden and :not(hidden) selectors to the POC and it would work just fine, then I could retrofit into the real accordion, but the animation doesn't seem to work with hidden attributes on the html. You can see a demo of that at http://jsfiddle.net/6zmdhqrn/2/ where the 2nd item animates because it does not have a hidden attribute. Items 1 and 3 have hidden attributes and do not even open up.

Does anyone know why this is happening and how I can get my transitions working with hidden attributes?

EDIT I have it sort of half working at http://jsfiddle.net/6zmdhqrn/3/ by overriding the [hidden] selector coming from bootstrap with some important statements. I still get a hard show, but the hide slides up. I suspect it has to do with the element being display:none where the animations have no dimensions/info to start animating from? Still looking for info/tips on how to get the opening animation.

magenta placenta
  • 1,461
  • 7
  • 22
  • 34

1 Answers1

2

You guessed right, the problem here is display isn’t an animatable CSS property.

You need to base your animation on an animatable property, such as opacity for example.

Here’s a quick demo:

const el = document.querySelector('div');

document.querySelector('button').addEventListener('click', () => {
  if (el.classList.contains('visible'))
    el.classList.remove('visible');
  else
    el.classList.add('visible');
})
div {
  opacity: 0;
  transition: opacity 0.3s ease;
}

.visible {
  opacity: 1;
}
<div class="visible">some content!</div>
<button>toggle visibility</button>

As you may have noticed, setting the opacity to 0 doesn’t hide the element completely (i.e. it still takes up space). In case this is something undesirable, you may consider animating a different property, such as width or height.

Simone
  • 20,302
  • 14
  • 79
  • 103