position: fixed prevents elements to be centered properly - html

I want to center .donut-graphs inside .dashboard horizontally, so the space between the right edge of the sidebar and the left edge of .donut-graphs is the same as the space from the right edge of .donut-graphs and the right edge of the screen. I have managed to do so, but I had to remove position: fixed from .navbar. The problem is, I can't do that because my sidebar has to stay on top of the screen when you scroll up/down, and with position: fixed on .navbar, the graphs aren't centered properly.
HTML:
<div class="container">
<div class="navbar">
</div>
<div class="content">
<div class="dashboard">
<div class="donut-graphs">
<div class="dashboard-income">
Div 1
</div>
<div class="dashboard-overall">
Div 2
</div>
<div class="dashboard-spent">
Div 3
</div>
</div>
</div>
</div>
</div>
CSS:
body {
margin: 0;
}
.container {
display: flex;
align-items: stretch;
max-width: 100%;
min-height: 100vh;
}
.navbar {
background-color: #ddd;
flex: 0 0 230px;
position: fixed;
height: 100vh;
width: 230px;
}
.content {
flex: 1;
overflow-x: auto;
text-align: center;
}
.donut-graphs {
display: inline-flex;
border: 1px solid;
margin: 50px auto 0;
position: relative;
text-align: left;
}
.dashboard-income,
.dashboard-overall,
.dashboard-spent {
height: 256px;
width: 357px;
display: inline-block;
}
.dashboard-income {
background-color: green;
}
.dashboard-overall {
background-color: blue;
}
.dashboard-spent {
background-color: red;
}
How can I overcome the issue?
Demo

position: fixed puts element above everything. That element won't attach to any element in body because it is the way that works. It only becomes dependent of viewport
What you want to achive could be done with position: absolute but parent (whose child you want to center) has to be position: relative for this to work.
Read more about positioning elements in css here

.content { padding-left:230px; }
Should do the trick.
Assigning your navbar a fixed position takes it out of the document flow, so when centering your donut graphs the browser doesn't take the navbar into account.
Giving the .content element a padding equivalent to the width of the navbar makes up for this.
The only problem with this approach is that if .navbar changes dimensions, you'll need to change the padding on .content to match.

Related

Issue with position sticky & bottom with different height flex children

I have a flex container with two children of different height.
The left item is shorter which I'm trying to make stick to the bottom while scrolling until the full container has been scrolled so they both align. Can't seem to get this to work. No parent overflows affecting this.
The desired behaviour is for the viewer(left) element to align at the top, scroll until it reaches the bottom, stick there until the full container (and side rail) has scrolled
Sandbox Here
.wrapper {
padding: 2rem;
background: lightgrey;
}
.container {
margin-inline: max(0px, ((100% - 1440px) / 2));
display: flex;
height: 2220px;
gap: 1rem;
> * {
border: 1px solid;
}
}
.viewer {
height: 1400px;
flex-grow: 3;
position: -webkit-sticky;
position: sticky;
bottom: 0;
background: white;
}
.side-rail {
height: 2190px;
flex-grow: 1;
background: white;
}
html,
body {
margin: 0;
}
<div class="wrapper">
<div class="container">
<div class="viewer">Viewer</div>
<div class="side-rail">Side rail</div>
</div>
</div>
Does making the the 'viewer' div
align-self: flex-end;
instead of flex-start do what you require ?
Seems like you have to make both the .viewer and the .side-rail of same height and overflow: auto the content within the side-rail

Vertically center element without it becoming inaccessible offscreen

I'm trying to center an element in the middle of the page. I can center it just fine, but if I resize the page vertically until the view height is smaller than the centered element, the element goes offscreen vertically without a scrollbar. You can see a demonstration of the issue here:
http://codepen.io/mse/pen/BWayXV
* {
padding: 0;
margin: 0;
}
html, body {
height: 100%;
}
.outer {
text-align: center;
position: relative;
top: 50%;
transform: translateY(-50%);
}
.inner {
display: inline-block;
width: 400px;
height: 800px;
background: grey;
}
<div class="outer">
<div class="inner"></div>
</div>
I should mention that I have tried a couple of other methods of vertical centering, including flexbox, and I'm still running into the same issue. Is there a way to solve this problem with this method of vertical centering, or is there at least a vertical centering method that does not have this issue?
Try this
* {
padding: 0;
margin: 0;
}
html, body {
height: 100%;
}
.outer {
display:flex;
justify-content:center;
align-items:center;
}
.inner {
background: #ccc;
width: 400px;
height: 600px
}
<div class="outer">
<div class="inner"> I'm a block-level element centered vertically within my parent.</div>
</div>
More info: https://css-tricks.com/centering-css-complete-guide/
CSS VH center generator: http://howtocenterincss.com/
This should work
* {
padding: 0;
margin: 0;
}
html, body {
height: 100vh;
}
.outer {
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.inner {
width: 400px;
height: 800px;
background: grey;
}
<div class="outer">
<div class="inner"></div>
</div>
You can try to limit the size of your inner element. If you define size by a fixed px amount it will start scrolling as soon as the screen becomes smaller than that px amount. If you are ok with changing the height of the inner element you could use vh or you can implement #media queries to decrease the size on smaller screens. Here#s an example:
.inner { height: 100vh; /* 100 view height percentage*/}
Note: The viewport-percentage lengths are relative to the size of the initial containing block and affected by the presence of scrollbars on the viewport.

shrink middle div horizontally on browser resize

I have a 3 column layout which I'm creating using inline-block divs. The left and right columns are fixed widths but the inner column is to hold dynamic content and should expand horizontally as required by it's content width.
That's easy enough... the tricky part is that when the browser window is smaller (horizontally) than the width of the left, right and expanded middle divs, I would like the middle div to scroll and the side columns to stay fixed. In other words, the middle div's size should shrink and grow with window resize but should not grow beyond the available space.
Simply laying out the divs looks like this
https://jsfiddle.net/xzjp5xef/1/
HTML:
<div id="container">
<div id="lcol">
left
</div>
<div id="midcol">
<div id="spacer">
150px spacer
</div>
</div>
<div id="rightcol">
right
</div>
</div>
CSS:
div {
height:200px;
border-style:solid;
display: inline-block;
border-width: 1px;
vertical-align: top;
}
#container{
white-space: nowrap;
}
#lcol {
background-color:blue;
width: 100px;
}
#midcol {
background-color: yellow;
overflow-x: auto;
}
#spacer {
min-width: 150px;
margin: 10px;
height: 20px;
}
#rightcol {
background-color: red;
width:100px;
}
The point of the "spacer" div is to represent the dynamic content which in this case I've fixed to 150px plus padding. So in this case I want the divs to lay out the way they do in the above fiddle, but then when the window is shrunk horizontally, I want the middle div to scroll and the left and right divs to remain fully visible.
That fails because then the window gets a scroll bar but the middle panel remains the same width and the right hand div disappears into the scrolled region.
My next attempt was using absolute positioning
https://jsfiddle.net/n4zrLqh2/
I fixed the left div to the left and the right div to the right and set the middle div's right and left properties. This is a neat trick which allows the middle div to stretch and take up all available space. This works nicely but doesn't create the effect I'm after when the window is big - because I don't want the middle column to expand further than is necessary to contain its content.
In the end I've solved this with javascript but would much prefer a CSS solution.
Edit: To help others see what I'm trying to achieve, here's the complete javascript solution (which I'd prefer to achieve with pure CSS):
HTML:
<div id="lcol">left</div>
<div id="midcol">
<div id="spacer">150px spacer</div>
</div>
<div id="rightcol">right</div>
CSS:
div {
height:200px;
display: inline-block;
vertical-align: top;
margin: 0px;
float:left;
}
body {
white-space: nowrap;
margin:0px;
max-height: 200px;
}
#lcol {
background-color:blue;
width: 100px;
}
#midcol {
background-color: yellow;
overflow-x: auto;
}
#spacer {
min-width: 150px;
height: 20px;
background-color: gray;
margin: 5px;
}
#rightcol {
background-color: red;
width:100px;
}
JAVASCRIPT (with jquery)
function adjustSizes() {
// Sizes of middle divs are dynamic. Adjust once
// built or whenever the viewport resizes
//
var $leftDiv = $('#lcol')
var $milddleDiv = $('#midcol');
var $rightDiv = $('#rightcol');
// 1. Resize middle div to available viewport space
var maxBodyWidth = $(window).innerWidth() - ($leftDiv.outerWidth() + $rightDiv.outerWidth());
$milddleDiv.css('maxWidth', maxBodyWidth);
}
$(window).resize(function () {
adjustSizes();
});
And the fiddle: https://jsfiddle.net/bjmekkgj/2/
I think setting max-width of spacer will solve your problem in case content increases.
Set max-width to calc(100vw - 200px) if all margin and padding are 0. Otherwise adjust the value 200px taking margin, padding into account.
I have created a plunker. Please check if it solves your issue. Try checking after running plunker in spearate window
http://plnkr.co/edit/WG9v0MyiD2hiaZrOA3Yw?p=preview
For the one example you provided, since the left and right columns are positioned absolutely, you should take up the space somehow. I used padding on the middle column, then nested a "content" block inside that represents the visible part of the middle column. Then, I put overflow-x: auto; on the new content block and set a max-width on the overall container to force the new block to shrink.
(In previous edits, I was attempting to do this same thing but with floats instead of absolutely positioned divs)
* { margin: 0px; padding: 0px; }
#container {
box-sizing: border-box;
display: inline-block;
position: relative;
max-width: 100%;
border: 1px solid black;
height: 200px;
}
.column {
box-sizing: border-box;
height: 100%;
}
#left {
position: absolute;
left: 0px;
top: 0px;
bottom: 0px;
width: 100px;
border-right: 1px solid black;
background: blue;
}
#mid {
border: none;
padding: 0px 100px;
}
#mid > .content {
box-sizing: border-box;
background-color: yellow;
overflow-x: auto;
height: 100%;
}
#spacer {
width: 150px;
height: 20px;
}
#right {
position: absolute;
right: 0px;
top: 0px;
bottom: 0px;
width: 100px;
border-left: 1px solid black;
background: red;
}
<div id="container">
<div id="left" class="column">
left
</div>
<div id="mid" class="column">
<div class="content">
<div id="spacer">
150px spacer
</div>
</div>
</div>
<div id="right" class="column">
right
</div>
</div>
...and in JSFiddle form
flexbox can do that.
div {
border-style: solid;
border-width: 1px;
}
#container {
height: 200px;
display: flex;
}
#lcol {
background-color: blue;
width: 100px;
}
#midcol {
background-color: yellow;
flex: 1;
overflow-x: auto;
}
#rightcol {
background-color: red;
width: 100px;
}
<div id="container">
<div id="lcol">
left
</div>
<div id="midcol">
</div>
<div id="rightcol">
right
</div>
</div>
JSfiddle Demo (showing overflow effect).
Support is IE10 and up.
Try setting the middle div to have a max width with a percentage so it will get thinner with the screen size:
.midcol {
max-width: 25%;
}
I put a value for the max-width in there for an example, but you can change the value.

Flex Layout with fixed position (no scrolling) sidebar

I have a layout with left and right canvas sidebars, enclosing the Main content area in the middle.
The sidebars and main content are flex items, positioned in a flex layout left to right.
The sidebars contain menus and meta links.
My question is: when scrolling the content area, is it possible to leave the sidebars in fixed position, such that they stay in top position and do not scroll down?
JS Fiddle: http://jsfiddle.net/Windwalker/gfozfpa6/2/
HTML:
<div class="flexcontainer">
<div class="flexitem" id="canvas-left">
<p>This content should not scroll</p>
</div>
<div class="flexitem" id="content">
<div>
<p>Scrolling Content</p>
</div>
</div>
<div class="flexitem" id="canvas-right">
<p>This content should not scroll</p>
</div>
</div>
CSS:
.flexcontainer {
display: flex;
flex-direction: row;
min-height: 100%;
align-items: stretch;
}
.flexitem {
display: flex;
}
#canvas-left {
background: yellow;
order: -1;
flex: 0 0 57px;
}
#content {
background: green;
order: 1;
padding: 1rem;
}
#content div {
display: block;
}
#canvas-right{
background: blue;
order: 2;
flex: 0 0 57px;
}
Please look at the similar question with provided solution: How to simulate 'position:fixed' behavior on Flexbox-aligned sidebar.
According to your code you can also wrap your inner content in "position: fixed" wrapper:
<div class="flexitem" id="canvas-left">
<div class="fixed">
<p>This content should not scroll</p>
</div>
</div>
And add proper styling in CSS:
.fixed {
position: fixed;
width: 57px; /* according to #canvas-left */
}
Here is an example of your code with fixed left sidebar: http://jsfiddle.net/8hm3849m/. Note that this trick won't provide you proper flexible grid for sidebars, width of the wrapper should be fixed (or set dynamically via JavaScript).
The question is old, but I solved a similar issue using
position: sticky;
top: 0;
for the left and right items.
Also I removed the
display: flex
css for the flex items, I don't think that's necessary.
https://jsfiddle.net/8mpxev0u/
i dont know how do it with flex, but here is a easyer/alternate css remove all that flex... and try to never add padding to a outer div, its easyer in inner items, then you dont need to calculate if there are to many divs
.flexcontainer {
display: block;
min-height: 100%;
align-items: stretch;
}
.flexitem {
display: flex;
}
#canvas-left {
background: yellow;
order: -1;
left: 0px;
width: 20%;
position: fixed;
}
#content {
position: absolute;
background: green;
order: 1;
width: 60%;
left: 20%;
}
#content p {
display: block;
padding: 1rem;
}
#canvas-right{
background: blue;
order: 2;
right: 0px;
width: 20%;
position: fixed;
}

How to change the width of a CSS flex-box column?

I have a menu div that fills 100% of its container height, and beside it, to the right, are the header, body and footer sections.
I managed to do this with the CSS flex property. However, I want to change the amount of width the "menu" div takes out of the container, as in, making it 10% width of container's width, and make the rest divs fill what's left (even if the "menu" div is hidden at a later time).
JS Fiddle of what I have right now: https://jsfiddle.net/jf29vr0x/3/
.container {
display: flex;
flex-flow: column wrap;
width: 75%;
height: 500px;
position: relative;
margin: 0 auto;
}
.menu {
flex: 0 0 100%;
background: lightblue;
}
.header {
flex: 0 0 10%;
background: lightgray;
}
.body {
flex: 0 0 80%;
background: purple;
}
.footer {
flex: 0 0 10%;
background: lightgreen;
}
<div class="container">
<div class="menu">
Menu
</div>
<div class="header">
Header
</div>
<div class="body">
Body
</div>
<div class="footer">
Footer
</div>
</div>
I found that if I set the width explicitly on the "menu" class, it resizes it, but the rest of the boxes don't fill the space left, unless I also explicitly state their width to 100%. However, doing this, makes the container overflow, and because the container is aligned to the center, it looks off.
I could also set the width to 90% (on header, footer body) and 10% on the menu, but the menu is sometimes set to display: none;, so when it disappears, the other layout parts are only going to be 90% of container's width.
Is there any way of doing this with only flex-box properties? I don't understand very well what flex-shrink and flex-grow are about, but I think they only affect (in this case) the height?
Thank you.
You have to add a wrapper around the right column, and then only specify flex-basis on the .menu element.
.container {
display: flex;
width: 75%;
height: 500px;
position: relative;
margin: 0 auto;
height: 500px;
overflow: hidden;
}
.right-col {
flex-flow: column wrap;
flex-grow: 1;
height: 100%;
display: flex;
}
.menu {
flex-basis: 10%;
background: lightblue;
}
.header {
flex: 0 0 10%;
background: lightgray;
}
.body {
flex: 0 0 80%;
background: purple;
}
.footer {
flex: 0 0 10%;
background: lightgreen;
}
<div class="container">
<div class="menu">Menu</div>
<div class="right-col">
<div class="header">Header</div>
<div class="body">Body</div>
<div class="footer">Footer</div>
</div>
</div>
Fiddle: https://jsfiddle.net/jf29vr0x/11/
Now when the menu is hidden, the right column expands the full amount.