aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsilverwind <me@silverwind.io>2024-03-20 18:00:35 +0100
committerGitHub <noreply@github.com>2024-03-20 17:00:35 +0000
commit99d7ef50917e8d61798715e1b0b3dc1a99709f27 (patch)
treee1f6f2b3c88232f5eb792686ad065dc574e751d1
parent21151474e36eecc5b808963b924cd27ec34e0608 (diff)
downloadgitea-99d7ef50917e8d61798715e1b0b3dc1a99709f27.tar.gz
gitea-99d7ef50917e8d61798715e1b0b3dc1a99709f27.zip
Prevent layout shift in `<overflow-menu>` items (#29831)
There is a small layout shift in when active tab changes. Notice how the actions SVG is unstable: ![](https://github.com/go-gitea/gitea/assets/115237/a6928e89-5d47-4a91-8f36-1fa22fddbce7) This is because the active item with bold text is wider then the inactive one. I have applied [this trick](https://stackoverflow.com/a/32570813/808699) to prevent this layout shift. It's only active inside `<overflow-menu>` because I wanted to avoid changing HTML and doing it in regular JS would cause a flicker. I don't expect us to introduce other similar menus without `<overflow-menu>`, so that place is likely fine. ![after](https://github.com/go-gitea/gitea/assets/115237/d6089924-8de6-4ee0-8db4-15f16069a131) I also changed the weight from 500 to 600, slightly reduced horizontal padding, merged some tab-bar related CSS rules and a added a small margin below repo-header so it does not look so crammed against the buttons on top. --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
-rw-r--r--web_src/css/base.css32
-rw-r--r--web_src/css/repo/header.css1
-rw-r--r--web_src/js/webcomponents/overflow-menu.js19
3 files changed, 41 insertions, 11 deletions
diff --git a/web_src/css/base.css b/web_src/css/base.css
index 018c7d7bcd..fdfbea610b 100644
--- a/web_src/css/base.css
+++ b/web_src/css/base.css
@@ -1778,15 +1778,6 @@ table th[data-sortt-desc] .svg {
border-color: var(--color-secondary);
}
-.ui.tabular.menu .item {
- padding: 11px 12px;
- color: var(--color-text-light-2);
-}
-
-.ui.tabular.menu .item:hover {
- color: var(--color-text);
-}
-
.ui.tabular.menu .active.item,
.ui.tabular.menu .active.item:hover {
background: var(--color-body);
@@ -1803,17 +1794,36 @@ table th[data-sortt-desc] .svg {
border-color: var(--color-secondary);
}
+.ui.tabular.menu .item,
.ui.secondary.pointing.menu .item {
+ padding: 11px 12px !important;
color: var(--color-text-light-2);
}
+.ui.tabular.menu .item:hover,
+.ui.secondary.pointing.menu a.item:hover {
+ color: var(--color-text);
+}
+
.ui.secondary.pointing.menu .active.item,
.ui.secondary.pointing.menu .active.item:hover,
-.ui.secondary.pointing.menu .dropdown.item:hover,
-.ui.secondary.pointing.menu a.item:hover {
+.ui.secondary.pointing.menu .dropdown.item:hover {
color: var(--color-text-dark);
}
+.ui.tabular.menu .active.item,
+.ui.secondary.pointing.menu .active.item,
+.resize-for-semibold::before {
+ font-weight: var(--font-weight-semibold);
+}
+
+.resize-for-semibold::before {
+ content: attr(data-text);
+ visibility: hidden;
+ display: block;
+ height: 0;
+}
+
.ui.header {
color: var(--color-text);
}
diff --git a/web_src/css/repo/header.css b/web_src/css/repo/header.css
index f66df4cd8b..e998bb9a73 100644
--- a/web_src/css/repo/header.css
+++ b/web_src/css/repo/header.css
@@ -8,6 +8,7 @@
flex-flow: row wrap;
justify-content: space-between;
gap: 0.5rem;
+ margin-bottom: 4px;
}
.repo-header .flex-item {
diff --git a/web_src/js/webcomponents/overflow-menu.js b/web_src/js/webcomponents/overflow-menu.js
index 9fa4585567..604fce7d4b 100644
--- a/web_src/js/webcomponents/overflow-menu.js
+++ b/web_src/js/webcomponents/overflow-menu.js
@@ -127,6 +127,25 @@ window.customElements.define('overflow-menu', class extends HTMLElement {
});
init() {
+ // for horizontal menus where fomantic boldens active items, prevent this bold text from
+ // enlarging the menu's active item replacing the text node with a div that renders a
+ // invisible pseudo-element that enlarges the box.
+ if (this.matches('.ui.secondary.pointing.menu, .ui.tabular.menu')) {
+ for (const item of this.querySelectorAll('.item')) {
+ for (const child of item.childNodes) {
+ if (child.nodeType === Node.TEXT_NODE) {
+ const text = child.textContent.trim(); // whitespace is insignificant inside flexbox
+ if (!text) continue;
+ const span = document.createElement('span');
+ span.classList.add('resize-for-semibold');
+ span.setAttribute('data-text', text);
+ span.textContent = text;
+ child.replaceWith(span);
+ }
+ }
+ }
+ }
+
// ResizeObserver triggers on initial render, so we don't manually call `updateItems` here which
// also avoids a full-page FOUC in Firefox that happens when `updateItems` is called too soon.
this.resizeObserver = new ResizeObserver((entries) => {