linkedlist

Collection of interesting bits and bytes about the Web. Mostly short and to the point.

Sitemap · Subscribe

Vertical Centering with CSS

#64 · 2024-03-09 · CSS

Vertical centering with CSS has been easy for a couple of years now. Both flexible box layout and grid layout support it. Just use them together with the align-content property.

div {
  display: grid; /* or flex */
  align-content: center;
}

And it is about to become even simpler. The specification of the align-content property was not limited to flexbox and grid layout, but it also included block containers. No browser supported that so far, though. But that is about to change as Firefox 125, Safari 17.4, and Chrome 123 (will) support it. Supporting browsers will vertically center even without defining a display property.

div {
  align-content: center;
}

For backward compatibility (and as feature detecting this particular behaviour is currently not possible in a sensible way), it is still recommended to only use it together with flex or grid for the foreseeable future.

DMA and Apple

#63 · 2024-02-28 (updated 2024-03-06) · Apple

The Digital Markets Act is the EU’s law to make the markets in the digital sector fairer and more contestable.

The Digital Markets Act (DMA) establishes a set of clearly defined objective criteria to identify “gatekeepers”. Gatekeepers are large digital platforms providing so called core platform services, such as for example online search engines, app stores, messenger services. Gatekeepers will have to comply with the do’s (i.e. obligations) and don’ts (i.e. prohibitions) listed in the DMA.

Source

Apple is trying to "comply" with the DMA by being even more anti-user than before. They are making both third-party app stores and other browser engines as painful to use as possible. And in addition they are killing Progressive Web Apps on iOS to keep their own App Store the only viable option. That is obviously not in the interest of the DMA at all.

If Apple wants to ruin user trust and face penalties from the EU, they should continue with this nonsense. iOS is not a decent platform anymore. Apple has proven that they are actively user-hostile, and they are looking for a conflict with the EU. Let the DMA win.

Update 2024-03-05, 2024-03-06: It seems Apple got too much—well deserved—negative press on this. They reversed their course and do not want to kill Progressive Web Apps anymore. But they still want to cripple them by forcing PWAs to build on WebKit. Hence, they are and will continue to be severely lacking as WebKit has been notoriously bad at PWAs for years. And that is entirely on purpose. Apple being Apple continues to spit into the face of the EU Commission.

CSS Custom Functions and Mixins

#62 · 2024-02-13 · CSS

The CSS working group (CSSWG) has decided to start working on an Editor's Draft (ED) about CSS Custom Functions and Mixins. These two may be the last big advantages that CSS preprocessors like Sass have over vanilla CSS.

CSS :has() now supported in all Browsers

#61 · 2023-12-26 · CSS

With the recent release of Firefox 121, the :has() pseudo-class is now supported in all important browsers.

Animate <details> Element when Expanding or Collapsing

#60 · 2023-11-19 · HTML, animation

The details and summary elements can be used for disclosure and accordion widgets. They are standard HTML elements and collapse or expand when the user clicks on the summary. An example usage could look as follows.

<details>
  <summary>Summary</summary>
  <p><!-- your content --></p>
</details>

These elements are not used that often, though. Many engineers usually implement their own disclosure or accordion widgets, or take an off-the-shelf library. One of the reasons for that is that the details element's expansion and collapsing cannot easily be animated. Instead, they will just open or close instantly which may suddenly move a large part of the surrounding content. That is not a very pleasant experience.

But we should still strive to use details instead of custom solutions. As details is a standard HTML element, it usually has better semantics than custom disclosure widgets. It is more accessible and works well with keyboard navigation by default. And in some browsers, even collapsed details can be searched and will expand automatically when they contain the search query. So ideally, fully custom disclosure widgets should not (need to) be a thing.

The good news is: details can be animated. Have a look at the following example. You can see the default behaviour of details without any animation at all. And you can see the animated details element that nicely grows the expanded content or shrinks it when collapsing. The animation works for both initially closed and open details. This post will show how this animation is implemented.

Example

Example content

Details without animation

Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat. Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.

Details with animation

Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat. Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.

Details with animation (initially open)

Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua.

Example content

There are already a couple of different approaches to animate the details disclosure element. But most of these rely on JavaScript to perform the actual animation or have other limitations, e.g. the engineer would need to know the height of the details content when expanded. The solution for the animation that you tried out above does not have these limitations. It is implemented with CSS animations and a little JavaScript. A CSS-only animation like this is currently not possible, unfortunately.

Animate Opening and Closing

CSS can animate the height of an element from 0px to auto using CSS grid. And we will apply that feature to the details element. The first step is to extend your HTML. Each details element should be extended by two nested div elements that in turn contain your actual content. The first one will be styled as a CSS grid and the second one will be its only grid item.

  <details>
    <summary>Summary</summary>
+   <div>
+     <div>
        <!-- your content -->
+     </div>
+   </div>
  </details>

To run the animation when expanding or collapsing, we have to apply the following CSS. It makes sure that the second div has a minimum height so that the first div can animate its height properly. And there are two custom classes that are applied when the animation is running. .animation is applied when expanding or collapsing, and .collapsing is only applied when collapsing. The latter class will make sure that the animation is reversed (e.g. from auto height to 0px). And in addition, we also define @keyframes which specifies the exact behaviour of our animation. Specifically, we animate CSS grid units from 0fr (i.e. height: 0px) to 1fr (i.e. height: auto).

details > div {
  overflow: hidden;
  display: grid;
  /* intentionally independent from .animation as Safari 16
  would otherwise ignore the expansion animation. */
  animation-duration: 0.2s;
}

details > .animation {
  animation-name: grid-expand;
  animation-timing-function: ease-out;
}

details > .collapsing {
  animation-direction: reverse;
  animation-timing-function: ease-in;
}

details > div > div {
  min-height: 0;
}

@keyframes grid-expand {
  0% {
    grid-template-rows: 0fr;
  }
  100% {
    grid-template-rows: 1fr;
  }
}

As mentioned earlier, some JavaScript is also required to smoothly animate opening and closing. The necessary code can be seen below. It adds a click handler to all summary elements. And as soon as the user either clicks the element or activates it with their keyboard, what essentially happens is the following:

document.querySelectorAll('summary')
  .forEach(element => element.addEventListener('click', (event) => {
    const detailsElement = event.target.parentElement;
    const contentElement = event.target.nextElementSibling;

    // Chrome sometimes has a hiccup and gets stuck.
    if (contentElement.classList.contains('animation')) {
      // So we make sure to remove those classes manually,
      contentElement.classList.remove('animation', 'collapsing');
      // ... enforce a reflow so that collapsing may be animated again,
      void element.offsetWidth;
      // ... and fallback to the default behaviour this time.
      return;
    }

    const onAnimationEnd = cb => contentElement.addEventListener(
      "animationend", cb, {once: true}
    );

    // request an animation frame to force Safari 16 to actually perform the animation
    requestAnimationFrame(() => contentElement.classList.add('animation'));
    onAnimationEnd(() => contentElement.classList.remove('animation'));

    const isDetailsOpen = detailsElement.getAttribute('open') !== null;
    if (isDetailsOpen) {
      // prevent default collapsing and delay it until the animation has completed
      event.preventDefault();
      contentElement.classList.add('collapsing');
      onAnimationEnd(() => {
        detailsElement.removeAttribute('open');
        contentElement.classList.remove('collapsing');
      });
    }
  }));

And that is it. When you apply the changes in your HTML, add the CSS styling, and wire up the JavaScript; your detail elements will be animated. Using details instead of custom disclosure widgets has many advantages. And having proper animations when expanding or collapsing makes using it a no-brainer.

Chrome Bug

There is a strange bug in the current version of Chrome 119. The browser may get stuck in a weird state where the animations do not always run anymore. The detail element will expand and collapse, but without a consistent animation. That state seemingly is (only?) entered when the users utilize their keyboard to collapse and then expand the disclosure element again.

As you can see in the JavaScript code above, there is some special handling for that case. That code ensures that expanding and collapsing at least work in Chrome at all. Even though there may be no or no consistent animation.

Using the mouse exclusively will not provoke that faulty behaviour. And exiting that faulty state is easy: use a mouse to expand or collapse the disclosure widget at least once. After that, it seems to be impossible to enter that faulty state again. This is definitely not ideal. But it does not prevent the usage of the details widget. And Google will hopefully fix that bug in a future version of Chrome.