I have created a vertical menu and I want to expand it over the entire height of the viewport but if this is not sufficient to contain it I would like some scroll mechanism (on the page or on the vertical menu it is fine in both cases) that allows me to do so. I've tried several ways but I can't get the desired effect.
With this solution header.sidebar is position:sticky and I can see all the vertical menu when I scroll on the body, but only when I have scrolled a lot and this isn't user friendly. This isn't acceptable.
/*#region BASE */
@import url("https://fonts.googleapis.com/css2?family=Anta&family=Madimi+One&display=swap");
*,
*::after,
*::before {
margin: 0;
padding: 0;
list-style: none;
box-sizing: border-box;
font-family: inherit;
}
html {
font-size: 16px;
}
body {
background-image: url("https://i.ibb.co/gDgZ3c9/background-Template.png");
background-size: cover;
background-attachment: fixed;
font-family: "Anta", sans-serif;
/* Non uso gridbox perchè gridbox imposta la dimensione delle colonne nell'elemento genitore(quindi qui nel body) con la
proprietà grid-template-columns e non riuscirei con il meccanismo dell'input:checkbox a cambiarne la dimensione
(perchè non posso selezionare il body quando l'input è checked perchè il body è l'elemento genitore).
Con flexbox invece quando clicco sull'hamburger menu basta cambiare la dimensione della sidebar */
display: flex;
/* Questa serve affinchè */
align-items: start;
}
a {
text-decoration: none;
}
/*#endregion BASE */
/*#region SIDEBAR*/
/* Uso position:sticky e top:0 left:0 perchè non voglio */
header.sidebar {
position: sticky;
/* overflow-y: auto;
overflow-x: visible; */
top: 0;
bottom: 0;
left: 0;
background-image: linear-gradient(
30deg,
rgba(5, 5, 75, 0.85),
rgba(5, 5, 75, 0.85) 20%,
rgb(5, 5, 75)
);
min-height: 100vh;
min-height: 100svh;
width: 65px;
padding: 0.4rem 0.8rem;
transition: all 0.5s ease;
}
/*#region SIDEBAR HEADER*/
.sidebar__header {
display: flex;
align-items: center;
justify-content: center;
}
.sidebar__header__logo {
display: flex;
align-items: center;
display: none;
}
.sidebar__header__logo img {
width: 50px;
}
.sidebar__header__logo span {
color: white;
}
.sidebar__header__hamburger {
cursor: col-resize;
margin-top: 0.4rem;
}
/*#endregion SIDEBAR HEADER*/
/*#region SIDEBAR USER*/
.sidebar__user {
display: flex;
justify-content: center;
}
.sidebar__user__img {
width: 50px;
height: 50px;
object-fit: cover;
border: 3px solid rgb(182, 5, 152);
border-top-color: rgb(23, 23, 201);
border-bottom-color: rgb(23, 23, 201);
border-radius: 50%;
margin-top: 20px;
}
.sidebar__user__name {
display: none;
}
/*#endregion SIDEBAR USER*/
/*#region SIDEBAR MENU*/
.sidebar__menu__item {
min-height: 40px;
margin: 10px 0;
display: flex;
align-items: center;
justify-content: center;
}
.sidebar__menu__item:hover {
border-radius: 10px;
background-color: white;
}
.sidebar__menu__item:hover .sidebar__menu__item__icon::before {
/* background-image: red; */
background-image: linear-gradient(rgb(5, 5, 75), rgb(5, 5, 75));
font-size: larger;
}
.sidebar__menu__item a {
position: relative; /* Serve per posizionare il tooltip */
display: block;
/* Le seguenti due regole servono per far si che il
tag a si sovrapponga perfettamente all'li
genitore in modo che la superficie cliccabile
del link cresca e sia uguale a quella dell'li */
width: 100%;
min-height: inherit;
display: flex;
justify-content: center;
align-items: center;
}
.sidebar__menu__item__text {
height: 3.2em;
min-width: 100px;
display: none;
font-size: 1rem;
background-color: rgb(182, 5, 152);
background-image: linear-gradient(
to right,
rgb(23, 23, 201),
rgb(182, 5, 152)
);
background-clip: text;
-webkit-text-fill-color: transparent;
}
/* Questa regola funge da fallback in caso -webkit-text-fill-color o background-clip: text;
non siano supportati */
.sidebar__menu__item__icon {
color: rgb(23, 23, 201);
}
:is(.sidebar__menu__item__icon, .sidebar__header__hamburger)::before {
background-image: linear-gradient(
to right,
rgb(23, 23, 201),
rgb(182, 5, 152)
);
background-clip: text;
-webkit-text-fill-color: transparent;
}
.sidebar__menu__tooltip {
position: absolute;
right: 0;
top: 50%;
/* 0.8rem è la dimensione del padding destro della sidebar */
/* 10px è la distanza con cui voglio distanziare il
tooltip dal bordo della sidebar */
transform: translate(calc(100% + 0.8rem + 10px), -50%);
background-color: white;
border-radius: 8px;
min-width: 75px;
text-align: center;
font-size: 0.7rem;
font-weight: 500;
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
padding: 5px;
letter-spacing: -0.2px;
display: none;
color: rgb(5, 5, 75);
}
.sidebar__menu__item a:hover .sidebar__menu__tooltip {
display: block;
}
/*#endregion SIDEBAR MENU*/
/*#region SIDEBAR INPUT*/
input#sidebar-toggle {
display: none;
}
input#sidebar-toggle:checked + header.sidebar {
width: 250px;
}
/*#endregion SIDEBAR INPUT*/
/*#endregion SIDEBAR*/
/*#region MAIN */
/* input#sidebar-toggle:checked ~ main.main-content {
} */
main.main-content {
flex-grow: 1;
}
/*#endregion MAIN */
/* per i devices che non supportano l'hover aggiungo il focus e l'active per intercettare il touch.
In questo modo avrò la comparsa del tooltip al touch (long touch).
Così più che realizzare l'hover ho realizzato il click ma mi sta bene
Questa soluzione potrebbe non funzionare per i browser mobile Edge per i quali devi aggiungere nell'html
aria-haspopup="true" */
/* In questo caso la media query @media all and (hover: none) serve perchè altrimenti se tieni premuto
una voce di menu si attiva il popup e rimane aperto (perchè è active) e rimarrà aperto finchè non cliccki altrove.
Per capirlo prova il codice su un computer con mouse rimuovendo la media query @media all and (hover: none)
Nota che stiamo trascurando altri dispositivi di puntamento (come i pennini)
*/
@media all and (hover: none) {
.sidebar__menu__item a:focus .sidebar__menu__tooltip,
.sidebar__menu__item a:active .sidebar__menu__tooltip {
background-color: red;
display: block;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Dashboard</title>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
integrity="sha512-DTOQO9RWCH3ppGqcWaEA1BIZOC6xxalwEsw9c2QQeAIftl+Vegovlnee1c9QX4TctnWMn13TZye+giMm8e2LwA=="
crossorigin="anonymous" />
<link rel="stylesheet" href="../css/dashboard.css" />
<script src="../js/dashboard.js" defer></script>
</head>
<body>
<input type="checkbox" name="sidebar-toggle" id="sidebar-toggle" />
<header class="sidebar">
<div class="sidebar__header">
<div class="sidebar__header__logo">
<!-- <i class="fa-brands fa-codepen"></i> -->
<img src="../../assets/img/logo.png" alt="" />
<span>Wardiere</span>
</div>
<label for="sidebar-toggle">
<i class="fa-solid fa-bars sidebar__header__hamburger"></i>
</label>
</div>
<div class="sidebar__user">
<img src="https://i.ibb.co/tP3Vryt/foto.jpg"
class="sidebar__user__img" alt="foto profilo" >
<p class="sidebar__user__name">Marco Rossi</p>
</div>
<nav class="sidebar__menu">
<ul>
<li class="sidebar__menu__item">
<a href="#">
<i
class="fa-solid fa-window-maximize fa-2xs sidebar__menu__item__icon"></i>
<span class="sidebar__menu__item__text">Dashboard</span>
<span class="sidebar__menu__tooltip">Dashboard</span>
</a>
</li>
<li class="sidebar__menu__item">
<a href="#">
<i
class="fa-solid fa-message fa-2xs sidebar__menu__item__icon"></i>
<span class="sidebar__menu__item__text">Messages</span>
<span class="sidebar__menu__tooltip">Messages</span>
</a>
</li>
<li class="sidebar__menu__item">
<a href="#">
<i
class="fa-solid fa-dollar-sign fa-2xs sidebar__menu__item__icon"></i>
<span class="sidebar__menu__item__text">Revenue</span>
<span class="sidebar__menu__tooltip">Revenue</span>
</a>
</li>
<li class="sidebar__menu__item">
<a href="#">
<i class="fa-solid fa-bell fa-2xs sidebar__menu__item__icon"></i>
<span class="sidebar__menu__item__text">Notifications</span>
<span class="sidebar__menu__tooltip">Notifications</span>
</a>
</li>
<li class="sidebar__menu__item">
<a href="#">
<i class="fa-solid fa-heart fa-2xs sidebar__menu__item__icon"></i>
<span class="sidebar__menu__item__text">Likes</span>
<span class="sidebar__menu__tooltip">Likes</span>
</a>
</li>
<li class="sidebar__menu__item">
<a href="#">
<i
class="fa-solid fa-wallet fa-2xs sidebar__menu__item__icon"></i>
<span class="sidebar__menu__item__text">Wallet</span>
<span class="sidebar__menu__tooltip">Wallet</span>
</a>
</li>
<li class="sidebar__menu__item">
<a href="#">
<i class="fa-solid fa-gear fa-2xs sidebar__menu__item__icon"></i>
<span class="sidebar__menu__item__text">Settings</span>
<span class="sidebar__menu__tooltip">Settings</span>
</a>
</li>
<li class="sidebar__menu__item">
<a href="../../index.html">
<i class="fa-solid fa-house fa-2xs sidebar__menu__item__icon"></i>
<span class="sidebar__menu__item__text">Home</span>
<span class="sidebar__menu__tooltip">Home</span>
</a>
</li>
</ul>
</nav>
</header>
<main class="main-content" style="margin-top: 2000px">
<h1 style="color: red">DASHBOARD</h1>
</main>
<script defer src="../js/dashboard.js"></script>
</body>
</html>
With this more canonical solution:
/*#region BASE */
@import url("https://fonts.googleapis.com/css2?family=Anta&family=Madimi+One&display=swap");
*,
*::after,
*::before {
margin: 0;
padding: 0;
list-style: none;
box-sizing: border-box;
font-family: inherit;
}
html {
font-size: 16px;
}
body {
background-image: url("https://i.ibb.co/gDgZ3c9/background-Template.png");
background-size: cover;
background-attachment: fixed;
font-family: "Anta", sans-serif;
/* Non uso gridbox perchè gridbox imposta la dimensione delle colonne nell'elemento genitore(quindi qui nel body) con la
proprietà grid-template-columns e non riuscirei con il meccanismo dell'input:checkbox a cambiarne la dimensione
(perchè non posso selezionare il body quando l'input è checked perchè il body è l'elemento genitore).
Con flexbox invece quando clicco sull'hamburger menu basta cambiare la dimensione della sidebar */
display: flex;
/* Questa serve affinchè */
align-items: start;
}
a {
text-decoration: none;
}
/*#endregion BASE */
/*#region SIDEBAR*/
/* Uso position:sticky e top:0 left:0 perchè non voglio */
header.sidebar {
position: fixed;
overflow-y: auto;
overflow-x: visible;
top: 0;
bottom: 0;
left: 0;
background-image: linear-gradient(
30deg,
rgba(5, 5, 75, 0.85),
rgba(5, 5, 75, 0.85) 20%,
rgb(5, 5, 75)
);
height: 100vh;
height: 100svh;
width: 65px;
padding: 0.4rem 0.8rem;
transition: all 0.5s ease;
}
/*#region SIDEBAR HEADER*/
.sidebar__header {
display: flex;
align-items: center;
justify-content: center;
}
.sidebar__header__logo {
display: flex;
align-items: center;
display: none;
}
.sidebar__header__logo img {
width: 50px;
}
.sidebar__header__logo span {
color: white;
}
.sidebar__header__hamburger {
cursor: col-resize;
margin-top: 0.4rem;
}
/*#endregion SIDEBAR HEADER*/
/*#region SIDEBAR USER*/
.sidebar__user {
display: flex;
justify-content: center;
}
.sidebar__user__img {
width: 50px;
height: 50px;
object-fit: cover;
border: 3px solid rgb(182, 5, 152);
border-top-color: rgb(23, 23, 201);
border-bottom-color: rgb(23, 23, 201);
border-radius: 50%;
margin-top: 20px;
}
.sidebar__user__name {
display: none;
}
/*#endregion SIDEBAR USER*/
/*#region SIDEBAR MENU*/
.sidebar__menu__item {
min-height: 40px;
margin: 10px 0;
display: flex;
align-items: center;
justify-content: center;
}
.sidebar__menu__item:hover {
border-radius: 10px;
background-color: white;
}
.sidebar__menu__item:hover .sidebar__menu__item__icon::before {
/* background-image: red; */
background-image: linear-gradient(rgb(5, 5, 75), rgb(5, 5, 75));
font-size: larger;
}
.sidebar__menu__item a {
position: relative; /* Serve per posizionare il tooltip */
display: block;
/* Le seguenti due regole servono per far si che il
tag a si sovrapponga perfettamente all'li
genitore in modo che la superficie cliccabile
del link cresca e sia uguale a quella dell'li */
width: 100%;
min-height: inherit;
display: flex;
justify-content: center;
align-items: center;
}
.sidebar__menu__item__text {
height: 3.2em;
min-width: 100px;
display: none;
font-size: 1rem;
background-color: rgb(182, 5, 152);
background-image: linear-gradient(
to right,
rgb(23, 23, 201),
rgb(182, 5, 152)
);
background-clip: text;
-webkit-text-fill-color: transparent;
}
/* Questa regola funge da fallback in caso -webkit-text-fill-color o background-clip: text;
non siano supportati */
.sidebar__menu__item__icon {
color: rgb(23, 23, 201);
}
:is(.sidebar__menu__item__icon, .sidebar__header__hamburger)::before {
background-image: linear-gradient(
to right,
rgb(23, 23, 201),
rgb(182, 5, 152)
);
background-clip: text;
-webkit-text-fill-color: transparent;
}
.sidebar__menu__tooltip {
position: absolute;
right: 0;
top: 50%;
/* 0.8rem è la dimensione del padding destro della sidebar */
/* 10px è la distanza con cui voglio distanziare il
tooltip dal bordo della sidebar */
transform: translate(calc(100% + 0.8rem + 10px), -50%);
background-color: white;
border-radius: 8px;
min-width: 75px;
text-align: center;
font-size: 0.7rem;
font-weight: 500;
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
padding: 5px;
letter-spacing: -0.2px;
display: none;
color: rgb(5, 5, 75);
}
.sidebar__menu__item a:hover .sidebar__menu__tooltip {
display: block;
}
/*#endregion SIDEBAR MENU*/
/*#region SIDEBAR INPUT*/
input#sidebar-toggle {
display: none;
}
input#sidebar-toggle:checked + header.sidebar {
width: 250px;
}
/*#endregion SIDEBAR INPUT*/
/*#endregion SIDEBAR*/
/*#region MAIN */
/* input#sidebar-toggle:checked ~ main.main-content {
} */
main.main-content {
flex-grow: 1;
}
/*#endregion MAIN */
/* per i devices che non supportano l'hover aggiungo il focus e l'active per intercettare il touch.
In questo modo avrò la comparsa del tooltip al touch (long touch).
Così più che realizzare l'hover ho realizzato il click ma mi sta bene
Questa soluzione potrebbe non funzionare per i browser mobile Edge per i quali devi aggiungere nell'html
aria-haspopup="true" */
/* In questo caso la media query @media all and (hover: none) serve perchè altrimenti se tieni premuto
una voce di menu si attiva il popup e rimane aperto (perchè è active) e rimarrà aperto finchè non cliccki altrove.
Per capirlo prova il codice su un computer con mouse rimuovendo la media query @media all and (hover: none)
Nota che stiamo trascurando altri dispositivi di puntamento (come i pennini)
*/
@media all and (hover: none) {
.sidebar__menu__item a:focus .sidebar__menu__tooltip,
.sidebar__menu__item a:active .sidebar__menu__tooltip {
background-color: red;
display: block;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Dashboard</title>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
integrity="sha512-DTOQO9RWCH3ppGqcWaEA1BIZOC6xxalwEsw9c2QQeAIftl+Vegovlnee1c9QX4TctnWMn13TZye+giMm8e2LwA=="
crossorigin="anonymous" />
<link rel="stylesheet" href="../css/dashboard.css" />
<script src="../js/dashboard.js" defer></script>
</head>
<body>
<input type="checkbox" name="sidebar-toggle" id="sidebar-toggle" />
<header class="sidebar">
<div class="sidebar__header">
<div class="sidebar__header__logo">
<!-- <i class="fa-brands fa-codepen"></i> -->
<img src="../../assets/img/logo.png" alt="" />
<span>Wardiere</span>
</div>
<label for="sidebar-toggle">
<i class="fa-solid fa-bars sidebar__header__hamburger"></i>
</label>
</div>
<div class="sidebar__user">
<img
src="https://i.ibb.co/tP3Vryt/foto.jpg"
class="sidebar__user__img"
alt="foto profilo" />
<p class="sidebar__user__name">Marco Rossi</p>
</div>
<nav class="sidebar__menu">
<ul>
<li class="sidebar__menu__item">
<a href="#">
<i
class="fa-solid fa-window-maximize fa-2xs sidebar__menu__item__icon"></i>
<span class="sidebar__menu__item__text">Dashboard</span>
<span class="sidebar__menu__tooltip">Dashboard</span>
</a>
</li>
<li class="sidebar__menu__item">
<a href="#">
<i
class="fa-solid fa-message fa-2xs sidebar__menu__item__icon"></i>
<span class="sidebar__menu__item__text">Messages</span>
<span class="sidebar__menu__tooltip">Messages</span>
</a>
</li>
<li class="sidebar__menu__item">
<a href="#">
<i
class="fa-solid fa-dollar-sign fa-2xs sidebar__menu__item__icon"></i>
<span class="sidebar__menu__item__text">Revenue</span>
<span class="sidebar__menu__tooltip">Revenue</span>
</a>
</li>
<li class="sidebar__menu__item">
<a href="#">
<i class="fa-solid fa-bell fa-2xs sidebar__menu__item__icon"></i>
<span class="sidebar__menu__item__text">Notifications</span>
<span class="sidebar__menu__tooltip">Notifications</span>
</a>
</li>
<li class="sidebar__menu__item">
<a href="#">
<i class="fa-solid fa-heart fa-2xs sidebar__menu__item__icon"></i>
<span class="sidebar__menu__item__text">Likes</span>
<span class="sidebar__menu__tooltip">Likes</span>
</a>
</li>
<li class="sidebar__menu__item">
<a href="#">
<i
class="fa-solid fa-wallet fa-2xs sidebar__menu__item__icon"></i>
<span class="sidebar__menu__item__text">Wallet</span>
<span class="sidebar__menu__tooltip">Wallet</span>
</a>
</li>
<li class="sidebar__menu__item">
<a href="#">
<i class="fa-solid fa-gear fa-2xs sidebar__menu__item__icon"></i>
<span class="sidebar__menu__item__text">Settings</span>
<span class="sidebar__menu__tooltip">Settings</span>
</a>
</li>
<li class="sidebar__menu__item">
<a href="../../index.html">
<i class="fa-solid fa-house fa-2xs sidebar__menu__item__icon"></i>
<span class="sidebar__menu__item__text">Home</span>
<span class="sidebar__menu__tooltip">Home</span>
</a>
</li>
</ul>
</nav>
</header>
<main class="main-content" style="margin-top: 2000px">
<h1 style="color: red">DASHBOARD</h1>
</main>
<script defer src="../js/dashboard.js"></script>
</body>
</html>
I have (with position:fixed and overflow-y:auto and overflow-x:visible) the vertical scrollbar on my vertical menu however I have an horizontal scrollbar too. I could hide it with overflow-x:hidden but in this way the tooltip that appears (on the right side of vertical menu) on :hover on an item menu isn't visible anymore. Instead with the horizontal scrollbar visible (without overflow-x:hidden) this tooltip is inglobated inside the sidebar menu and visible only with horizontal scroll.
This make me crazy. How could I resolve?
Above the solution: This was a problem that I had already tackled and I had forgot: My explication of the above solution is: If the height of the browser viewport cannot contain all the elements in the sidebar, a scroll bar is automatically introduced to the page. However, if the main tag contains more content than the sidebar, the sidebar will be shorter than the main tag next to it, which looks bad. So, I fix the height of the sidebar (with position:fixed and height:100vh) so that when scrolling the page, the sidebar remains fixed on the left. However, this way, if the viewport height is small, I risk not seeing the final part of the sidebar, and I want a scroll bar to be introduced on the sidebar itself (not on the page, but directly on the sidebar). And this is easy to do, just by giving overflow-y:auto. However, this way, I can no longer see the tooltips (which are a horizontal overflow) when I hover over the icons. Setting overflow-x:visible doesn't work. We've encountered one of those very strange CSS behaviors that make it hated. If you set overflow in one direction to auto, in the other direction, even if you set it to visible, it will still be auto, so a horizontal scroll bar appears, and you no longer see the tooltip unless you scroll horizontally. It's all documented here: CSS-Tricks.
At the link I provided, there is also a solution that requires the intervention of JavaScript and a modification to the CSS and HTML. We can give overflow-y:auto and overflow-x:hidden to the sidebar. Now, how do I see the tooltip since overflow-x:hidden? Thanks to a particular CSS mechanism:
If I want to see an element contained within an element with overflow:hidden, I can give position:absolute or position:relative to the element I want to see, and then its nearest ancestor with a position other than static must also be an ancestor of the element with position:hidden. In our case, the tooltip has a parent (the 'a' tag) with relative position (and the 'a' tag is not an ancestor of the sidebar), so we need to remove position:relative from the 'a' tag. We put the sidebar inside a wrapper element (the one with class .sidebar-wrapper) to which we will give position:fixed, and we will see our tooltips outside the sidebar on hover. However, tooltips with top, left, etc. will be positioned relative to the sidebar and not to the link. At this point, JavaScript comes in.
Note that the JavaScript event handler for mouseover is only needed if there is a vertical overflow of the sidebar. So, I could detect via JS if there is no vertical overflow and in that case remove the mouse event handlers (and manage centering via CSS) and vice versa. But it would complicate things without any great benefit.