shrink middle div horizontally on browser resize - html

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.

Related

Dynamic allocated row height of css grid gets stretched with growing content

Similar to this question I´m struggling with using CSS grid to create a layout with fixed header and footer containing an middle row, which should use the remaining space of the .static or .dynamic dynamic container. So in this case, both oth them should have a complete height of 200px. Subtracting the 40px (2x 20px for header + footer) the remaining space for the content should be 160px. As you can see at the example, the red reference div on the left is clearly smaller than the whole "sandwich" of div containers. The .dynamic div element is to large and will stretch the whole div container. I want to prohibit this!
Here are a few additional conditions I have to fullfill:
The whole layout should be dynamic, so the .wrapper div later wont have a static height, but will fill 100% of the given height. therefore onlydynamic will be used, since this also uses 100% of the height. The showcase with .static is just there to show that it doesn´t even work with fixed heights.
Neither static nor dynamic should work with overflow to create scrollbars or hidden overflowing content. It should just restrict the dynamic area between .header and .footer to an height.
The containing .content container will expand itself to 100% width and should be treatet as a kind of blackbox: every component should be able to be inserted here. The content will always use 100% of the height and should not strech the ambient parent divs. The content will contain an scrollbar on its own, if the height of the content will be heigher than the dynamically allocated space of the .dynamic container
How am I able to solve this issue with the given description?
Please see the provided example and feel free to adapt it as you need to!
.wrapper {
display: flex;
flex-direction: row;
height: 200px;
max-height: 200px;
width: 100%;
}
.measurement {
height: 200px;
max-height: 200px;
min-height: 200px;
min-width: 3px;
background-color: red;
border: 2px solid blue;
padding: 2px;
margin: 1px;
}
.static,
.dynamic {
display: grid;
grid-template-rows: 20px 1fr 20px;
width: 50%;
border: 2px solid blue;
padding: 2px;
margin: 1px;
}
.static {
height: 200px;
max-height: 200px;
/*should NOT have an overflow/scrollbar but fit to the remaining space*/
}
.dynamic {
height: 100%;
max-height: 100%;
/*should NOT have an overflow/scrollbar but fit to the remaining space*/
}
.content {
height: 100%;
width: 100%;
overflow: auto;
/* Blackbox like content, always expands to 100% width and height */
/* could contain content that is larger than the dynamic-height div and will get scrollbar then */
}
.fixed-height {
background-color: green;
}
<div class="wrapper">
<div class="measurement"></div>
<div class="static">
<div class="fixed-height">TOP</div>
<div class="dynamic-height">
<div class="content">
TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST
</div>
</div>
<div class="fixed-height">BOTTOM</div>
</div>
<div class="dynamic">
<div class="fixed-height">TOP</div>
<div class="dynamic-height">
<div class="content">
TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST
</div>
</div>
<div class="fixed-height">BOTTOM</div>
</div>
</div>
EDIT
As you can see in the image below, the TEST and BOTTOM text is beyond the blue borders. I´m not about the few pixels difference between the borders and the red reference but I'm concerned about the overflow over the bottom border.
This is the expected behaviour: there should be a scrollbar inside the content area, no overflow and no scrollbar inside dynamic div
You need to merge the div.content with the div.dynamic-height and set the max-height: 100% property to your .dynamic-height class.
.content doesn't need an height, it's setted by the definition of the grid row.
.wrapper {
display: flex;
flex-direction: row;
height: 200px;
max-height: 200px;
width: 100%;
}
.measurement {
height: 200px;
max-height: 200px;
min-height: 200px;
min-width: 3px;
background-color: red;
border: 2px solid blue;
padding: 2px;
margin: 1px;
}
.static,
.dynamic {
display: grid;
grid-template-rows: 20px 1fr 20px;
width: 50%;
border: 2px solid blue;
padding: 2px;
margin: 1px;
}
.static {
height: 200px;
max-height: 200px;
/*should NOT have an overflow/scrollbar but fit to the remaining space*/
}
.dynamic {
height: 100%;
max-height: 100%;
/*should NOT have an overflow/scrollbar but fit to the remaining space*/
}
.content {
width: 100%;
overflow: auto;
/* Blackbox like content, always expands to 100% width and height */
/* could contain content that is larger than the dynamic-height div and will get scrollbar then */
}
.fixed-height {
background-color: green;
}
.dynamic-height {
max-height: 100%;
}
<div class="wrapper">
<div class="measurement"></div>
<div class="static">
<div class="fixed-height">TOP</div>
<div class="dynamic-height content">
TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST
</div>
<div class="fixed-height">BOTTOM</div>
</div>
<div class="dynamic">
<div class="fixed-height">TOP</div>
<div class="content dynamic-height">
TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST
</div>
<div class="fixed-height">BOTTOM</div>
</div>
</div>

Two DIVs 1 with static width, other fliud, but how to get right div to stack UNDER # breakpoint?

I have two divs next to each/side by side..
The LEFT div has a FLUID width.
The RIGHT div has a static wdth.
When I resize the screen/browser... it work great! (and as intended).
However because of the way it was set up:
(Fiddle example: http://jsfiddle.net/VHcPT/384/)
The RIGHT div in physically first in the mark-up..(and floated RIGHT).
However at say 768px breakpoint.. I need this RIGHT (static) DIV to stack UNDER the LEFT div.. how can I achieve this?
If I physically have the RIGHT div AFTER the LEFT div in the markup.. it would stack as expected.. but I need to have it FIRST so the fluid/static behavior in place works as it should.
So to re-cap, its NOT about getting the two divs next to each other one fluid, one static.. its how to handle that at a responsive/breakpoint.. and get the static (RIGHT) div to stack UNDER the fluid (LEFT) div
Using the fiddle example.. the RED DIV would go UNDER (stack) the GREEN lines/div.. (the green would then be full width).. at a certain breakpoint.
and because code is required now:
HTML:
<div id="contentcontainer">
<div class="rightcontainer">mm</div>
<div class="leftcontainer">
<div class="item_1">
some text
</div>
<div class="item_2">
some text
</div>
</div>
</div>
CSS:
#directorycontainer {
padding:10px 10px;
display:table;
box-sizing: border-box;
width: 100%;
font-size: 0.8em;
font-weight: normal;
}
.directory {
background: green;
margin-right: 10px;
overflow: hidden;
padding-right: 10px;
position: relative;
}
.mapcontainer {
background: red;
display:table;
width:240px;
height:480px;
float:right;
position:relative;
overflow: hidden;
}
.providercontainer{
background-color: #f7f9fb;
border: 1px solid #e1dacd;
display: table;
margin-bottom: 0.625em;
padding: 0;
width: 100%;
}
OK well looks like this works and should be an acceptable answer/solution:
Fiddle:
http://jsfiddle.net/VHcPT/389/
HTML/Markup:
<div id="contentcontainer">
<div class="leftcontainer">
<div class="item_1">
some text
</div>
<div class="item_1">
some text
</div>
</div>
<div class="rightcontainer">mm</div>
</div>
CSS:
* {box-sizing: border-box;}
#contentcontainer {
padding:10px 10px;
display:table;
box-sizing: border-box;
width: 100%;
font-size: 0.8em;
font-weight: normal;
}
.leftcontainer {
background: green;
overflow: hidden;
padding: 5px;
float:left;
width:calc(100% - 240px);
}
.rightcontainer {
background: red;
display:table;
width:240px;
height:480px;
float:left;
position:relative;
overflow: hidden;
}
.item_1{
background-color: #f7f9fb;
border: 1px solid #e1dacd;
display: table;
margin-bottom: 0.625em;
padding: 0;
width: 100%;
}
works with whatever breakpoints you set and the elements will stack correctly.
you may like my FLEXBOX alternative to you problem. It may take a bit of practice, but it will eventually give you much more control.
The FIDDLE
Below the basic CSS structure, no other 'display', 'position' or 'overflow' needed. With this structure you can mix-match any number of fixed and/or fluid columns.
.flex--box { display: flex; flex-flow: row wrap }
.flex--fluid { flex: 1 1 auto }
.flex--fixed { flex: 0 0 auto; min-width: 240px }
/* MOBILE MQ */
#media all and (max-width: 360px) {
.flex--fluid, .flex--fixed {
flex: 1 1 auto;
}
}
Let me know if you have problem with it.
And of course, do give credit if you think it is worth it.
( BTW: I changed the colors to something less retina intensive &D )

center content inside centered div

I have the following:
<div class='container-main'>
<div class='container-inner'>
<div class='clickable-box'>
stuff
</div>
<div class='clickable-box'>
stuff
</div>
<div class='clickable-box'>
stuff
</div>
</div>
</div>
.container-main {
width: 100%;
}
.container-inner {
width: 90%;
}
.clickable-box {
width: 300px;
height: 300px;
/* ???? */
}
I'm trying to make it so the clickable box will be centered inside the inner container IF there isn't enough room for another clickable box next to it.
BUT if there is enough width (600px +) then they create 2 columns (which are together centered inside the inner container), and if theres more room even (900px +) then 3 columns etc...
in other words, when I start out with a window of width 500px, it should show 1 column of boxes all lined up under each other. As I drag the window out, the box should stay in the center until theres enough room for another to go next to it, and they create 2 columns instead, and so on.
But I don't want the column to float left or right while I'm dragging the window and leave a big empty space
Try this CSS:
.container-main {
width: 100%;
}
.container-inner {
width: 99%;
text-align:center
}
.clickable-box {
display: inline-block;
width: 32%;
margin: 0 auto;
}
I think what you're looking for is to set clickable-box to display: inline-block. Setting display: inline-block essentially makes the div act like text in regards to text-align rules, but still keeps some block properties as well. It's pretty sweet.
HTML
<div class='container-main'>
<div class='container-inner'>
<div class='clickable-box'>
stuff
</div>
<div class='clickable-box'>
stuff
</div>
<div class='clickable-box'>
stuff
</div>
</div>
</div>
CSS
.container-main {
background-color: red;
text-align: center;
}
.container-inner {
width: 90%;
}
.clickable-box {
background-color: blue;
width: 300px;
display: inline-block;
}
Here's a fiddle to demo it!
display:inline-block should be the best solution, this will display clickable boxes in one line if there is space for them:
.clickable-box {
width: 300px;
height: 300px;
display:inline-block;
}
Also add text-align:center to parent div in order for clickable boxes to be centered
.container-inner {
width: 90%;
text-align:center;
}
I think this should do it. I modified the CSS a bit to add some borders to see what the boxes look like. You could certainly remove those borders.
Fiddle Demo
.container-main {
width: 100%;
}
.container-inner {
width: 90%;
border:3px solid #454;
text-align:center;
}
.clickable-box {
width: 300px;
height: 300px;
border:1px solid #000;
margin:0 auto;
display:inline-block;
}
I'd use float rules because they can push down the boxes that do not fit. For instance, float:left will get you at least two boxes on a 1096px. display:inline might have issues on browser rendering.
.container-main {
width: 100%;
}
.container-inner {
width: 90%;
}
.clickable-box {
width: 300px;
height: 300px;
float:left; // right there.
}

Two column layout where width of main content DIV is fluid (using all space available to 100%)

I feel this question has been answered but I searched and searched and no answer seems to deal with dynamic main content width.
I simply want this scenario:
|-|nav|-|main content|-|
Where nav is a DIV and main content is a DIV and both are placed inside another DIV container which has a width of 100%. - is simpy a spacing between the DIVs, a margin.
nav has a fixed width of 300px and "main content" div should always take the rest of the space available (to fill the 100% of the parent div) - without the use of JavaScript.
Also I want to have some margins left and right of each DIV (nav, main content) so that they have some space between them and the "browser border"/body.
I experimented with table, table-cell but the border-collapsing drove me nuts so I am heading back to god old "float: left" and clearfix. This is what I have so far:
<div id="container" class="cf">
<div id="nav">
Nav stuff
</div>
<div id="main">
Main stuff
</div>
</div>
#container {
padding: 0;
width: 100%;
background-color: orange;
min-height: 50px;
}
#nav {
display: inline;
float: left;
min-width: 300px;
width: 300px;
margin-left: 10px;
margin-right: 10px;
}
#main {
display: inline;
float: left;
background-color: green;
margin-right: 10px;
}
.. /* clearfix stuff omitted (class 'cf') */
So now the problem is, how to make "main content" (#main) fill the rest of the parent (#container). If I use a width of 100% the 100% is of course the full width of the parent and the div will go under the "nav" div. If i use "auto" the same thing happens. It of course works if I pass in a fixed width e.g. in pixels but I don't know the correct pixels in advance and using JS to calculate that seems a bit odd to me.
I've seen a solution where the "nav" was put inside "main" but that leads to problems with the margins. Try to insert a margin to create some space beside a div that is inside another div... I don't think that's anyhow possible in this universe.
Thanks for your help!
Maybe you should create BFC to face this problem.
For example:
#container{
border: 1px solid red;
}
#nav{
float: left;
width: 300px;
border: 1px solid green;
height: 200px;
margin-left: 20px;
margin-right: 20px;
}
#main{
overflow: hidden;
height: 400px;
border: 1px solid blue;
margin-right: 20px;
}
overflow: hidden; is the key to create BFC for #main.
JSFiddle : http://jsfiddle.net/yujiangshui/yMFB6/
More about BFC : https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Block_formatting_context
For example:
#container {
width: 100%
position: relative;
}
#nav {
position: absolute;
top: 0;
left: 0;
width: 300px;
}
#main {
margin-left: 320px;
}
JSFIDDLE

How to horizontally center a larger div of variable width, within a smaller div of variable width

I want to achieve the following effect: http://jsfiddle.net/3KJta/1/
However the solution I have uses a known width for the small div and the larger div. I need this to work with variable sized divs. The use case for this is a tooltip that appears above a smaller flexible sized element. The tooltip content isn't known and so the width could be anything.
So far I have:
<div class="small">
<div class="smaller"></div>
<div class="larger"></div>
</div>
and
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
div {
border: 2px solid black;
}
.small {
width: 50px;
height: 50px;
position: absolute;
left: 200px;
top: 50px;
text-align: center;
}
.smaller {
width: 20px;
height: 20px;
border-color: red;
display: inline-block;
}
.larger {
width: 200px;
height: 200px;
border-color: blue;
display: inline-block;
margin-left: -75px /* NOTE: in reality, .small has a variable width, and so does .larger, so i can't just take off this fixed margin */
}
If you are ok with using css3 and only support modern browsers you can use transform: translateX(-50%); to center the bigger box (currently supported browsers).
See this example: http://jsfiddle.net/2SQ4S/1/
If you use and extra element you can do it:
<div class="small">
<div class="smaller"></div>
<div class="larger">
<div>I'm extra</div>
</div>
</div>
CSS
.larger {
position:relative;
left:50%;
width:8000%;
margin-left:-4000%;
text-align:center;
border:none;
}
.larger div {
width: 200px;
height: 200px;
border-color: blue;
margin:auto;
}
http://jsfiddle.net/3KJta/4/
although that does cause some issues with content being wider than the page so you would need it all in a container with overflow:hidden:
http://jsfiddle.net/3KJta/7/
All a bit ugly though. Perhaps there's a solution where you can avoid doing this. Maybe a JS solution that measures the size of the content you're trying to show and offsets it.