【jQuery】selectタグのデザインをカスタマイズ

フォームをつくるとき、見た目を変えたいことがあるかと思います。
だいたいの要素はCSSでカスタマイズできますが、selectタグのoption要素にはCSSが効きません。

そこで、CSSとjQueryでselectタグを操作する方法をまとめました。

demo

実装方法

HTML

<div id="select">
  <div class="selectBox">
    <div class="selectBox__output"></div>
    <div class="selectBox__selector">
      <div class="selectBox__selectorItem" data-select="cat1">カテゴリ1</div>
      <div class="selectBox__selectorItem" data-select="cat2">カテゴリ2</div>
      <div class="selectBox__selectorItem" data-select="cat3">カテゴリ3</div>
    </div>
    <select name="" id="select01">
      <option value="cat1">カテゴリ1</option>
      <option value="cat2">カテゴリ2</option>
      <option value="cat3">カテゴリ3</option>
    </select>
  </div>
</div>

CSS

*{
  box-sizing: border-box;
}
ul,li{
  margin: 0;
  padding: 0;
  list-style: none;
}

.selectBox{
  position: relative;
  width: 10em;
  height: 60px;
}
.selectBox select{
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
}
.selectBox__output{
  display: flex;
  align-items: center;
  position: relative;
  width: 100%;
  height: 100%;
  padding: 1em;
  border: 1px solid #ccc;
  background-color: #fff;
  border-radius: 5px;
  z-index: 2;
}
.selectBox__output::after{
  display: block;
  position: absolute;
  right: 3%;
  top: 50%;
  font-family: "CONDENSEicon";
  transform: translateY(-50%);
  content: "û";
}
.selectBox__output.open::after{
  transform: translateY(-50%) rotate(180deg);
}
.selectBox__selector{
  display: none;
  position: absolute;
  left: 0;
  top: calc(100% - 1px);
  width: 100%;
  border: 1px solid #ccc;
  background-color: #fff;
  z-index: 10;
}
.selectBox__selectorItem{
  width: 100%;
  padding: .75em;
}
.selectBox__selectorItem+.selectBox__selectorItem{
  border-top: 1px solid #ccc;
}
.selectBox__selectorItem:hover{
  background-color: #0d61ad;
  color:#fff;
}

jQuery

//初期値
$('.selectBox__output').each(function () {
  const defaultText = $(this).next('.selectBox__selector').children('.selectBox__selectorItem:first-child').text()
  $(this).text(defaultText);
})

//出力の枠をクリックした時の動作
$('.selectBox__output').on('click', function (e) {
  e.stopPropagation();
  if ($(this).hasClass('open')) {
    $(this).next('.selectBox__selector').slideUp();
  } else {
    $(this).next('.selectBox__selector').slideDown();
  }
  $(this).toggleClass('open');
});

//選択肢をクリックした時の動作
$('.selectBox__selectorItem').on('click', function () {
  const selectVal = $(this).data('select');
  const selectText = $(this).text();
  $(this).parent('.selectBox__selector').prev('.selectBox__output').text(selectText);
  $(this).parent('.selectBox__selector').slideUp();
  $(this).parents('.selectBox__output').slideDown();
  $(this).parent('.selectBox__selector').next('select').val(selectVal);
});

簡単な説明

空のdivタグ(.selectBox__output)を用意し、そこに選択しているoption要素のテキストをjQueryで取得して出力するようにしています。(jQueryのselectText変数に値が入る)

また、そのすぐ後に、option要素と同じ選択肢を入れたdivタグ(.selectBox__selector)を用意しています。この選択肢にはdata属性でoption要素のvalueと同じ値を持たせています。
そうすることで、この選択肢を選択すると、同じ値のoption要素が選ばれた状態にできるようになっています。(jQueryのselectVal変数に選択した値が入る)

こうして用意した要素はdivタグやspanタグなので、CSSで見た目をカスタマイズすることができます。
selectタグはCSSで後ろに隠してしまえばOKです。
(demoではわかりやすいように見える位置においています。)

まとめ

form系のタグはブラウザごとに見た目が異なるので、サイトのトンマナに合わせて変更したいということはよくあると思います。
radioやcheckboxなどはCSSだけでも見た目カスタマイズできるのですが、selectタグはどうにもならず、jQueryでいろいろすることになってしまいました。。。

もう少し手軽できればなあ、と思うのですが、optionにCSSが効かないのでどうしようもない。。。

トップへ戻る