Cross-browser styles for consistent select element styling

  • By Filament Group
  • Last update: Sep 23, 2022
  • Comments: 12

select-css

Cross-browser select element CSS for consistent select element styling.

Article: https://www.filamentgroup.com/lab/select-css.html


Demo page: http://filamentgroup.github.io/select-css/demo/

Download: select-css.css

Available on npm: npm install fg-select-css


Usage

Include the following file:

Its CSS will style any select with a class of select-css

Notes on the CSS

The CSS for this is fine to use as-is, but if you're editing it at all, you might want to be aware of a few numbers and values that help it look right.

  • The select is set to display: block by default but you can style it display: inline-block; width: auto; if you'd like it to sit alongside a label.
  • The background of the select is created using two background images: the first is an svg arrow icon (expressed inline as a data URI) and the second is a repeating linear gradient. Either URL could be an external image if you'd like. If you change the icon image, be aware that its size is set in the first section of the later background-size: .65em auto, 100%; property. And its position is set via background-position: right .7em top 50%, 0 0; (which is .7em from the right side, respectively). Also, if the size changes, you might want to make more right padding on the button so that it doesn't overlap the select's text, but be aware that in IE9 and older, the custom arrow will not appear, and the browser's default arrow will show to the left of the padding, so don't add too much there or IE9's arrow will be inset really far.
  • The linear gradient background is important to keep, because its presence actually prevents IE9 and older from recognizing the background property, and as a result it won't show the custom icon alongside its unhideable native one. If you want a flat color, use a linear gradient between two of the same color values.
  • The appearance rule and its and prefixed versions are important to unset some default browser select styling.
  • The font-size: 16px; rule is important because iOS Safari will zoom-in the site layout if the select's text is less than 16px. Generally, this behavior is annoying so we try to avoid it with a 16px font size on selects.
  • The .select-css option keeps option elements from inheriting the bold font weight of the select button itself.
  • As noted in Scott O'Hara's article, setting background color on the select (though not background image as I've used here, can cause option elements to inherit background colors as well, which can cause problems. So avoid doing that. )
  • The .select-css::-ms-expand rule instructs IE11 and IE10 to hide the menu icon pseudo element, so the custom icon behind it can appear. Thanks for the tip, Jelmer de Maat.

For Posterity:

If you’re looking for a custom select that uses JavaScript for additional features, check out select.

Github

https://github.com/filamentgroup/select-css

Comments(12)

  • 1

    Fix #17: compilation issues with gulp-sass + gulp-autoprefixer

    gulp-sass (node-sass) can’t compile with the multi-line @supports rule.

    Moving the comment above @supports and making the rule a single line allows node-sass to compile it properly.

  • 2

    Fixes #7: make option list readable in Firefox when parent has dark b…

    Resolves issue #7. In Firefox the option list inherits the background color of the closest ancestor that has a solid background color. If the .custom-select wrapper uses a dark solid background or only uses a gradient, then Firefox traces up through its ancestors until a solid color is found. If that color is dark then the option list is unreadable in Firefox (black text on dark background).

    By setting a solid fallback of #fff on the .custom-select (or in the demo's case: .button) Firefox will render the option list readably (black text on white background).

    I updated the demo to include a dark parent example. The issue can be reproduced by modifying the CSS for .button to remove the solid background fallback in the gradient declaration.

  • 3

    RTL, Arabic, Hebrew support

    The arrow sits on the right, but in a native select in Arabic, Hebrew, or any right-to-left text the arrow is on the left in a native unstyled select.

  • 4

    Update to the latest code

    Latest version:

    http://jsbin.com/horebic/

    What's new:

    • Wraps the display of the custom arrow and appearance: none behind @supports
    • Moves all hacks into an optional section
    • Leverages FF 35 support for -moz-appearance
    • Ensures that IE 8/9 doesn't show the custom arrow and native select arrow (old bug)
    • IE 10/11 has a custom arrow since we can hide the native arrow via hackiness
    • Removes the Opera hack for double arrows since we now shield the styles via @support

    Bug: Removing the FF hacks shows a double arrow in v4-35

    For FF, if I remove our hack to make it look good in versions 4-35, it looks like it's still showing the custom arrow even though it's display: none and visibility is tucked behind @supports. I had to add this to hide the arrow - why would older FF be passing @supports ( -moz-appearance: none ) to show the arrow?

    For now, I've added this rule inside @supports, then display it inside the old FF hack so we can delete the FF hacks and the native arrow will show up. Can we get rid of this?

        /* Show only the native arrow */
        @-moz-document url-prefix() { 
          .custom-select::after {
            display:none;
          }
        }
    

    I've confirmed I can remove the IE hacks and it falls back nicely to the native arrow with custom button styling

    TODO:

    • Separate out demo styles from core select styles
    • Break out backcompat for IE and FF - TODO: make sure we fallback to a native select arrow if these aren't in play
    • Final testing
    • Upstream into formcore
  • 5

    Hiding select area in IE11

    I have some annoying issue in IE 11.0.9600.19230 (Windows 7 Ultimate)

    When I choose some option (click on it) the select hides itself and the pack of options overlaps it.

    IE11 Issue

  • 6

    Readability issue with dark backgrounds in Firefox

    Noting an issue I ran into building a JS-driven select replacement and testing this technique as an alternative (95% there).

    Firefox uses the background CSS property for the select button and the menu which appears under interaction. This approach removes the background on select inputs:

    .custom-select select {
        background: none;
    }
    

    This allows the input to be invisible and users see the .custom-select wrapper's styling. But this makes Firefox (taxingly) fallback to using the body background for the menu options background. Example:

    firefox-select-css-dark-background

    I haven't found a fix other than don't use this technique on dark sites. In my JS-approach the select has opacity:0; background:#FFF; which forces Firefox to use a readable background, but this isn't possible here because the technique must render the select's text visibly.

  • 7

    Disabled styles

    This uses graytext as the color keyword for both the text color and SVG arrow fill. It also removes the border color change on hover, which can otherwise indicate it is still interactive.

    Because many accessibility best practices rely on aria-disabled I also added that as a selector. If nothing else, it is a visual reminder to developers who forget to toggle aria-disabled when they set disabled.

    Tested in Firefox, Edge, Internet Explorer and Chrome all on Windows. No Mac handy today to test.

  • 8

    Disable Styling

    What's an elegant way to handle the styling of the disabled select element? I could add disabled="disabled" to the select element itself but then I'd need to add a class to the wrapper div as well.

    Thoughts?

  • 9

    Don't set max-width on

    Correct me if I'm mistaken, but it looks like an unnecessary border appears around <select> element when it's being clicked. The border doesn't disappear until <select> loses its focus. Here's a fiddle demonstrating the issue and a possible fix.

    screen shot 2017-12-10 at 13 50 16

    Tested on latest Chrome and Firefox.

    In Firefox, there's additionally another border around the <select> element, that doesn't seem to go away even when removing outline and border. On the picture, the one visible only in FF is the inner one.

    screen shot 2017-12-10 at 13 48 50
  • 12

    Focus styling in Firefox

    Hi @scottjehl — Super excited your team is still working on making this better. I refactored a project using my custom styles based on the old version and got the pixel-for-pixel same outcome.

    I noticed one line on Firefox focus ring styles that uses a property I couldn't find any docs for: -moz-mac-focusring. Not sure I've ever seen a vendor-specific value before.

    .select-css:focus {
    	border-color: #aaa;
    	/* It'd be nice to use -webkit-focus-ring-color here but it doesn't work on box-shadow */
    	box-shadow: 0 0 1px 3px rgba(59, 153, 252, .7);
    	box-shadow: 0 0 0 3px -moz-mac-focusring;
    	color: #222; 
    	outline: none;
    }
    

    The :-moz-focusring pseduo-class seems to be the standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-focusring

    Firefox still renders the dotted focus ring after making a selection:

    screen shot 2018-12-20 at 12 14 59 pm

    I wasn't sure if it was intentional for the repo to keep this, but there is alternative focus styling for accessiblity.

    I removed the -moz-mac-focusring code, and tested a technique to hide disable the dotted line (Firefox is so weird) which feels gross but works:

    screen shot 2018-12-20 at 12 17 34 pm

    Are you open to PRs that modify this?

    I'd also like to see styling for :disabled included so it's covered minimally. I like doing opacity: 0.5