Definir um pseudo- select mantendo todas as funcionalidades nativas

Digamos que você precise estilizar um select</code> because a designer thought it was a great idea or because a product owner wants a select</code> to looks in a particular way. We all know how difficult it is to have form</code> elements look consistent across browsers or OS's let a alone a select</code>. If you ever ask a developer, how do you style a select</code>? The answer is most likely going to be "you don't".

Então, como você estiliza uma seleção sem estilizá-la? a ideia por trás dessa solução é adicionar um div absolutamente posicionado atrás doselect</code>, set the opacity to 0 on it, and style the element that was just injected. This way you never lose the functionality of a select and do not have to worry about another element triggering a change</code> event.

HTML

<form>
<fieldset>
<select class="pseudo-me">
<option value="Option 1">Option 1</option>
<option value="Option 2">Option 2</option>
<option value="Option 3 - A Longer Option">Really Really Long Option</option>
</select>
</fieldset>
</form>

CSS

body { margin:2%; }

select.pseudo-me,
.pseudo-select,
.select-container {
top
:0;
left
:0;
}

select.pseudo-me,
.pseudo-select,
.pseudo-select .down-arrow,
.pseudo-select .down-arrow-container {
position
:absolute;
}

.select-container { position: relative; }

select.pseudo-me {
opacity
:0;
z
-index:2;
}

.pseudo-select { z-index:1; }

.pseudo-select .down-arrow-container {
top
:0;
right
:0;
}

.pseudo-select .down-arrow {
display
: block;
border
-style:solid;
}

JS (requer jQuery)

$('select.pseudo-me').each(function() {

var $this = $(this),
BORDER
= ($this.css('border-width') == '' || parseInt($this.css('border-width')) == 0) ? '1px solid #000' : $this.css('border'),
BORDER_COLOR
= ($this.css('border-color') === '') ? '#000' : $this.css('border-color'),
COLOR
= $this.css('color'),
BORDER_RADIUS
= ($this.css('border-radius') == '' || parseInt($this.css('border-radius')) == 0) ? '5px' : $this.css('border-radius');

$this

.wrap('<div class="select-container"></div>')
.after('<div class="pseudo-select"><span class="pseudo-select-text"></span><div class="down-arrow-container"><span class="down-arrow"></span></div></div>')
.on('change', function() {
$
('.pseudo-select-text').text($(this).children('option:selected').text());
});

var $downArrow = $('.down-arrow'),
$downArrowContainer
= $('.down-arrow-container');

$
('.pseudo-select, .select-container')
.width($this.innerWidth())
.height($this.innerHeight());

// the down arrow is calculated as a third of the height of the select
$downArrow

.height($this.innerHeight())
.css({'border-width' : $this.innerHeight() / 3,
'top' : $this.innerHeight() / 3,
'right' : $this.innerHeight() / 6,
'border-color' : BORDER_COLOR + ' transparent transparent'});

// setting the height and width the same so that we have proportional spacing based on the select height.
$downArrowContainer

.height($this.innerHeight())
.width($this.innerHeight())
.css('border-left', BORDER);

$
('.pseudo-select')
.css({'font-family': $this.css('font-family'),
'font-size': $this.css('font-size'),
'padding-left': '5px',
'line-height': $this.innerHeight() + 'px',
'border': BORDER,
'color' : COLOR,
'border-radius' : BORDER_RADIUS });

$
('.pseudo-select-text').text($this.children('option:selected').text());
});​

Um Fiddle mostrando um exemplo funcional: http://jsfiddle.net/napotopia/gHDvZ/

Este exemplo faz um pouco mais que apenas ocultar o select</code> and show the faux-select</code> behind it. It gets computed styles and sets default ones when they are not specified. All the styles declared in the CSS portion are for positioning and layout purposes only. Everything that happens on the dynamically generated pseudo-select</code> is either a value retrieved from that element or a calculation most liked based on the border width and border color.

Se você mudar a borda, cor ou raio da borda, ele obterá qualquer um desses valores e atualizará o pseudo-select</code> accordingly: http://jsfiddle.net/napotopia/gHDvZ/186/

Também é importante notar o fato de que a mudança de borda e cor neste último exemplo está sendo aplicada ao select</code> so the hidden element still gets styled as its faux clone.

Eu realmente não gosto da ideia de toda essa hackeagem. Minha primeira resposta é sempre não estilize umselect</code>. Let each device and/or operating system handle how it should look or behave. This hack worked particularly well for a recent hybrid app where a select had to be styled in a specific way but the native functionality was still desired. Use with caution...