Welcome to the Hindi Tutor QA. Create an account or login for asking a question and writing an answer.
Pooja in Web Development

Is there a CSS-only way to style a <select> dropdown?

I need to style a <select> form as much as humanly possible, without any JavaScript. What are the properties I can use to do so in CSS?

This code needs to be compatible with all major browsers:

  • Internet Explorer 6, 7, and 8
  • Firefox
  • Safari

2 Answers

0 votes
Nadira

It is possible, but unfortunately mostly in WebKit-based browsers to the extent we, as developers, require. Here is the example of CSS styling gathered from Chrome options panel via built-in developer tools inspector, improved to match currently supported CSS properties in most modern browsers:

select {
 -webkit-appearance: button;
 -moz-appearance: button;
 -webkit-user-select: none;
 -moz-user-select: none;
 -webkit-padding-end: 20px;
 -moz-padding-end: 20px;
 -webkit-padding-start: 2px;
 -moz-padding-start: 2px;
 background-color: #F07575; /* Fallback color if gradients are not supported */
 background-image: url(../images/select-arrow.png), -webkit-linear-gradient(top, #E5E5E5, #F4F4F4); /* For Chrome and Safari */
 background-image: url(../images/select-arrow.png), -moz-linear-gradient(top, #E5E5E5, #F4F4F4); /* For old Firefox (3.6 to 15) */
 background-image: url(../images/select-arrow.png), -ms-linear-gradient(top, #E5E5E5, #F4F4F4); /* For pre-releases of Internet Explorer 10*/
 background-image: url(../images/select-arrow.png), -o-linear-gradient(top, #E5E5E5, #F4F4F4); /* For old Opera (11.1 to 12.0) */
 background-image: url(../images/select-arrow.png), linear-gradient(to bottom, #E5E5E5, #F4F4F4); /* Standard syntax; must be last */
 background-position: center right;
 background-repeat: no-repeat;
 border: 1px solid #AAA;
 border-radius: 2px;
 box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.1);
 color: #555;
 font-size: inherit;
 margin: 0;
 overflow: hidden;
 padding-top: 2px;
 padding-bottom: 2px;
 text-overflow: ellipsis;
 white-space: nowrap;
}

When you run this code on any page within a WebKit-based browser it should change the appearance of the select box, remove standard OS-arrow and add a PNG-arrow, put some spacing before and after the label, almost anything you want.

The most important part is appearance property, which changes how the element behaves.

It works perfectly in almost all WebKit-based browser, including mobile ones, though Gecko doesn't support appearance as well as WebKit, it seems.

0 votes
Nadira

I had this exact problem, except I couldn't use images and was not limited by browser support. This should be «on spec» and with luck start working everywhere eventually.

It uses layered rotated background layers to «cut out» a dropdown arrow, as pseudo-elements wouldn't work for the select element.

Edit: In this updated version I am using CSS variables and a tiny theming system.

:root {
  --radius: 2px;
  --baseFg: dimgray;
  --baseBg: white;
  --accentFg: #006fc2;
  --accentBg: #bae1ff;
}

.theme-pink {
  --radius: 2em;
  --baseFg: #c70062;
  --baseBg: #ffe3f1;
  --accentFg: #c70062;
  --accentBg: #ffaad4;
}

.theme-construction {
  --radius: 0;
  --baseFg: white;
  --baseBg: black;
  --accentFg: black;
  --accentBg: orange;
}

select {
  font: 400 12px/1.3 sans-serif;
  -webkit-appearance: none;
  appearance: none;
  color: var(--baseFg);
  border: 1px solid var(--baseFg);
  line-height: 1;
  outline: 0;
  padding: 0.65em 2.5em 0.55em 0.75em;
  border-radius: var(--radius);
  background-color: var(--baseBg);
  background-image: linear-gradient(var(--baseFg), var(--baseFg)),
    linear-gradient(-135deg, transparent 50%, var(--accentBg) 50%),
    linear-gradient(-225deg, transparent 50%, var(--accentBg) 50%),
    linear-gradient(var(--accentBg) 42%, var(--accentFg) 42%);
  background-repeat: no-repeat, no-repeat, no-repeat, no-repeat;
  background-size: 1px 100%, 20px 22px, 20px 22px, 20px 100%;
  background-position: right 20px center, right bottom, right bottom, right bottom;   
}

select:hover {
  background-image: linear-gradient(var(--accentFg), var(--accentFg)),
    linear-gradient(-135deg, transparent 50%, var(--accentFg) 50%),
    linear-gradient(-225deg, transparent 50%, var(--accentFg) 50%),
    linear-gradient(var(--accentFg) 42%, var(--accentBg) 42%);
}

select:active {
  background-image: linear-gradient(var(--accentFg), var(--accentFg)),
    linear-gradient(-135deg, transparent 50%, var(--accentFg) 50%),
    linear-gradient(-225deg, transparent 50%, var(--accentFg) 50%),
    linear-gradient(var(--accentFg) 42%, var(--accentBg) 42%);
  color: var(--accentBg);
  border-color: var(--accentFg);
  background-color: var(--accentFg);
}
<select>
  <option>So many options</option>
  <option>...</option>
</select>

<select class="theme-pink">
  <option>So many options</option>
  <option>...</option>
</select>

<select class="theme-construction">
  <option>So many options</option>
  <option>...</option>
</select>
...