Raum-Modal: Regler gedreht statt writing-mode, eigenes Aussehen

Der senkrechte Positionsregler liess sich am Handy kaum anfassen. Gebaut
war er mit writing-mode: vertical-rl - dem neueren Weg, aber einem, bei
dem der Browser das Ziehen als Wischen liest und die Seite blaettert,
statt den Griff mitzunehmen.

Jetzt liegt ein gewoehnlicher waagerechter Regler um 90 Grad gedreht in
seinem Kasten. Er bewegt sich in seinen eigenen Koordinaten waagerecht,
wird von jedem Browser unterstuetzt, traegt dieselbe Gestaltung wie die
liegenden Regler, und touch-action: none haelt die Seite still, solange
der Finger auf ihm liegt. Die Trefferflaeche ist 1,6 rem breit statt der
sichtbaren 0,375 rem Bahn. Nachgemessen: oben angeklickt 8 %, unten 93 %.

Die Neigung steht jetzt ebenfalls senkrecht, daneben das Lamellenbild -
Regler und Bild bilden ein Paar, das Bild sagt, was der Regler bedeutet.
Beide Spalten sind mit Namen und den Worten an ihren Enden beschriftet
("oben"/"unten", "auf"/"zu"); die Zahl darunter ist das, was sich beim
Ziehen aendert.

Die Regler im Raum-Modal haben ein eigenes Aussehen bekommen: Bootstraps
weisse Bahn mit blauem Griff stach auf den dunklen Karten heraus, und in
einem Raum mit drei Jalousien waren das sechs helle Balken. Bahn und Griff
tragen jetzt dasselbe Blaugruen wie der Temperaturregler, der ungefuellte
Teil ein Grau, das in beiden Themes traegt. Die Regler in den Modals fuer
Autoladung und Heizstab bleiben unberuehrt.

Die Regel fuer die Bahn steht zweimal da, einmal fuer -webkit- und einmal
fuer -moz-: als Liste notiert wirft der Browser beim unbekannten Selektor
die ganze Regel weg, und dann bliebe die Bahn ungestaltet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-31 21:53:49 +02:00
co-authored by Claude Opus 5
parent f6e0414866
commit e7fd7715ef
3 changed files with 153 additions and 82 deletions
+108 -25
View File
@@ -160,14 +160,75 @@ input[type='range']::-webkit-slider-runnable-track {
to { transform: rotate(360deg); } to { transform: rotate(360deg); }
} }
/* Schieberegler stehen dicht untereinander (Position und Neigung). Ohne den /* --------------------------------------------------------------------------
Regler im Raum-Modal
Eigenes Aussehen statt des Bootstrap-Standards: dessen weisse Bahn mit dem
blauen Griff sticht auf den dunklen Karten heraus, und in einem Raum mit
drei Jalousien sind das sechs helle Balken. Bahn und Griff tragen deshalb
dasselbe Blaugruen wie der Temperaturregler, und der ungefuellte Teil ist
ein Grau, das in beiden Themes traegt.
Bewusst nur innerhalb von #roomView: die Regler in den Modals fuer
Autoladung und Heizstab bleiben, wie sie sind.
-------------------------------------------------------------------------- */
#roomView input[type='range'] {
-webkit-appearance: none;
appearance: none;
width: 100%;
height: 1.5rem;
padding: 0;
margin: 0;
background: transparent;
}
#roomView input[type='range']:focus {
outline: 0;
}
/* Getrennt notiert, nicht als Liste: einen Selektor, den er nicht kennt,
wirft der Browser samt der ganzen Regel weg - und dann bliebe die Bahn
ungestaltet. */
#roomView input[type='range']::-webkit-slider-runnable-track {
height: 0.375rem;
border: 0;
border-radius: 0.375rem;
background: linear-gradient(to right, #00788F, #00788F), rgba(128, 128, 128, 0.32);
background-size: var(--background-size, 0%) 100%;
background-repeat: no-repeat;
}
#roomView input[type='range']::-moz-range-track {
height: 0.375rem;
border: 0;
border-radius: 0.375rem;
background: linear-gradient(to right, #00788F, #00788F), rgba(128, 128, 128, 0.32);
background-size: var(--background-size, 0%) 100%;
background-repeat: no-repeat;
}
#roomView input[type='range']::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 1.05rem;
height: 1.05rem;
/* (Bahnhoehe - Griffhoehe) / 2, damit der Griff auf der Bahn sitzt. */
margin-top: -0.34rem;
border: 2px solid #fff;
border-radius: 50%;
background: #00788F;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.45);
}
#roomView input[type='range']::-moz-range-thumb {
width: 1.05rem;
height: 1.05rem;
border: 2px solid #fff;
border-radius: 50%;
background: #00788F;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.45);
}
/* Schieberegler stehen dicht untereinander (Helligkeit, Farbe). Ohne den
Abstand kleben Beschriftung und Bahn aneinander. */ Abstand kleben Beschriftung und Bahn aneinander. */
.raum-regler + .raum-regler { .raum-regler + .raum-regler {
margin-top: 0.35rem; margin-top: 0.35rem;
} }
.raum-regler .form-range {
margin-bottom: 0;
}
/* Messwerte als Gitter statt als Textwurst: ein Stromzaehler hat sechzehn /* Messwerte als Gitter statt als Textwurst: ein Stromzaehler hat sechzehn
Werte, die in einer Zeile niemand findet. auto-fill statt fester Spalten, Werte, die in einer Zeile niemand findet. auto-fill statt fester Spalten,
@@ -216,10 +277,14 @@ input[type='range']::-webkit-slider-runnable-track {
align-items: stretch; align-items: stretch;
gap: 0.6rem; gap: 0.6rem;
} }
/* Neigungsregler und Lamellenbild gehoeren zusammen: das Bild sagt, was der
Regler daneben bedeutet, und laeuft beim Ziehen mit. */
.raum-jalousie .raum-neigung-block { .raum-jalousie .raum-neigung-block {
display: flex;
align-items: stretch;
gap: 0.4rem;
flex: 1 1 auto; flex: 1 1 auto;
min-width: 0; min-width: 0;
align-self: center;
} }
.raum-jalousie .dropdown { .raum-jalousie .dropdown {
align-self: flex-start; align-self: flex-start;
@@ -235,28 +300,42 @@ input[type='range']::-webkit-slider-runnable-track {
line-height: 1.4; line-height: 1.4;
} }
/* Die Hoehe als senkrechter Regler: der Griff steht dort, wo der Rollladen /* Eine Spalte mit senkrechtem Regler: Name, oberes Wort, Bahn, unteres
steht. writing-mode ist der Weg, den Chrome und Firefox heute gehen - Wort, Zahl. Breit genug fuer "Position" in der kleinen Schrift. */
slider-vertical war nie standardisiert und ist inzwischen entfernt. */ .raum-spalte {
.raum-position { flex: 0 0 3.4rem;
flex: 0 0 auto;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
gap: 0.1rem; text-align: center;
} }
.raum-position input[type='range'] { .raum-name {
writing-mode: vertical-rl; font-size: 0.62rem;
width: 1.2rem; opacity: 0.8;
height: 4.5rem; white-space: nowrap;
padding: 0; line-height: 1.2;
margin: 0;
} }
/* Die gefuellte Bahn laeuft hier von oben nach unten mit - "voll" heisst
heruntergefahren. */ /* Der Kasten, in dem ein gewoehnlicher Regler auf der Seite liegt.
.raum-position input[type='range']::-webkit-slider-runnable-track { Gedreht statt writing-mode: so gebaute Regler lassen sich am Handy kaum
background: linear-gradient(to bottom, #00788F, #00788F), #D7D7D7; anfassen - das Ziehen wird als Wischen gelesen und blaettert die Seite.
background-size: 100% var(--background-size, 0%); Gedreht bewegt sich der Regler in seinen eigenen Koordinaten waagerecht,
und touch-action haelt die Seite still, solange der Finger auf ihm liegt.
rotate(90deg) legt den kleinen Wert nach oben: "oben" ist 0 %. */
.raum-senkrecht {
position: relative;
width: 1.6rem;
height: 5rem;
margin: 0.1rem 0;
}
#roomView .raum-senkrecht input[type='range'] {
position: absolute;
top: 50%;
left: 50%;
width: 5rem; /* = Hoehe des Kastens, die Laenge der Bahn */
height: 1.6rem; /* = Breite des Kastens, die Flaeche zum Treffen */
transform: translate(-50%, -50%) rotate(90deg);
touch-action: none;
} }
/* Die Endstellungen in Worten statt in Prozent. */ /* Die Endstellungen in Worten statt in Prozent. */
@@ -271,9 +350,10 @@ input[type='range']::-webkit-slider-runnable-track {
aneinanderliegend heisst geschlossen. */ aneinanderliegend heisst geschlossen. */
.raum-lamellen { .raum-lamellen {
display: block; display: block;
width: 100%; flex: 1 1 auto;
height: 1.8rem; min-width: 2.5rem;
margin: 0.1rem 0; align-self: center;
height: 5rem;
/* Der Rahmen macht aus dem Streifen ein Fenster - ohne ihn liest sich das /* Der Rahmen macht aus dem Streifen ein Fenster - ohne ihn liest sich das
geschlossene Bild wie eine zweite Reglerbahn. */ geschlossene Bild wie eine zweite Reglerbahn. */
background: rgba(0, 120, 143, 0.14); background: rgba(0, 120, 143, 0.14);
@@ -283,4 +363,7 @@ input[type='range']::-webkit-slider-runnable-track {
.raum-lamelle { .raum-lamelle {
fill: currentColor; fill: currentColor;
opacity: 0.6; opacity: 0.6;
stroke: rgba(0, 0, 0, 0.35);
stroke-width: 0.6;
vector-effect: non-scaling-stroke;
} }
+7 -8
View File
@@ -282,9 +282,9 @@ function switchFloor(floor){
/** /**
* Anzeige, gefuellte Bahn und Lamellenbild eines Reglers nachziehen. * Anzeige, gefuellte Bahn und Lamellenbild eines Reglers nachziehen.
* *
* An den Endstellungen steht ein Wort statt der Zahl: "unten" liest sich * Was 0 % und 100 % bedeuten, steht bei den senkrechten Reglern als Wort
* ohne Umweg, "100 %" muss man erst uebersetzen. Dazwischen bleibt es bei * an ihren Enden ("oben"/"unten", "auf"/"zu"); die Anzeige braucht deshalb
* der Prozentzahl - fuer halb heruntergefahren gibt es kein Wort. * nur noch die Zahl, und die ist beim Ziehen das Interessante.
*/ */
function reglerAnzeigen(regler) { function reglerAnzeigen(regler) {
const schieber = regler.querySelector("input[type=range]"); const schieber = regler.querySelector("input[type=range]");
@@ -292,10 +292,7 @@ function switchFloor(floor){
const wert = Number(schieber.value); const wert = Number(schieber.value);
if (anzeige) { if (anzeige) {
const worte = regler.dataset.worte ? JSON.parse(regler.dataset.worte) : null; anzeige.textContent = wert + (schieber.dataset.einheit || "");
anzeige.textContent = (worte && worte[wert] !== undefined)
? worte[wert]
: wert + (schieber.dataset.einheit || "");
} }
// Der gefuellte Anteil der Bahn - dieselbe Eigenschaft, aus der auch // Der gefuellte Anteil der Bahn - dieselbe Eigenschaft, aus der auch
@@ -314,7 +311,9 @@ function switchFloor(floor){
* Gezeichnet wird die Hoehe, die eine gekippte Lamelle von vorn zeigt: * Gezeichnet wird die Hoehe, die eine gekippte Lamelle von vorn zeigt:
* w * sin(Winkel). Bei 0 % steht sie waagerecht und man sieht nur ihre * w * sin(Winkel). Bei 0 % steht sie waagerecht und man sieht nur ihre
* Kante, bei 100 % steht sie quer und deckt den Abstand zur naechsten * Kante, bei 100 % steht sie quer und deckt den Abstand zur naechsten
* vollstaendig ab - genau das, was das Licht abhaelt. * vollstaendig ab - genau das, was das Licht abhaelt. Der Abstand von
* Mitte zu Mitte ist 10, die Lamelle 11 tief: ab etwa 65 % schliesst
* das Bild, so wie es die Jalousie auch tut.
*/ */
function lamellenZeichnen(block, wert, min, max) { function lamellenZeichnen(block, wert, min, max) {
if (!block) return; if (!block) return;
+38 -49
View File
@@ -260,75 +260,57 @@ function reglerWert($wert, $min, $max)
return max($min, min($max, $wert)); return max($min, min($max, $wert));
} }
function reglerFeld($min, $max, $wert, $einheit) function reglerFeld($min, $max, $wert, $einheit, $beschriftung = "")
{ {
return "<input type='range' class='form-range range-color-track' min='" . $min . "' max='" . $max . "'" return "<input type='range' class='form-range range-color-track' min='" . $min . "' max='" . $max . "'"
. " step='1' value='" . $wert . "' data-einheit='" . htmlspecialchars($einheit, ENT_QUOTES) . "'>"; . " step='1' value='" . $wert . "' data-einheit='" . htmlspecialchars($einheit, ENT_QUOTES) . "'"
. ($beschriftung === "" ? ""
: " aria-label='" . htmlspecialchars($beschriftung, ENT_QUOTES) . "'")
. ">";
} }
/** /**
* Die beiden Endstellungen in Worten. * Ein senkrechter Regler mit Wort an jedem Ende.
* *
* "Position 100 %" muss man uebersetzen, "unten" nicht. Dazwischen bleibt es * Beide Werte einer Jalousie bewegen etwas, das oben und unten hat; ein
* bei der Zahl - fuer halb heruntergefahren gibt es kein Wort. Ausgewertet * waagerechter Schieber dafuer muss erst uebersetzt werden. Senkrecht steht
* wird das Attribut in raumBedienungAktivieren(), js/solar/homeMQTT.js. * der Griff dort, wo der Rollladen steht.
*/
function worteAttribut($beiNull, $beiHundert)
{
return " data-worte='" . htmlspecialchars(
json_encode([0 => $beiNull, 100 => $beiHundert], JSON_UNESCAPED_UNICODE), ENT_QUOTES) . "'";
}
/**
* Die Hoehe als senkrechter Regler - oben ist oben.
* *
* Einen waagerechten Schieber fuer eine Bewegung, die hoch und runter geht, * Gedreht wird mit transform, nicht mit writing-mode. writing-mode ist zwar
* muss man erst uebersetzen; senkrecht steht der Griff dort, wo der Rollladen * der neuere Weg, aber am Handy laesst sich ein so gebauter Regler nur
* steht. * schlecht anfassen - das Ziehen wird als Wischen gelesen und blaettert die
* Seite, statt den Griff mitzunehmen. Ein gedrehter gewoehnlicher Regler
* bewegt sich in seinen eigenen Koordinaten waagerecht, wird von jedem
* Browser unterstuetzt und traegt dieselbe Gestaltung wie die liegenden.
*/ */
function positionsRegler($cmd, $param, $wert) function senkrechterRegler($cmd, $param, $wert, $titel, $oben, $unten)
{ {
$min = reglerMin($param); $min = reglerMin($param);
$max = reglerMax($param); $max = reglerMax($param);
$wert = reglerWert($wert, $min, $max); $wert = reglerWert($wert, $min, $max);
return "<div class='raum-regler raum-position' data-cmd='" . intval($cmd["id"]) . "'" return "<div class='raum-regler raum-spalte' data-cmd='" . intval($cmd["id"]) . "'"
. " data-param='" . intval($param["id"]) . "'" . worteAttribut("oben", "unten") . ">" . " data-param='" . intval($param["id"]) . "'>"
. "<span class='raum-ende'>oben</span>" . "<span class='raum-name'>" . htmlspecialchars($titel) . "</span>"
. reglerFeld($min, $max, $wert, "%") . "<span class='raum-ende'>" . htmlspecialchars($oben) . "</span>"
. "<span class='raum-ende'>unten</span>" . "<div class='raum-senkrecht'>" . reglerFeld($min, $max, $wert, "%", $titel) . "</div>"
. "<span class='raum-ende'>" . htmlspecialchars($unten) . "</span>"
. "<span class='raum-regler-wert small fw-semibold'>" . $wert . "%</span>"
. "</div>"; . "</div>";
} }
/** /**
* Die Lamellenstellung mit einem Bild daneben. * Die sechs Lamellen neben dem Neigungsregler.
* *
* Bei 30 % oder 70 % sagt die Zahl nicht, ob man noch hinaussieht. Die vier * Bei 30 % oder 70 % sagt die Zahl nicht, ob man noch hinaussieht. Die
* Streifen zeigen es: schmal mit Luft dazwischen heisst offen, geschlossen * Streifen zeigen es: schmal mit Luft dazwischen heisst offen, geschlossen
* liegen sie aneinander. Gezeichnet wird die Hoehe, die eine gekippte * liegen sie aneinander. Gezeichnet wird die Hoehe, die eine gekippte
* Lamelle von vorn zeigt - genau das, was das Licht abhaelt. * Lamelle von vorn zeigt - genau das, was das Licht abhaelt. Die Hoehe setzt
* lamellenZeichnen() in js/solar/homeMQTT.js.
*/ */
function neigungsRegler($cmd, $param, $wert)
{
$min = reglerMin($param);
$max = reglerMax($param);
$wert = reglerWert($wert, $min, $max);
return "<div class='raum-regler raum-neigung raum-neigung-block'"
. " data-cmd='" . intval($cmd["id"]) . "'"
. " data-param='" . intval($param["id"]) . "'" . worteAttribut("auf", "zu") . ">"
. "<div class='d-flex justify-content-between small'>"
. "<span>Neigung</span>"
. "<span class='raum-regler-wert fw-semibold'>" . $wert . "%</span></div>"
. lamellenBild()
. reglerFeld($min, $max, $wert, "%")
. "<div class='d-flex justify-content-between raum-ende'><span>auf</span><span>zu</span></div>"
. "</div>";
}
/** Die vier Lamellen. Ihre Hoehe setzt der Browser, siehe homeMQTT.js. */
function lamellenBild() function lamellenBild()
{ {
$html = "<svg class='raum-lamellen' viewBox='0 0 100 40' preserveAspectRatio='none' aria-hidden='true'>"; $html = "<svg class='raum-lamellen' viewBox='0 0 100 60' preserveAspectRatio='none' aria-hidden='true'>";
foreach ([5, 15, 25, 35] as $mitte) { foreach ([5, 15, 25, 35, 45, 55] as $mitte) {
$html .= "<rect class='raum-lamelle' x='0' width='100' data-mitte='" . $mitte . "'" $html .= "<rect class='raum-lamelle' x='0' width='100' data-mitte='" . $mitte . "'"
. " y='" . ($mitte - 1) . "' height='2'></rect>"; . " y='" . ($mitte - 1) . "' height='2'></rect>";
} }
@@ -453,10 +435,17 @@ function zeichneBeschattung($d)
$html .= "</div>"; $html .= "</div>";
} }
if ($position) { if ($position) {
$html .= positionsRegler($position, $position["params"][0], $standPos); $html .= senkrechterRegler($position, $position["params"][0], $standPos,
"Position", "oben", "unten");
} }
if ($neigung) { if ($neigung) {
$html .= neigungsRegler($neigung, $neigung["params"][0], $standNeigung); // Regler und Lamellenbild bilden ein Paar: das Bild sagt, was der
// Regler daneben bedeutet, und laeuft beim Ziehen mit.
$html .= "<div class='raum-neigung-block'>"
. senkrechterRegler($neigung, $neigung["params"][0], $standNeigung,
"Neigung", "auf", "zu")
. lamellenBild()
. "</div>";
} }
$html .= mehrMenue($rest); $html .= mehrMenue($rest);
return $html . "</div>" . karteZu(); return $html . "</div>" . karteZu();