ladybird/Libraries/LibWeb/CSS/Default.css
Zaggy1024 21019c2fa9 LibWeb: Use UA shadow DOM for media elements' controls
Instead of using a custom paintable to draw the controls for video and
audio elements, we build them out of plain old HTML elements within a
shadow root.

This required a few hacks in the previous commits in order to allow a
replaced element to host children within a shadow root, but it's
fairly self-contained.

A big benefit is that we can drive all the UI updates off of plain old
DOM events (except the play button overlay on videos, which uses the
video element representation), so we can test our media and input event
handling more thoroughly. :^)

The control bar visibility is now more similar to how other browsers
handle it. It will show upon hovering over the element, but if the
cursor is kept still for more than a second, it will hide again. While
dragging, the controls remain visible, and will then hide after the
mouse button is released.

The icons have been redesigned from scratch, and the mute icon now
visualizes the volume level along with indicating the mute state.
2026-02-23 07:27:31 +01:00

929 lines
19 KiB
CSS

/* Default user-agent stylesheet for LibWeb
* Note: This stylesheet starts with a bunch of ad-hoc custom rules.
* After that, rules from the HTML spec follow.
*/
html {
font-family: serif;
}
body {
margin: 8px;
}
center {
text-align: -libweb-center;
}
blink {
display: inline;
}
/* FIXME: This doesn't seem right. */
label {
display: inline-block;
}
/* FIXME: This is a temporary hack until we can render a native-looking frame for these. */
input:not([type=submit], input[type=button], input[type=image], input[type=reset], input[type=color], input[type=checkbox], input[type=file], input[type=radio], input[type=range]), textarea {
border: 1px solid ButtonBorder;
min-height: 16px;
cursor: text;
background-color: Field;
color: FieldText;
}
textarea {
padding: 2px;
display: inline-block;
overflow: auto;
font-family: monospace;
resize: both;
}
input::placeholder, textarea::placeholder {
color: GrayText;
line-height: initial;
}
button, input[type=submit], input[type=button], input[type=reset], select, ::file-selector-button {
padding: 1px 4px;
background-color: ButtonFace;
border: 1px solid ButtonBorder;
color: ButtonText;
cursor: default;
&:hover {
background-color: -libweb-ButtonFaceHover;
}
&:disabled {
background-color: -libweb-ButtonFaceDisabled;
color: GrayText;
}
}
input[type=image] {
cursor: pointer;
}
option {
display: none;
}
/* Custom <input type="range"> styles */
input[type=range] {
display: inline-block;
width: 20ch;
height: 16px;
&::slider-track {
display: block;
position: relative;
height: 4px;
width: 100%;
margin-top: 6px;
background-color: AccentColorText;
border: 1px solid rgba(0, 0, 0, 0.5);
}
&::slider-fill {
display: block;
position: absolute;
height: 100%;
background-color: AccentColor;
}
&::slider-thumb {
display: block;
margin-top: -6px;
width: 16px;
height: 16px;
transform: translateX(-50%);
border-radius: 50%;
outline: 1px solid rgba(0, 0, 0, 0.5);
z-index: 1;
background-color: AccentColor;
}
}
/* Custom <meter> styles */
meter {
display: inline-block;
width: 300px;
height: 12px;
&::slider-track {
display: block;
height: 100%;
background-color: hsl(0, 0%, 96%);
border: 1px solid rgba(0, 0, 0, 0.5);
}
&::slider-fill {
display: block;
height: 100%;
}
&:optimal-value::slider-fill {
background-color: hsl(141, 53%, 53%);
}
&:suboptimal-value::slider-fill {
background-color: hsl(48, 100%, 67%);
}
&:even-less-good-value::slider-fill {
background-color: hsl(348, 100%, 61%);
}
}
/* Custom <progress> styles */
progress {
display: inline-block;
width: 300px;
height: 12px;
&::slider-track {
display: block;
height: 100%;
background-color: AccentColorText;
border: 1px solid rgba(0, 0, 0, 0.5);
}
&::slider-fill {
display: block;
height: 100%;
background-color: AccentColor;
}
}
/* 15.3.1 Hidden elements
* https://html.spec.whatwg.org/multipage/rendering.html#hidden-elements
*/
area, base, basefont, datalist, head, link, meta, noembed,
noframes, param, rp, script, style, template, title {
display: none;
}
[hidden]:not([hidden=until-found i]) {
display: none;
}
[hidden=until-found i]:not(embed) {
content-visibility: hidden;
}
embed[hidden] {
display: inline;
height: 0;
width: 0;
}
input[type=hidden i] {
display: none !important;
}
@media (scripting) {
noscript {
display: none !important;
}
}
/* 15.3.2 The page
* https://html.spec.whatwg.org/multipage/rendering.html#the-page
*/
html, body {
display: block;
}
/* 15.3.3 Flow content
* https://html.spec.whatwg.org/multipage/rendering.html#flow-content-3
*/
address, blockquote, center, dialog, div, figure, figcaption, footer, form,
header, hr, legend, listing, main, p, plaintext, pre, search, xmp {
display: block;
}
blockquote, figure, listing, p, plaintext, pre, xmp {
margin-block: 1em;
}
blockquote, figure {
margin-inline: 40px;
}
address {
font-style: italic;
}
listing, plaintext, pre, xmp {
font-family: monospace;
white-space: pre;
}
dialog:not([open]) {
display: none;
}
dialog {
position: absolute;
inset-inline-start: 0;
inset-inline-end: 0;
width: fit-content;
height: fit-content;
margin: auto;
border: solid;
padding: 1em;
background-color: Canvas;
color: CanvasText;
}
dialog:modal {
position: fixed;
overflow: auto;
inset-block: 0;
max-width: calc(100% - 6px - 2em);
max-height: calc(100% - 6px - 2em);
}
dialog::backdrop {
background: rgba(0, 0, 0, 0.1);
}
[popover]:not(:popover-open):not(dialog[open]) {
display:none;
}
dialog:popover-open {
display:block;
}
[popover] {
position: fixed;
inset: 0;
width: fit-content;
height: fit-content;
margin: auto;
border: solid;
padding: 0.25em;
overflow: auto;
color: CanvasText;
background-color: Canvas;
}
:popover-open::backdrop {
position: fixed;
inset: 0;
pointer-events: none !important;
background-color: transparent;
}
/* 4.2. The ::backdrop Pseudo-Element
* https://drafts.csswg.org/css-position-4/#backdrop
*/
::backdrop {
position: fixed;
inset: 0;
}
slot {
display: contents;
}
/* 15.3.4 Phrasing content
* https://html.spec.whatwg.org/multipage/rendering.html#phrasing-content-3
*/
cite, dfn, em, i, var {
font-style: italic;
}
b, strong {
font-weight: bolder;
}
code, kbd, samp, tt {
font-family: monospace;
}
big {
font-size: larger;
}
small {
font-size: smaller;
}
sub {
vertical-align: sub;
}
sup {
vertical-align: super;
}
sub, sup {
line-height: normal;
font-size: smaller;
}
ruby {
display: ruby;
}
rt {
display: ruby-text;
}
:link {
color: LinkText;
}
:visited {
color: VisitedText;
}
:link:active, :visited:active {
color: ActiveText;
}
:link, :visited {
text-decoration: underline;
cursor: pointer;
}
:focus-visible {
outline: auto;
}
mark {
background: Mark;
color: MarkText;
}
abbr[title], acronym[title] {
text-decoration: dotted underline;
}
ins, u {
text-decoration: underline;
}
del, s, strike {
text-decoration: line-through;
}
q::before {
content: open-quote;
}
q::after {
content: close-quote;
}
/*
NOTE: This isn't a real property and value. See https://github.com/whatwg/html/issues/2291
br {
display-outside: newline;
}
*/
/* this also has bidi implications */
nobr {
white-space: nowrap;
}
/*
NOTE: This isn't a real property and value. See https://github.com/whatwg/html/issues/2291
wbr {
display-outside: break-opportunity;
}
*/
/* this also has bidi implications */
nobr wbr {
white-space: normal;
}
/* 15.3.5 Bidirectional text
* https://html.spec.whatwg.org/multipage/rendering.html#bidi-rendering
*/
[dir]:dir(ltr), bdi:dir(ltr), input[type=tel i]:dir(ltr) {
direction: ltr;
}
[dir]:dir(rtl), bdi:dir(rtl) {
direction: rtl;
}
address, blockquote, center, div, figure, figcaption, footer, form, header, hr,
legend, listing, main, p, plaintext, pre, summary, xmp, article, aside,
:heading, hgroup, nav, search, section, table, caption, colgroup, col, thead,
tbody, tfoot, tr, td, th, dir, dd, dl, dt, menu, ol, ul, li, bdi, output,
[dir=ltr i], [dir=rtl i], [dir=auto i] {
unicode-bidi: isolate;
}
bdo, bdo[dir] {
unicode-bidi: isolate-override;
}
input[dir=auto i]:is([type=search i], [type=tel i], [type=url i],
[type=email i]), textarea[dir=auto i], pre[dir=auto i] {
unicode-bidi: plaintext;
}
/* 15.3.6 Sections and headings
* https://html.spec.whatwg.org/multipage/rendering.html#sections-and-headings
*/
article, aside, :heading, hgroup, nav, section {
display: block;
}
:heading { font-weight: bold; }
:heading(1) { margin-block: 0.67em; font-size: 2.00em; }
:heading(2) { margin-block: 0.83em; font-size: 1.50em; }
:heading(3) { margin-block: 1.00em; font-size: 1.17em; }
:heading(4) { margin-block: 1.33em; font-size: 1.00em; }
:heading(5) { margin-block: 1.67em; font-size: 0.83em; }
:heading(6, 7, 8, 9) {
font-size: 0.67em;
margin-block: 2.33em;
}
/* 15.3.7 Lists
* https://html.spec.whatwg.org/multipage/rendering.html#lists
*/
dir, dd, dl, dt, menu, ol, ul {
display: block;
}
li {
display: list-item;
text-align: match-parent;
}
dir, dl, menu, ol, ul {
margin-block-start: 1em;
margin-block-end: 1em;
}
:is(dir, dl, menu, ol, ul) :is(dir, dl, menu, ol, ul) {
margin-block-start: 0;
margin-block-end: 0;
}
dd {
margin-inline-start: 40px;
}
dir, menu, ol, ul {
padding-inline-start: 40px;
}
ol, ul, menu {
counter-reset: list-item;
}
ol {
list-style-type: decimal;
}
dir, menu, ul {
list-style-type: disc;
}
:is(dir, menu, ol, ul) :is(dir, menu, ul) {
list-style-type: circle;
}
:is(dir, menu, ol, ul) :is(dir, menu, ol, ul) :is(dir, menu, ul) {
list-style-type: square;
}
/* 15.3.8 Tables
* https://html.spec.whatwg.org/multipage/rendering.html#tables-2
*/
table {
display: table;
}
caption {
display: table-caption;
}
colgroup, colgroup[hidden] {
display: table-column-group;
}
col, col[hidden] {
display: table-column;
}
thead, thead[hidden] {
display: table-header-group;
}
tbody, tbody[hidden] {
display: table-row-group;
}
tfoot, tfoot[hidden] {
display: table-footer-group;
}
tr, tr[hidden] {
display: table-row;
}
td, th {
display: table-cell;
}
colgroup[hidden], col[hidden], thead[hidden], tbody[hidden],
tfoot[hidden], tr[hidden] {
visibility: collapse;
}
table {
box-sizing: border-box;
border-spacing: 2px;
border-collapse: separate;
text-indent: initial;
}
td, th {
padding: 1px;
}
th {
font-weight: bold;
/*
The text-align property for table headings is non-standard, but all existing user-agents seem to render them
centered by default. We use -libweb-inherit-or-center to prioritize any inherited text-align style.
See:
- https://trac.webkit.org/browser/trunk/Source/WebCore/css/html.css?rev=295625#L272
- https://searchfox.org/mozilla-central/rev/0b55b868c17835942d40ca3fedfca8057481207b/layout/style/res/html.css#473
*/
text-align: -libweb-inherit-or-center;
}
caption {
text-align: center;
}
thead, tbody, tfoot, table > tr {
vertical-align: middle;
}
tr, td, th {
vertical-align: inherit;
}
thead, tbody, tfoot, tr {
border-color: inherit;
}
table[rules=none i], table[rules=groups i], table[rules=rows i],
table[rules=cols i], table[rules=all i], table[frame=void i],
table[frame=above i], table[frame=below i], table[frame=hsides i],
table[frame=lhs i], table[frame=rhs i], table[frame=vsides i],
table[frame=box i], table[frame=border i],
table[rules=none i] > tr > td, table[rules=none i] > tr > th,
table[rules=groups i] > tr > td, table[rules=groups i] > tr > th,
table[rules=rows i] > tr > td, table[rules=rows i] > tr > th,
table[rules=cols i] > tr > td, table[rules=cols i] > tr > th,
table[rules=all i] > tr > td, table[rules=all i] > tr > th,
table[rules=none i] > thead > tr > td, table[rules=none i] > thead > tr > th,
table[rules=groups i] > thead > tr > td, table[rules=groups i] > thead > tr > th,
table[rules=rows i] > thead > tr > td, table[rules=rows i] > thead > tr > th,
table[rules=cols i] > thead > tr > td, table[rules=cols i] > thead > tr > th,
table[rules=all i] > thead > tr > td, table[rules=all i] > thead > tr > th,
table[rules=none i] > tbody > tr > td, table[rules=none i] > tbody > tr > th,
table[rules=groups i] > tbody > tr > td, table[rules=groups i] > tbody > tr > th,
table[rules=rows i] > tbody > tr > td, table[rules=rows i] > tbody > tr > th,
table[rules=cols i] > tbody > tr > td, table[rules=cols i] > tbody > tr > th,
table[rules=all i] > tbody > tr > td, table[rules=all i] > tbody > tr > th,
table[rules=none i] > tfoot > tr > td, table[rules=none i] > tfoot > tr > th,
table[rules=groups i] > tfoot > tr > td, table[rules=groups i] > tfoot > tr > th,
table[rules=rows i] > tfoot > tr > td, table[rules=rows i] > tfoot > tr > th,
table[rules=cols i] > tfoot > tr > td, table[rules=cols i] > tfoot > tr > th,
table[rules=all i] > tfoot > tr > td, table[rules=all i] > tfoot > tr > th {
border-color: black;
}
/* 15.3.10 Form controls
* https://html.spec.whatwg.org/multipage/rendering.html#form-controls
*/
input, button, textarea {
letter-spacing: initial;
word-spacing: initial;
line-height: initial;
}
input, select, button, textarea {
text-transform: initial;
text-indent: initial;
text-shadow: initial;
appearance: auto;
}
input:not([type=image i], [type=range i], [type=checkbox i], [type=radio i]) {
overflow: clip !important;
overflow-clip-margin: 0 !important;
}
input, select, textarea {
text-align: initial;
}
:autofill {
field-sizing: fixed !important;
}
input:is([type=reset i], [type=button i], [type=submit i]), button {
text-align: center;
}
input, button {
display: inline-block;
}
input[type=hidden i], input[type=file i], input[type=image i] {
appearance: none;
}
input:is([type=radio i], [type=checkbox i], [type=reset i], [type=button i],
[type=submit i], [type=color i], [type=search i]), select, button {
box-sizing: border-box;
}
textarea { white-space: pre-wrap; }
/* 15.3.11 The hr element
* https://html.spec.whatwg.org/multipage/rendering.html#the-hr-element-2
*/
hr {
color: gray;
border-style: inset;
border-width: 1px;
margin-block-start: 0.5em;
margin-inline-end: auto;
margin-block-end: 0.5em;
margin-inline-start: auto;
overflow: hidden;
}
/* 15.3.12 The fieldset and legend elements
* https://html.spec.whatwg.org/multipage/rendering.html#the-fieldset-and-legend-elements
*/
fieldset {
display: block;
margin-inline-start: 2px;
margin-inline-end: 2px;
border: groove 2px ThreeDFace;
padding-block-start: 0.35em;
padding-inline-end: 0.75em;
padding-block-end: 0.625em;
padding-inline-start: 0.75em;
min-inline-size: min-content;
}
legend {
padding-inline: 2px;
}
legend[align=left i] {
justify-self: left;
}
legend[align=center i] {
justify-self: center;
}
legend[align=right i] {
justify-self: right;
}
/* 15.4.1 Embedded content
* https://html.spec.whatwg.org/multipage/rendering.html#embedded-content-rendering-rules
*/
iframe {
border: 2px inset;
}
video {
object-fit: contain;
}
audio {
width: 300px;
}
/* 15.4.3 Attributes for embedded content and images
* https://html.spec.whatwg.org/multipage/rendering.html#attributes-for-embedded-content-and-images
*/
embed[align=left i], iframe[align=left i], img[align=left i],
input[type=image i][align=left i], object[align=left i] {
float: left;
}
embed[align=right i], iframe[align=right i], img[align=right i],
input[type=image i][align=right i], object[align=right i] {
float: right;
}
embed[align=top i], iframe[align=top i], img[align=top i],
input[type=image i][align=top i], object[align=top i] {
vertical-align: top;
}
embed[align=baseline i], iframe[align=baseline i], img[align=baseline i],
input[type=image i][align=baseline i], object[align=baseline i] {
vertical-align: baseline;
}
embed[align=texttop i], iframe[align=texttop i], img[align=texttop i],
input[type=image i][align=texttop i], object[align=texttop i] {
vertical-align: text-top;
}
embed[align=absmiddle i], iframe[align=absmiddle i], img[align=absmiddle i],
input[type=image i][align=absmiddle i], object[align=absmiddle i],
embed[align=abscenter i], iframe[align=abscenter i], img[align=abscenter i],
input[type=image i][align=abscenter i], object[align=abscenter i] {
vertical-align: middle;
}
embed[align=bottom i], iframe[align=bottom i], img[align=bottom i],
input[type=image i][align=bottom i], object[align=bottom i] {
vertical-align: bottom;
}
/* 15.5.5 The details and summary elements
* https://html.spec.whatwg.org/multipage/rendering.html#the-details-and-summary-elements
*/
details, summary {
display: block;
}
details > summary:first-of-type {
display: list-item;
counter-increment: list-item 0;
list-style: disclosure-closed inside;
}
details[open] > summary:first-of-type {
list-style-type: disclosure-open;
}
/* 15.5.12 The marquee element
* https://html.spec.whatwg.org/multipage/rendering.html#the-marquee-element-2
*/
marquee {
display: inline-block;
text-align: initial;
overflow: hidden !important;
}
/* 15.5.13 The meter element
* https://html.spec.whatwg.org/multipage/rendering.html#the-meter-element-2
*/
meter {
appearance: auto;
}
/* 15.5.14 The progress element
* https://html.spec.whatwg.org/multipage/rendering.html#the-progress-element-2
*/
progress {
appearance: auto;
}
/* https://www.w3.org/TR/mediaqueries-5/#descdef-media-inverted-colors
*/
@media (inverted-colors) {
img:not(picture>img),
picture,
video {
filter: invert(100%);
}
}
/* https://github.com/whatwg/html/pull/9546
*/
input[type=checkbox][switch] {
/* FIXME: Workaround until we can properly style dark switches */
color-scheme: light;
appearance: none;
height: 1em;
width: 1.8em;
vertical-align: middle;
border-radius: 1em;
position: relative;
overflow: hidden;
border-color: transparent;
background-color: ButtonFace;
}
input[type=checkbox][switch]::before {
content: '';
position: absolute;
height: 0;
width: 0;
border: .46em solid Field;
border-radius: 100%;
top: 0;
bottom: 0;
left: 0;
margin: auto;
}
input[type=checkbox][switch]:checked::before {
left: calc(100% - .87em);
}
input[type=checkbox][switch]:checked {
background-color: AccentColor;
}
/* https://drafts.csswg.org/css-ui/#propdef-user-select */
button, meter, progress, select {
user-select: none;
}
/* https://drafts.csswg.org/css-view-transitions-1/#ua-styles */
:root {
view-transition-name: root;
}
:root::view-transition {
position: fixed;
inset: 0;
}
:root::view-transition-group(*) {
position: absolute;
top: 0;
left: 0;
animation-duration: 0.25s;
animation-fill-mode: both;
}
:root::view-transition-image-pair(*) {
position: absolute;
inset: 0;
}
:root::view-transition-old(*),
:root::view-transition-new(*) {
position: absolute;
inset-block-start: 0;
inline-size: 100%;
block-size: auto;
}
:root::view-transition-image-pair(*),
:root::view-transition-old(*),
:root::view-transition-new(*) {
animation-duration: inherit;
animation-fill-mode: inherit;
animation-delay: inherit;
animation-timing-function: inherit;
animation-iteration-count: inherit;
animation-direction: inherit;
animation-play-state: inherit;
}
/* Default cross-fade transition */
@keyframes -ua-view-transition-fade-out {
to { opacity: 0; }
}
@keyframes -ua-view-transition-fade-in {
from { opacity: 0; }
}
/* Keyframes for blending when there are 2 images */
@keyframes -ua-mix-blend-mode-plus-lighter {
from { mix-blend-mode: plus-lighter }
to { mix-blend-mode: plus-lighter }
}