・文字がセンタリングできない ・スマホブラウザがどうしてもクセが強いこんな理由で、もう少し普通のエレメントのように扱いたいし、CSSもセットしたいという意見も良く聞きます。
通常のselectタグの見た目
<!DOCTYPE html>
<html>
<head>
<style>
select:nth-of-type(1){
border:1px solid black;
padding:5px;
width:100px;
}
</style>
</head>
<body>
<select>
<option value="1">AAA</option>
<option value="2">BBB</option>
<option value="3">CCC</option>
</select>
<select>
<option value="4">DDD</option>
<option value="5">EEE</option>
<option value="6">FFF</option>
</select>
</body>
</html>
GoogleChrome
Safari
Firefox
iPhone
1つ目のselectタグにだけ、cssを適用してみました。
こうやってみると、どのブラウザも見え方が違うので、
やはりデザイン統一するというのは、必須と思われますね。
ソースコード
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="select.css">
<script src="select.js"></script>
<style>
select:nth-of-type(1){
border:1px solid black;
padding:5px;
width:100px;
}
</style>
</head>
<body>
<select onchange="javascript:console.log(this.value);">
<option value="">選択してください。</option>
<option value="1">AAA</option>
<option value="2">BBB</option>
<option value="3">CCC</option>
</select>
<select onchange="javascript:console.log(this.value);">
<option value="4">DDD</option>
<option value="5">EEE</option>
<option value="6">FFF</option>
</select>
</body>
</html>
:root{
--select-color:orange;
}
[type="select"]{
border:2px solid var(--select-color);
position:relative;
display:inline-block;
width:100px;
height:40px;
line-height:40px;
text-align:center;
border-radius:4px;
vertical-align:middle;
margin:4px;
cursor:pointer;
color:var(--select-color);
white-space:nowrap;
overflow:hidden;
}
[type="select"]:before{
content:"";
position:absolute;
display:block;
width:0px;
height:0px;
right:5px;
top:50%;
transform:translate(0,-50%);
border-style: solid;
border-width: 12.1px 7px 0 7px;
border-color: var(--select-color) transparent transparent transparent;
}
[type="pulldown"]{
position:absolute;
border:0;
margin:2px 0 0 0;
padding:0;
list-style:none;
box-shadow:2px 2px 8px rgba(0,0,0,0.3)
}
[type="pulldown"] > *{
height:20px;
margin:0;
padding:5px;
border:2px solid var(--select-color);
color:var(--select-color);
text-align:center;
cursor:pointer;
white-space:nowrap;
overflow:hidden;
}
[type="pulldown"] > *:nth-of-type(n+2){
border-top:0;
}
[type="pulldown"] > *:hover{
background-color:var(--select-color);
color:white;
}
window.$$select = (function(){
// labelタグに入っているcheckboxボタンの一覧を取得
let MAIN = function(){
let selects = document.querySelectorAll("select");
if(!selects){return;}
for(let select of selects){
this.set_select(select);
}
window.addEventListener("click" , this.click_window.bind(this));
};
// ラジオボタンの設定フロー
MAIN.prototype.set_select = function(select){
if(!select){return;}
this.set_element(select);
this.set_value(select);
};
// 画面クリックした時の処理
MAIN.prototype.click_window = function(e){
// span-click
let span = this.upperSelector(e.target , "span[type='select']");
if(span){
let select = span.nextSibling;
if(!document.querySelectorAll("ul[type='pulldown']").length){
this.view_pulldown(select);
}
else{
this.close_pulldown();
}
return;
}
let li = this.upperSelector(e.target , "ul[type='pulldown'] li");
if(li){
this.click_list(li);
return;
}
this.close_pulldown();
};
// デザイン用エレメントの作成
MAIN.prototype.set_element = function(select){
let new_select = document.createElement("span");
new_select.setAttribute("type" , "select");
select.parentNode.insertBefore(new_select , select);
select.style.setProperty("display","none","");
};
// プルダウンメニューの表示
MAIN.prototype.view_pulldown = function(select){
if(!select){return;}
let view_select = select.previousSibling;
if(view_select.getAttribute("type") !== "select"){return;}
this.close_pulldown();
let pulldown = document.createElement("ul");
pulldown.setAttribute("type" , "pulldown");
pulldown.style.setProperty("top" , (view_select.offsetTop + view_select.offsetHeight) +"px","");
pulldown.style.setProperty("left" , view_select.offsetLeft +"px","");
pulldown.style.setProperty("width" , view_select.offsetWidth +"px","");
view_select.parentNode.insertBefore(pulldown , view_select);
for(let i=0; i<select.options.length; i++){
let li = document.createElement("li");
li.textContent = select.options[i].text;
li.value = select.options[i].value;
pulldown.appendChild(li);
}
}
MAIN.prototype.close_pulldown = function(){
let pulldowns = document.querySelectorAll("ul[type='pulldown']");
if(!pulldowns){return;}
for(let i=pulldowns.length-1; i>=0; i--){
pulldowns[i].parentNode.removeChild(pulldowns[i]);
}
};
MAIN.prototype.click_list = function(li){
if(!li){return;}
let ul = li.parentNode;
let span = ul.nextSibling;
let select = span.nextSibling;
select.value = li.value;
this.close_pulldown();
select.onchange();
this.set_value(select);
};
// 値処理
MAIN.prototype.set_value = function(select){
if(!select){return;}
let target = select.previousSibling;
let value = select.options[select.selectedIndex].text;
target.textContent = value;
};
// lib
MAIN.prototype.upperSelector = function(elm , selectors) {
selectors = (typeof selectors === "object") ? selectors : [selectors];
if(!elm || !selectors){return;}
var flg = null;
for(var i=0; i<selectors.length; i++){
for (var cur=elm; cur; cur=cur.parentElement) {
if (cur.matches(selectors[i])) {
flg = true;
break;
}
}
if(flg){break;}
}
return cur;
}
return MAIN;
})();
// 起動処理(ページ読み込み完了を待ってスタート)
switch(document.readyState){
case "complete" :
new $$select();
break;
case "interactive" :
window.addEventListener("DOMContentLoaded" , function(){new $$select()});
break;
default :
window.addEventListener("load" , function(){new $$select()});
break;
}
解説
思いの外、長いプログラムになってしまいました。 簡単に擬似エレメントを追加するだけと思っていたんですが、 プルダウンリストも擬似構築するハメになってしまいました。 (あたりまえですよね・・・) でも、もとのselectタグには、ほぼ影響せずにコントロール&表示することができるので、 どのブラウザでも依存せずに表示できますし、 DOM構造も、基本的に変えていないので、そのままのシステムで利用できるはずです。 ただ、cssで、要素に対するデザインを細かく設定をしておかないといけないので、 そうした点は、そもそもそれを目的にしているのでヨシと判断しました。 プルダウンらしさを出すために、表示の右端に擬似要素で逆三角形を表示して、おきました。 こういうの大事ですよね。 あと、selectタグにonchangeイベントがついている場合も多いので、 値を切り替えたあとで、onchangeイベントを実行して、できるだけ動作を継承できるようにはしています。 他のイベントも必要だったら、機能追加してお使いください。 ちなみに、iphone独特のプルダウン選択よりも、パソコンと同様のプルダウン表示の方が 個人的には好きなので、この方法は鉄板であると、 改めて感じましたね。デモ
See the Pen efo-select by YugetaKoji (@geta1972) on CodePen.
0 件のコメント:
コメントを投稿