Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
228 changes: 175 additions & 53 deletions src/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -747,80 +747,202 @@ input[type=file] {
}

select {
&:is([multiple], [size]) {
padding: 0;
/***
15.5.16 Rendering: The select element
https://html.spec.whatwg.org/multipage/rendering.html#the-select-element-2

&:focus option:checked {
--force-bg-hack: linear-gradient(0deg, var(--graphical-fg) 0%, var(--graphical-fg) 100%);
background: var(--force-bg-hack);
color: var(--bg);
}
- Revisit the spec above once browserlist supports base-select,
since some of the styles are just for e.g. Firefox.

- It's possible that a pseudo-element (e.g. :is-listbox) will eventually
be implemented, until then we follow the guidance of:
https://github.com/whatwg/html/issues/8189#issuecomment-2877242732

- Eventually, `field-sizing: fixed` will re-implement the automagic
width of the base appearance select.

- Keep in mind that `appearance: base-select` changes the keyboard
controls of a multiple select to be more accessible.

- While the spec change has relaxed the parsing rules for `<select>`,
deno-dom and html5ever have not updated to the spec yet (see this
issue for more: https://github.com/b-fuze/deno-dom/issues/199).
This means we cannot display <select><button><selectedcontent> or
<optgroup><legend> in our docs yet.

***/

--hover-color: color-mix(currentColor 10%, transparent);
--checked-color: color-mix(var(--graphical-fg) 20%, transparent);
--active-color: color-mix(var(--graphical-fg) 50%, transparent);
--padding: calc(var(--rhythm, 1rlh) / 4);
--indented: 1em;

&[multiple],
&[size]:not([size="1"]) {
/* Renders as a listbox */
padding: unset;
}
&:not([multiple], [size]) {
@supports (appearance: base-select) {

@supports (appearance: base-select) {
appearance: base-select;
field-sizing: fixed;
display: inline-flex !important;

&::picker(select) {
appearance: base-select;
field-sizing: fixed; /* Someday this will size to widest <option> */

&::picker(select) {
appearance: base-select;
background: inherit;
border: inherit;
border-radius: inherit;
scrollbar-width: thin;

color: inherit;
background: inherit;
border: inherit;
border-radius: inherit;
scrollbar-width: inherit;
}

&::picker-icon {
background-color: var(--accent);
opacity: 0.7;
mask-size: contain;
mask-position: center;
mask-repeat: no-repeat;
mask-image: var(--chevron-icon);
Comment thread
geoffrey-eisenbarth marked this conversation as resolved.
}

& > button:first-child {
/* Force UA styles */
all: unset;
display: contents;
interactivity: inert;
white-space: normal;
}

& > optgroup > legend {
/* Force UA styles */
all: unset;
display: block;
unicode-bidi: isolate;
padding-inline: var(--padding);
}

&[multiple][size=1] {
padding: var(--padding); /* Add back */
}
}

@supports selector(option::checkmark) {
& option::checkmark {
content: "";
visibility: hidden; /* must opt in */

block-size: 1em;
aspect-ratio: 1 / 1;

background-color: var(--accent);
mask-size: contain;
mask-position: center;
mask-repeat: no-repeat;
opacity: 0.7;
}

&:not([multiple], .checks, .checkboxes) {
/* Default for single select is no checkmarks */
& option::checkmark { display: none }
}

&:is([multiple], .checks, .checkboxes) {
/* Default for multi-select is checkmarks */
& option:checked::checkmark {
visibility: visible;
mask-image: var(--check-icon);
}
& > optgroup > option {
padding-inline-start: var(--padding);
}
}

&::picker-icon {
background-color: currentColor;
mask-image: var(--chevron-icon);
mask-repeat: no-repeat;
mask-position: center;
mask-size: contain;
opacity: 0.7;
&.checkboxes {
& option:not(:checked)::checkmark {
visibility: visible;
mask-image: var(--square-icon);
}
& option:checked::checkmark {
visibility: visible;
mask-image: var(--square-check-icon);
}
}

&.flip {
& option::checkmark {
content: "";
inline-size: 1rem;
block-size: 1rem;
background-color: currentColor;
mask-image: var(--check-icon);
mask-repeat: no-repeat;
mask-size: contain;
opacity: 0.7;
order: 1;
margin-inline-start: auto;
}
& > optgroup > option {
padding-inline-start: var(--indented);
}
}
}

& optgroup {
& > optgroup {
color: var(--muted-fg);
font-style: normal;
font-weight: bold;
&::before {
padding-inline-start: calc(var(--gap) / 4);
font-weight: bolder;

&:disabled {
cursor: not-allowed;
filter: grayscale(1);
opacity: 0.7;
}

& > option {
padding-inline: var(--indented) var(--padding);
}
/*& > option {
/* padding-inline: var(--gap);
/* &::checkmark {
/* margin-inline-start: calc(0px - var(--gap));
/* }
/*}*/
}

& option {
/*&:checked:not(:hover, :focus-visible) {
/* background: var(--bg);
/* color: var(--accent);
/*}*/
&:is(:hover, :focus-visible) {
background: var(--graphical-fg);
color: var(--box-bg);
}
color: var(--fg);
font-weight: normal;
padding-inline: var(--padding);

&:focus-visible {
outline: none;
outline: 2px dotted var(--graphical-fg);
}
&:enabled:hover {
background-color: var(--hover-color);
}
&:enabled:checked {
background-color: var(--checked-color);
}
&:enabled:checked:hover,
&:enabled:active {
background-color: var(--active-color);
}
:not(optgroup:disabled &):disabled {
cursor: not-allowed;
filter: grayscale(1);
opacity: 0.7;
}
}
}

textarea {
@supports not (appearance: base-select) {
& > optgroup::before {
padding-inline: var(--padding);
}

&:focus option:checked {
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like simply supporting base-select isn't enough here: in Chrome 146.0.7680.72 the SelectedItem and SelectedItemColors are still forced on select[size!=1]:focus option:checked. Canary seems to implement a revert-rule that doesn't add UA focus colors.

Because of this, we should probably move this rule outside of the @supports block. However, I'm not sure if --graphical-fg is best, or if it should just match the accompanying focus ring that is on select:focus-visible e.g. --accent. Chrome also flips the text color like FF does, so it needs to be something that work with both light/dark text and can't contain transparency.

/**
We can override UA's `background-color: SelectedItem !important` with a gradient.
In order for this to work, the chosen color cannot be color-mixed with transparent.

We can't override `color: SelectedItemText !important`, which is an inversion of
foreground text, so we use `--graphical-fg` to provide sufficient contrast.
**/
background: linear-gradient(
0deg,
var(--graphical-fg) 0%,
var(--graphical-fg) 100%
);
}
}
}

meter, progress {
Expand Down
6 changes: 6 additions & 0 deletions src/variables.css
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,12 @@
--check-icon: url(
'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>'
);
--square-icon: url(
'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="18" x="3" y="3" rx="2"/></svg>'
);
--square-check-icon: url(
'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="18" x="3" y="3" rx="2"/><path d="m9 12 2 2 4-4"/></svg>'
);
}

:root:not(:has(meta[name=color-scheme])) {
Expand Down
Loading