Tabs Below Address Bar and Bookmark Bar
-
A CSS mod to put the tabs below the other UI elements at the top of the browser. New updated version based on work by @dude99 from here.
Preview
Installation
- Follow the steps for Adding Style in Vivaldi 2.6 and above from the pinned post here.
Configuration
There are a few CSS variables at the top of the CSS that you might need to adjust for your installation.
--addressBarPaddingRight
was configured to work with the Windows 10 control buttons in mind. It can be adjusted up or down if you notice any extra space or overlap issues with your operating system's buttons.--unified: transparent;
can be commented out (like so/* --unified: transparent; */
) if you don't want the colors of all the top UI elements to be the same color.--allowWindowDrag: 1;
can be commented out if you want to disable the ability to drag the window by clicking and dragging on the tab bar and bookmark bar- This is important because this mod causes issues with extension popup dialogs
- When dragging is allowed, there is a dead zone in the popups where they cross the tab and bookmark bars, so I added a margin to push the popup further down the page
- When dragging is disabled, by commenting out the line with the variable, the popup can be positioned directly below the extension's button without issue. But you are no longer able to move the window around by dragging
CSS
/* == Tabs Below Address Bar Mod - made by nomadic on the Vivaldi Forums == */ /* Moves the tab bar below the address bar - https://forum.vivaldi.net/post/446311 */ #browser { --addressBarPaddingRight: 137px; --addressBarPaddingLeft: 50px; --headerElementsHeight: 34px; /* comment out the line below to NOT unify tab bar color with the address bar and bookmark bar*/ --unified: transparent; --backgroundColor: var(--unified, var(--colorBg)); --backgroundColorAccent: var(--unified, var(--colorAccentBg)); /* comment out the line below to remove the drag region on the bookmark bar and tab bar */ --allowWindowDrag: 1; } /* top addressbar above top tabbar */ #browser.tabs-top.address-top #header { padding-top: 36px; } /* allows mainbar to be positioned absolute */ #main { overflow: unset; position: unset; } .mainbar { position: absolute; top: 0; left: var(--addressBarPaddingLeft); width: calc(100% - var(--addressBarPaddingLeft) - var(--addressBarPaddingRight)); z-index: 2 !important; } /* not sure if needed... */ /* brings vivaldi button and win controls to front */ #browser.tabs-top #header { backdrop-filter: unset; contain: unset; } #browser.tabs-top.address-top #main { overflow: visible; } /* Sets tabs to fill entire bar */ #browser.tabs-top.address-top #tabs-tabbar-container.top > #tabs-container, #browser.tabs-top.address-top #tabs-tabbar-container.top > #tabs-subcontainer { padding-left: 2px; padding-right: 2px; } /* bookmark bar enabled */ #browser.tabs-top.address-top.bookmark-bar-top #header { padding-top: 65px; } #browser.tabs-top.address-top.bookmark-bar-top .bookmark-bar { position: fixed; top: 34px; left: 0; right: 0; } #browser.tabs-top.address-top.bookmark-bar-top.maximized:not(.tabs-at-edge) .bookmark-bar { top: 41px; } .color-behind-tabs-off .bookmark-bar, .color-behind-tabs-off .bookmark-bar button { background-color: var(--backgroundColorAccent); } .color-behind-tabs-on .bookmark-bar, .color-behind-tabs-on .bookmark-bar button { background-color: var(--backgroundColor); } .bookmark-bar { border-color: var(--unified, var(--colorAccentBgDark)) !important; } /* horizontal menu enabled */ #browser.tabs-top.address-top.horizontal-menu #header { --headerElementsHeight: 24px; } /* Make window controls same color as menu bar */ #browser.tabs-top.address-top.horizontal-menu .window-buttongroup { background-color: var(--colorTabBar); } #browser.tabs-top.address-top.horizontal-menu #header { padding-top: 38px !important; } #browser.tabs-top.address-top.horizontal-menu .topmenu { transform: translateY(-38px); margin-bottom: 0; color: var(--colorFg); } #browser.tabs-top.address-top.horizontal-menu #tabs-tabbar-container { padding-top: 0; } #browser.tabs-top.address-top.horizontal-menu .mainbar { left: 0; width: 100%; transform: translateY(24px); } /* bookmark bar & horizontal menu enabled */ #browser.tabs-top.address-top.horizontal-menu.bookmark-bar-top #header { padding-top: 65px !important; } #browser.tabs-top.address-top.horizontal-menu.bookmark-bar-top .topmenu { transform: translateY(-65px); } #browser.tabs-top.address-top.horizontal-menu.bookmark-bar-top .bookmark-bar { top: 58px !important; } /* ---------------------------- */ /* New Stuff */ /* ---------------------------- */ /* Shrink height of all the window action buttons */ .window-buttongroup button.window-minimize, .window-buttongroup button.window-maximize, .window-buttongroup button.window-close { height: var(--headerElementsHeight) !important; } /* Shrink height of Vivaldi menu button */ #titlebar button.vivaldi { height: var(--headerElementsHeight) !important; padding-top: 0; } /* Remove empty space above tabs*/ #tabs-tabbar-container.top { padding-top: unset !important; } /* Make other title bar elements have the same color as the address bar elements */ #titlebar button.vivaldi, .window-buttongroup { background-color: var(--backgroundColor); } .color-behind-tabs-off #titlebar button.vivaldi, .color-behind-tabs-off .window-buttongroup { background-color: var(--backgroundColorAccent); } .mainbar > .toolbar-mainbar { background-color: var(--backgroundColor); } .color-behind-tabs-off .toolbar-mainbar { background-color: var(--backgroundColorAccent); } /* Fix tabs showing above address bar and search dropdowns */ #tabs-tabbar-container.top { z-index: 0; } /* Remove line under address bar and extensions bar */ .address-top .mainbar { border-bottom: unset; } /* Move extension popups down to avoid crossing drag region which leads to dead zone */ /* Horizontal menu needs -24px margin when drag is disabled */ .extension-popup.top { margin-top: calc(var(--allowWindowDrag) * 29px); } #browser.tabs-top.address-top.horizontal-menu .extension-popup.top { margin-top: calc(var(--allowWindowDrag, -3.43) * 7px); } #browser.tabs-top.address-top.bookmark-bar-top .extension-popup.top { margin-top: calc(var(--allowWindowDrag) * 58px); } #browser.tabs-top.address-top.bookmark-bar-top.horizontal-menu .extension-popup.top { margin-top: calc(var(--allowWindowDrag, -0.71) * 34px); } #tabs-tabbar-container, .bookmark-bar { app-region: var(--allowWindowDrag, no-drag); } /* Fix broken unified color in 6.2 */ .color-behind-tabs-off.address-top .mainbar { background-color: var(--backgroundColorAccent); } .color-behind-tabs-on.address-top .mainbar { background-color: var(--backgroundColor); } /* Prevent menu button from shifting down */ .vivaldi { margin-top: unset; }
Updates
- August 10, 2022 - Changed from original version to adopt @dude99's version as a base.
- August 10, 2022 - Updated to work with version
5.4
. Thanks to everyone who has helped me iron out the issues. - August 12, 2022 - Fixed issue with transparent tab bar theme setting making the menu and window control buttons unclickable. Thanks to @wdefoe for narrowing down the problematic setting.
- June 30, 2023 - Fixed issues with border under address bar and unified color variable. Thanks to @eilegz for pointing it out.
- September 18, 2023 - Updates for version 6.2 including overflow 2nd row tabs issue. Thanks to @pato for pointing it out.
- October 20, 2023 - Fix accidental padding when address and tab bars aren't visible. Such as when in fullscreen. Thanks to @ruulrskybound for pointing it out.
- November 27, 2023 - Remove accidental background on extension buttons in ununified mode.
-
@nomadic You can also use
#tabs-tabbar-container.bottom {flex-direction: column/column-reverse;}
to flip the order of the tabbar containers. -
@nomadic
Hello! I'm not very experienced with CSS, could you tell me if there's a way to make the tab bar multiple rows? I have too many tabs open for one row to be practical. -
@RainbowMagicMarker A solution for this is already present in native Vivaldi, stacking tabs. You can enable stacking and the second tab row in
vivaldi://settings/tabs/
and even lock the second row, keeping it visible. Itβs not a bad thing if you got many tabs, because it forces you to organise them a little. You can combine this with sessions to close projects/topics you donβt need access to and everything should be more organized and neater. Just as a suggestion. -
@RainbowMagicMarker Using the native feature of tab stacking for multiple rows is probably the best solution, as @luetage said.
If that doesn't work well enough for you, then you can check out this separate CSS that adds multi line tabs:
-
-
Structural changes in
Snapshot 3.9.2289.3
break this mod. Thanks to @adacom for noticing the change.When set to
top
orbottom
, the tabs container is placed in locations that make moving it with CSS alone difficult.Left
andRight
still place it in a location that is potentially workable, but all the changes you would need to make plus figuring out the correctcalc()
s to position the tabs correctly was more than I was willing to take on. I tried, since I like CSS mods, but JavaScript looks like the way to go to fix this one.I will update the main post once these changes reach stable.
There is both a CSS and a JavaScript part to this mod (I like to keep them separate to allow easy customization of the styling in the CSS). Also, for the mod to work, the tab position should be set to
Top
.JavaScript:
// ============================================================================================================ // Tabs Below Address Bar and Bookmark Bar (JS Version) // URL: https://forum.vivaldi.net/topic/56809/tabs-below-address-bar-and-bookmark-bar // Description: Moves the tab bar under the other UI elements at the top of the screen // Author(s): @nomadic // CopyRight: No Copyright Reserved // Tested on: Snapshot 3.9.2289.3 // ============================================================================================================ (function () { function moveTabBarBelowTopUI() { function moveTabBar() { const tabBar = document.getElementById("tabs-tabbar-container"); const urlBar = document.querySelector(".UrlBar"); const bookmarkBar = document.querySelector(".bookmark-bar"); const insertAfter = bookmarkBar ? bookmarkBar : urlBar; if (tabBar && insertAfter) { tabBar.remove(); insertAfter.insertAdjacentElement("afterend", tabBar); } } moveTabBar(); } let intervalID = setInterval(() => { const browser = document.getElementById("browser"); if (browser) { clearInterval(intervalID); moveTabBarBelowTopUI(); } }, 300); })();
CSS:
/* Remove unnecessary gap at top of tabs */ #tabs-tabbar-container { padding-top: unset !important; } /* Remove line between address bar and bookmark bar */ .address-top .toolbar-mainbar:after { content: unset; } /* Remove line between bookmark bar and tabs */ .bookmark-bar { border-bottom-width: 0px !important; } /* Make bookmark bar blend in */ .bookmark-bar { background-color: var(--colorAccentBg); } .color-behind-tabs-off .bookmark-bar button { background-color: var(--colorAccentBg); } .color-behind-tabs-on .bookmark-bar { background-color: var(--colorBg); } .color-behind-tabs-on .bookmark-bar button { background-color: var(--colorBg); } /* Fix opaque tabbar */ #browser:not(.transparent-tabbar) #tabs-tabbar-container { background-color: var(--colorBgDark); } /* Fix header content positioning */ .vivaldi, #header #titlebar .window-buttongroup button:not(.vivaldi) { height: 25px !important; }
And if anyone is interested in trying to get a CSS only version working with setting the tab position to
Left
, here is some of my experimental CSS:Only expand if you want to make your own CSS mod, not necessary otherwise [very rough] ...
#tabs-tabbar-container.left { flex-direction: column-reverse; flex: 0 1 auto; padding: 0 0 4px 0; height: 33px; width: 100% !important; } #tabs-container.left { flex: 0 1 auto; flex-direction: unset; } #tabs-container.left .resize { flex-direction: unset; max-height: unset; overflow-x: unset; overflow-y: unset; } .tab-position { --newWidth: 180; --Width: calc(1px * var(--newWidth)) !important; --PositionX: calc(var(--PositionY) * (var(--newWidth) / 30)) !important; transform: translateX(var(--PositionX)) translateY(0px); }
-
@nomadic - thanks - it certainly moves the tabs below the navbar - other things to work out - dont know if thats something you planned and left to users to solve or if there is a bug
have done nothing and looked at nothing just loaded your code
-
@adacom Ah, yep. Only tested with a horizontal menu bar. No more modding late at night for me...
Should just need to add this:
.vivaldi, #header #titlebar .window-buttongroup button:not(.vivaldi) { height: 25px !important; }
-
@nomadic - again thanks
yes that gives the top bar the correct height - what i am trying to achieve is this
ie - no top bar - windows buttons and vivaldi button on navbar
i realise that needs more code so i may be jumping many steps ahead without thinking or looking and your code may well be the start point - too early here and not enough coffee yet to think clearly
-
@adacom If you can share the old code you are using to get that menu button and window control placement, then I can help you update it.
I don't know if you went for a JS or CSS approach, but tweaking a slightly broken existing solution is much easier.
-
@nomadic - thanks i have solved it by using
/* brings vivaldi button and win controls to front */ #browser.tabs-top #header { background-color: none; backdrop-filter: none; contain: none; }
no idea if its good code or not but it works
i have another problem with the moving of the zoom buttons to the tabbar - they dont show then they do - will start a new thread later on that
-
@nomadic said in Tabs Below Address Bar and Bookmark Bar:
And if anyone is interested in trying to get a CSS only version working with setting the tab position to
Left
, here is some of my experimental CSS:Only expand if you want to make your own CSS mod, not necessary otherwise [very rough] ...
#tabs-tabbar-container.left { flex-direction: column-reverse; flex: 0 1 auto; padding: 0 0 4px 0; height: 33px; width: 100% !important; } #tabs-container.left { flex: 0 1 auto; flex-direction: unset; } #tabs-container.left .resize { flex-direction: unset; max-height: unset; overflow-x: unset; overflow-y: unset; } .tab-position { --newWidth: 180; --Width: calc(1px * var(--newWidth)) !important; --PositionX: calc(var(--PositionY) * (var(--newWidth) / 30)) !important; transform: translateX(var(--PositionX)) translateY(0px); }
Been working on this since last night. This is probably not the best way to do this, and there are still some things that aren't exactly working (new tabs that exceed the browser width need to be scrolled to and compact tab stack tabs have a space after them for some reason probably hidden in the .js.
/* START LEFT TABS OVER WEBVIEW */ /* 3.9.2289.3 (Official Build) (64-bit) */ /* Order for containers is Tabs (on top) with Panels to the Right of Webview Panels and Webview order can be swapped, but for this to work the Tabs Order Number needs to be higher than the Order Number of the other Containers To display everything correctly set Margin Top of the other Containers to be 1px more than the Height of the Tabs Container Set Margin Left of the Tabs Container to be -100% so the Webview Container displays correctly */ /* CONTAINER ORDER */ /* Webview Container */ #webview-container { order: -2 !important; margin-top: 34px !important; } /* Panels Container */ #panels-container { order: -3 !important; margin-top: 34px !important; } /* For the 3.9.2289.3 SNAPSHOT this is the order of <ELEMENTS> in the Tabs Tabbar Container: <div id="tabs-tabbar-container" class="left"> (#tabs-tabbar-container.left) Contains Tabs Container Div, Tab Stack Two-Level Toolbar, and Slidebar Button <div id="tabs-container" class="left"> (#tabs-container.left) Contains the Resize Div, Sync and Trash Container, and Slidebar Button <div id="" class="resize"> (.resize) For the re-sizable area the Left/Right Tabs live <div id="" class="tab-strip"> (.tab-strip) Contains the Tab Spans as well as the New Tab Button <span id="" class=""> () Each Tab is inclosed in an empty Span <div id="" class="tab-position"> (.tab-position) Tab Position is calculated from the element.style, which is determined via javascript <div id="tab-[NUM]" class="tab"> (#tab-[NUM].tab) [NUM] is the random number assigned to each tab */ /* Tabs Tabbar Container */ #tabs-tabbar-container.left { flex-direction: unset !important; flex: none !important; padding: 0 !important; /* Height needs to be set to at least 3px more than Tab Height */ height: 33px !important; width: 100% !important; order: 1 !important; margin-left: -100% !important; /* Not really necessary */ z-index: 1 !important; /* enables horizonal scrolling */ /* Overlay puts the scrollbar over the tabs/ Scroll puts the scrollbar under the tabs */ overflow-x: overlay !important; } /* Tabs Tabbar Container Scrollbar */ /* Use [Ctrl] + Mouse Wheel */ /* Otherwise remove to display the default scrollbar */ #tabs-tabbar-container.left::-webkit-scrollbar { display: none !important; } /* Tabs Container */ #tabs-container.left { flex: 1 1 auto !important; flex-direction: unset !important; } /* Tabs Container Resize */ #tabs-container.left .resize { flex-direction: unset !important; max-height: unset !important; overflow-x: unset !important; overflow-y: unset !important; } /* Tab Strip "Bottom" Toolbar */ /* This contains the New Tab Button */ #tabs-container.left .tab-strip .toolbar.toolbar-tabbar.toolbar-large.tab-position { display: none !important; } /* Slidebar Button */ /* No tab slider */ .left button.SlideBar.SlideBar--FullHeight { display: none !important; } /* Tab Position */ .left .tab-position { max-height: 30px !important; height: 30px !important; --Height: 30px !important; --newWidth: 100; --Width: calc(1px * var(--newWidth)) !important; --PositionX: calc(var(--PositionY) * (var(--newWidth) / 30)) !important; transform: translateX(var(--PositionX)) translateY(0px) !important; bottom: 1px !important; } /* Tab */ /* Default Tab Height is 30px */ .left .tab { max-height: 30px !important; height: 30px !important; } /* No Sync/Trash */ /* would need to move after tabs */ .left .sync-and-trash-container { display: none !important; } /* END LEFT TABS OVER WEBVIEW */
This is super hacky, but it works
-
@elesands Haha, glad someone decided to give it a go.
I will have to check it out! Might be able to figure out some of the current issues as well.
My original intention was to use another
calc()
for--newWidth
to shrink tabs like the current tab bar behavior, but I decided to just make the JS version before I got around to implementing that aspect. -
@nomadic
I tried to assign the tabbar width to a variable, then divide by number of tabs.... but I don't think it's possible to get the tab amount with pure css.(I was thinking maybe get the tabstrip children minus one, or just count the spans? But I have no idea how to do that? Maybe possible with nth-child psuedo-class?)
-
Edit: Had some time to think about it, and I think it could probably be done in an easier way using stuff similar to the CSS for multi line tabs. Could also use percentages for widths to avoid all the media query nonsense.
@elesands Yeah, that is an issue. Maybe something like this could be used. It obviously wouldn't scale well to large numbers of tabs, but as long as you don't go overboard on the number of tabs it should work.
I wrote the above text, but then my curiosity got the better of me. I deviated from the original design intent a bit and ended up with something more along the lines of this: Make tabs span to full width
Here is the result I got:
Looks great, right? And all it took was about 120 lines of code! Well... not really...
I cheated a bit. I used
SCSS
instead ofCSS
. Those 120 lines generate just under 6500 lines of CSS, so we can call this more academic rather than something that should actually be used, but it does work.
The worst part was the way I determined the window width. There is probably a better way to do it, but my "solution" was to use media queries going through each pixel size from the minimum window width to the width of my screen.
Like so:
... @media screen and (min-width: 1320px) { .tab-strip { --screenWidth: 1320; } } @media screen and (min-width: 1321px) { .tab-strip { --screenWidth: 1321; } } ...
Here is the complete SCSS (I am not including the generated CSS for what I assume are obvious reasons):
// update screen size $minVivaldiWidth: 500; $maxVivaldiWidth: 1536; // your screen width @for $i from $minVivaldiWidth through $maxVivaldiWidth { @media screen and (min-width: #{$i}px) { .tab-strip { --screenWidth: #{$i}; } } } /* Webview Container */ #webview-container { order: -2 !important; margin-top: 34px !important; } /* Panels Container */ #panels-container { order: -3 !important; margin-top: 34px !important; } /* Tabs Tabbar Container */ #tabs-tabbar-container.left { flex-direction: unset !important; flex: none !important; padding: 0 !important; /* Height needs to be set to at least 3px more than Tab Height */ height: 33px !important; width: 100% !important; order: 1 !important; margin-left: -100% !important; /* Not really necessary */ z-index: 1 !important; /* enables horizonal scrolling */ /* Overlay puts the scrollbar over the tabs/ Scroll puts the scrollbar under the tabs */ overflow-x: overlay !important; } /* Tabs Tabbar Container Scrollbar */ /* Use [Ctrl] + Mouse Wheel */ /* Otherwise remove to display the default scrollbar */ #tabs-tabbar-container.left::-webkit-scrollbar { display: none !important; } /* Tabs Container */ #tabs-container.left { flex: 1 1 auto !important; flex-direction: unset !important; } /* Tabs Container Resize */ #tabs-container.left .resize { flex-direction: unset !important; max-height: unset !important; overflow-x: unset !important; overflow-y: unset !important; } /* Tab Strip "Bottom" Toolbar */ /* This contains the New Tab Button */ #tabs-container.left .tab-strip .toolbar.toolbar-tabbar.toolbar-large.tab-position { right: 0px; top: 3px; } .newtab { left: unset !important; top: unset !important; } /* Slidebar Button */ /* No tab slider */ .left button.SlideBar.SlideBar--FullHeight { display: none !important; } /* Position the tab close button */ .tab-position .tab .close { display: flex; visibility: hidden; } .tab-position .tab:hover .close { visibility: visible; } /* center tab title */ .tab-position .tab .title { flex: unset; margin: 0 auto; padding: 0 10px; } .tab-strip { --spaceForNewTabTrashSync: calc(28 * 2); --normalTabWidth: 180; } // give tabs a width that fits screen @for $i from 2 through 31 { .tab-strip > span:first-child:nth-last-child(#{$i}), .tab-strip > span:first-child:nth-last-child(#{$i}) ~ span { --newWidth: calc((var(--screenWidth) - var(--spaceForNewTabTrashSync)) / #{$i - 1}); } } /* Tab Position */ .left span .tab-position { max-height: 30px !important; height: 30px !important; --Height: 30px !important; --Width: calc(1px * var(--newWidth)) !important; --PositionX: calc(var(--PositionY) * (var(--newWidth) / 30)) !important; transform: translateX(var(--PositionX)) translateY(0px) !important; bottom: 1px !important; } /* Tab */ /* Default Tab Height is 30px */ .left .tab { max-height: 30px !important; height: 30px !important; }
I only made it work for a maximum of 30 tabs to keep the length of the CSS
reasonablefrom taking all the storage space on my laptop. The screen size can be set at the top of the file with the variable$maxVivaldiWidth
.This is the first real time I used SCSS and I am far from an expert as CSS, so I am sure someone else could make a better solution. This was just something I threw together late at night, so only view it as a wacky experiment by a sleep deprived novice.
-
@nomadic
Oh my gosh that is so much.I thought I had something by making a variable that took the width of the tab bar... It was working (or at least it seemed to be) like a day? ago? But then I edited it and of course I don't have previous versions of the file. Cause that would be silly
And now it isn't working and what I could google says that it isn't a thing so
Really I don't know why the tabs can't just be cells in a table row :πΈ
Why is something like this so difficult to do?
(i just noticed that the title bar is all donked up TTnTT It's not cropped; it's that way on my screen :C )
-
@elesands I wrote that late at night and wasn't thinking it all the way through. I don't have time to look at it right now, but you could take a look at the multi line tabs CSS and try to combine that in.
All that messing around with positioning probably isn't necessary.
-
Ok so I finally figured out that I could individually style pinned, etc, tabs by moving everything from .tab-position to .tab:
/* Tab Position */ .left .tab-position { position: unset !important; max-width: unset !important; width: unset !important; display: unset !important; transform: unset !important; } /* Tab */ /* Default Tab Height is 30px */ /* Moved everything from tab position to tab */ .left .tab-position .tab { position: absolute !important; max-height: 30px !important; max-width: 100% !important; width: var(--Width) !important; display: flex !important; height: 30px !important; --newWidth: 100 !important; --Width: calc(1px * var(--newWidth)) !important; --PositionX: calc(var(--PositionY) * (var(--newWidth) / 30)) !important; transform: translateX(var(--PositionX)) translateY(0px) !important; bottom: -1px !important; } .left .tab-position .tab.pinned { --newWidth: 30 !important; --Width: 30px !important; max-width: 30px !important; }
But that still leaves a gap after the tab; same issue I was running into with compact tab stack tabs.
Well, at least that is progress???
-
@nomadic Thank you very much for linking to this, it's definitely a big step in the right direction.
I'm getting a gap on both ends of the bar (see below), I don't know if that's fixable. If not, it's still a massive improvement, I really appreciate it.