1

I'm having a bit of trouble with a couple of <ul> list objects on one of my pages.

I have two <ul> list containers that are populated from the client browser. Unrelated to this discussion, these two containers will allow for users to drag-and-drop <li> options left<->right from each container, and will be used for a form of manual sorting.

My problem is that either of these lists may contain 0 to upwards of 60 items. When there are many list items in one of the list containers, the parent grows well past the size screen and scroll bars appear, while the <ul> container grows as large as it needs to be.

I'd prefer for the scroll bars to be on the <ul> objects only (and function properly.)

I've googled this, and I've found multiple answers regarding forcing content to the size of a parent container, but most examples usually involve <div> objects and I'm not sure if there is something different with the <ul> container which causes it to behave differently.

Below is my pertinent code.

HTML

...
<ul class="col_selector_container" id="ulUnusedColumns"></ul>
<ul class="col_selector_container" id="ulUsedColumns"></ul>
...

This content is contained in a third-party Telerik control. The content area of the Telerik control is a div that is sized to fit the available content area, with or without content provided by the developer. However, the content area does grow larger if the internal content doesn't fit and, thus, the automatic scroll bars appear when the <ul> containers are populated and over-sized.

CSS

ul.col_selector_container 
{
    overflow-y: scroll;
    list-style-type: none;
    height: 100%;
    width: 300px;
    display:inline-block;
    vertical-align:top;
    padding-left: 0px;
}

Note that the height: 100% doesn't appear to do anything. The list will grow or shrink to match the height of the internal content, not the height of the parent container. Also, overflow-y: scroll; doesn't do anything other than show the scroll bars, which is pointless if the UI is just going to resize the list.

How can I fix this?

ADDITIONAL NOTES

I am using jquery & jqueryui for for sortign and working with UI elements. A good answer can involve using one of these tools if there is an option within these tools that can fix my problem, but that's certainly not required. Pertaining to this questino, JQuery never touches the layout of these object, other than inserting <li> objects, derived from my data list at runtime.

For those wanting an example, the best I can give is an example of the problem.

Here is a JSFiddle. Notice that the <ul> list is populated so that the content region of the fiddle has a scroll bar. Also note the pointless scroll bar on the list? How can I make it so that the content area doesn't need a scroll bar because the <ul> sizes itself to the content window (with more or less list items) and you can scroll through the list content when the list region is to large.

RLH
  • 15,230
  • 22
  • 98
  • 182
  • 1
    Sounds like flexbox could be useful here.. – Nebula Jan 05 '16 at 16:23
  • Flexbox might be a solution but a minimal demo would be optimal...doesn't need to have all the bells and whistles just enough to show the issue. `Height:100%` does nothing of the parent height isn't know (or can't be calculated) – Paulie_D Jan 05 '16 at 16:25
  • Does the parent have a defined height? If so look at flexbox or make the parent `position: relative` use absolute positioning for the lists. – James Coyle Jan 05 '16 at 16:25
  • @JamesCoyle No. It grows with the window. If the user resizes their browser, the content area can/should resize too. – RLH Jan 05 '16 at 16:29
  • Possible duplicate of [How to Force Child Div to 100% of Parent's Div Without Specifying Parent's Height?](http://stackoverflow.com/questions/1122381/how-to-force-child-div-to-100-of-parents-div-without-specifying-parents-heigh) – Chris G Jan 05 '16 at 16:29
  • @ChrisG, I don't think it's a duplicate. I can't get these `
      ` elements to size properly, but I've had no issue with *most* divs.
    – RLH Jan 05 '16 at 16:32
  • @RLH So the `ul`s should be 100% browser height? If that's the case you need to either set `height: 100%` on `html`, `body` and any other parent elements OR use `height: 100vh` on the `ul`s. You may want to check browser support on the latter though. – James Coyle Jan 05 '16 at 16:33
  • No, there is content around this object, but it is embedded within a div that can either, a) grow/shrink with the browser window or, b) grow with it's contents if it's larger than the available space. Also, I am willing to wrap another div around these lists. I'm just not sure how to do it from here. Let me inspect chrome and see if I can get the style for the parent. I didn't style it and it's part of an embedded control, so I'll need to dig. – RLH Jan 05 '16 at 16:35
  • I'm pretty sure this has something to do with the way I handle the `
      ` elements. Basically, I can't seem to do anything to FORCE them to a specific height by a percent. Hardcoded pixel values work, but not percents. I wonder if this has to do with dynamically loading content?
    – RLH Jan 05 '16 at 16:42

3 Answers3

1

This can be achieved easy with jQuery:

jQuery:

$(document).ready(function(){

    var list = $('ul.col_selector_container');

    list.css({'min-height':list.parent().height(), 'max-height':list.parent().height()});


    $(window).resize(function(){
       list.css({'min-height':list.parent().height(), 'max-height':list.parent().height()});
    });

});

Or use "closest('selector')" to get the height of the parent higher in the DOM tree.

Update in 2017:

This can be achieved with FLEX now:

<style>
.parent{
    background:red;
    display: -webkit-box;
    display: -moz-box;
    display: -ms-flexbox;
    display: -webkit-flex;
    display: flex;
    height:300px;
}

ul{
    background:yellow;
}
</style>

<div class="parent">
    <ul>
        <li>Test1</li>
        <li>Test2</li>
    </ul>
</div>

https://css-tricks.com/snippets/css/a-guide-to-flexbox/

Dennis Heiden
  • 757
  • 8
  • 16
  • If the browser and, subsequently the content region, resize, will this resize the list? – RLH Jan 05 '16 at 16:31
  • I have updated my answer. Now it will resize on window resize. Does that help? – Dennis Heiden Jan 05 '16 at 16:45
  • 1
    Doesn't seem to help. Sorry. – RLH Jan 05 '16 at 16:56
  • Not the downvoter, but imo, forcing a solution to a CSS/HTML problem via jQ instead of actually correcting the CSS/HTML problem is never a good solution. – abluejelly Jan 05 '16 at 17:19
  • I agree, but at this point I don't see a pure CSS solution which is not hawkish and supported cross-browser. – Dennis Heiden Jan 05 '16 at 17:42
  • After playing around with my implementation, this actually appears to be the best answer. Resizing to the parent container seems to be the way to go. Thank you. – RLH Jan 05 '16 at 21:07
1

EDIT: I forgot a semicolon. Hah. Height works just fine on uls, I just committed the classic blunder. I've cleaned that chunk from this answer.

Note however that imposing a size via the ul rather than the wrapper causes some weirdness in some browsers. My work's Firefox 31 has the green box overlapping with the bottom of the list. At this point you'd have to use a positioning trick to keep it kosher, hence why wrapping is still honestly easiest.


Easiest is to wrap the ul in a div, and size the div- just remember to forward the drop events to the ul.

Two samples: https://jsfiddle.net/b6zu3Lhy/6/

First is a dynamically-added-to list forced to stay within its parent

Second is a ul with a height limit.... but not the right height limit.

If you're running into the issue of percentile sizes not quite liking you (ie: the percents do nothing), you'll need the html,body{ height:100%; } trick. If you can't do that, you might be able to bs it with screen units (vw/vh) mirroring the parent's size.

Demo code (from the fiddle) provided below for completeness.

function $(a, b) { return (b || document).getElementById(a); }
$.bind = function (ele, o) { for (var event in o) ele.addEventListener(event, o[event]); };
$.init = function (init, args, me) { if (document.readyState !== "loading") { init.apply(me, args); } else { document.addEventListener("DOMContentLoaded", function () { init.apply(me, args); }); } }
$.hasClass = function (ele, cls) { return ele.classList.contains(cls); }

$.init(function(){
    $.bind($("libtn"),{
        click:function(){
            var ul = $("ul");
            var li = document.createElement("li");
            li.innerHTML = "yo" + "oooooooooo".substr(Math.floor(10*Math.random()));
            ul.appendChild(li);
        }
    });

    $.bind($("szbtn"),{
        click:function(){
            var div = $("box");
            if($.hasClass(div,"sz1")){
                div.className="box sz2";
            }else if($.hasClass(div,"sz2")){
                div.className="box sz3";
            }else{
                div.className="box sz1";
            }
        }
    });
});
ul{
  margin-top:0; margin-bottom:0;
}

.box{
  border:2px solid gray;
  overflow-y:auto;
}

.sz1{ height:50px; }

.sz2{ height:100px; }

.sz3{ height:200px; }

.demo2{
  height:75px;
  overflow:visible;
  border:1px solid green;
}
.demo2 ul{
  font-style:italic;
  height:100%;
  overflow-y:auto;
}
<button type="button" id="libtn"> +li </button>
<button type="button" id="szbtn"> szTog </button>

<div id="box" class="box sz1">
  <ul id="ul">
  </ul>
</div>
<div class="demo2">
  <ul>
    <li>static list with size limit</li>
    <li>static list with size limit</li>
    <li>static list with size limit</li>
    <li>static list with size limit</li>
    <li>static list with size limit</li>
    <li>static list with size limit</li>
    <li>static list with size limit</li>
    <li>static list with size limit</li>
    <li>static list with size limit</li>
    <li>static list with size limit</li>
    <li>11 static list with size limit</li>
  </ul>
</div>
abluejelly
  • 1,266
  • 9
  • 17
  • This might do the trick. Your JSFiddle you posted appears to be functioning as I need. When I get a chance to integrate this, I'll comment and/or give an answer mark. Thank you. – RLH Jan 05 '16 at 17:26
  • np. Like I said, it was just you trying to assign a height to something that is mandated "as tall as its contents". I only even noticed that it straight up gets ignored because firebug wasn't even seeing the `height` or `overflow-y` in its "styles on this element" pane. – abluejelly Jan 05 '16 at 17:29
  • @RLH I'm da best, there was a missing semicolon. I still "fixed" the issue with the working part, just the bottom "that don't work" chunk is bunk. – abluejelly Jan 05 '16 at 17:58
1

If I'm understanding your question correctly, you have a few options.

Assuming you have one list per container, you can do something like this:

HTML

<div class="list-container">
    <ul class="col_selector_container" id="ulUnusedColumns"></ul>
</div>
<div class="list-container">
    <ul class="col_selector_container" id="ulUsedColumns"></ul>
</div>

CSS

.list-container { position: relative; }
.col_selector_container {
    position: absolute;
    overflow-y: scroll;
    list-style-type: none;
    height: 100%;
    width: 300px;
    display:inline-block;
    vertical-align:top;
    padding-left: 0px;
}

All of the quirks with position absolute apply here, but it should give you the effect you're looking for. If you're supporting IE10+, Flexbox is definitely the option to use here instead. You can also use css tables here as an alternative to child absolute/parent relative if you want.

If this isn't going to work, we'll probably need more of your HTML structure to see how things are laid out.

Hope this helps!

Benjamin Solum
  • 2,281
  • 18
  • 29
  • Had to move the `display:inline-block;` to the list-container, and define a height/width on it. Still runs into the same issue on percentile, [but works](http://dabblet.com/gist/52a67dc038eff386cc8e). Odd, wonder if it's the removing from natural flow that lets `ul` have a height, or something else- as that height value is being obeyed in this instance. – abluejelly Jan 05 '16 at 17:52
  • OKAY so ul normally does acknowledge height. It just doesn't acknowledge `height:75px overflow-y:auto;`. Note the lack of semicolon. Ha. Hope that's the biggest oops I make all day. – abluejelly Jan 05 '16 at 17:57