Skip to content

[css-ui] UA stylesheet for appearance:base <select> #10857

@josepharhar

Description

@josepharhar

I'd like to propose a UA stylesheet for <select> which applies when the <select> has size=1, no multiple attribute, and appearance:base.

Based on the discussion here and the proof of concept in the chromium prototype I implemented, we can make these styles only apply when <select> has appearance:base.

Styles from #10908 - the names were resolved, but not necessarily the properties:

select option::checkmark {
  content: '\2713' / '';
}
select option:not(:checked)::checkmark {
  visibility: hidden;
}
select::picker-icon {
  /* margin-inline-start pushes the icon to the right of the box */
  margin-inline-start: auto;
  display: block;
  content: counter(fake-counter-name, disclosure-open);
}

Styles from #10909

select {
  border: 1px solid currentColor;
  background-color: transparent;
  color: inherit;
}
select:enabled:hover {
  background-color: color-mix(in lab, currentColor 10%, transparent);
}
select:enabled:active  {
  background-color: color-mix(in lab, currentColor 20%, transparent);
}
select:disabled {
  color: color-mix(in srgb, currentColor 50%, transparent);
}

::picker(select) {
  /* Same properties as popover and dialog */
  color: CanvasText;
  background-color: Canvas;
  border: 1px solid;
}

select option:enabled:hover {
  background-color: color-mix(in lab, currentColor 10%, transparent);
}
select option:enabled:active {
  background-color: color-mix(in lab, currentColor 20%, transparent);
}
select option:disabled {
  color: color-mix(in lab, currentColor 50%, transparent);
}

Remaining properties to be resolved on:

select {
  /* Padding prevents the text from sticking to the borders.
   * optically centered to account for half leading */
  padding-block: 0.25em;
  padding-inline: 0.5em;

  /* <select>s and <button>s should have border-radius to be
   * distinct from <input>s: https://github.com/w3c/csswg-drafts/issues/10857#issuecomment-2520875011*/
  border-radius: 0.5em;

  /* These min-size rules ensure accessibility by following WCAG rules:
   * https://www.w3.org/WAI/WCAG22/Understanding/target-size-minimum.html
   * The 1.2em is there to make sure that options without text don't change
   * the block size of the button. */
  min-block-size: max(24px, 1lh);
  min-inline-size: 24px;

  /* box-sizing comes from existing UA styles which happen to
   * already be interoperable. */
  box-sizing: border-box;

  /* Push picker icon to the right of the box and have some space
   * in between it and the text. */
  display: inline-flex;
  gap: 1em;
}

select > button:first-child {
  /* Prevents button from setting font, color, or background-color */
  all: unset;

  /* Prevents duplicate box decorations */
  display: contents;

  /* Prevents button activation behavior so select can handle events */
  interactivity: inert;
}

select::picker(select) {
  /* box-sizing is set to match the button. */
  box-sizing: border-box;

  /* Remove [popover] padding which
   * prevents options from extending to edges */
  padding: 0;

  /* Anchor positioning and scrollbars */
  inset: auto;
  margin: 0;
  min-inline-size: anchor-size(self-inline);
  min-block-size: 1lh;
  /* Go to the edge of the viewport, and add scrollbars if needed. */
  max-block-size: stretch;
  overflow: auto;
  /* Below and span-right, by default. */
  position-area: block-end span-inline-end;
  position-try-order: most-block-size;
  position-try-fallbacks:
    /* First try above and span-right. */
    block-start span-inline-end,
    /* Then below but span-left. */
    block-end span-inline-start,
    /* Then above and span-left. */
    block-start span-inline-start;
}

select option {
  /* These min-size rules ensure accessibility by following WCAG rules:
   * https://www.w3.org/WAI/WCAG22/Understanding/target-size-minimum.html
   * Unset if the author provides a child button element.
   * The 1lh is there to make sure that options without text don't change
   * the block size of the option. */
  min-inline-size: 24px;
  min-block-size: max(24px, 1lh);

  /* Centers text within the block (vertically). From OpenUI discussion:
   * https://github.com/openui/open-ui/issues/1026#issuecomment-2103187647. */
  align-content: center;

  /* centering + gap between checkmark and option content */
  /* also easily reversed, when checkmark should be inline-end */
  display: flex;
  align-items: center;
  gap: 0.5em;

  /* Makes options with long text widen picker instead
   * of making options tall. */
  white-space: nowrap;
}

select optgroup {
  /* font-weight makes optgroups visually distinct from options. */
  font-weight: bolder;
}

select optgroup option {
  /* Undo font-weight:bolder rule from optgroups. */
  font-weight: normal;
}

select legend,
select option {
  /* spacing ownership moves to children */
  /* space inline from border edges */
  /* this creates a full bleed hover highlight */
  padding-inline: 0.5em;
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions