From 43d0e549fbf4f4e8cc2be0989bd6d4a8d90fa19c Mon Sep 17 00:00:00 2001 From: "Valentin V. Bartenev" Date: Sat, 16 May 2026 02:20:34 +0300 Subject: [PATCH] Web: fix hover effect on disabled buttons MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Disabled save buttons (e.g. the OTA upload button and the MQTT IATA save button) were still showing a hover background change because the generic `button:hover` rule applied unconditionally to all buttons, including disabled ones. The attempt in fbab1483 to fix this was incorrect: it added a `.savebtn:not(:disabled):hover` rule, but that rule sets the same `var(--accent-hover)` value that `button:hover` already provides. It never prevented `button:hover` from firing on a disabled element — it simply didn't match when the button was disabled, leaving `button:hover` to win unchallenged. The rule had zero net effect and was dead CSS. The correct fix is to guard the root rule itself: button:not(:disabled):hover { background: var(--accent-hover); } Adding `:not(:disabled)` raises the selector's specificity from (0,1,1) to (0,2,1), which would have overridden `.iconbtn:hover` and `.themebtn:hover` (both (0,2,0), no element selector). Those two rules are compensated by adding the `button` element qualifier, restoring their specificity to (0,2,1) and keeping source-order tie-breaking intact. The now-redundant `.savebtn:not(:disabled):hover` rule is removed. --- src/helpers/web/WebPanelServer.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/helpers/web/WebPanelServer.cpp b/src/helpers/web/WebPanelServer.cpp index d3488054..94bf8445 100644 --- a/src/helpers/web/WebPanelServer.cpp +++ b/src/helpers/web/WebPanelServer.cpp @@ -411,13 +411,13 @@ const char kWebPanelAppHtml[] PROGMEM = R"HTML( input:not([type="checkbox"]), textarea, select, button { -webkit-appearance:none; appearance:none; } textarea { min-height:100px; resize:vertical; } button { width:auto; cursor:pointer; background:var(--accent); color:var(--button-text); border:none; font-weight:700; transition:background .2s ease,color .2s ease,border-color .2s ease; } - button:hover { background:var(--accent-hover); } + button:not(:disabled):hover { background:var(--accent-hover); } .row { display:grid; grid-template-columns:1fr 1fr; gap:12px; } .row-command { display:grid; grid-template-columns:minmax(0,1fr) auto; gap:12px; align-items:center; } .row3 { display:grid; grid-template-columns:1fr 1fr 1fr; gap:12px; } .quick { display:flex; flex-wrap:wrap; gap:10px; } .quick button, .iconbtn, .themebtn { background:var(--surface2); color:var(--button-secondary-text); border:1px solid var(--border); } - .quick button:hover, .iconbtn:hover, .themebtn:hover { background:var(--surface1); } + .quick button:hover, button.iconbtn:hover, button.themebtn:hover { background:var(--surface1); } button.action-advert { background:linear-gradient(135deg,#d97706,#f59e0b); color:#fff7ed; border:none; } button.action-advert:hover { background:linear-gradient(135deg,#ea8f17,#ffb938); } button.action-caution { background:linear-gradient(135deg,#b94747,#d66a5f); color:#fff5f5; border:none; } @@ -437,7 +437,6 @@ const char kWebPanelAppHtml[] PROGMEM = R"HTML( .iconbtn { width:44px; padding:12px 0; } .placeholder-slot { display:block; width:44px; height:44px; } .savebtn { width:100%; background:var(--accent); color:var(--button-text); border:none; } - .savebtn:not(:disabled):hover { background:var(--accent-hover); } .savebtn:disabled { opacity:0.45; cursor:not-allowed; } .broker-stack { display:grid; grid-template-columns:minmax(0,1fr) minmax(0,2fr); gap:12px; align-items:start; } .broker-group { display:grid; gap:8px; align-content:start; }