Skip to content

Latest commit

 

History

History
216 lines (166 loc) · 5.83 KB

answer-02-using-css.md

File metadata and controls

216 lines (166 loc) · 5.83 KB

Answer Exercise 2

HTML

<div class="row vertical">
  <label for="type_of_bicycle" title="Type of bicycle">Type of bicycle</label>
  <select id="type_of_bicycle">
    <option value=""></option>
    <option value="road">Road</option>
    <option value="mountain">Mountain</option>
  </select>
</div>

<div id="bicycle-fields">
  <div id="size-row" class="row vertical">
    <label for="size" title="Size">Size</label>
    <input id="size" type="text" autocomplete="off">
  </div>

  <div id="chain-size-row" class="row vertical">
    <label for="chain_size" title="Chain size">Chain size</label>
    <input id="chain_size" type="text" autocomplete="off">
  </div>

  <div id="tire-size-row" class="row vertical">
    <label for="tire_size" title="Tire size">Tire size</label>
    <input id="tire_size" type="text" autocomplete="off">
  </div>

  <div id="front-shocks-row" class="row vertical">
    <label for="front_shocks" title="Front shocks">Front shocks</label>
    <input id="front_shocks" type="text" autocomplete="off">
  </div>

  <div id="rear-shocks-row" class="row vertical">
    <label for="rear_shocks" title="Rear shocks">Rear shocks</label>
    <input id="rear_shocks" type="text" autocomplete="off">
  </div>

  <div id="tape-color-row" class="row vertical">
    <label for="tape_color" title="Tape color">Tape color</label>
    <input id="tape_color" type="text" autocomplete="off">
  </div>
</div>

The two new fields, "Size" and "Rear shocks", were added to the HTML.

Each row now has a id attribute that can be used in a CSS selector to, for example, hide the row.

All rows are now wrapped by a div element with id #bicycle-fields. We'll see how that is used in a bit.

JavaScript

var $ = ITRP.$;            // jQuery
var $extension = $(this);  // The UI extension container with custom HTML

var $bicycleType   = $("#type_of_bicycle", $extension);
var $bicycleFields = $("#bicycle-fields", $extension);

$bicycleType.change(function() {
  $bicycleFields.removeAttr('class');

  if (this.value === "road") {
    $bicycleFields.addClass('with-road-selected');

  } else if (this.value === "mountain") {
    $bicycleFields.addClass('with-mountain-selected');
  }
}).change();

We got rid of some code, hurray! Less code, less bugs :)

The lines calling hide() on each row were replaced by a single line:

$bicycleFields.removeAttr('class');

This removes the entire class attribute from the #bicycle-fields element.

Note, that this is only possible when there are no other CSS classes already set on the #bicycle-fields element. Otherwise, you should explicitly remove the classes to avoid removing the existing classes as well. For example:

<div id="bicycle-fields" class="blink">
  ...
</div>

Calling $bicycleFields.removeAttr('class') would also remove the blink class in this case. Instead we have to specify explicitly which classes to remove:

$bicycleFields.removeClass('with-road-selected with-mountain-selected');

The lines calling show on each row were replaced by:

$bicycleFields.addClass('with-road-selected');

That will set the CSS class with-road-selected on the #bicycle-fields element when the "Road" option is selected.

Now, let's look at the CSS to see how those classes are used.

CSS

#bicycle-fields {
  .row { display: none; }
}

#bicycle-fields.with-road-selected {
  #size-row,
  #chain-size-row,
  #tire-size-row,
  #tape-color-row {
    display: block;
  }
}

#bicycle-fields.with-mountain-selected {
  #size-row,
  #chain-size-row,
  #tire-size-row,
  #front-shocks-row,
  #rear-shocks-row {
    display: block;
  }
}

Let's look at the CSS selectors to see how they help us to hide and show the correct rows depending on which type of bicycle is selected.

When no type of bicycle has been selected (e.g. the empty option has been selected) all rows are hidden. The following selector achieves this:

#bicycle-fields {
  .row { display: none; }
}

The JavaScript will add either with-road-selected or with-mountain-selected to the #bicycle-fields wrapper element depending on which type of bicycle was selected. Two CSS selectors are used for this:

#bicycle-fields.with-road-selected { ... }
#bicycle-fields.with-mountain-selected { ... }

These selectors are more specific than the first selector. This means that every CSS rule added to these blocks overrides (or is more !important) than similar rules defined in the first selector.

We can use this to override the display: none rule on the .row elements by display: block for each row that needs to be shown for the selected type of bicycle:

#size-row,
#chain-size-row,
#tire-size-row,
#tape-color-row {
  display: block;
}

You might have noticed that it is not actually CSS. It is actually SCSS. It is converted to CSS on the server before rendering it in the HTML page.

SCSS is an extension of the syntax of CSS. This means that every valid CSS stylesheet is a valid SCSS file with the same meaning.

SCSS allows you (among other things) to nest your CSS selectors. This makes it possible to write simpler, more readable CSS. For example, let's take a look what the above SCSS selectors looks like in CSS:

#bicycle-fields .row {
  display: none;
}

#bicycle-fields.with-road-selected #size-row,
#bicycle-fields.with-road-selected #chain-size-row,
#bicycle-fields.with-road-selected #tire-size-row,
#bicycle-fields.with-road-selected #tape-color-row {
  display: block;
}

#bicycle-fields.with-mountain-selected #size-row,
#bicycle-fields.with-mountain-selected #chain-size-row,
#bicycle-fields.with-mountain-selected #tire-size-row,
#bicycle-fields.with-mountain-selected #front-shocks-row,
#bicycle-fields.with-mountain-selected #rear-shocks-row {
  display: block;
}

Continue to the next exercise.