62

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.

Vadim Ovchinnikov
  • 13,327
  • 5
  • 62
  • 90
Patrick D'appollonio
  • 2,722
  • 1
  • 18
  • 34
  • 1
    `action` elements do not allow to be used as `pseudo` handlers – Roko C. Buljan Jan 13 '14 at 23:43
  • 1
    possible duplicate of [problem with – showdev Jan 13 '14 at 23:43
  • 1
    I think, this is already answered on SO: http://stackoverflow.com/questions/3532649/problem-with-select-and-after-with-css-in-webkit – Dev Jan 13 '14 at 23:46
  • What exactly are you trying to achieve, maybe someone has an alternate solution? – Cam Jan 13 '14 at 23:48
  • @Cam I'm trying to add an image inside a SELECT to act as an arrow without wrapping the select within a div. – Patrick D'appollonio Jan 13 '14 at 23:50
  • So when your hovering over a option you see an arrow?? – Cam Jan 13 '14 at 23:51
  • @Cam no, not when hovering... Always. – Patrick D'appollonio Jan 13 '14 at 23:52
  • Is there a issue with just adding a html entity before it?? Like ⇒ – Cam Jan 14 '14 at 00:00
  • @Cam the idea is to style a SELECT with custom CSS. If you add an entity or a div outside, you'll polute your code with unnecesary divs. Right now, you can add custom DOM elements using :after and styling them the proper way. – Patrick D'appollonio Jan 14 '14 at 00:03
  • Im aware of Divitus i was just meerley asking. – Cam Jan 14 '14 at 00:11
  • @PatrickD'appollonio You were concerned with 'polluting code with unneccessary divs', but your answer below requires the jQuery lirary, additional JS which then places the `select` in a `div` and also adds a `
      ` replicating what's in the `select`.
    – davidpauljunior Jan 14 '14 at 00:23
  • Yep. But just adding your entity isn't enough. It would be great if you just add custom css to the SELECT element to style as you want, and with an `:after` add a down arrow and you're done, but that doesn't work. Full personalization? Use the code below. A simple → will not do the job. Thank you, anyway. – Patrick D'appollonio Jan 14 '14 at 00:45
  • IE 10+ supports an [::ms-expand pseudo-selector](https://developer.mozilla.org/en-US/docs/Web/CSS/::-ms-expand). Probably not much help to you unfortunately, if you're targeting non-IE. – Jonathan Mar 05 '18 at 13:53

3 Answers3

37

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

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;
}
<div class="select-wrapper">
  <select>
    <option>United Kingdom</option>
    <option>Canada</option>
    <option>United States</option>
  </select>
</div>
iorgv
  • 787
  • 2
  • 11
  • 26
user1124838
  • 371
  • 1
  • 3
  • 3
  • 21
    You must add `pointer-events: none;` to the `after` pseudo element otherwise when you click on the FontAwesome icon the select combo box wont show up. – Carlos Roso Mar 12 '16 at 03:12
  • I do this with Chris Coyier's CSS Triangle trick, too: https://css-tricks.com/snippets/css/css-triangle/ - then you don't even need a font icon. – Nathan Jun 02 '16 at 21:11
  • @caroso1222 - your comment is great, too, for those that don't want to go the javascript route, below. `pointer-events: none` is key! – Macnab Aug 16 '16 at 21:03
  • I don't think that adding the FontAwesome character code into the content property works in IE. – Chris Smith Mar 20 '17 at 15:07
19

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/

Vadim Ovchinnikov
  • 13,327
  • 5
  • 62
  • 90
Patrick D'appollonio
  • 2,722
  • 1
  • 18
  • 34
  • There are multiple plugins that do this too http://jquery-plugins.net/tag/select-list – davidpauljunior Jan 14 '14 at 00:25
  • 3
    Yeah, but which one of them comes with the option to EASILY edit their design. Almost all of them comes with their own preinstalled design that looks nice in general, but not in cases you need full control. Later, you'll need to overwrite all css styles in order to style as you want. That's why I pasted the code I found, so you are free to style as you want. – Patrick D'appollonio Jan 14 '14 at 00:44
  • More info here: http://stackoverflow.com/questions/8621127/list-of-html-elements-that-support-the-css-before-and-after-pseudo-elements – Tom Carver Jan 14 '15 at 09:35
10

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.

AuRise
  • 2,253
  • 19
  • 33