I'm working on a web app for which I want to have two independently scrollable areas on larger screens: a main content area on the left, and a smaller sidebar on the right.
I've managed to implement such a layout in CSS using absolute positioning and overflow properties, see this JSFiddle: http://jsfiddle.net/XLceP/
This is great, however I'm also attempting to make use of Bootstrap (3.1.1) in order to make the site responsive and for the components/styling. However I'm at a loss at how to do so.
Basically, I'd ideally like to use Bootstrap conventions (the column classes etc.) to make it so that on mobile screens the right pane collapses below the left pane (or disappears entirely) for a conventional vertical layout, with both taking up the full width. However it seems impossible to do this while using absolute positioning for the larger screen layout.
How can I attempt to tackle this problem?
Update 2019
Bootstrap 4
Now that Bootstrap 4 uses flexbox, you can this layout using flex-grow and the new overflow utility classes. This minimizes the extra CSS that was needed before in BSv3...
<div class="container-fluid d-flex flex-column flex-grow-1 vh-100 overflow-hidden">
<nav class="navbar navbar-light bg-light navbar-expand-md px-0 flex-shrink-0">
<a class="navbar-brand" href="#">App</a>
<ul class="navbar-nav">
<li class="nav-item">Nav</li>
</ul>
</nav>
<div class="row flex-grow-1 overflow-hidden">
<div class="col-2 mh-100 overflow-auto py-2">
<h6>Sidebar</h6>
<ul class="nav flex-column">
<li class="nav-item">
<a class="nav-link active" href="#">Link</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
</ul>
</div>
<div class="col mh-100 overflow-auto py-2">
<h3>Body content</h3>
</div>
</div>
<div class="row flex-shrink-0 bg-light">
<div class="col-12 py-2">
<p>Footer ...</p>
</div>
</div>
</div>
https://codeply.com/go/LIaOWljJm8
Bootstrap 3 (original answer)
You can use a CSS media query to "disable" the absolute positioning on mobile screens. This will let Bootstrap's responsiveness kick in...
#media (min-width: 768px){
#left {
position: absolute;
top: 0px;
bottom: 0;
left: 0;
width: 75%;
overflow-y: scroll;
}
#right {
position: absolute;
top: 0;
bottom: 0;
right: 0;
overflow-y: scroll;
width: 25%;
}
}
Demo: http://bootply.com/126137
I forked Skelly's bootply here while using col-xs-12 and hidden-xs.
<div class="col-xs-12 col-sm-6" id="left">
<p>Left contents</p>
</div>
<div class="hidden-xs col-sm-6" id="right">
<p>Right contents</p>
</div>
I prefer this because it avoids media queries in a css file.
You don't need Bootstrap to do what you want. You can simply modify your existing CSS to following:
#left {
float: left;
width: 75%;
height: 100px;
overflow-y: scroll;
background-color: #FC6E51;
text-align: center;
}
#right {
float: left;
overflow-y: scroll;
height: 100px;
width: 25%;
background-color: #4FC1E9;
text-align: center;
}
And then, in your media query for mobile screens, make both #left and #right flow:none, width: 100% and height: auto;
If you really want to use Bootstrap, just put both #left and #right in the following structure:
<div class="row">
<div class="col-md-8" id="left">Your Code Here</div>
<div class="col-md-4" id="right">Your Code Here</div>
</div>
Related
I'm trying to make the indicated div below scrollable, but it always seems to extend the document size beyond screen space instead of creating a scrollbar. One solution is to set a fixed pixel height for the div, but I want to avoid this to ensure scalability between devices. Any ideas?
<div class="row no-gutters w-100 flex-grow-1">
<div class="col-8">
<div id="playarea" class="container-fluid border-top border-end h-100 px-0">
<!-- Cards go here -->
</div>
</div>
<div class="col-4">
<div class="container-fluid border rounded-top w-100 h-100 d-flex flex-column">
<div class="container my-3 d-flex mb-0">
<h5 class="flex-grow-1">Side Content</h5>
</div>
<hr class="border mt-2 mb-3">
<div class="container mb-3 d-flex">
<!-- Non-scrollable search area -->
</div>
<div class="container flex-grow-1 overflow-auto">
<!-- Scrollable content goes here -->
</div>
<div class="card mt-2 bg-light mb-3" id="info-panel">
<div class="card-body">
<!-- Non-scrollable info box -->
</div>
</div>
</div>
</div>
</div>
Many thanks in advance
Your question is a bit confusing because your .row has .flex-grow-1 which one would only add if you want .row to grow in available height of its parent, not in width. This would mean .row should always have a height and my solution can be simplified. So let me know if that's the case, because my answer assumes .row has no height.
My solution that requires no fixed height uses a container inside col-4 with absolute positioning:
#overflow-container {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
padding: inherit;
}
This container will take up all available space inside col-4 and will grow or shrink with it. Now the element with overflow: scroll will work as you want.
The only drawback here is that if col-8 (or row) has no content - and thus no height - the #overflow-container will also have no height and any content inside the .overflow-auto element will not be visible. So if col-8 can be empty, a min-height on col-4s parent is needed.
The line padding: inherit is there to give the column its padding back; Bootstrap uses the selector row > * to give columns their padding.
I removed all unnecessary classes for this snippet to work for simplicity, but I added the sm breakpoint on the columns so they stack on mobile screen sizes. If you don't want this, you can simply remove the -sm part on the columns and the #media in the CSS. It's only there to show how it can be done.
.col-sm-8 {
background: lightyellow;
}
.col-sm-4 {
background: lightgreen;
}
#media (min-width: 576px) {
#overflow-container {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
padding: inherit;
}
}
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-GLhlTQ8iRABdZLl6O3oVMWSktQOp6b7In1Zl3/Jr59b6EGGoI1aFkw7cmDA6j6gD" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.3.0-alpha1/dist/js/bootstrap.bundle.min.js" integrity="sha384-w76AqPfDkMBDXo30jS1Sgez6pr3x5MlQ1ZAGC+nuZB+EYdgRZgiwxhTBTkF7CXvN" crossorigin="anonymous"></script>
<div class="container-fluid">
<div class="row">
<div class="col-sm-8">
<p>This column should have enough content...</p>
<br><br><br><br><br>
<p>...So `Overflowing content` will have a height.</p>
</div>
<div class="col-sm-4 position-relative">
<div class="d-flex flex-column" id="overflow-container">
<div class="">
<h5>Aside Content</h5>
</div>
<div class="">
<p>Some content here.</p>
</div>
<div class="overflow-auto">
<p>Overflowing content.</p>
<br><br><br><br><br><br><br><br><br>
<p>Unless col-8 is long enough for me to fit.</p>
</div>
<div class="">
<p>Some content here.</p>
</div>
</div>
</div>
</div>
</div>
I have a modal with fixed size. It contains multiple panes selectable with nav buttons. On one of the panes I have a div containing a grid of thumbnail images and a button at the bottom. Currently the images and the button extend far past the bottom of the modal window. I would like the button to remain at the bottom of the pane, and the remaining height of the pane be occupied with the thumbnail div.row, wherein if the image content does not fit inside of the div.row, the content scrolls.
My attempt at this was to make the pane flex-column, and make the div.row overflow-auto, but it has no effect it seems.
HTML
<div class="modal modal-base">
<div class="modal-overlay"></div>
<div class="modal-window">
<div class="close">×</div>
<div class="modal-content">
<div class="nav-wrapper">
<ul class="nav nav-pills flex-row" role="tablist">
<li class="nav-item">
<a class="nav-link mb-3 active" href="#" role="tab">Image List</a>
</li>
<li class="nav-item">
<a class="nav-link mb-3" href="#" role="tab">Upload</a>
</li>
</ul>
</div>
<div class="card shadow mb-0">
<div class="card-body">
<div class="tab-content">
<div class="tab-pane fade show active d-flex flex-column" role="tabpanel">
<div class="row overflow-auto">
<div class="col-6 mb-2">
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Terrier_mixed-breed_dog.jpg/1024px-Terrier_mixed-breed_dog.jpg" class="img-thumbnail">
</div>
<div class="col-6 mb-2">
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Terrier_mixed-breed_dog.jpg/1024px-Terrier_mixed-breed_dog.jpg" class="img-thumbnail">
</div>
<div class="col-6 mb-2">
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Terrier_mixed-breed_dog.jpg/1024px-Terrier_mixed-breed_dog.jpg" class="img-thumbnail">
</div>
</div>
<button type="button" class="btn btn-primary w-100 btn-lg">Insert</button>
</div>
<div class="tab-pane fade" role="tabpanel">
<div class="upload-widget"></div>
<div class="text-center mt-2">
<button type="button" class="btn btn-primary">Upload</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
CSS (scss)
.modal {
&.modal-base {
display: flex;
align-items: center;
justify-content: center;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
&-overlay {
position: absolute;
z-index: 2000;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
}
&-window {
background: #fff;
border-radius: 4px;
margin: auto;
position: relative;
width: 400px;
height: 300px;
z-index: 2001;
.close {
position: absolute;
right: 2px;
top: 2px;
color: gray;
font-size: 25px;
z-index: 2002;
}
}
&-content {
width: 100%;
height: 100%;
padding: 20px;
}
}
Codepen
Using Bootstrap 4 CSS framework. The JS code for the pane switching has been omitted since it is superfluous. I would like a solution that does not require me to fix the height of the div containing the images.
Note: this is a continuation of the question asked here. In that question I had simplified my setup to make everyone's life easier, and was able to get a working solution for that simplified setup, but it does not seem to work when translated over the actual setup I have, hence this question.
Thank you for looking at my question!
Just provide your div containing the card class with appropriate overflow property like this:
<div class="card shadow mb-0" style="overflow-x: hidden; overflow-y: scroll;">
You should include an overflow:auto; or do the css code at your containing element
containing element {
content:"";
display:table;
clear:both;
}
I solved this issue (with help from an online friend) over the course of a few hours, allow me to share the insight gained.
Essentially, flex is the way to go here. We need flex in the pane to keep the button on the bottom while the images take up the remaining space with scrolling overflow. We should also make enclosing divs have a height of 100% (.tab-content, .card-body).
When we get to the .card itself is where things get tricky. We want it to fill the parent, but applying h-100 here is not acceptable since it has a sibling, its height shouldn't be 100% of the parent content area, but rather 100% - height of the .nav-wrapper. It's close to what we want, but not quite.
Seems like we need another flex here to allow the .card to grow just into the remaining space, but if you set the flex here, it is not respected and the card extends way outside of the modal. The secret sauce is that by default, the .card with .d-flex is getting min-height:auto, and what this means is that it will not shrink smaller than the size of its content. Setting min-height:0 on the div.card solves the problem. Since I do not see any Bootstrap utility to do this, I've added one myself globally for this purpose to use in the future as well.
.d-flex > .flex-shrink-content {
min-height: 0;
}
The full code / demo can be found here for those interested:
Codepen
<div class="modal modal-base">
<div class="modal-overlay"></div>
<div class="modal-window">
<div class="close">×</div>
<div class="modal-content d-flex flex-column">
<div class="nav-wrapper flex-grow-1">
<ul class="nav nav-pills flex-row" role="tablist">
<li class="nav-item">
<a class="nav-link mb-3 active" href="#" role="tab">Image List</a>
</li>
<li class="nav-item">
<a class="nav-link mb-3" href="#" role="tab">Upload</a>
</li>
</ul>
</div>
<div class="card flex-shrink-content shadow">
<div class="card-body h-100">
<div class="tab-content h-100">
<div class="tab-pane fade show active d-flex flex-column h-100" role="tabpanel">
<div class="row flex-grow-1 overflow-auto">
<div class="col-6 mb-2">
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Terrier_mixed-breed_dog.jpg/1024px-Terrier_mixed-breed_dog.jpg" class="img-thumbnail">
</div>
<div class="col-6 mb-2">
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Terrier_mixed-breed_dog.jpg/1024px-Terrier_mixed-breed_dog.jpg" class="img-thumbnail">
</div>
<div class="col-6 mb-2">
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Terrier_mixed-breed_dog.jpg/1024px-Terrier_mixed-breed_dog.jpg" class="img-thumbnail">
</div>
</div>
<button type="button" class="btn btn-primary w-100 btn-lg mt-2">Insert</button>
</div>
<div class="tab-pane fade h-100" role="tabpanel">
<div class="upload-widget"></div>
<div class="text-center mt-2">
<button type="button" class="btn btn-primary">Upload</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
.modal {
&.modal-base {
display: flex;
align-items: center;
justify-content: center;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
&-overlay {
position: absolute;
z-index: 2000;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
}
&-window {
background: #fff;
border-radius: 4px;
margin: auto;
position: relative;
width: 400px;
height: 300px;
z-index: 2001;
.close {
position: absolute;
right: 2px;
top: 2px;
color: gray;
font-size: 25px;
z-index: 2002;
}
}
&-content {
width: 100%;
height: 100%;
padding: 20px;
}
}
.d-flex > .flex-shrink-content {
min-height: 0;
}
How to properly stretch a child to parent's height? I've tried a lot of variants I found (many quite complicated), but it never worked for me. I would prefer to do this with flex-box, as that seems the newest method. Here is my try:
<div class="main h-100">
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
<a href class="navbar-brand">Menu</a>
</nav>
<div class="container-fluid h-100">
<div class="row h-100">
<div class="col-xs-2 bg-light h-100 pr-3 menuContainer">
<button class="btn btn-outline-primary mt-3 btn-sm btn-block"> Test </button>
<nav class="navbar navbar-light list">
<ul class="navbar-nav flex-column">
<li class="nav-item">A1</li>
<li class="nav-item">A1</li>
</ul>
</nav>
</div>
<div class="col-xs-10 p-0">
Content
</div>
</div>
</div>
body {
height: 100vh;
}
.bg-light {
background-color: green !important;
}
.list {
overflow-y: auto;
height: 100%;
align-items:start
}
.menuContainer {
display: flex;
flex-flow: row wrap;
}
.list {
flex: 1;
background-color: red;
}
http://jsfiddle.net/x1hphsvb/2065/
In the end I'd like to remove the scroll, so that the menu (red box) starts where it starts now and ends exactly where the screen end is.
The aim is also to be able to put anything instead of Content with height: 100% so it does the same.
Both content and menu can be bigger - in that case I expect them to add a scroll on it's own - I use overflow-y: auto for that.
http://jsfiddle.net/x1hphsvb/2083/
html, body {
height: 100%;
}
.bg-light {
background-color: green !important;
}
.list {
overflow-y: auto;
align-items:start
}
.menuContainer {
display: flex;
flex-direction: column;
}
.list {
flex: 1;
background-color: red;
}
.site-content {
height: calc(100% - 56px);
}
Key differences:
flex-direction: column on sidebar items.
Remove height 100% on .site-content, instead do calc(100% - 56px) which is the header height.
You're getting an overflow because you're giving many (if not all) of your elements height: 100%. It's coming with the Bootstrap code:
.h-100 {
height: 100% !important;
}
As a result, when there is more than one element in a container, the siblings overflow the parent.
I would remove height: 100% from elements that you want to have fill the height of the container. Flexbox offers a more efficient method.
When you set display: flex on an element it applies align-items: stretch on the child elements. This means that the children will automatically expand to fill the height of the container.
Set a height on one element (i.e., an ancestor). Then keep adding display: flex to each child down the HTML structure. There is no problem nesting flex containers.
In Bootstrap 4.1 there is a flex-fill utility class for this purpose.
.flex-fill {
flex: 1 1 auto;
}
In your case, add it to your container-fluid and you won't need all the h-100s. Also, make the container fluid d-flex so that flex-fill can also be applied on the row.
<div class="main h-100 d-flex flex-column">
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
<a href class="navbar-brand">Menu</a>
</nav>
<div class="container-fluid flex-fill d-flex">
<div class="row flex-fill">
<div class="col-xs-2 bg-light pr-3 menuContainer d-flex flex-column">
<button class="btn btn-outline-primary mt-3 btn-sm btn-block"> Test </button>
<nav class="nav navbar-light list">
<ul class="navbar-nav flex-column">
<li class="nav-item">A1</li>
<li class="nav-item">A1</li>
</ul>
</nav>
</div>
<div class="col-xs-10 p-0">
Content
</div>
</div>
</div>
</div>
https://www.codeply.com/go/GEiw0PABgi
Also, note that col-xs-* is col-* in Bootstrap 4 as the -xs infix has been removed. Here's a simplified example w/o the extra CSS.
Related questions:
Bootstrap 4 Navbar and content fill height flexbox
html, body, .sidebar-container, .sidebar-row {
height: 100%;
}
.sidebar {
background-color: #2C3544;
}
#media (min-width: 992px) {
.sidebar {
position: fixed;
top: 0;
left: 0;
bottom: 0;
z-index: 1000;
display: block;
background-color: #2C3544;
}
}
img{
margin: auto;
display: block;
}
.sidebar-image{
margin-top: 15px;
}
.sidebar-items{
margin-top: 15px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.3/umd/popper.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css" rel="stylesheet"/>
<div class="container-fluid sidebar-container">
<div class="row sidebar-row">
<div class="col-md-2 sidebar">
<div class="container-fluid">
<div class="col-md-12 sidebar-image">
<img src="assets/logo-white.png" width="75px" height="75px"/>
</div>
</div>
<div class="row sidebar-items">
<div class="col-md-12">
<ul class="list-group">
<li class="list-group-item">Dashboard</li>
<li class="list-group-item">Projects</li>
<li class="list-group-item">Statistics</li>
</ul>
</div>
</div>
<div class="row align-bottom">
hafldjalfjsdlfsjdlfsjlfs
</div>
</div>
<div class="col-md-10 offset-md-2 content">
Main Content
</div>
</div>
</div>
I wrote this HTML/CSS code trying to align a div to the bottom inside another div:
I want to align this last div in the col-md-2 to the bottom of the sidebar-container which height is 100%. I tried adding the bootstrap class align-bottom but somehow this doesn't work. Could anyone help me out?
Suppose you have 2 divs. Div A(Outer) and Div B(Inner). To achieve your task just place Div B code in Div A code and in Div B css class add this
position : absolute
bottom : 0
You can also just use bootstrap flexbox to do this.
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
<div class="d-flex align-items-start flex-column bg-success" style="height: 200px;">
<div class="mb-auto p-2">Flex item-1</div>
<div class="p-2">Flex item-2</div>
<div class="p-2">Flex item-3</div>
</div>
<div class="d-flex align-items-end flex-column bg-info" style="height: 200px;">
<div class="p-2">Flex item-a</div>
<div class="p-2">Flex item-b</div>
<div class="mt-auto p-2">Flex item-c</div>
</div>
align items to the left or right make sure that you include the entire d-flex align-items-end flex-column on the parent element and choose start or end depending if you want it to be aligned left or right.
align item to the bottom Then, use mt-auto on the div that you want to stick to the bottom of the parent.
When using Bootstrap grid system, my go-to solution is like this:
add d-flex to each col-*
add d-flex flex-column to each card-body
add mt-auto mx-auto to the last element (or last div of elements) I want to stick to the end
This prevents any further styling mess-up in my opinion.
Relevant Documentation:
Flex Alignment in Bootstrap 5.0: https://getbootstrap.com/docs/5.0/utilities/flex/#align-items
Vertical Alignment in Bootstrap 5.0: https://getbootstrap.com/docs/5.0/utilities/vertical-align/
Relevant Code:
What worked for me to align a div (of text) at the bottom of a row/container
<div class="d-flex align-content-end flex-wrap mb-2">
<span class="display-4 fw-bold text-black text-start mt-0 mb-0">Active Mural Projects</span>
</div>
I would like the content in the main part of this page to be down slightly off the heading and in the centre of the page and not sitting on the left margin.
https://www.comparestonehengetours.com/tour/products.php?q=Christmas+Day+Traditional+Lunch+Cruise+on+the+River+Thames
Any help you can offer would be much appreciated!
To introduce a gap beneath the navigation, add some margin bottom to it:
#mj-righttop {
margin-bottom: 25px;
}
To centralise the main content, give it automatic left and right margins:
.site-content.container {
margin-left: auto;
margin-right: auto;
}
After the above, the main content will be offset to the left more than desired, due to this CSS that you already have:
#media (min-width: 1200px) {
.row {
margin-left: -30px;
}
}
So remove that margin-left on the row class, or override it specifically for rows within the container:
.site-content.container .row {
margin-left: auto;
}
Put it all together and this is what you'll need to add:
#mj-righttop {
margin-bottom: 25px;
}
.site-content.container {
margin-left: auto;
margin-right: auto;
}
.site-content.container .row {
margin-left: auto;
}
Jsfiddle Maybe this no the best answer but it can solve your problem
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="#">WebSiteName</a>
</div>
<ul class="nav navbar-nav">
<li class="active">Home</li>
<li>Page 1</li>
<li>Page 2</li>
<li>Page 3</li>
</ul>
</div>
</nav>
<div class="container">
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
<div class="col-lg-6 col-md-6 col-sm-6 col-xs-6">
<img src="https://www.google.com/search?q=testing&espv=2&biw=1842&bih=1014&source=lnms&tbm=isch&sa=X&ved=0ahUKEwje-43Yy9_PAhUDvY8KHZqMB0QQ_AUICCgD#imgrc=p8m10A4tMfsszM%3A" alt="testing" width="100px" height="100px" align="right">
</div>
<div class="col-lg-6 col-md-6 col-sm-6 col-xs-6">
<p>
testing testing testing testing testing testing testing testing testing testing testing testing testing testing testing testing
</p>
</div>
</div>
</div>
I see that you use Zurb foundation !!
So why you don't try :
`<div class="site-content large-9 large-centered small-12 columns">`
Rather than
`<div class="site-content container">`