Optimize styles; clean up <fieldset>

This commit is contained in:
2026-02-03 15:33:37 +01:00
parent bd1a664caa
commit 675eb0aad8
3 changed files with 108 additions and 120 deletions

View File

@@ -15,6 +15,7 @@
*= require_self *= require_self
*/ */
/* Strive for simplicity. Style elements only, if possible. */
:root { :root {
--color-focus-gray: #f3f3f3; --color-focus-gray: #f3f3f3;
--color-border-gray: #dddddd; --color-border-gray: #dddddd;
@@ -48,27 +49,11 @@
} }
/* TODO: collapse gaps around empty rows (`topside`) once possible /* Color coding of input controls' background:
* with grid-collapse property and remove alternative grid-template * blue - target for interaction with pointer
* https://github.com/w3c/csswg-drafts/issues/5813 */ * gray - target for interaction with keyboard
body { * red - destructive, non-undoable action
display: grid; */
gap: 0.8em;
grid-template-areas:
"header header header"
"nav nav nav"
"leftside topside rightside"
"leftside main rightside";
grid-template-columns: 1fr minmax(max-content, 2fr) 1fr;
font-family: system-ui;
margin: 0.4em;
}
body:not(:has(.topside)) {
grid-template-areas:
"header header header"
"nav nav nav"
"leftside main rightside";
}
button, button,
details, details,
input, input,
@@ -82,11 +67,6 @@ input,
select { select {
text-align: inherit; text-align: inherit;
} }
/* blue - target for interaction with pointer */
/* gray - target for interaction with keyboard */
/* TODO: remove non-font-size rems from buttons/inputs below */
a, a,
button, button,
input[type=submit] { input[type=submit] {
@@ -109,7 +89,7 @@ input[type=submit]:not([hidden]),
button, button,
input[type=submit] { input[type=submit] {
font-size: 0.8rem; font-size: 0.8rem;
padding: 0.4em; padding: 0.6em 0.5em;
width: fit-content; width: fit-content;
} }
input:not([type=submit]):not([type=checkbox]), input:not([type=submit]):not([type=checkbox]),
@@ -120,74 +100,25 @@ textarea {
} }
.button, .button,
button, button,
details,
input, input,
select, select,
summary,
textarea { textarea {
border: solid 1px var(--color-gray); border: solid 1px var(--color-gray);
border-radius: 0.25em; border-radius: 0.25em;
} }
fieldset, input[type=checkbox],
svg,
textarea { textarea {
margin: 0 margin: 0
} }
.button > svg,
.tab > svg,
button > svg {
height: 1.8em;
width: 1.8em;
}
.button > svg:not(:last-child),
.tab > svg:not(:last-child),
button > svg:not(:last-child) {
padding-right: 0.4em;
}
fieldset {
padding: 0.4em;
}
fieldset:not(:has(input, select, textarea)) {
display: none;
}
legend {
color: var(--color-gray);
display: flex;
gap: 0.4em;
width: 100%;
}
legend span {
align-content: center;
flex-grow: 1;
}
/* TODO: move normal non-button links (<a>:hover/:focus) styling here (i.e.
* page-wide, top-level) and remove from table.items - as the style should be
* same everywhere */
.button:focus-visible,
button:focus-visible,
input[type=submit]:focus-visible {
background-color: var(--color-focus-gray);
}
.button:hover,
button:hover,
input[type=submit]:hover {
background-color: var(--color-blue);
border-color: var(--color-blue);
color: white;
fill: white;
}
.dangerous:hover {
background-color: var(--color-red);
border-color: var(--color-red);
}
input[type=checkbox] { input[type=checkbox] {
accent-color: var(--color-blue); accent-color: var(--color-blue);
appearance: none; appearance: none;
-webkit-appearance: none; -webkit-appearance: none;
display: flex; display: flex;
height: 1.1rem; height: 1.1em;
margin: 0; width: 1.1em;
width: 1.1rem;
} }
input[type=checkbox]:checked { input[type=checkbox]:checked {
appearance: checkbox; appearance: checkbox;
@@ -205,45 +136,96 @@ input::-webkit-outer-spin-button {
-webkit-appearance: none; -webkit-appearance: none;
margin: 0; margin: 0;
} }
details:hover, .button > svg,
.tab > svg,
button > svg {
height: 1.4em;
width: 1.4em;
}
.button > svg:not(:last-child),
.tab > svg:not(:last-child),
button > svg:not(:last-child) {
margin-right: 0.2em;
}
/* TODO: move normal non-button links (<a>:hover/:focus) styling here (i.e.
* page-wide, top-level) and remove from table.items - as the style should be
* same everywhere */
.button:focus-visible,
button:focus-visible,
input[type=submit]:focus-visible {
background-color: var(--color-focus-gray);
}
input:focus-visible,
select:focus-visible,
select:focus-within,
/* TODO: how to achieve summary:focus-within for ::details-content? */
summary:focus-visible,
textarea:focus-visible {
accent-color: var(--color-dark-blue);
background-color: var(--color-focus-gray);
}
.button:hover,
button:hover,
input[type=submit]:hover {
background-color: var(--color-blue);
border-color: var(--color-blue);
color: white;
fill: white;
}
.dangerous:hover {
background-color: var(--color-red);
border-color: var(--color-red);
}
input:hover, input:hover,
select:hover, select:hover,
summary:hover,
textarea:hover { textarea:hover {
border-color: var(--color-blue); border-color: var(--color-blue);
outline: solid 1px var(--color-blue); outline: solid 1px var(--color-blue);
} }
select:hover,
summary:hover {
cursor: pointer;
}
input:invalid, input:invalid,
select:invalid, select:invalid,
textarea:invalid { textarea:invalid {
border-color: var(--color-red); border-color: var(--color-red);
outline: solid 1px var(--color-red); outline: solid 1px var(--color-red);
} }
details:hover,
select:hover {
cursor: pointer;
}
details:focus-visible,
input:focus-visible,
select:focus-within,
select:focus-visible,
textarea:focus-visible {
accent-color: var(--color-dark-blue);
background-color: var(--color-focus-gray);
}
fieldset,
input[type=text]:read-only, input[type=text]:read-only,
textarea:read-only { textarea:read-only {
border: none; border: none;
padding-left: 0; padding-inline: 0;
padding-right: 0;
} }
/* NOTE: collapse gaps around empty rows (`topside`) once possible
* with grid-collapse property and remove alternative grid-template
* https://github.com/w3c/csswg-drafts/issues/5813 */
body {
display: grid;
gap: 0.8em;
grid-template-areas:
"header header header"
"nav nav nav"
"leftside topside rightside"
"leftside main rightside";
grid-template-columns: 1fr minmax(max-content, 2fr) 1fr;
font-family: system-ui;
margin: 0.4em;
}
body:not(:has(.topside)) {
grid-template-areas:
"header header header"
"nav nav nav"
"leftside main rightside";
}
header { header {
grid-area: header; grid-area: header;
} }
.navigation { .navigation {
display: flex; display: flex;
grid-area: nav; grid-area: nav;
@@ -256,7 +238,7 @@ header {
flex: 1; flex: 1;
font-size: 1rem; font-size: 1rem;
justify-content: center; justify-content: center;
padding-block: 0.3em; padding-block: 0.4em;
} }
.navigation > .tab:hover, .navigation > .tab:hover,
.navigation > .tab:focus-visible { .navigation > .tab:focus-visible {
@@ -268,7 +250,6 @@ header {
fill: var(--color-blue); fill: var(--color-blue);
} }
.topside { .topside {
grid-area: topside; grid-area: topside;
} }
@@ -282,7 +263,6 @@ header {
grid-area: rightside; grid-area: rightside;
} }
.buttongrid { .buttongrid {
display: grid; display: grid;
gap: 0.4em; gap: 0.4em;
@@ -355,7 +335,7 @@ header {
} }
/* TODO: Update styling, including rem removal. */ /* TODO: Update form styling: simplify selectors, deduplicate, remove non-font rem. */
form table { form table {
border-spacing: 0.8rem; border-spacing: 0.8rem;
} }
@@ -385,16 +365,15 @@ form td.error::after {
form em { form em {
color: var(--color-text-gray); color: var(--color-text-gray);
font-size: 0.75rem; font-size: 0.75rem;
font-weight: normal;
} }
form input[type=submit] { form input[type=submit] {
float: none;
font-size: 1rem; font-size: 1rem;
margin: 1.5rem auto 0 auto; margin: 1.5rem auto 0 auto;
padding: 0.75rem; padding: 0.75rem;
} }
/* TODO: remove .items class and make 'form table' work properly */
table.items { table.items {
border-spacing: 0; border-spacing: 0;
border: solid 1px var(--color-border-gray); border: solid 1px var(--color-border-gray);
@@ -402,6 +381,9 @@ table.items {
font-size: 0.85rem; font-size: 0.85rem;
text-align: left; text-align: left;
} }
table:not(:has(tr)) {
display: none;
}
table.items thead { table.items thead {
font-size: 0.8rem; font-size: 0.8rem;
} }
@@ -478,7 +460,7 @@ table.items tr.form td {
} }
/* TODO: replace :hover:focus-visible combos with proper LOVE stye order */ /* TODO: replace :hover:focus-visible combos with proper LOVE stye order */
/* TODO: Update styling, including rem removal. */ /* TODO: Update table styling: simplify selectors, deduplicate, remove non-font rem. */
table.items td.link a:hover, table.items td.link a:hover,
table.items td.link a:focus-visible, table.items td.link a:focus-visible,
table.items td.link a:hover:focus-visible { table.items td.link a:hover:focus-visible {
@@ -502,8 +484,12 @@ table.items td:not(:first-child),
fill: var(--color-table-gray); fill: var(--color-table-gray);
} }
table.items svg { table.items svg {
height: 1.2rem; height: 1rem;
vertical-align: middle; vertical-align: middle;
width: 1rem;
}
table.items svg:last-child {
height: 1.2rem;
width: 1.2rem; width: 1.2rem;
} }
table.items td.svg { table.items td.svg {
@@ -516,7 +502,8 @@ table.items .button,
table.items button, table.items button,
table.items input[type=submit] { table.items input[type=submit] {
font-weight: normal; font-weight: normal;
padding: 0.3em; height: 100%;
padding: 0.4em;
} }
table.items input:not([type=submit]):not([type=checkbox]), table.items input:not([type=submit]):not([type=checkbox]),
table.items select, table.items select,
@@ -542,7 +529,6 @@ table.items select:focus-within,
table.items select:focus-visible { table.items select:focus-visible {
color: black; color: black;
} }
form a[name=cancel] { form a[name=cancel] {
border-color: var(--color-border-gray); border-color: var(--color-border-gray);
color: var(--color-nav-gray); color: var(--color-nav-gray);
@@ -560,6 +546,7 @@ form table.items td:first-child {
color: inherit; color: inherit;
} }
.centered { .centered {
margin: 0 auto; margin: 0 auto;
} }
@@ -592,7 +579,8 @@ form table.items td:first-child {
} }
[disabled] { [disabled] {
/* label:has(input[disabled]) { /* label:has(input[disabled]) {
* TODO: disabled checkbox blue square focus removal; disabled label styling * TODO: disabled checkbox blue square focus removal; disabled label styling;
* focused label styling (currently only checkbox has focus)
* */ * */
border-color: var(--color-border-gray) !important; border-color: var(--color-border-gray) !important;
color: var(--color-border-gray) !important; color: var(--color-border-gray) !important;
@@ -630,8 +618,10 @@ summary:has(.button) {
padding-inline-end: 0; padding-inline-end: 0;
} }
summary .button { summary .button {
border: 1px var(--color-border-gray); border: solid 1px var(--color-border-gray);
border-radius: 0; border-radius: inherit;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
border-style: none none none solid; border-style: none none none solid;
height: 100%; height: 100%;
} }
@@ -644,15 +634,13 @@ details[open] summary::before {
summary::marker { summary::marker {
padding-left: 0.25em; padding-left: 0.25em;
} }
/* TODO: use ::details-content ? */ /* NOTE: use details[open]::details-content once widely available */
details[open] ul { details[open] ul {
background: white; background: white;
border: solid 1px var(--color-border-gray); border: solid 1px var(--color-border-gray);
border-radius: 0.25em; border-radius: 0.25em;
box-sizing: content-box;
box-shadow: 1px 1px 3px var(--color-border-gray); box-shadow: 1px 1px 3px var(--color-border-gray);
margin: 0; margin: -1px 0 0 0;
margin-left: -0.9px;
padding-left: 0; padding-left: 0;
position: absolute; position: absolute;
width: 100%; width: 100%;

View File

@@ -114,6 +114,7 @@ function formProcessKey(event) {
window.formProcessKey = formProcessKey window.formProcessKey = formProcessKey
function detailsProcessKey(event) { function detailsProcessKey(event) {
// TODO: up/down arrows to move focus to prev/next line
switch (event.key) { switch (event.key) {
case "Escape": case "Escape":
if (event.currentTarget.hasAttribute("open")) { if (event.currentTarget.hasAttribute("open")) {

View File

@@ -1,12 +1,11 @@
<%= tabular_form_with model: Measurement.new, id: :measurement_form, <%= tabular_form_with model: Measurement.new, id: :measurement_form,
class: 'topside vflex', html: {onkeydown: 'formProcessKey(event)'} do |form| %> class: 'topside vflex', html: {onkeydown: 'formProcessKey(event)'} do |form| %>
<fieldset> <table class="items centered">
<table class="items centered"> <tbody id="readouts"></tbody>
<tbody id="readouts"></tbody> </table>
</table>
</fieldset>
<div class="hflex"> <div class="hflex">
<%# TODO: right-click selection %>
<details id="quantity_select" class="hexpand" open <details id="quantity_select" class="hexpand" open
onkeydown="detailsProcessKey(event)"> onkeydown="detailsProcessKey(event)">
<summary autofocus> <summary autofocus>