Pseudo elements and SELECT tag

CssHtml SelectPseudo Element

Css Problem Overview


Does the select tag allows to use the :after selector in order to create a pseudo element after it?

I've tried on Chrome, Safari and Firefox on Mac and it doesn't seem to work.

Css Solutions


Solution 1 - Css

Here is a compromise that I have used. http://jsfiddle.net/pht9d295/3/

<div class="select-wrapper">
    <select>
        <option>United Kingdom</option>
        <option>Canada</option>
        <option>United States</option>
    </select>
</div>

And CSS

body {
    background-color: #f6f6f6;
    padding: 10px;
}
.select-wrapper {
    background-color: #FFF;
    display: inline-block;
    position: relative;
}
.select-wrapper:after {
    content:"\f078";
    font-family:'FontAwesome';
    position: absolute;
    top: 13px;
    right: 10px;
    z-index: 5;
    pointer-events: none;
 }
select {
    padding: 10px 40px 10px 10px;
    -webkit-appearance: none;
    -ms-appearance: none;
    -moz-appearance: none;
    appearance: none;
    border: 1px solid #bbb;
    background-color: transparent;
    border-radius: 0;
    position: relative;
    cursor: pointer;
    z-index: 10;
}

Solution 2 - Css

Well, it looks like the select tags doesn't allow :after or :before pseudos because they are customized by each vendor, so it's quite hard to modify them and that's because they don't allow :before or :after pseudo elements on them.

To everyone who sees this, there's a good option to create a custom select element with jQuery and minimal modification… Create a select and then use jQuery to edit it:

// Iterate over each select element
$('select').each(function() {
  // Cache the number of options
  var $this = $(this),
    numberOfOptions = $(this).children('option').length;

  // Hides the select element
  $this.addClass('s-hidden');

  // Wrap the select element in a div
  $this.wrap('<div class="select"></div>');

  // Insert a styled div to sit over the top of the hidden select element
  $this.after('<div class="styledSelect"></div>');

  // Cache the styled div
  var $styledSelect = $this.next('div.styledSelect');

  // Show the first select option in the styled div
  $styledSelect.text($this.children('option').eq(0).text());

  // Insert an unordered list after the styled div and also cache the list
  var $list = $('<ul />', {
    'class': 'options'
  }).insertAfter($styledSelect);

  // Insert a list item into the unordered list for each select option
  for (var i = 0; i < numberOfOptions; i++) {
    $('<li />', {
      text: $this.children('option').eq(i).text(),
      rel: $this.children('option').eq(i).val()
    }).appendTo($list);
  }

  // Cache the list items
  var $listItems = $list.children('li');

  // Show the unordered list when the styled div is clicked (also hides it if the div is clicked again)
  $styledSelect.click(function(e) {
    e.stopPropagation();
    $('div.styledSelect.active').each(function() {
      $(this).removeClass('active').next('ul.options').hide();
    });
    $(this).toggleClass('active').next('ul.options').toggle();
  });

  // Hides the unordered list when a list item is clicked and updates the styled div to show the selected list item
  // Updates the select element to have the value of the equivalent option
  $listItems.click(function(e) {
    e.stopPropagation();
    $styledSelect.text($(this).text()).removeClass('active');
    $this.val($(this).attr('rel'));
    $list.hide();
    /* alert($this.val()); Uncomment this for demonstration! */
  });

  // Hides the unordered list when clicking outside of it
  $(document).click(function() {
    $styledSelect.removeClass('active');
    $list.hide();
  });
});

body {
  padding: 50px;
  background-color: white;
}

.s-hidden {
  visibility: hidden;
  padding-right: 10px;
}

.select {
  cursor: pointer;
  display: inline-block;
  position: relative;
  font: normal 11px/22px Arial, Sans-Serif;
  color: black;
  border: 1px solid #ccc;
}

.styledSelect {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background-color: white;
  padding: 0 10px;
  font-weight: bold;
}

.styledSelect:after {
  content: "";
  width: 0;
  height: 0;
  border: 5px solid transparent;
  border-color: black transparent transparent transparent;
  position: absolute;
  top: 9px;
  right: 6px;
}

.styledSelect:active,
.styledSelect.active {
  background-color: #eee;
}

.options {
  display: none;
  position: absolute;
  top: 100%;
  right: 0;
  left: 0;
  z-index: 999;
  margin: 0 0;
  padding: 0 0;
  list-style: none;
  border: 1px solid #ccc;
  background-color: white;
  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
  -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
}

.options li {
  padding: 0 6px;
  margin: 0 0;
  padding: 0 10px;
}

.options li:hover {
  background-color: #39f;
  color: white;
}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<select id="selectbox1">
  <option value="">Select an option&hellip;</option>
  <option value="aye">Aye</option>
  <option value="eh">Eh</option>
  <option value="ooh">Ooh</option>
  <option value="whoop">Whoop</option>
</select>

<select id="selectbox2">
  <option value="">Month&hellip;</option>
  <option value="january">January</option>
  <option value="february">February</option>
  <option value="march">March</option>
  <option value="april">April</option>
  <option value="may">May</option>
  <option value="june">June</option>
  <option value="july">July</option>
  <option value="august">August</option>
  <option value="september">September</option>
  <option value="october">October</option>
  <option value="november">November</option>
  <option value="december">December</option>
</select>

http://jsfiddle.net/tovic/ZTHkQ/

Solution 3 - Css

This is a modern solution I cooked up using font-awesome. I'm not sure how cross-browser friendly it is. Vendor extensions have been omitted for brevity.

HTML

<fieldset>
    <label for="color">Select Color</label>
    <div class="select-wrapper">
        <select id="color">
            <option>Red</option>
            <option>Blue</option>
            <option>Yellow</option>
        </select>
        <i class="fa fa-chevron-down"></i>
    </div>
</fieldset>

SCSS

fieldset {
    .select-wrapper {
        position: relative;

        select {
            appearance: none;
            position: relative;
            z-index: 1;
            background: transparent;

            + i {
                position: absolute;
                top: 40%;
                right: 15px;
            }
        }
    }

If your select element has a defined background color, then this won't work as this snippet essentially places the Chevron icon behind the select element (to allow clicking on top of the icon to still initiate the select action).

However, you can style the select-wrapper to the same size as the select element and style its background to achieve the same effect.

Check out my CodePen for a working demo that shows this bit of code on both a dark and light themed select box using a regular label and a "placeholder" label and other cleaned up styles such as borders and widths.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPatrick D&#39;appollonioView Question on Stackoverflow
Solution 1 - Cssuser1124838View Answer on Stackoverflow
Solution 2 - CssPatrick D'appollonioView Answer on Stackoverflow
Solution 3 - CssTessaView Answer on Stackoverflow