XPagesのラジオボタンをカッコいいデザインに変える方法

通常、ラジオボタンをCSSだけでデザインする場合によく使われる方法

通常、ラジオボタン、チェックボックスをデフォルトのブラウザの持つデザインではなくカスタマイズしようとした場合、HTMLソースコードを以下のように用意します。

<p>
  <input type="radio" id="radio">
  <label for="radio">ラジオボタン</label>
</p>

ここでまず、ラジオボタンのINPUTタグとLabelタグを兄弟関係で持たせるということが重要になります。その後、CSSによって以下のように指定します。

input[type="radio"]{
  opacity: 0;
}

これにより、丸ポチを100%透過してしまい見えないようにしてやります。
次にLabelタグを使い、好きなようにボタンのデザインを作成してやります。

input[type="radio"]+label:before{
  display: inline-block;
  content: "";
  background-color: lightpink;
  color: crimson;
  border-style: solid;
  border-width: 0.1875em;
  width: 0.625em;
  height: 0.625em;
  margin-top: 0.25em;
  margin-right: 0.25em;
  border-radius: 0.5em;
}
input[type="radio"]:checked+label:before{
  border-style: double;
  border-width: 0.5em;
  width: 0;
  height: 0;
}

こうすることでこのようなラジオボタンにカスタマイズすることができます。

custom-radio

このCSSで重要なのは ”input[type=”radio”]+label:before” としている点です。
つまり、+label とすることでinputタグの兄弟関係にある labelタグのデザインをカスタマイズしています。
なお、なぜこのような遠回りなことをしなければいけないかというと、input タグには「:before」が使えず、またinputタグ自体は非表示しなければならないため、labelを使ってこのような対応になってしまうわけです。

と、ここまではXPagesに全く関係のないHTMLとCSSのお話なので、ラジオボタンをカスタマイズしたい場合はググってみると色々なデザインを発見できると思います。
前置きがかなり長くなりましたが、XPagesで同等のことをしたい場合の説明をします。

XPagesのラジオボタン(ラジオボタングループ)はHTML構造が違う!?

同様のことをXPagesのラジオボタンで行いたい場合、まずXPagesが出力するHTMLソースコードをチェックします。ここではラジオボタングループを利用します。

	<xp:radioGroup id="radioGroup1">
		<xp:selectItem itemLabel="Radio A" itemValue="A"></xp:selectItem>
		<xp:selectItem itemLabel="Radio B" itemValue="B"></xp:selectItem>
	</xp:radioGroup>

すると出力されるコードは以下の通りです。(Domino 9.0.1)

<fieldset id="view:_id1:radioGroup1" class="xspRadioButton">
  <table role="presentation" class="xspRadioButton">
    <tr>
      <td>
        <label for="view:_id1:radioGroup1:0">
          <input type="radio" id="view:_id1:radioGroup1:0" name="view:_id1:radioGroup1" value="A">
          Radio A
        </label>
      </td>
      <td>
        <label for="view:_id1:radioGroup1:1">
          <input type="radio" id="view:_id1:radioGroup1:1" name="view:_id1:radioGroup1" value="B">
          Radio B
        </label>
      </td>
    </tr>
  </table>
</fieldset>

見て頂いて分かるようにinputタグを子にもつようにlabelタグで括られています。これがXPagesでラジオボタンのデザインをカスタマイズすることを難しくしています。

ラジオボタンがチェックされたか、親のタグのLabelから分からない

上記CSSで、”input[type=”radio”]:checked+label:before”というセレクターがありますが、「ラジオボタンがチェックされたとき、その兄弟のラベルのデザインを変更する」という箇所になります。CSSでは「XXXという子要素を持つ親の要素」という逆順のセレクターを指定することが出来ないため、XPagesの「INPUTタグ(ラジオボタン)を選択された時の親のLabelのデザインを変更する」ということが技術的に不可能になります。
(jQuery等を使いJavascriptで処理する場合は可能であったりします。。。)

それでもCSSだけを使って頑張って実装する!

上記CSSによるラジオボタンのデザイン変更が出来ないため、別の方法による実装をする必要があります。

「box-shadow」を駆使して実装する!

XPagesのラジオボタン用のCSSは以下のようになります。

fieldset table td label{
	cursor       : pointer;
	position     : relative;
	padding-left : 5px;
	margin-right : 20px;
	overflow     : hidden;
	height       : 20px;
	padding-left : 22px;
	padding-top  : 8px;
	display      : inline-block;
}
fieldset table td label:before {
	position      : absolute;
	width         : 15px;
	height        : 15px;
	border        : 2px solid lightpink;
	border-radius : 50%;
	left          : 0px;
	top           : 4px;
	content       : '';
	z-index       : 3;
}
fieldset table td label:after {
	content          : '';
	position         : absolute;
	width            : 11px;
	height           : 11px;
	border-radius    : 100%;
	left             : 4px;
	top              : 8px;
	background-color : crimson;
	z-index          : 1;
}
fieldset table td label input[type="radio"] {
	-moz-appearance: none;
	-webkit-appearance: none;
	position   : absolute;
	z-index    : 2;
	width      : 20px;
	height     : 20px;
	left       : -23px;
	top        : 1px;
	margin     : 0px;
	box-shadow : 20px -1px #fff;
}

fieldset table td label input[type="radio"]:checked {
	box-shadow : none;
}
fieldset table td label input[type="radio"]:focus {
	opacity    : 0.2;
	box-shadow : 20px -1px #fff;
}

こちらのCSSでは”label:before”でラジオボタンの外枠を描画、”label:after”で選択時の丸ポチを描画しています。キーはクリック時の丸ポチの表示・非表示を”box-shadow “でマスクすることで実装しています。
多少複雑ですが、こうすることでXPagesの出力するHTMLにCSSを被せるだけでデザインをカスタマイズすることができるようになりました。

なお、このCSSですが、IE8以前のブラウザでは残念ながら正しく動作しません。”box-shadow”がIE8ではまだサポートされていないためです。

おまけ

上記CSSの応用みたいなものですが、ラジオボタンに画像を使うなどアイデア次第でより大幅にデザインを変更することができるようになります。
以下のソースコードでは”box-shadow”を使い選択された値の画像を濃淡により表現しています。

<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">

	<style>
		fieldset {border:none;}
		fieldset table{
		border:none;
		width:30%;
		padding:10px;
		}
		fieldset table td {width:50px;}
		fieldset table td label{
		position : relative;
		width : 30px;
		height : 30px;
		overflow : hidden;
		cursor : pointer;
		}
		fieldset table td label:before {
		content : '';
		display : block;
		width : 30px;
		height : 30px;
		border-radius : 100%;
		position : absolute;
		z-index : 1;
		}
		fieldset table td:nth-child(1) label:before{background:url(./yes.png)
		no-repeat;}
		fieldset table td:nth-child(2) label:before{background:url(./no.png)
		no-repeat;}
		fieldset table td:nth-child(3) label:before{background:url(./maybe.png)
		no-repeat;}
		fieldset table td label input[type="radio"] {
		-moz-appearance: none;
		-webkit-appearance: none;
		margin : 0px;
		position : absolute;
		z-index : 2;
		left : -30px;
		width : 0px;
		height : 0px;
		display : block;
		box-shadow : 30px 0px 0 30px #fff;
		opacity : 0.7;
		}

		fieldset table td label input[type="radio"]:checked {
		box-shadow : none;
		opacity : 1;
		}
		fieldset table td label input[type="radio"]:focus {
		opacity : 0.0;
		}
		fieldset table td label input[type="radio"]:hover {
		box-shadow : 30px 0px 0 30px #fff;
		opacity : 0.5;
		}
	</style>

	<xp:radioGroup id="yesno">
		<xp:selectItem itemLabel="" itemValue="1">
		</xp:selectItem>
		<xp:selectItem itemLabel="" itemValue="0">
		</xp:selectItem>
		<xp:selectItem itemLabel="" itemValue="2">
		</xp:selectItem>
	</xp:radioGroup>
</xp:view>

こちらのコードを実行した場合のイメージがこちらです。アイコン画像をクリックすると選択状態を表すように色が濃くなります。

custom-radio-img