I have a fixed width and height container that consists of arbitrary height elements that need to be stacked vertically. How can I hide any elements that do not fit? overflow: hidden could still show the part of an element that doesn’t overflow.
.container {
border: 1px solid #eee;
height: 200px;
overflow: hidden;
}
.box {
background-color: #ccc;
line-height: 54px;
margin: 20px;
text-align: center;
width: 60px;
}
.incorrect {
background-color: #fa9;
}
<div class="container">
<div class="box">show</div>
<div class="box">show</div>
<div class="box incorrect">hide</div>
</div>
Assuming that your child elements have the same width as the container, this can be achieved by leveraging the containing box created from the flex property.
The trick is to use flex-flow: column wrap; in conjunction with overflow: hidden; on the container. The former dictates that the content is stacked vertically and that anything that does not fit should be wrapped into a second column, outside of the content box of the container. The latter dictates that this second column (and any subsequent columns) should be hidden.
.container {
width: 300px;
height: 200px;
display: flex;
flex-flow: column wrap;
overflow: hidden;
}
.box {
width: 300px;
height: 75px;
}
.box:nth-child(1) {
background: red;
}
.box:nth-child(2) {
background: green;
}
.box:nth-child(3) {
background: blue;
}
<div class='container'>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
An easy way of doing this would be to use CSS columns instead of flex.
Just use a column-width equal to the width of the container. Apply break-inside: avoid on child divs. And there you go.
It resolves all of the asks:
[..]have a fixed width and height container that consists of arbitrary
height elements that need to be stacked vertically. How can I hide any
elements that do not fit?
You can notice that the red div (the last one) is hidden completely.
Example Snippet:
* { box-sizing: border-box; margin: 0; padding: 0; }
.container {
border: 1px solid #999;
height: 200px; width: 300px;
overflow: hidden;
column-width: 300px;
}
.box {
padding: 8px; text-align: center; color: #fff;
width: 250px; height: 80px;
break-inside: avoid
}
.box:nth-child(1) { background: #3b3; }
.box:nth-child(2) { background: #33b; width: 200px; height: 75px; }
.box:nth-child(3) { background: #b33; }
<div class="container">
<div class="box">show</div>
<div class="box">show</div>
<div class="box">hide</div>
</div>
Note: As of now, Firefox is still a problem area with CSS columns. The break-inside, although documented on MDN, is buggy in Firefox. The bug is still open: https://bugzilla.mozilla.org/show_bug.cgi?id=549114.
Related
I was wondering how I can not see the orange background when there isn't enough in the to make the item-container overflow. So, if I put 4 divs in there, it wont over flow and you will see orange to the right, but if you add one more item to my example, a horizontal scrollbar will appear and cover the orange background on the right. I want the
item background to cover the whole item-container even if item-container doesn't have a scrollbar
Image with scrollbar
/* Copyright 2014 Owen Versteeg; MIT licensed */
body {
background: rgba(25, 25, 25, 255)
}
#header-text {
color: red;
text-align: center;
margin-top: 0;
margin-bottom: 0;
}
#header-text2 {
color: blue;
text-align: center;
margin-top: 0;
}
.item-container {
background: orange;
width: 418px;
height: 100px;
margin: 0 auto;
overflow-y: auto;
}
.item {
width: 100px;
height: 100px;
background: red;
display: inline-block;
}
<div class="container">
<h1 id="header-text">Hello</h1>
<h3 id="header-text2">Hello</h3>
<div class="item-container">
<div class="item">Item1</div><div class="item">Item1</div><div class="item">Item2</div><div class="item">Item2</div>
</div>
</div>
Simple, make your .item-container have no background:
.item-container {
width: 418px;
height: 100px;
margin: 0 auto;
overflow-y: auto;
}
Or have your items take up the full-width using flex like so:
.item-container{
background-color: red;
display: flex;
}
.item{
background-color: yellow;
flex-grow:1;
}
<div class="item-container">
<div class="item">Item1</div><div class="item">Item1</div><div class="item">Item2</div><div class="item">Item2</div>
</div>
Your layout is troublesome. Rather than pixel-perfect scrollbar gaps, why not set your inner blocks to 25% or use flexbox?
.item {
width: 25%;
...
}
I am creating a splitter-resizer in Angular to adjust the width of 2 panels. There are 2 horizontal sections and the columns widths on each side needs to be the same. However, I noticed that the width calculation is wrong at the boundary that touches the text overflow element. This causes the top and bottom panels to be off by roughly the size of a single text character.
What can I do to ensure the div width respects the ngStyle setting?
EDIT: I noticed that if I set width to undefined for the blue panel2, it seems the 2 panels size and align correctly, but I think that is not the correct way.
app.component.html
<div #container class="container">
<div class="section flex-container-row">
<div [ngStyle]="stylePanel1" class="panel1">1</div>
<div class="resizer" (click)="startdrag()" (mousedown)="startdrag($event)"></div>
<div [ngStyle]="stylePanel2" class="panel2 flex-container-row">2</div>
</div>
<div class="section flex-container-row">
<div [ngStyle]="stylePanel1" class="panel1">
<div class="longtext">this is a very long text that should be cut off when resizing.</div>
</div>
<div class="resizer" (click)="startdrag()" (mousedown)="startdrag($event)"></div>
<div [ngStyle]="stylePanel2" class="panel2">4</div>
</div>
</div>
app.component.scss
* {
box-sizing: border-box;
margin: 0; padding: 0;
}
html, body {
width: 100%;
height: 100%;
}
.container {
width: 100%;
height: 100%;
background-color: pink;
}
.section {
width: 100%;
height: 130px;
border: 1px solid magenta;
}
.flex-container-row {
display: flex;
flex-direction: row;
}
.resizer {
flex: 0 0 5px;
background-color: #ddd;
cursor: ew-resize;
}
.panel1 {
background-color: red;
width: 100px;
}
.panel2 {
background-color: blue;
}
.longtext {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
Instead of this.refContainer.nativeElement.clientWidth.
Can you please consider refContainer.nativeElement.getBoundingClientRect()
Within a footer there are 4 small boxes (created with divs that have a red border around them) and they all need to be made responsive to the width of the browser window as it is re-sized. They need to be centered and have an equal percentage space in between each other no matter what the window size is. Boxes have to stay 100px by 100px.
Here is a rough illustration of what I mean: http://s14.postimg.org/58xunsv0h/example_of_boxes.png
#footer {
width: 100%;
clear: both;
text-align: center;
background-color: black;
opacity: 0.7;
height: 200px;
}
#fbox1 {
border: 5px outset #ea2f2f;
width: 100px;
height: 100px;
position: inline-block;
float: left;
}
#fbox2 {
border: 5px outset #ea2f2f;
width: 100px;
height: 100px;
position: inline-block;
float: left;
}
#fbox3 {
border: 5px outset #ea2f2f;
width: 100px;
height: 100px;
position: inline-block;
float: left;
}
#fbox4 {
border: 5px outset #ea2f2f;
width: 100px;
height: 100px;
position: inline-block;
float: left;
}
<body>
<div id="footer">
<div id="fbox1">
</div>
<div id="fbox2">
</div>
<div id="fbox3">
</div>
<div id="fbox4">
</div>
<div>
</body>
You have two very simple ways to do that.
If you are targeting modern browsers, then you could make use of the CSS3 flex model. This is the simplest method. You won't have to change anything in your markup. Of course, I would suggest using the footer tag instead of div, because it semantically is a footer.
In this example, I am omitting browser prefixes for two reasons: (1) brevity of this snippet, and (2) most modern browsers now don't need prefixes for this. This example snippet works perfectly as-is in IE-11, FF-34 and GC-39.
The trick is to use the justify-content: space-around; property to distribute the spacing evenly between the divs. Remember, that space-around will cause the space before the first div and space after the last div to be half of the spacing between divs. This will cause, the spacing after the last div to be large because of the size of the div. To mitigate this, use margin: auto.
Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/justify-content
And: http://dev.w3.org/csswg/css-flexbox/#propdef-justify-content
Fiddle: http://jsfiddle.net/abhitalks/j8fpp0so/2/
Snippet:
footer {
background-color: #000; opacity: 0.7;
height: 200px;
display: flex;
justify-content: space-around; /* this is important */
align-items: center; text-align: center;
}
footer > div {
border: 1px solid red;
width: 100px; height: 100px;
margin: 0 auto; /* this is important */
}
<footer>
<div></div>
<div></div>
<div></div>
<div></div>
<footer>
If you really need to support older browsers i.e. back up to IE-8, FF-31, GC-31 etc., then you could make use of display:table and display:table-cell to achieve that. This is also very simple, but you would have to change your markup a little bit. Just wrap your inner-divs inside wrapper-divs. Apply display to the footer container and the wrapper-divs.
The trick here is to use the display:table-cell on the wrapping divs which, will cause them to evenly distribute. But, this will cause them to stretch. To mitigate this, we apply vertical-align to the wrapper divs and also a margin: auto to the inner divs.
Fiddle: http://jsfiddle.net/abhitalks/Lvysyuuh/
Snippet:
#footer {
background-color: #000; opacity: 0.7;
width: 100%; height: 200px;
display: table; /* this is important */
}
#footer > div {
display: table-cell; /* this is important */
text-align: center; vertical-align: middle; /* this is important */
}
#footer > div > div {
border: 1px solid red;
width: 100px; height: 100px;
margin: 0 auto; /* this is important */
}
<div id="footer">
<div><div></div></div>
<div><div></div></div>
<div><div></div></div>
<div><div></div></div>
<div>
//HTML BLOCK
<div id="footer">
<div class="fbox"></div>
<div class="fbox"></div>
<div class="fbox"></div>
<div class="fbox"></div>
<div>
//CSS BLOCK
#footer {
display: flex;
display: -webkit-flex;
justify-content: center;
-webkit-justify-content: center;
align-items: center;
-webkit-align-items:center;
width: 100%;
background: black;
opacity: 0.7;
height: 200px;
}
.fbox {
display: flex;
display: -webkit-flex;
flex: 1;
-webkit-flex: 1;
min-height: 100px;
min-width: 100px;
max-width: 100px;
max-height: 100px;
margin: 0 auto;
border: 5px outset #ea2f2f;
}
Alternative to flex box if you can't use that for compatibility reasons:
The formula for the width of the space between blocks is (footer_width - 4*box_width)/5. Basically you've got a percentage width minus a fixed width: footer_width/5 - 4*box_width/5 ->
20% of footer width - 4*110px/5 -> 20% - 88px. Note the boxes actually take up 110px because of the border. We can do this at least two ways:
Using float:
You want 20% - 88px between each box. Float each box to the left with a margin-left of 20%. Then pull the boxes to the left by setting a negative right margin on each box. this does not effect the first box, but does make the space between boxes correct, so position all of them relatively and move them over 88px to the left.
#footer {
width: 100%;
clear: both;
background-color: black;
opacity: 0.7;
height: 200px;
box-sizing: border-box;
position: relative;
}
div div {
border: 5px outset #ea2f2f;
width: 100px;
height: 100px;
float:left;
margin-left:20%;
margin-right:-88px;
position:relative;
left:-88px;
top:45px;
}
This way feels a little fragile to me, but I can't immediately see why...
Using absolute positioning:
You want 20% - 88px between each box. Start with the first box. Move it over 20%, then back left 88px by using the left and margin-left properties. Next box we need to move the same, but from the right edge of the first box, so we need to move it over 20% - 88px + 110px to get to the right edge of the first box, then the +20% - 88px again, giving 40% - 66px. Repeat for each box. You can see the pattern below. Note the position:relative on #footer.
#footer {
width: 100%;
clear: both;
background-color: black;
opacity: 0.7;
height: 200px;
box-sizing: border-box;
position: relative;
}
div div {
border: 5px outset #ea2f2f;
width: 100px;
height: 100px;
position: absolute;
top:45px;
}
#fbox1 {
left: 20%;
margin-left: -88px;
}
#fbox2 {
left: 40%;
margin-left: -66px;
}
#fbox3 {
left: 60%;
margin-left: -44px;
}
#fbox4 {
left: 80%;
margin-left: -22px;
}
You might also be able to use inline-block with text-align:justify as seen here: "text-align: justify;" inline-block elements properly?
Hope this helps!
EDIT:
Just noticed your req that they be vertically centered as well. In this case, because you have a fixed height container and fixed height boxes, in both cases above you just have to nudge each box down by (200px - 110px)/2 = 45px which can be done with top:45px;.
I am battling with the positioned element that I want to be able to resize.
I have an element that has a position absolute.
Inside I am making three divs, .left, .center, .right.
I want to be able to resize element dragging on .left, .right, which will shrink the element down.
(I do not include JS to dragging, it is irrelevant so far - you can just increase/decrease width of an element in a console).
Question:
My problem is that elements don't seem to align inside the div - content of .center and .right are pushed down. If I make them float, on resizing the element same behavior appears.
And because I am going to resize the .holder element width, I am not in control of the width of .center element, so technically it should just shrink to fit to width minus width of .left and .right.
I made this jsfiddle for the question.
Edit: updated, merged .holder and .second into .second
Edit: I didn't make that clear, but height cannot grow above 60 pixels.
Edit: The text in center can be hidden, if element is super small in width, I don't care for the text.
Edit: thank you everyone who participated! everyone was close with the table positioning. i didn't use it before.
Selecting this: jsfiddle.net/abhitalks/c5L6tLt0/25 and http://jsfiddle.net/abhitalks/1o3vbhhp/ fiddles as what I needed, I am still further to find how to shrink it to just .left and .right and keep height to 60pixels, but these 2 are very close to what I was looking for.
Thank you everyone again!
html:
<body>
<div class="first">
<div class="second">
<div class="left"></div>
<div class="center">Should be center</div>
<div class="right"></div>
</div>
</div>
</body>
css:
.first {
position: relative;
border: solid 1px green;
width: 600px;
height: 600px;
}
.second {
position: absolute;
border: solid 1px red;
left: 100px;
top: 10px;
}
.left, .right, .center {
height: 60px;
}
.left, .right {
min-width: 1px;
width: 5px;
max-width: 5px;
background-color: skyblue;
}
You could make use of display: table on container and display: table-cell on .left, .center, .right divs to fit.
Giving a width:100% to .center will cause to stretch to available space. Changing widths is then easy.
In the example snippet below, you can try changing width by clicking .left (to reduce) or .right (to increase).
Your updated fiddle: http://jsfiddle.net/abhitalks/c5L6tLt0/22/
Code Snippet:
$(".right").on("click", function () {
$(this).parent().css("width", "+=10px");
});
$(".left").on("click", function () {
$(this).parent().css("width", "-=10px");
});
.first {
position: relative;
border: solid 1px green;
width: 400px; height: 240px;
}
.second {
position: absolute;
border: solid 1px red;
left: 100px; top: 10px;
width: 120px; height: 60px;
display: table; transition: all 250ms;
}
.left, .right, .center {
display: table-cell;
height: 100%;
overflow: hidden; text-align: center; vertical-align: middle;
word-wrap: break-word; word-break: break-all;
}
.left, .right {
min-width: 5px; width: 5px; max-width: 5px;
background-color: skyblue; cursor: pointer;
}
.center { width: 100%; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<div class="first">
<div class="second holder">
<div class="left" title="Click to shrink"></div>
<div class="center">Center</div>
<div class="right" title="Click to grow"></div>
</div>
</div>
</body>
If you want to remove height restrictions and make it grow or shrink as per contents, then simply remove the height from all divs.
See this fiddle: http://jsfiddle.net/abhitalks/1o3vbhhp/
If you want contents to be hidden or scrolled when the div width is changed, then table-cell won't allow that. You will have to wrap an inner div to do that.
Fiddle with inner div scroll: http://jsfiddle.net/abhitalks/c5L6tLt0/23/
Fiddle with contents hidden and height fixed: http://jsfiddle.net/abhitalks/c5L6tLt0/24/
Or this, if you are happy with word breaks to allow smaller size upto 1 character:
Fiddle with word break: http://jsfiddle.net/abhitalks/c5L6tLt0/25/
.
Remove the following section from your CSS
.holder {
width: 100px;
height: 60px;
}
Why are you applying two classes on same div anyway ?
UPDATE
here is the updated code that might work for you. Treat your Div as Table. Its very lightweight and powerful.
.first {
display: table;
border: solid 1px green;
}
.second {
display: table-row;
border: solid 1px red;
left: 100px;
top: 10px;
}
.left, .right, .center {
display:table-cell;
}
.left, .right {
min-width: 1px;
width: 5px;
max-width: 5px;
background-color: skyblue;
}
Do you want them displayed as table cells?
.holder {
width: 300px;
height: 90px;
display: table;
}
.left, .right, .center {
display: table-cell;
vertical-align: middle;
text-align: center;
}
http://jsfiddle.net/c5L6tLt0/20/
Remove the following .holder CSS as #Adnan said
and add the following
.left .right .center {
max-width: 200px;
overflow: auto;
}
overflow property will add scrollbar when your content exceeds 200 x 60 dimension.
I am trying to align these blocks so they are expandable, but also inline. But I can't seem to get them to maintain their own space correctly. The layout I am going for is as follows
Where box 2, and 3 are auto expanding to fill in space on whatever resolution is viewing.
JSFiddle and JSFiddle 2
CSS / HTML:
.container {
width: 75%;
min-width: 1005px;
max-width: 1428px;
height: 330px;
margin: 0 auto;
background-color: gray;
}
.box1 {
float: left;
width: 455px;
height: 250px;
background-color: rgba(0, 0, 0, 0.75);
margin-right: 5px;
margin-bottom: 5px;
}
.box2 {
float: left;
width: 75%;
min-width: 340px;
height: 250px;
background-color: rgba(100, 50, 50, 0.75);
margin-right: 5px;
margin-bottom: 5px;
}
.box3 {
float: left;
width: 25%;
min-width: 190px;
height: 250px;
background-color: rgba(50, 50, 100, 0.75);
margin-right: 5px;
margin-bottom: 5px;
}
.box4 {
display: block;
width: 100%;
height: 60px;
background-color: rgba(50, 100, 50, 0.75);
}
<div class="container">
<div class="box1">Test</div>
<div class="box2">Test</div>
<div class="box3">Test</div>
<div class="box4">Test</div>
</div>
Here are three techniques
"Show code snippet" and run to see the complete example.
#1 - display: inline-block and calc
Compatibility: IE 9 + and all modern browsers. There are workarounds to get this working with IE8+ if needed.
The margins and fixed column are removed from the percentage calculation with width: calc(50% - 60px)
The divs are given min-height: 100% and will re-size with content. This is possible thanks to
html,body { height: 100%; }
The inline gap is removed by placing the closing div tags right next to the next opening tag. More info here.
Example
Note: The child selectors can be replaced with class selectors if wanted.
html,
body {
height: 100%;
margin: 0;
}
div {
background: #f50057;
min-height: calc(50% - 5px);
width: calc(50% - 60px);
display: inline-block;
vertical-align: top;
margin-right: 10px;
}
/*Fix first div*/
div:first-child {
width: 100px;
}
/*Remove third divs right margin*/
div:nth-child(3) {
margin: 0;
}
/*Top margin for last div*/
div:last-of-type {
width: 100%;
display: block;
margin: 10px 0 0;
}
<div></div><div></div><div></div><div></div>
#2 - display: table / display: table-cell
Compatibility: IE 8 + and all modern browsers
The top three divs are wrapped in a div with display: table
The top three divs are given display: table-cell
The fixed left div is given a fixed width
To allow the "cells" to evenly spread out the available width, the wrapper is given table-layout: fixed
The spacing between the top three divs is given by the border property. This is calculated into the percentage calculation thanks to * { box-sizing: border-box }
The bottom div is outside the wrapper and is given display: block. It is given a top border to create the faux margin
Example
* {
box-sizing: border-box;
}
html,
body {
height: 100%;
margin: 0;
background: #000;
}
.table {
display: table;
height: 50%;
width: 100%;
table-layout: fixed;
border-collapse: collapse;
}
.table > div {
background: #f50057;
display: table-cell;
border-left: solid 10px #FFF;
}
.table > div:first-child {
border-left: none;
width: 100px;
}
.footer {
width: 100%;
display: block;
background: #f50057;
height: 50%;
border-top: solid 10px #FFF;
}
<div class="table">
<div></div>
<div></div>
<div></div>
</div>
<div class="footer"></div>
#3 - The future! display: flex
Compatibility: IE 11, all modern browsers and Safari (with -webkit- prefix)
This is my favourite! Mainly due to the fact that I created it in about 3 minutes.
The top three divs are wrapped in a container with display: flex
The first div is given its fixed pixel width and flex: 0 0 auto. This tells the div not to grow or shrink
The 2 flexible divs are given flex: 1 and will grow and shrink as needed; automatically ignoring the fixed column
The last div is outside the flex container and is independent
The height and widths of the flexible divs are created with viewport width (vw) and viewport height (vh) units.
Refer here for a fantastic flexbox guide.
Example
* {
box-sizing: border-box;
}
body {
margin: 0;
}
.flex {
display: flex;
height: 50vh;
width: 100vw;
}
.flex > div {
background: #f50057;
flex: 1;
margin-left: 10px;
}
.flex > div:first-child {
width: 100px;
flex: 0 0 auto;
margin: 0;
}
.footer {
width: 100%;
display: block;
background: #f50057;
height: calc(50vh - 10px);
margin-top: 10px;
}
<div class="flex">
<div></div>
<div></div>
<div></div>
</div>
<div class="footer"></div>
Its not perfect but seems to do what you want with css tables.
<div class="table">
<div class="trow">
<div class="tcell">box1</div>
<div class="tcell">box2</div>
<div class="tcell">box3</div>
</div>
</div>
<div class="table">
<div class="tcell last">box4</div>
</div>
.table{display:table; width:100%; text-align:center;}
.tcell{display:table-cell; background:#000; color:#fff; min-height:100px; padding:20px; border:1px solid #fff; }
.trow{display:table-row; }
.last{ background:red; }
.trow .tcell:first-child{ width:300px; }
http://jsfiddle.net/fjsvnrLp/5/
You dont actually need the row