Animating and transitioning display:none elements

11 June, 2013 § 7 Comments

The current release of Firefox introduces a nice animation when opening and closing the Find bar. Upon opening the Find bar, the toolbar fades in and slides up. Exiting the toolbar will make it fade out and slide down.

As you may or may not know, the user interface for Firefox is implemented using XUL+HTML/CSS/JavaScript.

We use the XUL hidden attribute, which is very similar to the HTML5 hidden attribute, to hide the Find bar when it is dismissed. The presence of the hidden attribute sets display:none on the referenced element. If you’ve ever played around with CSS Transitions or Animations, you’ve probably noticed that display is not a transitionable property.

To maintain add-on compatibility, as well as code simplicity, we wanted to keep using the hidden attribute. Doing so also allowed us to leave the JavaScript unchanged.

This poses a hard problem. If display is not transitionable, how could we animate the behavior here? It turns out that visibility is a transitionable property.

The various states of visibility are atomic. There is no defined behavior for what should happen when an element transitions from visibility:hidden to visibility:visible or visibility:collapse. However, we can use a zero second duration to make the change happen at the instant that we want.

This brings us to our solution:

findbar {
  transition-property: margin-bottom, opacity, visibility;
  transition-duration: 150ms, 150ms, 0s;
  transition-timing-function: ease-in-out, ease-in-out, linear;
  margin-bottom: 0;
  opacity: 1;
}

findbar[hidden] {
  /* Override display:none to make the transition work. */
  display: -moz-box;
  visibility: collapse;
  margin-bottom: -1em;
  opacity: 0;
  transition-delay: 0s, 0s, 150ms;
}

To explain how this works we’ll start by looking at findbar[hidden], since it’s the default state for the Find bar.

When it is hidden, we will force it to be displayed (using display:-moz-box, which is an internal-to-Gecko display value, you could replace this with display:block or display:inline as needed). We then set visibility to collapse, which will effectively make the element invisible and also not consume any space (except for margins, which is important here). We then use a negative margin-bottom to force the element to be placed just out of view of the browser window. Setting opacity here is used to fade the element in and out. I’ll describe the transition-delay last.

When the Find bar is shown, we set margin-bottom to zero which will slide the toolbar up. We also set opacity to one which will make it fade in. The opposite happens in reverse when the Find bar is dismissed.

The key here is the transition-delay that is set in the findbar[hidden] case.

When the Find bar is hidden and transitions to being visible, we don’t have a transition-delay applied. This causes the visibility to change immediately at the beginning of the animation. The Find bar becomes visible and then it slides and fades in to view.

When the Find bar is visible and transitions to being hidden, we delay changing the visibility until the margin and opacity transitions have completed. Running the visibility transition immediately in this case would cause the element to disappear instantly, which would ruin the animation.

That explains how I implemented the Find bar transition in Firefox without affecting themes or having to change JS. It’s a pretty cool technique for showing and hiding elements, and has opened the doors to implementing some other types of animations in the Firefox user interface. Let me know what you think! :)

Update: I’ve been told by Frank Yan that this won’t work on non-XUL content since display:-moz-box is needed to get the visibility:collapse to work as needed. Still a cool technique to see!

CSS tip: Creating an elliptical gradient in a square container

6 June, 2012 § Leave a comment

Creating an elliptical background gradient in a square container isn’t the most straight-forward in CSS. This is simple to do if you can change the shape of the container, but requires using a separate CSS property to change the shape of the gradient.

To change the shape of the radial gradient, you can use the background-size property to change the bounding box of the background-image.

div {
  width: 200px;
  height: 200px;
  background-image: -moz-radial-gradient(center, closest-side, red, blue);
  background-color: violet;
  background-repeat: no-repeat;
  background-position: center;
  background-size: 100px 200px;
}

See the page on background-size at MDN for more information.

Notes on Firefox development

27 June, 2011 § 2 Comments

Today marks the start of my third week at Mozilla. I’d like to mark this occasion with some things that I have learned that are pertinent to developing for Firefox.

  1. review?

    When I submitted my first patch to Mozilla, I added a reviewer by appending r=reviewer to my patch. While this may say what you mean, it doesn’t do what you mean.

    To properly request a review, set review to ? in Bugzilla when you are adding an attachment. This will properly email the reviewer so they can become aware of the request.

  2. make -s -C objdir

    Running a clean build of Firefox can take about 25-30 minutes, while an incremental build can still take about 2 minutes. This is clearly not conducive to an iterative-style of coding.

    To make builds faster, you only need to rebuild the parts that have changed. To do this, simply run make -s -C objdir, where objdir is the parent directory within the object directory of the code that you have changed. It may be necessary to also re-link if native code has changed.

  3. -moz-appearance: none

    This was the first XUL gotcha that I ran into. I bumped in to this as I was working on bug 598169 and trying to make a XUL:textbox styleable.

    Many XUL elements use OS-dependent styling, and if you want to apply styles to them then you will have to turn off the default styling. -moz-apperance: none does just that.

  4. hg qpush –move patch

    Many of the developers at Mozilla use the mq extension for Mercurial. mq is a tool that allows you to keep all of your changesets in separate queues. This makes it easier to work on different patches in parallel.

    Most work can be done with three of the mq commands: hg qnew, hg qpush, and hg qpop.

    A normal hg qpush patch will push the current patch as well as all preceding patches on the tip, whereas hg qpush --move patch allows a user to push just the single patch on the tip.

  5. pymake

    If you’re working on Windows, Firefox can take a while to build when using the standard make -f client.mk. Fortunately, there exists a tool that makes your builds run a lot faster by taking advantage of the multiple cores on your system.

    Running python -O "..\build\pymake\make.py" -s -j12 will build Firefox with 12 concurrent compilations. I chose 12 because it is 1.5x the number of threads on my system. :dolske ran some benchmarks to find the optimal -j setting and advised me on the 1.5x multiplier.

    You can learn more about pymake on the Mozilla development website.

Where Am I?

You are currently browsing entries tagged with CSS at JAWS.

Follow

Get every new post delivered to your Inbox.

Join 100 other followers