Overflow auto on unknown children height - css

I have an element (on which I know the width & height, I can't remove the height) with some elements inside. I've simplified it in the snippet so I just have a title (with unknown length) and a list.
I need the list (only the list, not the whole container) to be overflow: auto but I can't figure it out since I don't know its height and I can't use flexbox (IE9+ :/).
I want to avoid using JavaScript for this (I can do it in JavaScript but I really don't want a FOUC).
div {
margin: 20px;
padding: 15px;
border: 1px solid;
width: 200px;
height: 400px;
}
h1 {
margin-top: 0;
border: 1px dashed red;
}
ul {
margin: 0;
padding: 0;
overflow: auto;
}
li {
display: block;
padding: 5px 0;
border-top: 1px solid;
}
<div>
<h1 contenteditable>
My long title that can be on multiple lines
</h1>
<ul>
<li>a list</li>
<li>of element</li>
<li>that can</li>
<li>be long</li>
<li>that should</li>
<li>overflow auto</li>
<li>bla</li>
<li>bla</li>
<li>bla</li>
<li>bla</li>
<li>bla</li>
</ul>
</div>

You cannot make the height of both dynamic, without something like JavaScript.
For one to overflow, it needs a reference. Why would the list overflow but not the header for example?
You can go set the list position to absolute, but then you need coordinates for top and bottom, which you won't have because in CSS you can't get that from other element (the header).
Without something like flex, you other option is JS I think.
You can render the header and list with visibility hidden (not display block, so their dimentions can be calculated), and remove that once you apply your JS for minimal FLOC effect.

just add overflow-y: auto; to your container element
.wrapper {
margin: 20px;
padding: 15px;
border: 1px solid;
width: 200px;
height: auto;
display: inline-block;
}
h1 {
margin-top: 0;
border: 1px dashed red;
float: left;
}
.container {
overflow-y: auto;
height: 300px;
width: 100%;
float: left;
}
ul {
margin: 0;
padding: 0;
overflow: auto;
}
li {
display: block;
padding: 5px 0;
border-top: 1px solid;
word-break: break-word;
}
<div class="wrapper">
<h1 contenteditable>
My long title that can be on multiple lines
</h1>
<div class="container">
<ul>
<li>a list</li>
<li>of element</li>
<li>that can</li>
<li>be long</li>
<li>that should</li>
<li>overflow auto</li>
<li>blaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</li>
<li>bla</li>
<li>bla</li>
<li>bla</li>
<li>bla</li>
</ul>
<div>
</div>

If you can't use flexbox, use CSS tables:
Set the height of the table
Set height: 0 to the title cell to make it be only as tall as required by its contents.
Wrap the ul inside a table-row, which will take the remaining space left by the title.
Take the ul out-of-flow (to avoid circular definitions) and make it have the same sizes as that wrapper.
#container {
display: table;
margin: 20px;
padding: 15px;
border: 1px solid;
width: 200px;
height: 400px;
}
#container > h1 {
display: table-cell;
height: 0;
margin-top: 0;
border: 1px dashed red;
}
#container > div {
display: table-row;
position: relative;
}
#container ul {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: 0;
padding: 0;
overflow: auto;
}
li {
display: block;
padding: 5px 0;
border-top: 1px solid;
}
<div id="container">
<h1 contenteditable>
My long title that can be on multiple lines
</h1>
<div>
<ul>
<li>a list</li>
<li>of element</li>
<li>that can</li>
<li>be long</li>
<li>that should</li>
<li>overflow auto</li>
<li>bla</li>
<li>bla</li>
<li>bla</li>
<li>bla</li>
<li>bla</li>
</ul>
</div>
</div>

Here my JS solution for now, I'd like to have it in CSS if possible but it's working in the meantime:
const height = container.clientHeight - list.offsetTop
list.style.height = height + 'px'

There are couple of ways to do it
First would be just remove the height prop on div.
If you don't want to do so.. you can either choose to cut (overflow:hidden) or scroll overflow:scroll the list
ie, you div styling can be:
div {
margin: 20px;
padding: 15px;
border: 1px solid;
width: 200px;
height: 400px;
overflow: scroll; /* or hidden */
}
or just
div {
margin: 20px;
padding: 15px;
border: 1px solid;
width: 200px;
}
EDIT:If you dont want the whole container to overflow (as said in comments) just add max-hight to ul
your ul styling would be something like:
ul {
margin: 0;
padding: 0;
max-height: 100px; /*or anything you think appropriate */
overflow: auto;
}
and rest of the css can be same as in OP.

Related

Align item left, or right if no room left in window

How can you display an item per default in its "normal" position (preferably over any following items), like this:
div {
border: 1px solid black;
}
ul {
display: flex;
padding: 0;
list-style: none;
width: 250px;
border: 1px solid black;
}
li {
display: flex;
position: relative;
}
.item {
padding: 0.4em;
background-color: #f99;
}
.dropdown {
position: absolute;
left: 100%;
z-index: 1;
padding: 0.4em;
opacity: 0.7;
background-color: #2f6f44;
}
<ul>
<li>
<div class="item">First</div>
</li>
<li>
<div class="item">Second</div>
<div class="dropdown">Dropdown</div>
</li>
<li>
<div class="item">Third</div>
</li>
<li>
<div class="item">Fourth</div>
</li>
</ul>
but if the window becomes too small (represented by the ul here), it sticks to the right:
div {
border: 1px solid black;
}
ul {
display: flex;
position: relative;
padding: 0;
list-style: none;
width: 150px;
border: 1px solid black;
}
li {
display: flex;
}
.item {
padding: 0.4em;
background-color: #f99;
}
.dropdown {
position: absolute;
right: 0;
z-index: 1;
padding: 0.4em;
opacity: 0.7;
background-color: #2f6f44;
}
<ul>
<li>
<div class="item">First</div>
</li>
<li>
<div class="item">Second</div>
<div class="dropdown">Dropdown</div>
</li>
<li>
<div class="item">Third</div>
</li>
<li>
<div class="item">Fourth</div>
</li>
</ul>
In other words, if (this.left + this.width > totalWidth) stick right else stay left.
I can either get one or the other behaviour (like above), but not so that it switches seamlessly between the two.
The simplest solution is to compute the element width and the window width and position it using JavaScript, but bugs/edge cases easily slip in, so I'm trying to look for a complete CSS solution.
Any number of containers/wrappers are welcome. One solution I tried looking at was wrapping all the "following" elements (Third and Fourth in the examples above) in a separate li with Dropdown. That way a flex element can take up the space between the previous element (Second) and the edge of the container, but then Dropdown can't go any further left than Second (if the container gets too small).
The elements are dynamic in width based upon changing content.

Position element relative to parent element

For example I have fixed nav, is there a way to anchor the list items to the bottom of the nav? I attempted to give the list items a fixed position too but this messes up their layout as you can see at fiddle
here is my code:
#nav {
height: 75px;
width: 100%;
position: fixed;
top: 0;
z-index: 1;
border-bottom: 1px solid white;
background-color: #157FFB;
border-bottom: 2px solid #eeeeee;
}
#nav>ul {
list-style: none;
margin: 0;
}
#nav>ul>li {
display: inline;
/*these two lines were my attempt at anchoring the list items to the bottom f the #nav, but it throws everything out of wack*/
position: fixed;
top: 45px;
}
<div id="nav">
<ul>
<li class="align_left">LOGO</li>
<li class="align_right">Repairs/Upgrades</li>
<li class="align_right">Networking</li>
<li class="align_right">Remote Backups</li>
<li class="align_right">Data Recovery</li>
</ul>
</div>
Any suggestions on how this can be done?
When you use a fixed or absolute position it takes an element out of the flow of the document and hence they stack up on top of each other when you apply those positions to the li elements.
Instead you should be absolutely positioning the ul block to the bottom of the #nav:
#nav > ul {
list-style: none;
margin: 0;
position: absolute;
bottom: 0;
}
#nav > ul>li {
display: inline;
}
As I understand your question, you wish to have the list elements at the bottom of your header. Just change position: fixed; to position: relative;. This keeps the elements flow along with the flow of the page.
Here is your solution:
#nav{
height: 75px;
width: 100%;
position: fixed;
top: 0;
z-index: 1;
border-bottom: 1px solid white;
background-color: #157FFB;
border-bottom: 2px solid #eeeeee;
}
#nav > ul{
list-style: none;
margin: 0;
}
#nav > ul>li{
display:inline;
/*these two lines were my attempt at anchoring the list items to the bottom f the #nav, but it throws everything out of wack*/
position: relative;
top:50px;
}
<div id="nav">
<ul>
<li class="align_left">LOGO</li>
<li class="align_right">Repairs/Upgrades</li>
<li class="align_right">Networking</li>
<li class="align_right">Remote Backups</li>
<li class="align_right">Data Recovery</li>
</ul>
</div>
If you want something to be anchored to the bottom of an element, but still remain in the flow of the page, try using relative positioning. That essentially means you give the #nav element relative positioning, and you give the li elements relative positioning as well:
#nav {
height: 75px;
width: 100%;
position: relative;
top: 0;
z-index: 1;
border-bottom: 1px solid white;
background-color: #157FFB;
border-bottom: 2px solid #eeeeee;
}
#nav>ul {
list-style: none;
margin: 0;
}
#nav ul li {
display: inline;
position: relative;
top: 45px;
}
<div id="nav">
<ul>
<li class="align_left">LOGO</li>
<li class="align_right">Repairs/Upgrades</li>
<li class="align_right">Networking</li>
<li class="align_right">Remote Backups</li>
<li class="align_right">Data Recovery</li>
</ul>
</div>
This seems to work pretty well, please tell me if it doesn't.
The problem you encountered was that fixed positioning put them all in a mess. Fixed positioning positions ALL the items relative to the viewport, so if you had all the lis with
position: fixed;
top: 45px;
They would all go in the same spot.

What is this random extra space between these two elements(<li>)?

I have this problem. I searched the site and others were having similar problems, but none of the answers seemed to work. Those included setting line-height to 0px; and setting all margins/paddings to 0px. I use Google Chrome's Inspect Element material to check the margins/paddings. I hovered over my "a" element and "li" element to see if they had any unnecessary paddings or margins, but they didn't.
What was weird is that they had a little white space, not occupied by any element in the entire document, between each link.
Right now, as there are no borders between the text, it is unrecognizable, but the space around the "a" in Link4 is smaller than the space around the text in Link1. The width of the first "li" element is strangely 4px wider than the 4th "li" container, and there is a little white space. I want to get rid of the white space, any ideas?
Here is the code:
CSS:
html {
overflow-y: scroll;
}
body {
background-color: #ffdeff;
overflow: hidden;
}
#wrapper {
width: 1000px;
height: 0px;
overflow: hidden;
margin: auto;
background-color: white;
border-left: 1px solid rgb(210, 210, 210);
}
#header {
width: 1000px;
height: 0px;
overflow: hidden;
margin: auto;
}
#header-toolbar {
width: 1000px;
list-style-type: none;
border-radius: 3px;
position: absolute;
}
#nav-position {
position: absolute;
float: left;
padding: 0px;
margin: 0px;
}
.nav-link-container {
background-color: #FF66CC;
display: inline;
padding: 0px;
text-align: center;
}
.nav-link {
padding: 0px;
margin-top: 5px;
margin-bottom: 5px;
text-align: center;
line-height: 0px;
display: table;
display: inline;
margin: 0 auto;
}
HTML document:
<body>
<script src="jquery-1.9.1.js"></script>
<script>
</script>
<div id="wrapper">
<div id="header">
<div id="header-toolbar">
<ul id="nav-position">
<li class="nav-link-container">
<a class="nav-link">Link1</a>
</li>
<li class="nav-link-container">
<a class="nav-link">Link2</a>
</li>
<li class="nav-link-container">
<a class="nav-link">Link3</a>
</li>
<li class="nav-link-container">
<a class="nav-link">Link4</a>
</li>
</ul>
</div>
</div>
<div id="main"></div>
<div id="footer"></div>
</div>
</body>
</html>
Anything helps! Thank you very much!
there are some spaces when you put <li> to new line. so one solution is to add them all in same line like here: http://jsfiddle.net/6tzxj/1/

How do i align my Thumb Nail images horizontally in CSS?

I am trying to align a set of images horizontally within a div tag and then display a horizontal scroll bar when the images exceed the length of the div tag. I am relatively new to CSS and have tried everything I can think of. The below code displays my images vertically!!!
Thank you very much for any help.
Inside the body tag:
<div id="TNBox">
<ul class="imagelist">
<li>
<img id="tnimage1" src="images/tn-images/Rio-Street-Art-TN01.jpg">
</li>
<li>
<img id="tnimage2" src="images/tn-images/Rio-Street-Art-TN02.jpg">
</li>
<li>
<img id="tnimage3" src="images/tn-images/Rio-Street-Art-TN03.jpg">
</li>
<li>
<img id="tnimage4" src="images/tn-images/Rio-Street-Art-TN04.jpg">
</li>
<li>
<img id="tnimage5" src="images/tn-images/Rio-Street-Art-TN05.jpg">
</li>
</ul>
</div>
And the CSS:
#TNBox {
width: 500px;
height: 88px;
border: 1px solid black;
position: absolute;
left: 50px;
top: 320px;
overflow-x: auto;
display: inline-block;
text-decoration: none;
}
.imagelist {
list-style: none;
margin: 0px;
padding: 0px;
}
#TNBox{
width: 500px;
height: 88px;
border: 1px solid black;
position: absolute;
left: 50px;
top: 320px;
overflow-x: auto;
display: inline-block;
text-decoration: none;
white-space:nowrap;
}
.imagelist{
list-style: none;
margin: 0px;
padding: 0px;
}
.imagelist li{
display:inline-block;
}
Preview >> jsfiddle (I have styled images too)
Link to fiddle. I also changed the image urls to point to something that exists
http://jsfiddle.net/GVdMz/2/
Here is what I added:
To get the images to display horizontally
.imagelist li{
display: inline;
}
And this will make a horizontal scroll appear if the images extend past the width of #TNBox
#TNBox{
white-space:nowrap;
}

Fluid layout with even width navigation items

I'm building a site for mobile devices and therefore has a fluid layout.
My navigation list looks like this:
<ul>
<li>home</li>
<li>about</li>
<li>work</li>
<li>contact</li>
</ul>
Problem is, the first list item needs to be 100px only (left aligned always), and the other 3 split evenly, therefore is it possible to have even width for all list items except for the first one (without using javascript).
This is the simplest way I could think of:
ul { overflow: hidden; padding-left: 100px; position: relative; }
li { width: 33.33%; float: left; }
li:first-child { position: absolute; top: 0; left: 0; width: 100px; }
The main idea is taking the first li out of the flow (position: absolute) and adding a padding-left to the ul (space for the first li). Now if we set the percentage width for the other lis, they will take up the remaining space.
And here is a jsFiddle Demo. I added a red border on the ul which shows that because of the percentages lis will not accurately fill it.
I am unsure what mobile browsers you want to support, but except :first-child (which can be worked around by adding a class on the first list item) I assume they must support everything I used.
hmm a bit cludgy - but this seems to work, it does require nesting the list (second 3 links in separate list) and a span for the "home" link, theory is that you need the first link to float, width: 100px, then you need the second group not to float and have their overflow hidden so the group take up the remaining space.. then you float the 3 links # 33% inside the non-floated container
Example : HERE
CSS:
div {
width: 90%;
margin: 0 auto;
}
ul {
margin: 0; padding: 0; list-style: none; /* reset */
float: left;
width: 100%;
}
li {
float: left;
width: 100%;
text-align: center;
}
li span {
float: left;
width: 99px;
background: #eee;
border-right: 1px solid #000;
}
ul ul {
float: none;
overflow: hidden;
width: auto;
}
li li {
width: 33%;
background: #ffe;
border-right: 1px solid #000;
}
HTML:
<div>
<ul>
<li><span>home</span>
<ul>
<li>about</li>
<li>work</li>
<li>contact</li>
</ul>
</li>
</ul>
</div>
For what it's worth, this was what I was thinking of when I made my comment on your question:
http://jsfiddle.net/4t9fV/
ul {
display: table;
width: 100%;
background: #ccc;
table-layout: fixed
}
li {
display: table-cell;
text-align: center;
outline: 1px dashed red
}
li:first-child {
width: 100px
}

Resources