State Changes with CSS Transitions

CSS transitions create a gradual change from one visual state to another, which is just what you need to make Ottergram’s show/hide effect more polished.

When you create a CSS transition, you are telling the browser, “I would like this element’s styles to change to these new properties, and I would like for that change to take exactly as long as I tell you.”

One common example is the fly-out menu seen on many sites, such as the small-screen version of bignerdranch.com. In a browser with a narrow viewport, clicking the menu icon makes the navigation menu appear from the top – but it does not appear all at once. Instead, it slides down from the header, visually animating from the initial state (hidden) to the end state (visible) (Figure 7.11). Clicking the menu icon again causes the navigation menu to slide back up until it is hidden again.

Figure 7.11  Fly-out navigation on bignerdranch.com

Fly-out navigation on bignerdranch.com

Before you create the transition effect for showing and hiding the detail image, you will build a simpler transition for your thumbnails.

In general, you should create transitions in three steps:

  1. Decide what the end state should be. One good approach is to add the CSS declarations for the end state to the target element. This allows you to see them in the browser and make sure that they look the way you intend.

  2. Move the declarations from the target element’s existing declaration block to a new CSS declaration block. You may want to use a new class for the selector for the new block.

  3. Add a transition declaration to the target element. The transition property tells the browser that it will need to visually animate the changes from the current CSS values to the end-state CSS values and that the transition should take place over a specific period of time.

Working with the transform property

Your first transition will increase the size of a thumbnail when you hover over it with the cursor (Figure 7.12). However, you will not directly change the width or height styles. You will use the transform property, which can alter the shape, size, rotation, and location of an element without interrupting the flow of the elements around it.

Figure 7.12  A thumbnail with zoom effect

A thumbnail with zoom effect

The target element for this transition is the .thumbnail-item. You will begin by adding a transform declaration directly to the .thumbnail-item element.

After you have tested it and determined that it is working the way you want, you will move the transformation to a new .thumbnail-item:hover declaration block. Finally, you will add a transition declaration to .thumbnail-item.

In styles.css, begin by adding a transform declaration to .thumbnail-item.

...
.thumbnail-item {
  display: inline-block;
  min-width: 120px;
  max-width: 120px;
  border: 1px solid rgb(100%, 100%, 100%);
  border: 1px solid rgba(100%, 100%, 100%, 0.8);

  transform: scale(2.2);
}
...

transform: scale(2.2) tells the browser that the element should be drawn at 220% of its original size. There are many values that can be used with transform, including advanced 3D effects. The MDN has good coverage of them at developer.mozilla.org/​en-US/​docs/​Web/​CSS/​transform.

Save and view the changes in your browser (Figure 7.13).

Figure 7.13  Dramatically large otter thumbnails

Dramatically large otter thumbnails

You can see that the thumbnails are now much larger than before. In fact, they are too large. Change the value so that they are only a little bit larger:

...
.thumbnail-item {
  display: inline-block;
  min-width: 120px;
  max-width: 120px;
  border: 1px solid rgb(100%, 100%, 100%);
  border: 1px solid rgba(100%, 100%, 100%, 0.8);

  transform: scale(2.2);
  transform: scale(1.2);
}
...

After you save, you should see that the otter thumbnails are only slightly larger than their original size (Figure 7.14).

Figure 7.14  Reasonably large otter thumbnails

Reasonably large otter thumbnails

This scale for the thumbnails looks good, so you can move on to the next step.

Adding a CSS transition

Now it is time to move the end-state style to a new style declaration and set up the transition for the .thumbnail-item element.

When the user hovers the mouse cursor over a thumbnail, that thumbnail should increase its scale by 120%. Add a declaration block to styles.css that uses the modifier :hover to designate styles that should only be applied when the user hovers over the element.

...
.thumbnail-item {
  display: inline-block;
  min-width: 120px;
  max-width: 120px;
  border: 1px solid rgb(100%, 100%, 100%);
  border: 1px solid rgba(100%, 100%, 100%, 0.8);

  transform: scale(1.2);
}

.thumbnail-item:hover {
  transform: scale(1.2);
}
...

The proper name for this modifier is pseudo-class. The psuedo-class :hover matches an element when the user holds the mouse cursor over it. There are a number of pseudo-class keywords that describe the various states an element can be in. You will encounter some when you work with forms later in this book, and you can search the MDN to learn more.

Next, make this change happen as a transition by adding a transition declaration to .thumbnail-item in styles.css. You need to specify the property to animate and how long the animation should take.

...
.thumbnail-item {
  display: inline-block;
  min-width: 120px;
  max-width: 120px;
  border: 1px solid rgb(100%, 100%, 100%);
  border: 1px solid rgba(100%, 100%, 100%, 0.8);

  transition: transform 133ms;
}

.thumbnail-item:hover {
  transform: scale(1.2);
}
...

You set a transition for the transform property. This tells the browser that it will need to animate the change, but only for the transform property. You also specified that the transition should take place over a period of 133 milliseconds.

Save and give your new transition a try. You should see that each thumbnail enlarges when you hover over it. When you move your mouse away, the transition runs in reverse, and the thumbnail returns to its original size (Figure 7.15).

Figure 7.15  Transition occurs when hovering, reverses on mouse out

Transition occurs when hovering, reverses on mouse out

The DevTools give you a handy way to test pseudo-class states. Go to the elements panel and expand the tags until one of the <li> tags is displayed. Click the tag so that it is highlighted and you will see an ellipsis to the left. Click the ellipsis, and in the contextual menu that is revealed choose :hover from the list of pseudo-classes (Figure 7.16).

Figure 7.16  Toggling a pseudo-class in the elements panel

Toggling a pseudo-class in the elements panel

An orange circle appears to the left of the <li> tag in the elements panel, telling you that one of the pseudo-classes has been activated via the DevTools. The corresponding thumbnail will remain in the :hover state, even if you mouse over it and then mouse away from it.

Open the contextual menu again, by clicking the orange circle, and disable the :hover state before you continue.

Your transition is nice, but there is a small bug. Currently, the hover effect causes parts of the thumbnail to be cut off. This is because the transform applied to the .thumbnail-item does not cause its parent to adjust its size. The solution is to add a bit of padding to the .thumbnail-list. Change the vertical padding for .thumbnail-list in styles.css.

...
.thumbnail-list {
  flex: 0 1 auto;
  order: 2;
  display: flex;
  justify-content: space-between;
  list-style: none;
  padding: 0;
  padding: 20px 0;

  white-space: nowrap;
  overflow-x: auto;
}
...

You used the shorthand for the padding property. The first value, 20px, applies to the top and bottom padding, while the second value applies to the left and right padding. Make a similar adjustment inside your @media query, but add an extra padding of 35px to the left and right.

...
@media all and (min-width: 768px) {
  .main-content {
  ...
  }

  .thumbnail-list {
    flex-direction: column;
    order: 0;
    margin-left: 20px;

    padding: 0 35px;
  }
  ...

Save and check the results in your browser. This produces a nicer effect for the thumbnails (Figure 7.17).

Figure 7.17  Extra room for the hover effect in portrait and landscape

Extra room for the hover effect in portrait and landscape

Using a timing function

Your hover effect is looking good! But it lacks that visual pop that would make it really special. With CSS transitions, you can not only specify how much time a transition should take, but also make it transition at different speeds during that time.

There are several timing functions that you can use with transitions. By default, the linear timing function is used, which makes the transition animate at a single, constant rate. The others are more interesting, and give the transition the feeling of speeding up or slowing down.

Update your transition in styles.css so that it uses the ease-in-out timing function. This will make the rate of the transition slower at the beginning and end and faster in the middle.

...
.thumbnail-item {
  display: inline-block;
  min-width: 120px;
  max-width: 120px;
  border: 1px solid rgb(100%, 100%, 100%);
  border: 1px solid rgba(100%, 100%, 100%, 0.8);

  transition: transform 133ms ease-in-out;
}
...

Save and then hover over one of your thumbnails. The effect is subtle, but noticeable.

There are a number of timing functions available. See the list on the MDN at developer.mozilla.org/​en-US/​docs/​Web/​CSS/​transition-timing-function.

Your transition uses the same duration value and timing function for both the transition to the end state and the transition from the end state. That does not have to be the case – you can use different values depending on the direction of the transition. If you specify a transition property on both the beginning-state declaration and the end-state declaration, the browser uses the value of the declaration it is moving toward.

It might be easier to see this in action. For a quick demonstration, add a transition declaration to .thumbnail-item:hover in styles.css. (You will delete it after trying it out in the browser.)

...
.thumbnail-item:hover {
  transform: scale(1.2);
  transition: transform 1000ms ease-in;
}
...

Save and again hover over one of the thumbnails in the browser. The scaling effect will be very slow, taking a full second to complete. This is because it is using the value declared for .thumbnail-item:hover. Now, move your mouse off of the thumbnail. This time, the transition takes 133 milliseconds, the value declared for .thumbnail-item.

Remove the transition declaration from .thumbnail-item:hover before you continue.

...
.thumbnail-item:hover {
  transform: scale(1.2);
  transition: transform 1000ms ease-in;
}
...

Transition on class change

Your second transition will make the .detail-image-frame look like it is zooming in from very far away.

Instead of using a pseudo-class selector to trigger a transition, this time you will add and remove class names with JavaScript to trigger a transition. Why? Because there is no pseudo-class that corresponds to a click event. Using JavaScript gives you much more control over how and when these UI changes are triggered.

Also, you will set different duration times for the beginning and end of the transition. The end result will be that when you click a thumbnail the corresponding otter image will be used for the detail image. It will immediately be sized down to a tiny dot in the center of the detail area, then it will transition to its full size (Figure 7.18).

Figure 7.18  Clicking a thumbnail scales it from very small to full size

Clicking a thumbnail scales it from very small to full size

Start by adding a style declaration for a new class named is-tiny in styles.css.

...
.detail-image-frame {
  ...
}

.is-tiny {
  transform: scale(0.001);
  transition: transform 0ms;
}

.detail-image {
  ...

You added two styles for .is-tiny. The first scales the element down to a small fraction of its original size. The second specifies that any transition for the transform property should last 0 milliseconds, applying the style change immediately. Put another way, going toward the .is-tiny class styles, the detail image will effectively have no transition. Because it lasts for 0 milliseconds, there is no need to specify a timing function.

Next, you will add another transition declaration with a 333 millisecond duration. This value will be used when transitioning away from the .is-tiny class, making the detail image grow to normal size over a period of a third of a second. Add this transition declaration to the .detail-image-frame in styles.css.

...
.detail-image-frame {
  position: relative;
  text-align: center;

  transition: transform 333ms;
}
...

Save styles.css before you move on.

Triggering transitions with JavaScript

Now that your transition styles are in place, you need to trigger them with JavaScript. To give your JavaScript a hook, add a data attribute to the .detail-image-frame element in index.html.

...
      <div class="detail-image-container">
        <div class="detail-image-frame" data-image-role="frame">
    <img class="detail-image" data-image-role="target" src="img/otter1.jpg" alt="">
    <span class="detail-image-title" data-image-role="title">Stayin' Alive</span>
        </div>
      </div>
...

Save index.html. Now, in main.js, you just need to add variables for your .is-tiny class and data-image-role="frame" selector, and then you will update showDetails to perform the class name changes to that trigger the transition.

Begin with the variables. Add a DETAIL_FRAME_SELECTOR variable for a selector string '[data-image-role="frame"]'. Also, add a TINY_EFFECT_CLASS variable for the is-tiny class name.

var DETAIL_IMAGE_SELECTOR = '[data-image-role="target"]';
var DETAIL_TITLE_SELECTOR = '[data-image-role="title"]';
var DETAIL_FRAME_SELECTOR = '[data-image-role="frame"]';
var THUMBNAIL_LINK_SELECTOR = '[data-image-role="trigger"]';
var HIDDEN_DETAIL_CLASS = 'hidden-detail';
var TINY_EFFECT_CLASS = 'is-tiny';
var ESC_KEY = 27;
...

It is not required that you put your variables in this order. (It makes no difference to the browser.) But it is a good idea to keep them organized. In main.js, all of the selector variables are grouped together, followed by the class variables, followed by the numeric code for the Escape key.

Now, update showDetails in main.js so that it gets a reference to the [data-image-role="frame"] element. To trigger the transition, you will need to add the TINY_EFFECT_CLASS and remove it.

...
function showDetails() {
  'use strict';
  var frame = document.querySelector(DETAIL_FRAME_SELECTOR);
  document.body.classList.remove(HIDDEN_DETAIL_CLASS);
  frame.classList.add(TINY_EFFECT_CLASS);
  frame.classList.remove(TINY_EFFECT_CLASS);
}
...

If you saved this and tried it in the browser, you would not see a transition take place. Why not? Because the TINY_EFFECT_CLASS is added and then immediately removed. The net result is that there is no actual class change to render. This is an optimization on the part of the browser.

You need to add a small delay before removing the TINY_EFFECT_CLASS. JavaScript, however, does not have a built-in delay or sleep function, as some other languages do. Time for a workaround!

You are going to use the setTimeout method, which takes a function and a delay (specified in milliseconds). After the delay, the function is queued for execution by the browser.

Add a call to setTimeout after calling frame.classList.add in main.js. Pass it two arguments: a function with a list of steps to perform and the number of milliseconds to wait before invoking that function argument. There is only one step to perform, and that is to remove TINY_EFFECT_CLASS.

...
function showDetails() {
  'use strict';
  var frame = document.querySelector(DETAIL_FRAME_SELECTOR);
  document.body.classList.remove(HIDDEN_DETAIL_CLASS);
  frame.classList.add(TINY_EFFECT_CLASS);
  setTimeout(function () {
    frame.classList.remove(TINY_EFFECT_CLASS);
  }, 50);
}
...

Let’s take a closer look at what this code does. First, it adds the .is-tiny class to the frame element. This applies your transform: scale(0.001).

Then, the browser is told to wait 50 milliseconds, after which it will add an anonymous function to its execution queue. The showDetails function finishes. Fifty milliseconds later, the anonymous function is queued for execution. (Basically, it gets in line for the CPU, waiting behind any other functions that were already in line.)

When this anonymous function runs, it removes the TINY_EFFECT_CLASS from the frame’s class list. This causes the transform transition to run over a period of 333 milliseconds, making the frame grow to its normal size.

Save your changes and admire the results. Click the thumbnails and enjoy those wacky otters zooming into view.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.59.197.213