CSS: Grid, Scrollbars and Tooltip issue - css

I've been pulling my hairs over a CSS issue that I will try to describe here:
In the following example (https://codesandbox.io/s/jjq4km89y5), you can see a scrollable content (purple background), and a "tooltip" (always showing in this example for practical reasons, red background) that is half hidden by the left panel.
What I need is for both the purple content to be scrollable, AND for the red tooltip to show:
The CSS uses CSS Grid, but the problem is the same if I use flex instead.
The problem seems to lies on the overflow: auto statement, (line 59 of styles.css in the code sandbox).
Thanks!!
(to see the example live, please go to https://codesandbox.io/s/jjq4km89y5)
The code, otherwise, can be seen here:
<div class="page">
<div class="menu">Menu</div>
<div class="content">
<div class="grid">
<div class="nav">Top Nav</div>
<div class="panel">Left Panel</div>
<div class="analysis">
<div>
<p>Some random content</p>
<div class="tooltip-trigger">
A div with a Tooltip (always showing here)
<div class="tooltip">
You should be able to see the entirety of this text here,
going over the Left Nav
</div>
</div>
<div class="long-content">
Some very long content that should make the purple div scroll
</div>
</div>
</div>
</div>
</div>
</div>
And the CSS:
.page {
display: flex;
margin: 0;
height: 100%;
width: 100%;
position: fixed;
}
.menu {
width: 40px;
background-color: orange;
height: 100%;
}
.content {
flex: 1;
}
.grid {
display: grid;
grid-template-columns: 210px auto;
grid-template-rows: 60px auto;
grid-template-areas:
"nav nav"
"panel analysis";
height: 100%;
}
.nav {
grid-area: nav;
padding: 10px 40px;
display: flex;
justify-content: space-between;
align-items: center;
background-color: grey;
border-bottom: 3px solid black;
}
.panel {
grid-area: panel;
border-right: solid 3px black;
background-color: grey;
}
.panel > div {
height: calc(100vh - 60px);
}
.analysis {
grid-area: analysis;
padding: 60px;
height: calc(100vh - 60px);
background-color: purple;
/* The problem is here:
if set to "auto", then we have a scrollbar but the red tooltip is not visible
If set to "visible", we get the red tooltip but the scroll is gone
*/
overflow: auto;
}
.tooltip-trigger {
position: relative;
background-color: green;
border: 5px dashed rebeccapurple;
}
.tooltip {
position: absolute;
border: 5px dashed orange;
background-color: red;
height: 200px;
width: 200px;
top: 10px;
left: -200px;
}
.long-content {
height: 3000px;
background-color: pink;
border: 5px dashed darkred;
}
You can also see the real-world app and what it does:
The tooltip as you can see will display for all these cells in the table, and needs to be precisely attached to that cell.
The content where the table is needs to be scrollable as well.

This may be a solution, or just a nudge in the right direction.
Instead of the tooltip being absolutely-positioned relative to the parent element, make it relative to a more distant ancestor, so it's not affected by the overflow of the purple div.
So, instead of this:
.grid {
display: grid;
grid-template-columns: 210px auto;
grid-template-rows: 60px auto;
grid-template-areas:
"nav nav"
"panel analysis";
height: 100%;
}
.tooltip-trigger {
position: relative;
background-color: green;
border: 5px dashed rebeccapurple;
}
.tooltip {
position: absolute;
border: 5px dashed orange;
background-color: red;
height: 200px;
width: 200px;
top: 10px;
left: -200px;
}
Try something along these lines:
.grid {
position: relative; /* new */
display: grid;
grid-template-columns: 210px auto;
grid-template-rows: 60px auto;
grid-template-areas:
"nav nav"
"panel analysis";
height: 100%;
position: relative;
}
.tooltip-trigger {
/* position: relative; */
background-color: green;
border: 5px dashed rebeccapurple;
}
.tooltip {
position: absolute;
border: 5px dashed orange;
background-color: red;
height: 200px;
width: 200px;
top: 200px; /* adjusted */
left: 60px; /* adjusted */
}
revised demo

This may be a bit of a hack, but I think it can be made to work without too bad side effects: Instead of arranging the left panel and analysis as sibling DOM-nodes, you could layer analysis inside and over left panel.
With some tweaking to adjust placement of content you could make it look like they are side by side. Instead of scrolling analysis, with a static left panel, you can scroll left panel and make the left panel content absolutely positioned.
I made a quick and dirty implementation to demonstrate the mechanics:
Revised code example
Markup:
<div className="panel">
<div className="panelContent">Left Panel</div>
<div className="panelSpacer" />
<div className="analysis">
<div>
<p>Some random content</p>
<div className="tooltip-trigger">
A div with a Tooltip (always showing here)
<div className="tooltip">
You should be able to see the entirety of this text here,
going over the Left Nav
</div>
</div>
<div className="long-content">
Some very long content that should make the purple div scroll
</div>
</div>
</div>
</div>
CSS:
.panel {
grid-area: panel;
border-right: solid 3px black;
background-color: gray;
display: flex;
justify-content: space-between;
overflow: auto;
}
.panelSpacer {
width: 210px;
position: relative;
top: 0;
}
.panelContent {
width: 210px;
position: absolute;
top: 60px;
}
.panel > div {
height: calc(100vh - 60px);
}
.analysis {
position: relative;
width: calc(100% - 210px);
padding: 60px;
height: 100%;
background-color: purple;
/* The problem is here:
if set to "auto", then we have a scrollbar but the red tooltip is not visible
If set to "visible", we get the red tooltip but the scroll is gone
*/
}

Related

Centered element with an `aspect-ratio` take up the maximum available space

I'm trying to make a centered element with an aspect-ratio take up the most available space, can be either vertical or horizontal.
To do this I simply created an outer element with display: grid; place-content: center;, and an inner element with aspect-ratio.
By adding height: 100%; width: 100%; to the inner element I get it to fill the available space on Chrome and Firefox, but this doesn't work in Safari.
Any ideas why this happens?
.outer {
display: grid;
place-content: center;
margin: 3px;
background: green;
}
.horizontal {
width: 100px;
height: 50px;
}
.vertical {
width: 100px;
height: 100px;
}
.inner {
aspect-ratio: 16 / 9;
height: 100%;
width: 100%;
background-color: red;
font-size: 10px;
}
<div class="outer horizontal">
<div class="inner">Horizontal</div>
</div>
<div class="outer vertical">
<div class="inner">Vertical</div>
</div>
Chrome and Firefox
Safari

Why does eliminating scrollbars leave a gap?

There is a mysterious gap at the bottom of the ".one" column.
I gathered that this results from requesting no scroll bars.
Yet somehow the vertical scrollbar disappears entirely, but the horizontal scroll disappears while leaving a gap in its place.
What is this gap and how do I get rid of it?
d3.select('.one')
.selectAll('div')
.data(d3.range(40))
.enter()
.append('div')
.attr('class', 'picture box')
.append('h2')
.text(d => d);
html, body {
width: 100%; height: 100%; margin: 0;
}
.container {
width: 100%; height: 100%;
display: grid;
grid-template-columns: 10%;
}
.box {
background-color: #484848;
color: #fff;
border-radius: 5px;
padding: 1px; margin: 1px;
}
.menu {
text-align: center;
overflow: scroll;
}
.menu::-webkit-scrollbar {
width: 0 !important;
}
.one { grid-column: 1; grid-row: 1; }
.two { grid-column: 2; grid-row: 1; }
div.picture {
box-sizing: content-box;
max-width: 100%;
border: 2px solid gray;
border-radius: 5px;
background-color: #222;
display: flex;
justify-content: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div class="container">
<div class="box one menu noscrollbar">
<h2>One</h2>
</div>
<div class="box two menu noscrollbar">
<h2>Two</h2>
</div>
</div>
It's because when you allow it to scroll, it's leaving a place for the horizontal scrollbar. Tell it to only scroll on the y-axis (up and down) with overflow-y: scroll in the css.
From Mozilla:
Content is clipped if necessary to fit the padding box. Browsers always display scrollbars whether or not any content is actually clipped, preventing scrollbars from appearing or disappearing as content changes. Printers may still print overflowing content.
Full page explainer on overflow: https://developer.mozilla.org/en-US/docs/Web/CSS/overflow
See solution below:
d3.select('.one')
.selectAll('div')
.data(d3.range(40))
.enter()
.append('div')
.attr('class', 'picture box')
.append('h2')
.text(d => d);
html, body {
width: 100%; height: 100%; margin: 0;
}
.container {
width: 100%; height: 100%;
display: grid;
grid-template-columns: 10%;
}
.box {
background-color: #484848;
color: #fff;
border-radius: 5px;
padding: 1px; margin: 1px;
}
.menu {
text-align: center;
overflow-y: scroll;
}
.menu::-webkit-scrollbar {
width: 0 !important;
}
.one { grid-column: 1; grid-row: 1; }
.two { grid-column: 2; grid-row: 1; }
div.picture {
box-sizing: content-box;
max-width: 100%;
border: 2px solid gray;
border-radius: 5px;
background-color: #222;
display: flex;
justify-content: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div class="container">
<div class="box one menu noscrollbar">
<h2>One</h2>
</div>
<div class="box two menu noscrollbar">
<h2>Two</h2>
</div>
</div>
It would help to know which browser you’re seeing this problem in. In Firefox on a Mac with hidden scrollbars there is no gap at the bottom of the .one column.
However, you could try overflow-y: scroll on .menu, instead of overflow as this will only scroll the container along the y-axis. overflow-x is, of course, the companion.

three circles in a line with equal spacing

I have a design which I am trying to replicate in HTML and CSS.
At this moment, I am able to get this in fiddle.
I am wondering how I can make the above three circles in a row with equal spacing in each of them in my fiddle as shown exactly in the design. I tried using,
<span class="circle"></span>
.circle:before {
content: ' \25CF';
font-size: 200px;
}
And,
#circle {
background: #f00;
width: 200px;
height: 200px;
border-radius: 50%;
}
But unfortunately, I was not able to get the same design in my above fiddle.
You can create the circles with css:
.circle {
width: 40px;
height: 40px;
border-radius: 20px;
margin: 0 auto;
}
And set each of them the relevant color:
.circle.purple {
background: purple;
}
.circle.orange {
background: orange;
}
.circle.green {
background: green;
}
Here is the fix based on your jsfiddle:
https://jsfiddle.net/Lh5m11ya/3/embedded/result/
You don't really need to futz with :before. Just set the thing to display: block;
.circle {
display: block;
height: 100px;
width: 100px;
background: red;
border-radius: 100%;
}
https://jsfiddle.net/Lh5m11ya/2/
here is a flex box based approach: https://jsfiddle.net/z2s8zq72/
put a container class with display flex and some config:
.item-container {
display: flex;
flex-direction: column;
align-items: center;
}
This jus defines it as a flex display and the direction sets it to display items top to bottom and then aligns everything in the center.
and the circles like:
.circle {
width: 50px;
height: 50px;
border-radius: 50%;
}
.circle.red {
background: #f00;
}
.circle.green {
background: green;
}
.circle.blue {
background: blue;
}
and in html:
<div id="healthy" class="col-lg-4 item-container">
<div class="circle blue"></div>
<h3>title</h3>
<p>text.</p>
</div>

Absolute positioning inside a div positioned in grid

I am trying out CSS grid layout and currently facing a problem. I would like to use position: absolute for a child of a div positioned in a grid. As you can see below (code snippet) the red box is set with position: absolute and is a child of .left.
How do I make it so that the red box visually stays in the orange div (left side) and doesn't "overflow" in the brown div (right side)?
I have tried setting position: relative to the parent element, without result.
Below is a simplified version showing the problem (you can modify the value to see the separator move)
html,
body,
section {
height: 100%;
margin: 0px;
padding: 0px;
}
.window {
display: grid;
grid-template-areas: "first seperator last";
grid-template-columns: 100px 10px auto;
/* | this one */
}
.left {
background: #ff9e2c;
grid-area: first;
position: relative;
}
.right {
background: #b6701e;
grid-area: last;
}
.separator {
background: white;
}
.abs-pos {
width: 100px;
height: 100px;
background-color: red;
position: absolute;
top: 100px;
left: 75px;
}
<section class="window">
<div class="left">
<div class="abs-pos"></div>
</div>
<div class="separator"></div>
<div class="right"></div>
</section>
The following is a GIF of the problem:
PS: In the actual file I have a JS script that allows me to move the .separator div horizontally to change the sizes of the two divs: .left and .right. It basically modìfies the property grid-template-columns: 100px 10px auto of .window therefore resizing the grid.
Setting overflow: hidden; on the .left pane will keep the red box from showing up outside its parent's bounds.
html,
body,
section {
height: 100%;
margin: 0px;
padding: 0px;
}
.window {
display: grid;
grid-template-areas: "first seperator last";
grid-template-columns: 100px 10px auto;
/* | this one */
}
.left {
background: #ff9e2c;
grid-area: first;
position: relative;
overflow: hidden;
}
.right {
background: #b6701e;
grid-area: last;
}
.separator {
background: white;
}
.abs-pos {
width: 100px;
height: 100px;
background-color: red;
position: absolute;
top: 100px;
left: 75px;
}
<section class="window">
<div class="left">
<div class="abs-pos"></div>
</div>
<div class="separator"></div>
<div class="right"></div>
</section>
Have you tried to give your classes a z-index
z-index: -1;
Z index sets the stack order And works with positioned elements. I.e absolute, relative, fixed.
So if you can give your .right and or .seperator class a position relative it should work.
.right {
position:relative;
z-index: 1;
}
.separator {
position:relative;
z-index: 1;
}
.abs-pos {
position:absolute;
z-index: -1;
}

Divider with centered logo in CSS - strange bug when multiple instances are used

I have trouble coding a 1px horizontal seperator line with a logo displayed in the center as pure CSS. Should look like this:
Divider with logo centered
There is a problem with multiple instances: When I add more dividers on a single page only one or two will be displayed with a line, the others will just display the logo.
A question about a centered logo was answered here - but none adressed the bug that happens with multiple instances: Divider with centred image in CSS?
Here is a adapted solution out of that discussion, fiddle below.
CSS:
body {
margin: 0;
background: white;
}
header:after {
content: '';
display: block;
width: 100%;
height: 1px;
background: #ccc;
margin-top: -90px; /* Negative margin up by half height of logo + half total top and bottom padding around logo */
}
.logo {
position: relative; /* Brings the div above the header:after element */
width: 200px;
height: 100px;
padding: 40px;
margin: 0 auto;
background: white url("http://placehold.it/200x100") no-repeat center center;
}
.logo img {
display: block;
}
HTML:
<body>
<header>
<div class="logo">
</div>
<div class="logo">
</div>
<div class="logo">
</div>
</header>
</body>
The fiddle:
http://jsbin.com/delixecobi/edit?html,css,output
I totally changed the CSS. Give the .logo a position: relative and :after a position: absolute. You are using it for one single header. That's why it didn't work.
body {
margin: 0;
background: white;
}
.logo:after {
content: ' ';
display: block;
width: 100%;
height: 1px;
background: #ccc;
position: absolute;
top: 50%;
margin-top: -1px;
left: -50%;
width: 200%;
}
.logo {
position: relative; /* Brings the div above the header:after element */
width: 200px;
height: 100px;
padding: 40px;
margin: 0 auto;
background: white url("http://placehold.it/200x100") no-repeat center center;
}
.logo img {
display: block;
}
<header>
<div class="logo">
</div>
<div class="logo">
</div>
<div class="logo">
</div>
</header>
Preview
If you want the line not to cross or cut, use a negative z-index.
I found a solution also for my question how to get text centered within the div - thanks to web-tiki for his approach here: Line before and after title over image
In the JSBin I put all together and formatted / commented it a bit to make it easy to work with. You will find:
divider formats with img, text and text in multiple lines
stable in multiple instances
body {
margin: 0;
background: white;
}
.logo:after {
content: ' ';
display: block;
width: 100%;
height: 1px;
background: #ccc;
position: absolute;
top: 50%;
margin-top: -1px;
left: -50%;
width: 200%;
z-index: -1;
}
.logo {
position: relative;
/* Brings the div above the header:after element */
width: 200px;
height: 100px;
padding: 20px;
/* also padding between line and logo */
margin: 0 auto;
background: white url("http://placehold.it/200x100") no-repeat center center;
}
.logo img {
display: block;
}
.logotext {
width: 100%;
margin: 20 auto;
overflow: hidden;
text-align: center;
font-weight: 300;
color: green;
/* color text */
}
.logotext:before,
.logotext:after {
content: "";
display: inline-block;
width: 50%;
margin: 0 20 0 -55%;
/* 2nd no: space text to line on the left */
vertical-align: middle;
border-bottom: 1px solid #ccc;
/* last: color line */
}
.logotext:after {
margin: 0 -55% 0 20;
/* last no: space text to line on the right */
}
span {
display: inline-block;
vertical-align: middle;
}
<header>
<div class="logo">
</div>
<div class="logo">
</div>
<div class="logotext">
somesome</div>
<div class="logotext">
somesome</div>
</header>
One major drawback to this solution is that it does not allow the width of the line to be defined to % of the main viewport.

Resources