Go to English Blog

Usando CSS3 para formatar radio buttons

Leia em 2 minutos

Quando você não precisa dar suporte para versões antigas do Internet Explorer, sua vida fica infinitamente mais simples. Muitas funcionalidades que antes exigiam JavaScript agora podem ser feitas com apenas CSS.

Estou fazendo o novo site do HOWTO e em uma das partes do formulário de inscrição eu exibo os meios de pagamento.

Meios de pagamentos

A ideia é que ele se comporte como um radio button comum, mas que adicione uma borda e um ícone indicando o pagamento selecionado. O markup que usei é bastante simples e sem elementos especiais.

<ul class="payment-methods">
  <li class="payment-method paypal">
    <input name="payment_methods" type="radio" id="paypal">
    <label for="paypal">PayPal</label>
  </li>

  <li class="payment-method pagseguro">
    <input name="payment_methods" type="radio" id="pagseguro">
    <label for="pagseguro">PagSeguro</label>
  </li>

  <li class="payment-method bankslip">
    <input name="payment_methods" type="radio" id="bankslip">
    <label for="bankslip">Boleto</label>
  </li>
</ul>

O CSS que define cada uma das caixas é bastante simples.

.payment-methods {
  list-style: none;
  margin: 0;
  padding: 0;
}

.payment-methods:after {
  content: "";
  clear: both;
}

.payment-method {
  border: 1px solid #ccc;
  box-sizing: border-box;
  float: left;
  height: 70px;
  position: relative;
  width: 120px;
}

.payment-method + .payment-method {
  margin-left: 25px;
}

Isso fará com que as caixas tenham essa aparência.

Caixas tomando forma

Agora, vamos fazer com que o label fique por cima do radio button. Para fazer isso, vamos adicionar uma cor de fundo e posicionar o elemento.

.payment-method label {
  background: #fff no-repeat center center;
  bottom: 1px;
  cursor: pointer;
  display: block;
  font-size: 0;
  left: 1px;
  position: absolute;
  right: 1px;
  text-indent: 100%;
  top: 1px;
  white-space: nowrap;
}

.pagseguro label {
  background-image: url(uol.png);
}

.paypal label {
  background-image: url(paypal.png);
}

.bankslip label {
  background-image: url(bankslip.png);
}

Fazendo a substituição do texto por imagens

Agora, vamos fazer o elemento ser destacado quando é focado. Para isso nós iremos usar o pseudo-seletor :focus.

.payment-methods input:focus + label {
  outline: 2px dotted #21b4d0;
}

Definindo o outline do elemento com foco

Para fazer o elemento selecionado ser marcado, basta adicionar uma regra semelhante usando o pseudo-seletor :checked.

.payment-methods input:checked + label {
  outline: 4px solid #21b4d0;
}

Marcando o elemento selecionado

Só falta definir o ícone de “checked”. Para fazer isso, vamos definir um pseudo-elemento com uma imagem de fundo.

.payment-methods input:checked + label:after {
  background: url(checked.png);
  bottom: -10px;
  content: "";
  display: inline-block;
  height: 20px;
  position: absolute;
  right: -10px;
  width: 20px;
}

Infelizmente, isso não funcionou muito bem no Firefox, embora tenha funcionado em todos os outros navegadores, incluindo Internet Explorer 9. Aparentemente ele se perde por que o label não tem suas dimensões especificadas; em vez de definir a altura e largura, posicionei o elemento com top, right, bottom e left, expandindo o elemento.

Erro de renderização do Firefox

Como eu não quis definir as dimensões, mudei a abordagem e deixei o ícone com uma aparência quadrada somente no Firefox. E para fazer isso usei a instrução @-moz-document.

@-moz-document url-prefix() {
  .payment-methods input:checked + label:after {
    bottom: 0;
    right: 0;
    background-color: #21b4d0;
  }
}

Uma cara diferente para corrigir o Firefox

A vantagem de ter feito tudo isso usando CSS é que todo o comportamento dos radios buttons permaneceu inalterado, como a seleção através de teclado e o foco no elemento, sem ter que usar nenhuma linha de JavaScript sequer. \m/

O resultado final pode ser visto no Codepen.