diff options
author | silverwind <me@silverwind.io> | 2024-03-20 18:00:35 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-03-20 17:00:35 +0000 |
commit | 99d7ef50917e8d61798715e1b0b3dc1a99709f27 (patch) | |
tree | e1f6f2b3c88232f5eb792686ad065dc574e751d1 | |
parent | 21151474e36eecc5b808963b924cd27ec34e0608 (diff) | |
download | gitea-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.css | 32 | ||||
-rw-r--r-- | web_src/css/repo/header.css | 1 | ||||
-rw-r--r-- | web_src/js/webcomponents/overflow-menu.js | 19 |
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) => { |