Why does eliminating scrollbars leave a gap? - css

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.

Related

An alternative design without a scrollbar caused by padding

The code that appears below creates the following layout:
The important part is that the content, although centered on the screen when not overflowing, never overlaps the navbar and has its own scrollbar:
The problem is that this layout is achieved with the help of padding (marked by a comment in the code below), which results in the additional scrollbar on the right of the screen.
How can I design the same layout that would have only one scrollbar - the one in the content?
Please note that the solution should not break the following details:
The rounded corners and the shadow.
The title in the content block not participating in scrolling.
The image covering the whole scrollable content, so it scrolls together with the content.
In addition, it would be great if this can be achieved without as many nested div's as I have right now.
Edit: I am ready to go with the suggestion of #JHeth in the comments section. However, I would still be interested if someone can come up with an alternative design that does not rely on padding for centering.
Here is the code (CodePen):
* {
padding: 0;
margin: 0;
}
html {
font-size: 62.5%;
}
:root {
--navbar-height: 3rem;
}
.navbar {
width: 100%;
text-align: center;
font-size: 2rem;
line-height: var(--navbar-height);
background-color: lightgreen;
}
.centering {
position: absolute;
inset: var(--navbar-height) 0 0 0;
display: flex;
flex-direction: column;
align-items: center;
& .auto-margin {
margin: auto;
// For scrollable content
display: flex;
max-height: 100%;
padding-bottom: calc(var(--navbar-height)); // Causes scrolling
}
}
.content-block {
display: flex;
flex-direction: column;
.title {
font-size: 2rem;
position: sticky;
}
.content-outer-container {
display: flex;
flex-direction: column;
overflow-y: auto;
border-radius: 1em;
box-shadow: 0 1em 2em rgba(black, 0.4);
.content-container {
width: 300px;
overflow-y: auto;
.content {
position: relative;
padding: 1em;
&:before {
content: "";
z-index: -1;
position: absolute;
top: 0;
left: 0;
right: 0;
height: 100%;
background-position: center;
background-image:
url(http://www.freegreatpicture.com/files/147/18380-hd-color-background-wallpaper.jpg);
}
}
}
}
}
<div class="navbar">An Amazing Navbar</div>
<div class="centering">
<div class="auto-margin">
<div class="content-block">
<div class="title">My Title</div>
<div class="content-outer-container">
<div class="content-container">
<div class="content">
<h1>Line1</h1>
<h1>Line2</h1>
<h1>Line3</h1>
<h1>Line4</h1>
<h1>Line5</h1>
</div>
</div>
</div>
</div>
</div>
</div>
simply remove max-height:100%; to .centering .auto-margin and it'll works!
.centering .auto-margin {
margin: auto;
display: flex;
/* max-height: 100%; */
padding-bottom: calc(var(--navbar-height));
}

button not aligned with image in div

In the following image , the button (Questions) is lower than the image (white rectangle). They both are inside the same div. Why? The page has a top level css-grid with 3 rows.
.grid-container {
display: grid;
grid-template-rows: [nav-row-start]auto [nav-row-end logo-nav-row-start] auto [logo-nav-row-end content-row-start] auto [content-row-end];
}
.nav-style {
height: 5vh;
/*make nav div take 5% of space of viewport*/
background-color: black;
}
.logo-nav-style {
height: 20vh;
/*make logo-nav div take 20% of space of viewport*/
background-color: gray;
}
.nav-flexbox-container {
display: flex;
flex-direction: row-reverse;
}
.content-style {
height: 75vh;
/*make content div take 75% of space of viewport*/
background-color: white;
}
#nav {
grid-row: nav-row-start/nav-row-end;
margin: 0px;
}
#logo-nav {
grid-row: logo-nav-row-start/logo-nav-row-end;
margin: 0px;
}
#content {
grid-row: body-row-start/body-row-end;
margin: 0px;
}
#profile-pic {
margin: 5px;
}
#mail-icon-pic {
margin: 5px;
}
#stats-icon-pic {
margin: 5px;
}
#logo-image {
/*the max width and max height rule will make the image fit inside the div. If the image is bigger than div, the image will
contract, if the image is smaller than the div, the image will expand*/
max-width: 100%;
max-height: 100%;
}
body {
margin: 0px;
}
<div class="grid-container">
<div id="nav" class="nav-style nav-flexbox-container">
<img id="stats-icon-pic" src="stats_icon.png">
<img id="mail-icon-pic" src="mail_icon.png">
</div>
<div id="logo-nav" class="logo-nav-style">
<img id="logo-image" src="example_logo.png"/>
<button type="button">Questions</button>
<!-- this button is lower than the image-->
</div>
<div id="content" class="content-style">body</div>
</div>
I can't answer the "why" part, but one solution is to add display: flex and align-items: flex-end to .logo-nav-style.
Also, I wouldn't lock .content-style to height: 75vh but use min-height: 75vh instead so the content can expand beyond that.
I'm also confused why you got flex-direction: row-reverse; on your .nav-flexbox-container. Why not just put the elements in the correct order to begin with?
.grid-container {
display: grid;
grid-template-rows: [nav-row-start]auto [nav-row-end logo-nav-row-start] auto [logo-nav-row-end content-row-start] auto [content-row-end];
}
.nav-style {
height: 5vh;
/*make nav div take 5% of space of viewport*/
background-color: black;
}
.logo-nav-style {
height: 20vh;
/*make logo-nav div take 20% of space of viewport*/
background-color: gray;
/* Rickard's addition */
display: flex;
align-items: flex-end;
}
.nav-flexbox-container {
display: flex;
flex-direction: row-reverse;
}
.content-style {
min-height: 75vh;
/*make content div take 75% of space of viewport*/
background-color: white;
}
#nav {
grid-row: nav-row-start/nav-row-end;
margin: 0px;
}
#logo-nav {
grid-row: logo-nav-row-start/logo-nav-row-end;
margin: 0px;
}
#content {
grid-row: body-row-start/body-row-end;
margin: 0px;
}
#profile-pic {
margin: 5px;
}
#mail-icon-pic {
margin: 5px;
}
#stats-icon-pic {
margin: 5px;
}
#logo-image {
/*the max width and max height rule will make the image fit inside the div. If the image is bigger than div, the image will
contract, if the image is smaller than the div, the image will expand*/
max-width: 100%;
max-height: 100%;
}
body {
margin: 0px;
}
<div class="grid-container">
<div id="nav" class="nav-style nav-flexbox-container">
<img id="stats-icon-pic" src="stats_icon.png">
<img id="mail-icon-pic" src="mail_icon.png">
</div>
<div id="logo-nav" class="logo-nav-style">
<img id="logo-image" src="example_logo.png"/>
<button type="button">Questions</button>
<!-- this button is lower than the image-->
</div>
<div id="content" class="content-style">body</div>
</div>

CSS: flex-grow maintain vertical aspect ratio

I am creating a website with a circular menu. The website content should fit all onto the homepage without the need to scroll. The menu needs to fill the remaining space on the homepage. However, I am unsure how to maintain the shape of the circle while filling the remaining space on the homepage using flex-grow: 1. Is there a way I can do this with pure CSS? Setting the menu to a set viewport size is not acceptable, it needs to fill the remaining space. I am not having luck using the traditional padding-top: 100% to maintain aspect ratio. The circle is not quite circular and it takes up twice the remaining space.
body {
height: 100vh;
display: flex;
flex-direction: column;
margin: 0;
}
#title {
font-size: 30px;
}
#circle {
background: black;
border-radius: 50%;
flex-grow: 1;
padding-top: 100%;
}
#footer {
background: black;
color: white;
}
<body>
<div id="title">Title</div>
<div>navigation</div>
<div id="circle"></div>
<div id="footer">Footer</div>
</body>
Edit
I have figured out a way to maintain the aspect ratio of the circle filling the remaining space with flex grow. However, it is what I would consider a hack so I am leaving this question open.
body {
height: 100vh;
display: flex;
flex-direction: column;
margin: 0;
}
#title {
font-size: 30px;
}
#circle {
background: black;
border-radius: 50%;
flex-grow: 1;
/*width: max-content;*/
padding: 0%;
align-self: center;
}
#circle img {
height: 100%;
width: auto;
justify-content: center;
}
#footer {
background: black;
color: white;
}
<body>
<div id="title">Title</div>
<div>navigation</div>
<div id="circle"><img src="https://luxury.zappos.com/search/imgs/blank.20190219170746.png"></div>
<div id="footer">Footer</div>
</body>
Edit 2
It seems I was mislead by caniuse.com. This solution does not seem to work in most browsers besides chrome. Is there another solution?
Put the circle div inside a wrapper div in your HTML:
<div id="circle-wrap">
<div id="circle"></div>
</div>
Then move the flex rule to the wrapper:
#circle-wrap {
flex-grow: 1;
}
body {
height: 100vh;
display: flex;
flex-direction: column;
margin: 0;
}
#title {
font-size: 30px;
}
#circle-wrap {
flex-grow: 1;
}
#circle {
background: black;
border-radius: 50%;
padding-top: 100%;
}
#footer {
background: black;
color: white;
}
<body>
<div id="title">Title</div>
<div>navigation</div>
<div id="circle-wrap">
<div id="circle"></div>
</div>
<div id="footer">Footer</div>
</body>

CSS: Grid, Scrollbars and Tooltip issue

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
*/
}

Flex css layout with fixed and variable elements

I am hoping to create the following layout in pure CSS. I know that I can achieve this with a JavaScript solution, but a CSS solution would be much cleaner, if it is possible.
I have created a jsFiddle which I know is incorrect, to provide a starting point. The HTML and CSS I use in the jsFiddle are shown below.
Notes:
I would like this to fill the full height of the window, so that there is no scroll bar for the page (but see my last point)
There are two sections that can contain a variable number of elements.
The red elements are images which the user can add on the fly, and which will be given a frame with a fixed aspect ratio (shown here as a square)
The green section will contain a list which will have at least one item, so it will have a fixed minimum height. It may have up to four items, so its height may change. I would prefer not to have this section scroll. If the user makes the window too short for both the green and the blue elements to show full height, then the page as a whole will have to scroll.
My question is: can this be done in pure CSS? If you know that there is a solution, and if you can provide some pointers as to how I can achieve it, then I can continue to work towards that solution. If you know that there is no solution, then I will simply adopt a JavaScript approach.
If there is a solution, and you would be happy to share it, then I will be delighted that you have saved me a lot of time.
<!DOCTYPE html>
<html>
<head>
<title>Flex</title>
<style>
body, html {
height: 100%;
margin: 0;
background: #000;
}
main {
width: 30em;
height: 100%;
margin: 0 auto;
background: #333;
display: flex;
-webkit-flex-direction: column;
flex-direction: column;
}
.head{
width:100%;
-webkit-flex: 3em;
flex: 3em;
background: #fcc;
}
.expand{
width:100%;
overflow:auto;
}
.filler {
width:100%;
height:20em;
background: #003;
border-bottom: 1px solid #fff;
}
.space {
width:100%;
height:10em;
border-bottom: 1px solid #fff;
}
.foot{
width:100%;
-webkit-flex: 0 0 2em;
flex: 0 0 2em;
background: #cfc;
}
</style>
</head>
<body>
<main>
<div class="head">HEAD</div>
<div class="expand">
<div class="space"></div>
<div class="filler"></div>
<div class="space"></div>
</div>
<div class="foot">FOOT</div>
</main>
</body>
</html>
If I understand it well,
main {
height: auto;
min-height: 100%;
}
.head {
min-height: 3em;
}
.foot {
min-height: 2em;
}
.expand {
flex-basis: 0; /* Initial height */
flex-grow: 1; /* Grow as much as possible */
overflow: auto;
}
body,
html {
height: 100%;
margin: 0;
background: #000;
}
main {
width: 20em;
min-height: 100%;
margin: 0 auto;
background: #333;
display: flex;
-webkit-flex-direction: column;
flex-direction: column;
}
.head {
width: 100%;
min-height: 3em;
background: #fcc;
}
.expand {
width: 100%;
flex-basis: 0;
flex-grow: 1;
overflow: auto;
}
.filler {
width: 100%;
height: 20em;
background: #003;
border-bottom: 1px solid #fff;
}
.space {
width: 100%;
height: 2em;
border-bottom: 1px solid #fff;
}
.foot {
width: 100%;
min-height: 2em;
background: #cfc;
}
<main>
<div class="head">HEAD</div>
<div class="expand">
<div class="space"></div>
<div class="filler"></div>
<div class="space"></div>
</div>
<div class="foot">FOOT</div>
</main>

Resources