ユーザーの目的や行動に合わせ、タスクが分岐し、選択に応じてその下流で必要となる情報が変わってくるような場合があります。必要となりうる全ての情報をいちどに画面に表示すると、情報量が多くなり視覚的に煩雑になるとともに、ユーザーが自分の場合に必要な情報を拾い上げる負荷が高くなってしまいます。非常に頻度の低いタスクが混じっている場合にはなおさらです。
単に量の問題だけでなく、その表示ではおそらく注釈や説明文(「〇〇を選んだかたは下記〈a〉から〈d〉に入力を、△△を選んだ方は〈e〉と〈f〉にも入力してください」など)を用いて、ユーザー自身に必要な情報を判断させる負担を強いることにもなるでしょう。
入力に合わせて表示を制御
ユーザーの選択によって続く必要な情報のセットが分岐する場合には、当初の状態では分岐の下流となる情報は最も頻度の高い・重要な選択に合わせたものを初期表示としておき、ユーザーの入力を得てから置き換えるようにします。そのユーザーに関係のあるものだけが表示されるため、無関係な情報の中に必要な要素が埋没してユーザーが見つけにくくなるのを避けるとともに、表示される全体の情報量を減らせるため、心理的な抵抗やおっくうさを感じさせることも防げます。
あるいは初期状態では表示をせず、ユーザーが要求するか必要となるまでは隠しておく「進行性の追加表示」という考え方も有効です。何かの設定などで、ユーザーが滅多に変更しない設定はデフォルト値を用意しておくとともにユーザーが変更したいと意思表示するまで隠しておくといったケースが考えられます。
動的に成長するように展開していくタスクを見ながら、ユーザーはそのタスクについての正しいメンタルモデルをより素早く形成することができます。
また、いちどに全てを表示しないことで、量的にだけでなく構造的に、一連のUIを1つのページに収めておくことができるので、画面の遷移コストをかけずに済みます。
下記は入力(選択)に合わせて、続く入力の表示を切り替えるパターンです。個別の入力単位あるいはある程度まとまった情報グループ単位での切り替え制御とするかは、実際のシステムでの必然性をよく考慮してください。
トリガとなるチェックボックスの<label>に.js-check_item、任意のidをつけます。
対象となる要素に.js-check_itemチェックボックスのid__tgtをつけます。
<div class="row">
<div class="col-sm-3">
<div class="form-group">
<label class="checkbox checkbox-inline js-check_item" id="01-01">
<input type="checkbox" value="1" data-toggle="checkbox" checked>
品目を指定
</label>
</div>
</div>
</div>
<div class="js-check_item01-01__tgt">
...
</div>
/**
* チェックボックス動作確認
* @type {Object}
*/
const checkView = {
/**
* 動作
* @param {String} id クリックされた要素のID
*/
behavior: function(id) {
const $tgt = $('.js-check_item' + id + '__tgt');
const $tgtId = $('#' + id);
if($tgtId.hasClass('checked')) {
$tgt.hide();
tgtDisable($tgt);
} else {
$tgt.fadeIn('fast');
tgtEnable($tgt);
}
}
};
/**
* ターゲットとなるjQueryオブジェクト
* @type {Object}
*/
const $tgtCheckItem = $('.js-check_item');
$tgtCheckItem.on('click', function() {
/**
* クリックされた要素のID取得
* @type {String}
*/
const id = $(this).attr('id');
checkView.behavior(id);
});
トリガとなるスイッチを囲った.form-groupに.js-switch_item、任意のidをつけます。
対象となる要素に.js-switch_itemスイッチのid__tgtをつけます。
<div class="row">
<div class="col-sm-3">
<div class="form-group js-switch_item" id="02-01">
<span class="label-additional js-label-tgl-swt">上級者モード</span>
<div class="js-tgl-swt js-tgl-swt--rnd">
<input type="checkbox" checked data-toggle="switch" components="switch" />
</div>
</div>
</div>
</div>
<div class="js-switch_item02-01__tgt">
...
</div>
/**
* スイッチ動作確認
* @type {Object}
*/
const switchView = {
/**
* 動作
* @param {String} id クリックされた要素のID
*/
behavior: function(id) {
const $tgt = $('.js-switch_item' + id + '__tgt');
const $tgtId = $('#' + id).find('.switch-animate');
if($tgtId.hasClass('switch-off')) {
$tgt.hide();
tgtDisable($tgt);
} else {
$tgt.fadeIn('fast');
tgtEnable($tgt);
}
}
};
/**
* ターゲットとなるjQueryオブジェクト
* @type {Object}
*/
const $tgtSwitchItem = $('.js-switch_item');
$tgtSwitchItem.find('[data-toggle="switch"]').on('change', function() {
const switchItem = $(this).parents('.js-switch_item');
const id = switchItem.attr('id');
switchView.behavior(id);
});
対象となる要素のクラスに.js-radio_itemラジオのname__tgt、idにラジオのname_valueの値をつけます。
<div class="row">
<div class="col-md-12">
<div class="form-group">
<label class="radio radio-inline js-radio_item">
<input type="radio" name="03-01" value="1" data-toggle="radio">
メンズ
</label>
<label class="radio radio-inline js-radio_item">
<input type="radio" name="03-01" value="2" data-toggle="radio" checked>
レディース
</label>
</div>
</div>
</div>
<div class="js-radio_item03-01__tgt displaynone" id="03-01_1">
...
</div>
<div class="js-radio_item03-01__tgt" id="03-01_2">
...
</div>
/**
* ラジオ切替え動作確認
* @type {Object}
*/
const radioView = {
behavior: function($tgt, name, _this) {
let selectedRadio = '';
let $onChangeRadio = $(_this);
if($onChangeRadio.prop('checked')) {
$tgt.hide();
tgtDisable($tgt);
if($onChangeRadio.prop('checked') && selectedRadio != _this.value) {
$('#' + name + '_' + _this.value).fadeIn('fast');
tgtEnable($tgt);
selectedRadio = _this.value;
}
}
}
};
/**
* ターゲットとなるjQueryオブジェクト
* @type {Object}
*/
const $tgtInputRadio = $('.js-radio_item').find('input:radio');
$tgtInputRadio.on('change', function() {
const name = $(this).attr('name');
const $tgt = $('.js-radio_item' + name + '__tgt');
radioView.behavior($tgt, name, this);
});
トリガとなる<select>に.js-select_item、任意のidをつけます。
対象となる要素に.js-select_item-selectのid__tgt、idにselectのid_optionのvalueの値をつけます。
<div class="row">
<div class="col-sm-4">
<div class="form-group">
<label><span class="label-text">ラベル</span></label>
<select name="input" class="select-block form-control js-select_item" id="04-01">
<option value="1" selected>Drinks</option>
<option value="2">Vegitables</option>
<option value="3">Fruits</option>
<option value="4">Others</option>
</select>
</div>
</div>
<div class="col-sm-4">
<div class="form-group js-select_item-04-01__tgt" id="04-01_1">
<label><span class="label-text"> </span></label>
<select name="input" class="select-block form-control">
<option value="1">beer</option>
<option value="2">wine</option>
<option value="3">sake</option>
</select>
</div>
<div class="form-group js-select_item-04-01__tgt" id="04-01_2" style="display: none;">
<label><span class="label-text"> </span></label>
<select name="input" class="select-block form-control">
<option value="1">broccoli</option>
<option value="2">onion</option>
<option value="3">tomato</option>
</select>
</div>
<div class="form-group js-select_item-04-01__tgt" id="04-01_3" style="display: none;">
<label><span class="label-text"> </span></label>
<select name="input" class="select-block form-control">
<option value="1">peach</option>
<option value="2">apple</option>
<option value="3">watermelon</option>
</select>
</div>
<div class="form-group js-select_item-04-01__tgt" id="04-01_4" style="display: none;">
<label><span class="label-text"> </span></label>
<input type="text" class="form-control" placeholder="品目名を入力">
</div>
</div>
</div>
/**
* ドロップダウン動作確認
* @type {Object}
*/
const selectView = {
/**
* 動作
* @param {String} id クリックされた要素のID
* @param {Number} rel セレクトされた要素のインデックス
*/
behavior: function(id, rel) {
const $tgt = $('.js-select_item-' + id + '__tgt');
const $tgt2 = $('#' + id + '_' + rel);
$tgt.hide();
tgtDisable($tgt);
$tgt2.fadeIn('fast');
tgtEnable($tgt2);
}
};
$(document).find('.js-select_item').find('.dropdown-menu').on('click', 'li', function() {
const id = $(this).closest('.js-select_item').find('select').attr('id');
const rel = parseInt($(this).attr('data-original-index')) + 1;
selectView.behavior(id, rel);
});
下記は表示に合わせて入力の有効/無効も制御するために共通で使用する関数です。
/**
* 無効にする関数
* @see 入力に合わせて表示を制御
* @type {Function}
* @param {Object} tgt ターゲットとなるオブジェクト
*/
const tgtDisable = function tgtDisable($tgt) {
$tgt.find('select, input').attr('disabled', 'disabled');
$tgt.find('.select-block, .btn').addClass('disabled');
};
/**
* 有効にする関数
* @see 入力に合わせて表示を制御
* @type {Function}
* @param {Object} tgt ターゲットとなるオブジェクト
*/
const tgtEnable = function tgtEnable($tgt) {
$tgt.find('select, input').removeAttr('disabled');
$tgt.find('.select-block, .btn').removeClass('disabled');
};
反応的な追加表示のように、ユーザーの入力(選択)に応じて入力を制御するものに、「反応的なイネーブル化」があります。あるパラメーターなどの入力が通常時は無効化されていて、特定の属性を選択した場合のみ有効化されるといったものです。反応的な追加表示との違いは、無効化されている状態でも表示はされている点です。ユーザーの選択によって有効化されるコントロールの存在をあらかじめ知らせておけるため、その時点では使う必要がないものも含めてユーザーに利用可能なコントロールの全貌を把握させることができるという利点があります。
しかしながら、表示する情報量を抑えることで視覚的なシンプルさを保ち、構造的にユーザーの理解を助け、ユーザーの負荷を減らすというそもそもの観点からは相容れない側面もあります。見た目の複雑さ・煩雑さがユーザーの判断力を要求しすぎ、ストレスを招くことにならないように、限られた箇所でごく少ない量のコントロールに対して、必然性のある範囲にとどめて使用します。そしてそれらが有効化されるための入力はすぐ近くに近接しているようにします。