Horizontally centering two stacked divs, when one has a vertical scrollbar - html

Centering elements horizontally is easy using margin: 0 auto;
However, it doesn't work if there are two elements stacked in a column and one has a scrollbar and the other does not. In that case, the two horizontal centered elements aren't aligned anymore.
Question: Is there any way to align the two elements without using Javascript to adjust the margin of the first one?
JSFIDDLE DEMO
<head>
<style>
body {
margin: 0; height: 100vh;
}
.header {
height: 50px; background: red;
}
.content {
overflow-y: scroll; background: blue;
}
.inner {
background: rgba(255,255,255,.5); max-width: 300px;
margin: 0 auto; min-height: 50px;
}
.content > .inner {
min-height: 300px;
}
</style>
</head>
<body>
<div class="header">
<div class="inner"></div>
</div>
<div class="content">
<div class="inner"></div>
</div>
</body>

The main problem is obviously the centering. So why not circumvent it and use margin-left?
Try this CSS:
.inner { margin-left: calc(50vw - 150px); } /* half viewport width less half element width
(for precise centering) */
body {
margin: 0;
height: 100vh;
}
.header {
height: 50px;
background: red;
}
.content {
background: blue;
overflow-y: scroll;
}
.inner {
background: rgba(255,255,255,.5);
max-width: 300px;
/* margin: 0 auto; <-- remove */
margin-left: calc(50vw - 150px); /* new */
min-height: 50px;
}
.content > .inner {
min-height: 300px;
}
<div class="header">
<div class="inner"></div>
</div>
<div class="content">
<div class="inner"></div>
</div>
Revised Fiddle

Answer from Wes in chat:
This can be solved by adding a scrollbar to the first one, but hiding it from the user.
.header {
height: 50px;
background: red;
overflow-y: scroll;
width: 120%;
margin-left: -10%;
}
JSFIDDLE DEMO
If you're concerned a user could have a scrollbar wider than 10%, increase it width: 300% and margin-left: -100%. If somebody has a scrollbar as wide as the page, he / she can't use the page anyway.

Related

HTML -> Fixed top, Flexible bottom with min-height and dynamic squared content

I'm really struggling to create css layout like this:
Top row: fixed size: Ex: 50px;
Content: the biggest square the current width can fit. So width = height for this one. It should respect the bottom row min-height.
Bottom row: take all remaining space available, and with min-height. Ex: 50px.
No scrollbar. The idea is to use the current screen the best way possible for any resolution. No javascript unless it's only possible with js.
Any ideas?
That's the best I've got so far:
<div class="shell">
<div class="header"></div>
<div class="square"></div>
<div class="footer"></div>
</div>
css
body {
margin: 0px;
}
.shell {
background-color: #000000;
height: 100vh;
max-width: calc(100vh - 100px);
overflow: hidden;
margin-left: auto;
margin-right: auto;
}
.header {
background-color: #0000ff;
height: 50px;
}
.square {
width: 100%;
background-color: #dc143c;
}
.footer {
background-color: #00008b;
height: 100vh;
}
You can use padding to get the aspect ratio:
body {
margin: 0px;
}
.shell {
background-color: #000000;
height: 100vh;
max-width: calc(100vh - 100px);
overflow: hidden;
margin-left: auto;
margin-right: auto;
}
.header {
background-color: blue;
height: 50px;
}
.square {
width: 100%;
padding-top: 100%;
background-color: green;
}
.footer {
background-color: red;
height: 100%;
}
<div class="shell">
<div class="header"></div>
<div class="square"></div>
<div class="footer"></div>
</div>
Reference here
I think your question was already solved here:
Make a div fill the height of the remaining screen space
Mixed with your try:
body {
margin: 0;
}
.box {
display: flex;
flex-flow: column;
background-color: #000000;
height: 100vh;
max-width: calc(100vh - 100px);
overflow: hidden;
margin-left: auto;
margin-right: auto;
}
.box .row.header {
flex: 0 1 50px;
background-color: #0000ff;
}
.box .row.content {
flex: 1 1 auto;
width: 100%;
background-color: #dc143c;
}
.box .row.footer {
flex: 0 1 40px;
background-color: #00008b;
}
<div class="box">
<div class="row header">
</div>
<div class="row content">
</div>
<div class="row footer">
</div>
</div>
Fiddle: https://jsfiddle.net/901s2kdL/
Content: the biggest square the current width can fit. So width =
height for this one. It should respect the bottom row min-height.
If you want the biggest square, the footer height will be fixed and it will be equal to min-height always (and it should be), so it doesn't matter if you will set it's height to 100% or 50px. max-width of square determining really sizes. If you look at this max-width: calc(100vh - 100px), the - 100px part is the real remaining space including header and footer, so if the header height is set to 50px, the footer height is also 50px.
body {
margin: 0px;
}
.shell {
background-color: black;
}
.header {
height: 50px;
background-color: red;
}
.square {
max-width: calc(100vh - 100px);
margin: 0 auto;
background-color: green;
}
.square:after {
content: "";
display: block;
padding-bottom: 100%;
}
.footer {
height: 50px;
background-color: blue;
}
<div class="shell">
<div class="header"></div>
<div class="square"></div>
<div class="footer"></div>
</div>

Fixed position sidebar within a flex container

I have a layout which uses flexbox to position a main content section and a sidebar element beside each other, with justify-content: space-between for consistent spacing within a container, however I need the sidebar on the right to also scroll down the page with the user by using position: fixed, whilst also remaining pinned to the right edge of the container.
Example pen: https://codepen.io/StyleMeLikeOneOfYourFrenchGirls/pen/BazQOLj
.container {
width: 1000px;
margin: auto;
border: 1px solid black;
}
.content {
display: flex;
justify-content: space-between;
}
.left-content {
height: 1000px;
width: 70%;
background-color: red;
}
.right-sidebar {
height: 200px;
width: 20%;
background-color: yellow;
/*position: fixed;*/
}
<div class="container">
<div class="content">
<div class="left-content">
left content
</div>
<div class="right-sidebar">
right sidebar
</div>
</div>
</div>
I understand that fixed removes the element from document flow, and thus eliminates the simplicity of the flex layout and the ability to 'contain' something within it's parent element.
I've been able to achieve something close to what I want, but it requires specific values for different viewport widths (e.g. using Bootstrap's offset classes, transform: translateX() or various combinations of margins). These methods are messy though, and don't provide a consistent solution to keeping the sidebar aligned with the edge of the parent container.
Is there a simpler/more elegant solution to this problem?
You can use position: sticky;. It respects the flex and has a fixed purpose.
DEMO:
.container {
width: 1000px;
margin: auto;
border: 1px solid black;
}
.content {
display: flex;
justify-content: space-between;
}
.left-content {
height: 1000px;
width: 70%;
background-color: red;
}
.right-sidebar {
height: 200px;
width: 20%;
background-color: yellow;
position: -webkit-sticky;
position: sticky;
top: 0;
}
<div class="container">
<div class="content">
<div class="left-content">
left content
</div>
<div class="right-sidebar">
right sidebar
</div>
</div>
</div>
Please have a look...
body {
margin: 0;
}
.container {
width: 1000px;
display: block;
margin: 0 auto;
}
.content {
background: #999;
height: 100vh;
overflow: auto;
display: flex;
}
.leftContent {
display: flex;
width: calc( 100% - 300px );
}
.rightSidebar {
position: absolute;
right: calc(50% - 500px);
background: #666;
height: 100vh;
width: 300px;
overflow: auto;
}
<div class="container">
<div class="content">
<div class="leftContent">
a a a a a a a a a a a a a a a a a. a a a a. a a a a a a a a. a a a a a a a aa. a a a a a a a a a a a a a a a a a a a. a a a a. a a a a a a a a. a a a a a a a aa. a aa<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>
</div>
<div class="rightSidebar">
b<br>b<br>b<br>b<br>b<br>b<br>b<br>b<br>b<br>b<br>b<br>b<br>b<br>b<br>b<br>b<br>b<br>b<br>b<br>b<br>b<br>b<br>b<br>b<br>b<br>b<br>b<br>b<br>b<br>b<br>b<br>b<br>b<br>b<br>b<br>b<br>b<br>
</div>
</div>
</div>
Here is a try with minimum impact on your code.
The setup you have limits a bit the options you have, but I think below Pen would be a nice workaround.
.left-content {
height: 1000px;
width: 100%;
max-width: 70%;
background-color: red;
}
.right-sidebar {
height: 200px;
width: 100%;
max-width: 15%;
background-color: yellow;
position: fixed;
right: 20%;
}
CodePen
Sidebar on the right hand side scrolls down the page with the user by using position: fixed, whilst also remaining pinned to the right edge of the container.

How to eliminate the space under the content? [duplicate]

This question already has an answer here:
Margin collapsing with floated element, why there is an extra margin added?
(1 answer)
Closed 3 years ago.
I would like to create a conainer element, which is at least the height of the page. I set it like this: min-height: 100vh
The body has no margin.
For some reason, an empty space appears under the element. How is it possible to eliminate that?
I can observe this error in Chrome and Edge, but not in Firefox.
My code:
body {
margin: 0;
background: red;
}
.container {
margin: auto;
max-width: 200px;
background: gray;
min-height: 100vh;
box-sizing: border-box;
}
.item {
background: white;
margin-bottom: 1em;
height: 100px;
}
<div class="container">
<div class="item">...</div>
<div class="item">...</div>
<div class="item">...</div>
</div>
This is how it looks like:
You can get it to work by removing the margin of the last .item element.
body {
margin: 0;
background: red;
}
.container {
margin: auto;
max-width: 200px;
background: gray;
min-height: 100vh;
box-sizing: border-box;
}
.item {
background: white;
margin-bottom: 1em;
height: 100px;
}
.item:last-child {
margin:0;
}
<div class="container">
<div class="item">...</div>
<div class="item">...</div>
<div class="item">...</div>
</div>
The issue is caused by the .container margin to center with auto and the .item children having a bottom margin. For some reason the causing a lack of collapse which is, in turn, causing the margin to overflow (or append to) it's owner, even if margin-bottom: 0 is applied to .container.
To resolve this, we have come up with a different way, by not using margin: auto;, of centering the .container.
As well as, to force a collapse by setting a height relationship between culprit of the overflow and it's parent. We will accomplish this by setting height: 100%; to html, body.
I will propose three solutions which solve the display discrepancy.
Option 1
Edit: This solution does not seem to be consistent to me in Edge upon further testing. Sometimes I have to open DevTools and toggle min-height: 100vh; in .container to get it to render correctly.
html, body {
height: 100%;
}
.container {
/* Remove the margin */
/* margin: auto; */
position: relative;
left: 50%;
transform: translateX(-50%);
This fixes the issue in Edge and Chrome. To answer the question, this is the only edit required.
jsFiddle
html,
body {
height: 100%;
}
body {
margin: 0;
background: red;
}
.container {
position: relative;
left: 50%;
transform: translateX(-50%);
min-height: 100vh;
max-width: 200px;
background: grey;
}
.item {
position: relative;
margin-bottom: 1em;
height: 100px;
background: white;
}
<div class="container">
<div class="item">...</div>
<div class="item">...</div>
<div class="item">...</div>
</div>
Option 2
This method is a slight modification to how the .item margin is applied where we will apply to all .item's except the last one using :not(last-child).
jsFiddle
html, body {
height: 100%;
}
body {
margin: 0;
background: red;
}
.container {
margin: auto;
min-height: 100vh;
max-width: 200px;
background: grey;
}
.item {
position: relative;
height: 100px;
background: white;
}
.item:not(:last-child) {
margin-bottom: 1em;
}
<div class="container">
<div class="item">...</div>
<div class="item">...</div>
<div class="item">...</div>
</div>
Option 3
If you're familiar with Flexbox, you could solve it that way with the following edits to your CSS:
body {
margin: 0;
background: red;
display: flex;
flex-direction: column;
justify-content: center;
}
.container {
/* Without a min height set the width
/* will default to the content's width */
/* max-width: 200px; */
width: 200px;
margin: auto;
background: gray;
min-height: 100vh;
box-sizing: border-box;
}
.item {
position: relative;
margin-bottom: 1em;
height: 100px;
background: white;
}
<body>
<div class="container">
<div class="item">...</div>
<div class="item">...</div>
<div class="item">...</div>
</div>
</body>
Here, we set body as flexbox, set as column direction, and center the content (direct children).
Importantly, we have to set a minimum width so that if our content is less than 200px it won't get squished.
You can just set height: 100% on the container for it to be the height of the page at all times.
The below modified code should help you. Set margin: 0 in the html and body elements
html, body { /* or use * to apply this margin reset to all elements */
margin :0;
}
body{
background: red;
}
.container {
margin: auto;
max-width: 200px;
background: gray;
height:100vh;
box-sizing: border-box;
}
.item {
background: white;
margin-bottom: 1em;
height: 100px;
}
<div class="container">
<div class="item">...</div>
<div class="item">...</div>
<div class="item">...</div>
</div>
You might try to add some padding to your .item

Make an element overlap others when viewport runs out of room

I have the blue square that will contain things adding up to 800px.
I want the red square to always be fully visible. That is when you narrow the viewport, the red square should overlap the blue square, and not disappear on the right like it does actually.
How can I achieve that?
.container {
display: flex;
}
div {
height: 80px;
}
.should-be-overlapped {
width: 100%;
min-width: 800px;
background: blue;
}
.always-full-width {
width: 400px;
background: red;
}
<div class="container">
<div class="should-be-overlapped"></div>
<div class="always-full-width"></div>
</div>
To accomplish that, there is mainly 2 ways.
Either add a wrapper around the blue (which I recommend).
Updated codepen
Stack snippet
.container {
position: relative;
display: flex;
}
div {
height: 80px;
}
.wrapper {
flex: 1;
overflow: hidden;
}
.should-be-overlapped {
width: 100%;
min-width: 800px;
background: blue;
}
.always-full-width {
flex: 0 0 400px;
background: red;
}
<div class="container">
<div class="wrapper">
<div class="should-be-overlapped">
</div>
</div>
<div class="always-full-width">
</div>
</div>
Or use position: absolute.
Updated codepen
.container {
display: flex;
position: relative;
overflow: hidden;
}
div {
height: 80px;
}
.should-be-overlapped {
width: 100%;
min-width: 800px;
background: blue;
}
.always-full-width {
position: absolute;
right: 0;
width: 400px;
background: red;
}
.<div class="container">
<div class="should-be-overlapped">
</div>
<div class="always-full-width">
</div>
</div>
I have the blue square that will contain things adding up to 800px.
Then you should do it with the flex: 0 1 800px, which will enable it to shrink:
.container {
display: flex;
}
div {
height: 80px;
}
.should-be-overlapped {
/*min-width: 800px;*/
flex: 0 1 800px; /* doesn't grow but shrinks, initial width set to 800px (this is also its "max-width") */
background: blue;
word-break: break-all; /* for longer unbreakable strings, just for demo */
}
.always-full-width {
/*width: 400px;*/
flex: 0 0 400px; /* since you're using flexbox, doesn't grow nor shrink, initial width set to 400px (fixed) */
background: red;
}
<div class="container">
<div class="should-be-overlapped">aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</div>
<div class="always-full-width"></div>
</div>

Creating a cross-browser fixed height scrollable display: table-row

I am trying to create a container, of height 80% of the page height, which has a fixed height header and footer with a content pane that stretches to fit the rest of the available space.
I've tried to use display: table with the following layout:
<body>
<div class="ticket">
<div class="header">header</div>
<div class="body">
<div class="wrapper">
<div class="content">content</div>
</div>
</div>
<div class="footer">footer</div>
</div>
</body>
With these styles
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
.ticket {
background: #ccc;
width: 600px;
margin: 0 auto;
height: 80%;
display: table;
}
.header {
background: blue;
height: 36px;
display: table-row;
}
.body {
background: orange;
display: table-row;
}
.wrapper {
height: 100%;
overflow-y: auto;
overflow-x: hidden;
}
.content {
height: 600px;
}
.footer {
background: green;
height: 72px;
display: table-row;
}
In Chrome this gives me a scrollable middle panel that grows with the height of the container:
Unfortunately this doesn't work in IE8 or Firefox, the '.body' div stretches to fit the '.content'.
Is there a way to do this that will work cross browser, and IE8+?
Check out http://caniuse.com/#search=flexbox and/or http://caniuse.com/#search=vh
Those are the ways to get it, but none of them works on IE 8.
You must use JS