overflow-x container with variable width items - html

I'm trying to get a vertical navigation list that will allow for elements that are wider than the nav itself. Users can enter whatever names they like for items that will appear here, so I have no control over their width, aside from maybe a very high max character length.
I've tried a few different methods, and seem to be coming up with multiple ways to achieve the same wrong result, once with flexbox once without. In both cases, if I have some "normal" sized elements that don't overflow outside of the nav, they look fine at first. But if I have an oversized element that overflows outside the container, and the user scrolls to the right, they will see the items boundaries don't extend to the right.
If I use the outer "item" for visual styling (light blue), they all end up the same width, but not wide enough to account for the overflow. If instead try styling the inner item (green), it is the correct width for only the overflowing item, and all the rest of the items are different widths based on their length.
Is there a way to:
Have all items appear to be the same width when there is a large item that overflows larger than the container
Without setting some arbitrary width, because I don't have control over how long the user strings might be
CSS only, no javascript
Initial View, looks ok...
Scroll to the right... looks bad!
Codepen
Here's the Codepen
HTML
<div id="container">
<div class="item"><span>Item 1</span></div>
<div class="item"><span>Item 2</span></div>
<div class="item"><span>Item 3</span></div>
<div class="item"><span>Item 4</span></div>
<div class="item"><span>Super Long Item Name of Obliteration</span>
</div>
</div>
<div id="flex-container">
<span class="flex-item"><span>Item 1</span></span>
<span class="flex-item"><span>Item 2</span></span>
<span class="flex-item"><span>Item 3</span></span>
<span class="flex-item"><span>Item 4</span></span>
<span class="flex-item"><span>Super Long Item Name of Obliteration</span>
</span>
</div>
CSS
#container {
width:200px;
height:400px;
background-color: red;
overflow:auto;
}
.item {
height: 40px;
border: 1px solid blue;
background-color:lightblue;
white-space: nowrap;
}
#flex-container {
width:200px;
height:400px;
background-color: red;
overflow:auto;
display: flex;
flex-direction:column;
}
.flex-item {
height: 40px;
border: 1px solid blue;
background-color:lightblue;
white-space: nowrap;
}
/* Content */
span > span,
div > span {
background-color: green;
}

Use overflow and text overflow
.item,
.flex-item {
overflow: hidden;
text-overflow: ellipsis;
max-width: 100%:;
}
Codepen link

Related

Set max-width of element based on sibling using flexbox

I'm working on a layout for a thumbnails component which contains an image and text element. The images have a height: 100px; and auto width, while the text should span up to the width of the image width and the overflow should be hidden.
<div>
<img src="...">
<span>a bunch of text that should be cut off</span>
</div>
I've tried accomplishing this using flexbox but I can't get the text width to be equal to the image width. Instead, the text just grows 100% and stretches out the image.
See my jsbin
You need to specify container's width -> so that your text box knows it's width.
You need tell text to not wrap.
You need to hide the overflowing text.
You need ellipsis for overflowing text.
Following code works:
.main {
border: 1px solid red;
display: flex;
flex-wrap: wrap;
width: 50%; // px would also work
}
.main img {
height: 100px;
flex: 0 0 100%;
}
.main div {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
<div class="main">
<img src="http://i.imgur.com/uiGur1h.jpg" alt="">
<div>Text go here </div>
</div>
<div class="main">
<img src="http://i.imgur.com/uiGur1h.jpg" alt="">
<div>Text would go here but would be cut off if it's very long </div>
</div>
Refer example in https://developer.mozilla.org/en/docs/Web/CSS/text-overflow

Make spans in div horizontally scrollable

I have a container div (fixed width, float left) and a set of spans (fixed width and height) inside the container.
<div id="cont">
<span class="box">1</span>
<span class="box">2</span>
<span class="box">3</span>
...
</div>
While reaching the width of the container, the spans are broken to a new row. How can I make them stay in one row next to each other and have the area scrollable horizontally?
Here is the jsFiddle.
Thanks very much in advance!
Simply add white-space:nowrap; to #cont:
The white-space CSS property is used to to describe how white spaces
inside the element is handled.
nowrap collapses whitespace as for normal, but suppresses line breaks
(text wrapping) within text.
#cont {
overflow: auto;
width: 500px;
float: left;
white-space: nowrap;
}
.box {
background-color: #BBBBBB;
height: 100px;
display: inline-block;
margin: 5px 4px 5px 10px;
width: 100px;
}
<div id="cont">
<span class="box">1</span>
<span class="box">2</span>
<span class="box">3</span>
<span class="box">4</span>
<span class="box">5</span>
<span class="box">6</span>
<span class="box">7</span>
</div>
Just add
white-space:nowrap;
to your container div
fiddle here:http://jsfiddle.net/g1e3ztnu/3/
You are setting a width in the #cont. Remove the width: 500px to width : auto; If you want to force it with the widht you have you must set a new rule: white-space: nowrap.
Option 1 - CSS
#cont {
overflow:auto;
width:auto;
}
Option 2 - CSS
#cont {
overflow:auto;
width: 500px;
white-space: nowrap;
}
DEMO HERE

HTML position variable

I know this is easy with Javascript but... is there any way with just CSS?
Let's say we have two elements (green and red) within a parent one (beige). The red element should be always to the right of the green one, except if the green one (because of the content) is too big to fit the parent in which case the red one will be over the green one (the normal behaviour would be the red element staying to the right of the green one and therefore being hidden because of the overflow of the parent)
In other words: red.x = min(green.x + green.w, beige.x+beige.w-red.w)
For more info, here's the concrete HTML:
<div class="beige" style="width:250px"> <!-- parent with a given width (unknown until the page is rendered) & overflow hidden -->
<a class="green"> <!-- link with display:inline -->
content
<em class="red"></em> <!-- actually a button, 15 px width -->
</a>
</div>
EDIT: #kyledws answer is awesome but I'll update the question with more info (needed things) such as:
red is only displayed when green:hover (that's why it's inside green)
you don't know beige width in CSS (in the real world beige is inside a with defined width but not known until the page is rendered)
green content is a variable length text, and the reason of red being pushed
if the green content does not fit into the parent, it should show the ellipsis (text-overflow: ellipsis; overflow: hidden)
must work in IE8+
If you're able to wrap the content inside <a> in a span then try this.
HTML
<div class="beige">
<a class="green" href="#">
<span class="content">This is some text.</span><em class="red"></em>
</a>
</div>
CSS
.beige {
background-color: #EBDFA0;
height: 32px;
overflow: hidden;
border: 4px solid #EBDFA0;
white-space: nowrap;
width: 400px;
}
.green {
background-color: #4CA73D;
color: #222;
display: inline-block;
height: 100%;
text-decoration: underline;
vertical-align: middle;
}
.content {
display: inline-block;
height: 100%;
margin-left: 4px;
position: relative;
width: 100%;
max-width: 364px;
top: -50%;
}
.red {
border: 2px solid red;
display: inline-block;
height: 28px;
position: absolute;
width: 28px;
}
Essentially the <a class="green">, <span class="content"> and <em class="red"> need to be display: inline-block and the <span class="content"> has to be width: 100% with a max-width of the different between the <div class="beige"> and the <em class="red" minus any additional padding/margin/border etc. (So in this example, max-width: 364px) By setting a width on the span you force the em outside of it's container but by setting a max-width you stop the em from flowing outside of the main wrapper.
Here is a codepen.io link to an example.
(Note: Most of the CSS above is just to make the example look like your images.)
UPDATE:
To show or hide the <em class="red"> add the :hover pseudo-class to .beige and visibility or opacity to .red. (Use opacity if you want to use a transition.)
.red {
opacity: 0;
}
.beige:hover .red {
opacity: 1;
}
Because the width of <div class="beige"> is unknown you can't use CSS to set max-width on <span class="content">.
(The 100% in max-width: calc(100% - 28px) is width of <a class="green"> not <div class="beige">. I couldn't hack it with pseudo-elements, positioning, floats or different display types like flex either.)
The way around this is to fix the max-width of the <span class="content"> in CSS (as is shown above) or use Javascript to detect the width of <div class="beige"> and then set the max-width.
content.style.maxWidth = beige.clientWidth - red.clientWidth + "px";
I updated the example with visibility and Javascript versions.
Also, I added position: absolute to .red so <span class="content"> doesn't have empty space on the right.
So I found a way that you can handle this in just CSS. I have setup a jsbin with a example. I don't have a fancy slider so you will need to use the inspector tool to resize the width or do it manually.
Basically I set up a dive as a table. Because you can't drop to different rows the right most column is forced to collapse but leaves the block visible because it is position absolute. The size of the container is based on the block which has been changed to a inline block to maintain the coloration and push its parent to become larger. Excuse me not making the styles match exactly what you had int he graphics.
http://jsfiddle.net/93u5E/3/
HTML
<div class="beige">
<div class="table">
<!-- parent with a given width & overflow hidden -->
<ul>
<li><a class="green"> <!-- link with display:inline -->
content
</a>
</li>
<li><em class="red"></em>
<!-- actually a button, 15 px width -->
</li>
</ul>
</div>
</div>
CSS
.beige {
background-color:grey;
overflow:hidden;
white-space:no-wrap;
}
.table{
display:table;
}
ul {
display:table-row;
list-style-type:none;
}
li {
display:table-cell;
position:relative;
}
li:last-child{
width:30px;
}
.green {
display:inline-block;
background-color:green;
}
.red {
border:3px solid red;
display:inline-block;
width:20px;
position:absolute;
right:0px
}
li:hover + li .red{
height:20px;
}
*Updating to include hover

only top-border is showing not complete border around container

Border is not displayed properly.Side and bottom ones
are missing.
here shorthand property is acting like top-border
property.
If we apply height tag to container than container than
borders are displayed correctly but it should work on its own.
CSS
.container
{
border:1px solid black;
}
.container DIV
{
width: 15px;
border: 1px solid Blue;
margin: 1px;
}
HTML
<div style="width: 200px; " class="container">
<div style="float: left;">1</div>
<div style="float: left;">2</div>
<div style="float: left;">3</div>
<div style="float: left;">4</div>
<div style="float: right;">5</div>
<div style="float: right;">6</div>
<div style="float: right;">7</div>
<div style="float: right;">8</div>
</div>
You need to provide more code (including the html that shows the actual container element). However, my guess from what you have said is that adding overflow:hidden to your style should fix it.
.container
{border:1px solid black;
margin:auto;
margin-top:33px;
overflow:hidden;
}
If elements within your container are floating, then the container acts like it has a height of 0. This would cause a border to be a single line at the top. Overflow:hidden gives it the height including any floating elements (see http://www.w3.org/TR/CSS21/visudet.html#root-height )
As I say, more code would be required to say if that is what the issue is in your case but it is a common cause of that style problem.
Update your container class like below.
.container
{
border:1px solid black;
display:table;
}
Fiddle DEMO
As you are using float property on child elements. to fix it just use overflow:hidden on parent element i.e. in your case use add overflow on class .container.
Here is a DEMO.
.container
{
border:1px solid black;
overflow:hidden;/* Added Line*/
}

What is the proper way to make an element fill the remaining vertical space in its container

I have a div with a set height which will hold arbitrary elements and another div that I wish to fill the remaining space, so that the div is filled.
jsfiddle
html:
<div class=container>
<div class=title>
<h1> title </h1>
</div>
<div class=body>
<h1> stuff here </h1>
</div>
</div>​
css:
.container {
border: 1px red solid;
height: 300px;
}
.title {
background: blue;
}
.body {
background: green;
}
I want the green div to fill the white space within the red border so that it looks like this but without setting the height explicitly, because the sizes of the title and containing divs are dynamic.
The way I would do it would be to put the title inside the body. Then you can set the body height to 100% (since its container has a fixed height) and the title will only fill what it needs, with its own background. By combining related elements into one container, it can be much simpler to move stuff around in your layout, too.
html:
<div class=container>
<div class=body>
<div class=title>
<h1> title </h1>
</div>
<h1> stuff here </h1>
</div>
</div>​
css:
.container {
border: 1px red solid;
height: 300px;
}
.title {
background: blue;
}
.body {
height:100%;
background: green;
}
You can always add another element inside the container to contain your multi-select, and have it inherit the properties of the parent container.