I have a list of items in an unordered list inside a div with overflow hidden. The items in the list are represented by boxes with text content and a border round them. It can be a long list of useful, but not essential information, that can be hidden if used on a smaller device.
If some items in the list overflow I would like to set the entire item that overflows as hidden, not just part of it.
currently the list can look like this when clipped:
---------
| A |
| |
---------
---------
| B |
Since B overflows only half of it is displayed. I would like only A to be displayed if this occurs.
The items do not have to be in an unordered list, can be in whatever. Is it any way to do this with only html and css?
I am able to do it in jQuery, but I just wonder if there is a css way to do it.
It is possible with the "Flex" property. See: http://jsfiddle.net/dsmzz4ks/
In the fiddle, make the window display width smaller. You will see whatever list items that don't fit are removed completely until the window gets bigger again.
It is a bit hokey in that it is adding the bullet using the li:before clause but it works nonetheless.
CSS:
.box {
width: 30%;
float: left;
margin: 8px 16px 8px 0;
position: relative;
border: 1px solid black;
padding: 15px;
}
ul {
height: 90px;
display: flex;
flex-direction: column;
flex-wrap: wrap;
overflow: hidden;
padding-left: 15px;
justify-content: space-around;
margin: 0;
}
li {
display: block;
width: 100%;
padding-left: 10px;
position: relative;
}
li:before {
content: '\2022';
position: absolute;
left: -5px;
}
The key properties here is that display: flex uses flex box on the parent. flex-direction: column makes sure that the order of elements is vertical, while flex-wrap: wrap wraps any overflowing element to another column. This can be shortened to:
display: flex;
flex-flow: column wrap;
If all children elements are behaving in such a way that they are covering the entire width of their parent, then that means any overflowing elements are wrapped into another column, effectively being hidden from view and avoiding any clipping.
Related
I am currently designing a book website and on the right-hand side want to have a "Table of contents" which is in a fixed position and scrollable. I set the header for my website to "display: table-row" and similarly did so with the table of contents and its internal elements. (A header and a the scrollable list of chapters) As I understand it, display: table row should make a div element fill the remaining height and only the remaining height. [1] However, in this case, the content continues offscreen instead of allowing the user to scroll through it. (You can see the problem on this jsfiddle: https://jsfiddle.net/chrmon2/9wzjckvn/6/)
My css:
#container {
height: 300px;
border: 1px solid black;
}
#header {
background: blue;
display: table-row;
}
#toc h1 {
background: red;
display: table-row;
}
#toc #content {
background: yellow;
overflow-y: scroll;
display: table-row;
}
Is this not a capability of display: table-row or am I doing something wrong? Thanks
https://www.whitebyte.info/programming/css/how-to-make-a-div-take-the-remaining-height
As I understand it, the effect you want is as follows:
When there is remaining space, stretch the table of contents items;
When the space is too small, begin scrolling.
This is an ideal application of CSS Flexboxes. Flexboxes allow you to define how items stretch (or don't), how they align with each other, how they wrap etc.
In this case, we're going to use flexboxes for all the divs in this example.
.container, .toc, .content {
display: flex; /* begins flexbox layout */
flex-direction: column; /* Flexboxes can be aligned from left-to-right
or from top-to-bottom. In this case, we want
them to be top-to-bottom. */
flex-grow: 1; /* On .container, this does nothing. However, for
children of Flexboxes, this tells them to grow
if any space is still available. */
min-height: 0; /* For a more complicated reason, this is necessary
to make flexboxes scroll correctly. This needs
to be set on all the flexboxes in this example. */
}
.toc .content .item {
flex-grow: 1; /* Make items grow when there is room available */
}
.content {
overflow-y: scroll;
}
You can see the effects of this at this JSFiddle.
Just remove display: table-row from #toc #content and add this :
#content{
max-height:200px;
}
height can be as per your requirement.
This question already has answers here:
Can't scroll to top of flex item that is overflowing container
(12 answers)
How to use safe center with flexbox?
(3 answers)
Closed 5 years ago.
I have the following situation, the text get cuts off at the top when it not longer fits inside the container. What can I do to fix that? I'd still like the text to be centered if it's smaller than the container, and I can't change the container size.
div {
display: flex;
align-items: center;
width: 100px;
height: 50px;
overflow: auto;
word-break: break-word;
}
<div>
sdjhfkahsdkjfadsfhk jaskjfsj fsldflkasjklsjflakj flksjfakljflksjflkasfjklasjflfd
</div>
The problem here is caused by the fact that when using align-items (or justify-content) to center a flex row item, it will, by design, overflow at its top/bottom (or left/right).
To solve that a new keyword, safe, is introduced, though not many browsers support it yet.
How to use safe center with flexbox?
The other option is to use auto margin's, though with the given markup you can't, as the text doesn't have an inner wrapper (well, it has an anonymous one, though those we can't target with a CSS selector).
So by adding an inner wrapper (fiddle with wrapper) you can use auto margin's, and is well explained here:
Can't scroll to top of flex item that is overflowing container
But sometimes we just can't change the markup, and when, here is a little trick, using the pseudo elements, and use auto margin's on them.
To vertical center the text we also need the flex direction to be column so the pseudo is rendered above/below.
Stack snippet
div {
display: flex;
flex-direction: column; /* added */
width: 100px;
height: 50px;
overflow: auto;
word-break: break-word;
border: 1px solid gray;
}
div::before, div::after {
content: '';
}
div::before {
margin-top: auto; /* added */
}
div::after {
margin-bottom: auto; /* added */
}
<div>
sdjhfkahsdkjfadsfhk jaskjfsj fsldflkasjklsjflakj flksjfakljflksjflkasfjklasjflfd
</div>
<div>
sdjhf
</div>
If you wrap the text into another tag, and set margin: auto 0; it seems to be working well.
div {
display: flex;
width: 100px;
height: 50px;
overflow: auto;
word-break: break-word;
background: pink;
margin-bottom: 20px;
}
span {
margin: auto 0;
}
<div>
<span>sdjhfkahsdkjfadsfhk jaskjfsj fsldflkasjklsjflakj flksjfakljflksjflkasfjklasjflfd</span>
</div>
<div>
<span>sdjhfkah</span>
</div>
I would like to make a row consisting of three columns, where the left column is always on the left, and the right two columns are joined together (i.e. wrap together to the next line, if there is not enough space). This is easily achievable using flex and may look like this: https://jsfiddle.net/znxn9x1r/
The catch here is that I would also like the middle column (violet colored always-right/left) to be shrinkable up to some min-width using text-overflow: ellipsis. This means that when I start lowering the width of the page, the middle column should first start shrinking, and only after it is no longer possible, then the right two columns should wrap to the next line.
A mockup of what I want to achieve:
Then when the shrinking reaches the min-width of the middle column, it should wrap to the next line as before:
Now if there was no left yellow column and the whole row consisted only from the two right columns, I could use the answer from the following question: How to keep a flex item from overflowing due to its text?
This really behaves like it should, but only after the right group already wraps:
It does not shrink the middle column when it is still on the same line as the first yellow column:
^^ This should not happen, there is enough space for an ellipsis!
Here is my code, is it possible to achieve what I want with pure HTML/CSS?
* {
padding: 5px;
}
#container {
background-color: lightgreen;
display: flex;
flex-wrap: wrap;
}
#always-left {
background-color: yellow;
margin: auto;
margin-left: 0;
}
#right-group {
margin: auto;
margin-right: 0;
display: flex;
}
#shrinkable {
background-color: violet;
vertical-align: middle;
order: 1;
flex: 0 1 auto;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
#not-shrinkable {
background-color: lightblue;
vertical-align: middle;
order: 2;
flex: 1 0 auto;
}
<div id="container">
<div id="always-left">
always-left
</div>
<div id="right-group">
<div id="shrinkable">
always-right / left
</div>
<div id="not-shrinkable">
always-right / right
</div>
</div>
</div>
https://jsfiddle.net/mnmyw245/
One method that may work for you involves disabling flex-wrap: wrap on the flex container.
#container {
background-color: lightgreen;
display: flex;
/* flex-wrap: wrap; <-- REMOVE THIS */
}
This forces everything to stay on the same line.
Then, when you feel it's okay for wrapping to begin, restore wrap with a media query.
This takes wrap control away from the browser and puts it in your hands.
Here's an example:
#media ( max-width: 200px ) {
#container { flex-wrap: wrap; }
}
revised fiddle
I am developing a forum theme at the moment, and am trying to figure out how to do the last bits, the posts. Example of what I'd like to make:
So the key things to keep in mind here is how User Info and Post Content have different colors, as well as the Post Description in the grid is in the same column as the Post Content.
Using a simple div setup doesn't work, as I need the User Info height to control the height of Post Content and vice versa. Having a wrapper element with the background color of User Info would work, but only if the Post Content is taller than User Info.
I am really just looking for brainstorming here. What would be the best way to go about doing this?
I created a draft of what the final result should look like here:
It should be fine with the code you have provided altered slightly, but I have some questions.
1) You commented the description has a set height? Does it need to? Worst case scenario I just adjust this height in media queries.
2) I probably need to have some columns within Post description too. As you see in my draft there's a left container with the timestamp (let's call that desc-meta) of the post, and to the right there's a permalink with ID (let's call that desc-ID). There's also a set of post options (Edit, report etc.) between the two (let's call that desc-edit), but aligned to the right side of the description. From my brief understanding of flex I can't figure out how to always keep the desc-meta and desc-ID on the same row, while desc-meta can be moved down if needed on smaller screens.
This layout can be achieved with CSS flexbox.
For both columns to have equal height we can use the align-items property, which controls space distribution among flex items on the cross-axis.
The default value is stretch, which enables items to extend the full length of the container.
.container-outer { align-items: stretch; }
We can also use the flex-grow property to control how free space is distributed among flex items in the main-axis.
.post-content { flex-grow: 1; }
The code below renders this (with borders only for demo purposes):
.container-outer {
display: flex;
align-items: stretch; /* tells boxes to stretch vertically (default value) */
width: 75%;
min-height: 250px;
border: 5px solid mistyrose;
}
.user-info {
display: flex; /* nested flexbox, to enable flex properties */
flex-direction: column;
justify-content: center;
align-items: center;
width: 25%;
border: 3px solid red;
font-family: verdana;
font-weight: bold;
font-size: 2em;
color: red;
box-sizing: border-box;
overflow: auto;
}
.container-inner {
display: flex; /* nested flexbox */
flex-direction: column;
width: 100%;
border: 3px dashed black;
overflow: auto;
}
.post-description {
display: flex; /* nested flexbox */
justify-content: center;
align-items: center;
height: 50px; /* fixed height */
border: 3px solid green;
font-family: verdana;
font-weight: bold;
font-size: 1.5em;
color: green;
box-sizing: border-box;
overflow: auto;
}
.post-content {
display: flex; /* nested flexbox */
justify-content: center;
align-items: center;
flex-grow: 1; /* box takes all available space (stretch, basically) */
border: 3px solid blue;
font-family: verdana;
font-weight: bold;
font-size: 2em;
color: blue;
box-sizing: border-box;
overflow: auto;
}
<article class="container-outer">
<section class="user-info">USER<br>INFO</section>
<div class="container-inner">
<section class="post-description">POST DESCRIPTION</section>
<section class="post-content">POST CONTENT</section>
</div><!-- end .container-inner -->
</article><!-- end .container-outer -->
jsFiddle
Regardless of how much or how little content is placed in USER INFO or POST CONTENT, both columns will remain equal height.
The container is given a minimum height (min-height: 250px;) to ensure it doesn't get too small if there is no content in either box.
flex-grow is only applied to POST CONTENT because USER INFO already expands full height by inheriting height from the container, and POST DESCRIPTION has a fixed height, so it won't expand.
Browser support: Flexbox is supported by all major browsers, except IE < 10. Some recent browser versions, such as Safari 8 and IE10, require vendor prefixes. For a quick way to add prefixes use Autoprefixer. More details in this answer.
My initial thoughts would be to do something like this:
<div class="one">
</div>
<div class="container">
<div class="two">
</div>
<div class="three">
</div>
</div>
And then give the left div a display of inline-block and the right container of inline-block, and the inner divs remain block.
.one {
display: inline-block;
}
.container {
display: inline-block;
}
I would use display: table with the corresponding rows/cells. See this http://jsfiddle.net/ycsmo9vg/ it should be easy extend this for your needs
notice how in the second cell, I have 2 divs, 1 has class row and the second div is plain (no class needed). This is up to you. Since a div is a block level element it will automatically take a row. Though I'd say keep it consistent and have a class of row wherever you have a row
I am trying to setup a form such that:
All inputs will be horizontally aligned, even when they have no label.
Inputs will be vertically aligned within their row for when the label wraps.
The inputs will stretch to fill the remaining space (or squished)
The submit button will fill an entire row.
I have achieved the first and fourth requirements but I am having trouble with making the inputs fill the row and be vertically aligned.
Here's my progress so far:
http://jsbin.com/kozozabo/3/edit?html,css,output
The LESS:
* {
box-sizing: border-box;
padding: 0;
margin: 0;
}
#narrow-form {
width: 300px;
overflow: hidden;
padding-right: 0.5em;
}
#wide-form {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
margin-left: 300px;
}
.row {
#label-width: 100px;
width: 100%;
overflow: hidden;
label {
width: #label-width;
float: left;
display: inline-block;
}
.no-label {
margin-left: #label-width;
}
input, select {
/* Trying to make these aligned to the right of
* their respective labels filling any remaining
* width.
*/
display: inline-block;
}
button {
width: 100%;
}
}
I tried giving the inputs absolute positioning with a left margin of the same width of the label but that didn't work.
Okay I have come up with a solution that I am happy with. It does involve some table abuse unfortunately.
I have only tested this in Chromium.
http://jsbin.com/kozozabo/5/edit?output
I set the form to display: table, each .row to display: table-row and the labels, inputs, selects and buttons to display: table-cell.
This made everything line up and fill all available space.
I then added two new classes intended to be affixes to the .row class, this is where the real table abuse begins.
.no-label - With the intent of "skipping" the first psuedo-cell. To accomplish this I defined it as such:
.no-label:before {
content: "";
display: table-cell;
}
Essentially inserting a hidden cell, forcing the subsequent inputs to be in the second column.
.full-width - With the intent of making it's contents the full width of the "table". To accomplish this I defined it as such:
.full-width {
display: table-caption;
caption-side: bottom;
}
A table caption spans the entire width of the table. I know I am only going to do this to the button so I forced it to be at the bottom with caption-side.
It would have been better to just define the DOM as a table but I didn't want to reprogram the javascript that was setting up this form. I always wouldn't get to of played with css, all be it in a menacing manner.