Learning jQuery(Fourth Edition)
上QQ阅读APP看书,第一时间看更新

Modifying CSS with inline properties

Before we jump into the nifty jQuery effects, a quick look at CSS is in order. In previous chapters, we have been modifying a document's appearance by defining styles for classes in a separate stylesheet and then adding or removing those classes with jQuery. Typically, this is the preferred process for injecting CSS into HTML because it respects the stylesheet's role in dealing with the presentation of a page. However, there may be times when we need to apply styles that haven't been or can't easily be defined in a stylesheet. Fortunately, jQuery offers the .css() method for such occasions.

This method acts as both a getter and a setter. To get the value of a single style property, we simply pass the name of the property as a string and get a string in return. To get the value of multiple style properties, we can pass the property names as an array of strings to get an object of property-value pairs in return. Multiword property names such as backgroundColor can be interpreted by jQuery when in hyphenated CSS notation (background-color) or camel-cased DOM notation (backgroundColor):

// Get a single property's value
.css('property')
// returns "value"

// Get multiple properties' values
.css(['property1', 'property-2'])
// returns {"property1": "value1", "property-2": "value2"}

For setting style properties, the .css() method comes in two flavors. One flavor takes a single style property and its value and the other takes an object of property-value pairs:

// Single property and its value
.css('property', 'value')

// Object of property-value pairs
.css({
  property1: 'value1',
  'property-2': 'value2'
})

These simple key-value collections, called object literals, are real JavaScript objects that are created directly in code.

Tip

Object literal notation

In a property value, strings are enclosed in quotes as usual, but other data types such as numbers do not require them. Since property names are strings, they typically would be contained in quotes. However, quotation marks are not required for property names if they are valid JavaScript identifiers, such as when they are written in camel-cased DOM notation.

We use the .css() method the same way we've been using .addClass(); we apply it to a jQuery object, which in turn points to a collection of DOM elements. To demonstrate this, we'll play with a style switcher similar to the one from Chapter 3, Handling Events:

  <div id="switcher">
  <div class="label">Text Size</div>
  <button id="switcher-default">Default</button>
  <button id="switcher-large">Bigger</button>
  <button id="switcher-small">Smaller</button>
</div>
<div class="speech">
  <p>Fourscore and seven years ago our fathers brought forth
       on this continent a new nation, conceived in liberty, 
       and dedicated to the proposition that all men are created 
       equal.</p>
  ...
</div>
Tip

Downloadable code examples

As with many of the HTML, CSS, and JavaScript examples in this book, the previous markup is merely a fragment of the complete document. To experiment with the examples, we can download them from the Packt Publishing website at http://www.packtpub.com/support. In addition, the examples can be viewed in an interactive browser at http://book.learningjquery.com/.

By linking to a stylesheet with a few basic style rules, the page will initially look like this:

Once we're done with our code, clicking on the Bigger and Smaller buttons will increase or decrease the text size of <div class="speech">, while clicking on the Default button will reset <div class="speech"> to its original text size.

Setting computed style-property values

If all we wanted was to change the font size a single time to a predetermined value, we could still use the .addClass() method. But, let's suppose now that we want the text to continue increasing or decreasing incrementally each time the respective button is clicked. Although it might be possible to define a separate class for each click and iterate through them, a more straightforward approach would be to compute the new text size each time by getting the current size and increasing it by a set factor (for example, 40 percent).

Our code will start with the $(document).ready() and $('#switcher-large').click() event handlers:

$(document).ready(function() {
  $('#switcher-large').click(function() {
  });
});

Listing 4.1

Next, the font size can be easily discovered by using the .css() method: $('div.speech').css('fontSize'). However, the returned value is a string, containing both the numeric font size value and the units of that value (px). We'll need to strip the unit label off in order to perform calculations with the numeric value. Also, when we plan to use a jQuery object more than once, it's generally a good idea to cache the selector by storing the resulting jQuery object in a variable. We'll take care of these needs with the introduction of a couple of local variables:

$(document).ready(function() {
  var $speech = $('div.speech');
  $('#switcher-large').click(function() {
    var num = parseFloat($speech.css('fontSize'));
  });
});

Listing 4.2

The first line inside $(document).ready() now creates a variable containing a jQuery object pointing to <div class="speech">. Notice the use of a dollar ($) sign in the variable name, $speech. Since the dollar sign is a legal character in JavaScript identifiers, we can use it as a reminder that the variable is storing a jQuery object. Unlike in other programming languages such as PHP, the dollar symbol holds no special significance in JavaScript, the language of jQuery.

Inside the .click() handler, we use parseFloat() to get the font size property's numeric value only. The parseFloat() function looks at a string from the left-hand side to the right-hand side until it encounters a non-numeric character. The string of digits is converted into a floating-point (decimal) number. For example, it would convert the string '12' to the number 12. In addition, it strips non-numeric trailing characters from the string, so '12px' becomes 12 as well. If the string begins with a non-numeric character, parseFloat() returns NaN, which stands for Not a Number.

All that's left to do is to modify the parsed numeric value and to reset the font size based on the new value. For our example, we'll increase the font size by 40 percent each time the button is clicked. To achieve this, we'll multiply num by 1.4 and then set the font size by concatenating num and 'px':

$(document).ready(function() {
  var $speech = $('div.speech');
  $('#switcher-large').click(function() {
    var num = parseFloat($speech.css('fontSize'));
    num *= 1.4;
    $speech.css('fontSize', num + 'px');
  });
});

Listing 4.3

Now when a user clicks on the Bigger button, the text becomes larger. Another click and the text becomes larger:

To get the Smaller button to decrease the font size, we will divide rather than multiply: —num /= 1.4. Better still, we'll combine the two into a single .click() handler on all the <button> elements within <div id="switcher">. Then, after finding the numeric value, we can either multiply or divide depending on the ID of the button that was clicked. Listing 4.4 illustrates this.

$(document).ready(function() {
  var $speech = $('div.speech');
  $('#switcher button').click(function() {
    var num = parseFloat($speech.css('fontSize'));
    if (this.id == 'switcher-large') {
      num *= 1.4;
    } else if (this.id == 'switcher-small') {
      num /= 1.4;
    }
    $speech.css('fontSize', num + 'px');
  });
});

Listing 4.4

Recall from Chapter 3, Handling Events, that we can access the id property of the DOM element referred to by this, which appears here inside the if and else if statements. Here, it is more efficient to use this than to create a jQuery object just to test the value of a property.

It would also be nice to have a way to return the font size to its initial value. To allow the user to do so, we can simply store the font size in a variable immediately when the DOM is ready. We can then restore this value whenever the Default button is clicked. To handle this click event, we could add another else if statement.Instead, though, we will use a switch statement, which is appropriate when we have several cases to handle:

$(document).ready(function() {
  var $speech = $('div.speech');
  var defaultSize = $speech.css('fontSize');
  $('#switcher button').click(function() {
    var num = parseFloat($speech.css('fontSize'));
    switch (this.id) {
      case 'switcher-large':
        num *= 1.4;      
        break;
      case 'switcher-small':
        num /= 1.4;
        break;
      default:
        num = parseFloat(defaultSize);        
    }
    $speech.css('fontSize', num + 'px');
  });
});

Listing 4.5

Here, we're still checking the value of this.id and changing the font size based on it, but if its value is neither 'switcher-large' nor 'switcher-small', it will default to the initial font size.

Using vendor-specific style properties

When browser vendors introduce experimental style properties, they often prefix the property name until the browser's implementation aligns with the CSS specification. When both the implementation and the specification are stable enough, vendors will shed that prefix and allow the standard name to be used. In a stylesheet, therefore, it is not uncommon to see a set of CSS declarations like the following:

-webkit-property-name: value;
-moz-property-name: value;
-ms-property-name: value;
-o-property-name: value;
property-name: value;

If we wanted to apply the same in JavaScript, we would need to test for the existence of the DOM equivalent of these variations: propertyName, WebkitPropertyName, msPropertyName, and so on. With jQuery, however, we can simply the standard property name, like.css('propertyName', 'value'). If that name is not found as a property of the style object, jQuery loops through the vendor prefixes behind the scenes—Webkit, O, Moz, and ms—and uses the first one it does find as a property, if any.