14

I have a <table> which is made scrollable by wrapping it in a <div> of fixed height.

This <table> has a dropdown component (blue container in 2nd column of 1st row in the image and jsfiddle given below) which is hiding behind the container <div>. I want it to display all the options Instead.

current output

JSFIDDLE (example)

How should I bring the dropdown component outside the container <div> to display all the options as in the image below?

desired output

If I remove the pRelative container, then the dropdown is fully visible - But when I scroll, the dropdown does not scroll along with it's container.

Thanks in advance.

PS: Looking for CSS/javascript solution only.

T J
  • 42,762
  • 13
  • 83
  • 138
Mr_Green
  • 40,727
  • 45
  • 159
  • 271
  • You can't do that easily because your `.main` has `overflow: hidden`... When scrolling, you'd like your dropdown to scroll also, right? – Nicolae Olariu Jun 19 '14 at 07:55
  • @NicolaeOlariu yes which is happening in my provided fiddle. **I just want to show the dropdown completely.** – Mr_Green Jun 19 '14 at 07:57
  • Its not possible with just CSS. z-index doesn't work if any of the ancestors have a relative positioning. Your only option is to use JS to position it dynamically on the element under focus. – Palash Jun 19 '14 at 08:00
  • Unfortunatelly this won't be possible using just plain CSS. You could make your dropdown's position fixed, and then on scroll modify it's top offset. Ugly... I know... but viable... – Nicolae Olariu Jun 19 '14 at 08:04
  • @NicolaeOlariu seems as I should give up on only CSS solution here. I thought it should be simple enough to solve using just CSS. Okay, I can have a solution in javascript. – Mr_Green Jun 19 '14 at 08:08

8 Answers8

10

You can change positioning of the dropdown to fixed and handle the scroll using js, like the following.

var main = document.getElementsByClassName('main')[0];
var dd = document.getElementsByClassName('pAbsolute')[0];
var offset = dd.getBoundingClientRect().top;
main.onscroll = function() {
  var st = main.scrollTop;
  ddt = (offset - st);
  dd.style.top = ddt + 'px';
}
.main {
  height: 100px;
  overflow-y: scroll;
  overflow-x: hidden;
}
.pRelative {
  position: relative;
}
.pAbsolute {
  position: fixed;
}
.dropdown {
  width: 100px;
  background-color: cornflowerblue;
  z-index: 1000;
}
.option {
  border-top: 1px solid green;
  border-bottom: 1px solid green;
}
table td {
  border: 1px solid black;
  padding: 10px;
}
<div class="main">
  <table>
    <tr>
      <td>row1 column1</td>
      <td>
        <div class="pRelative">
          <div class="pAbsolute dropdown">
            <div class="option">Zero</div>
            <div class="option">One</div>
            <div class="option">Two</div>
            <div class="option">Three</div>
            <div class="option">Four</div>
            <div class="option">Five</div>
            <div class="option">Six</div>
          </div>
        </div>
      </td>
      <td>row1 column3</td>
    </tr>
    <tr>
      <td>row2 column1</td>
      <td>row2 column2</td>
      <td>row2 column3</td>
    </tr>
    <tr>
      <td>row3 column1</td>
      <td>row3 column2</td>
      <td>row3 column3</td>
    </tr>
    <tr>
      <td>row4 column1</td>
      <td>row4 column2</td>
      <td>row4 column3</td>
    </tr>
    <tr>
      <td>row5 column1</td>
      <td>row5 column2</td>
      <td>row5 column3</td>
    </tr>
    <tr>
      <td>row6 column1</td>
      <td>row6 column2</td>
      <td>row6 column3</td>
    </tr>
    <tr>
      <td>row7 column1</td>
      <td>row7 column2</td>
      <td>row7 column3</td>
    </tr>
    <tr>
      <td>row8 column1</td>
      <td>row8 column2</td>
      <td>row8 column3</td>
    </tr>
  </table>
</div>

Demo

Update

You can fix the margin-top issue by creating a new stacking context.

(tested only in safari 6.1 mac - unfortunately doesn't works in any latest browsers) Updated Demo or Another Demo

Update

The only possible cross browser workaround i could find for hiding the fixed elements overflow is to clip the container (this requires it to be a positioned element)

var main = document.getElementsByClassName('main')[0];
var dd = document.getElementsByClassName('pAbsolute')[0];
var offset = dd.getBoundingClientRect().top;
main.onscroll = function() {
  var st = main.scrollTop;
  ddt = (offset - st);
  dd.style.top = ddt + 'px';
}
.main {
  height: 100px;
  overflow-y: scroll;
  overflow-x: hidden;
  margin-top: 100px;
  position: absolute;
  clip: rect(auto, auto, 99999px, auto);
}
.pRelative {
  position: relative;
}
.pAbsolute {
  position: fixed;
}
.dropdown {
  width: 100px;
  background-color: cornflowerblue;
  z-index: 1000;
}
.option {
  border-top: 1px solid green;
  border-bottom: 1px solid green;
}
table td {
  border: 1px solid black;
  padding: 10px;
}
<div class="main">
  <table>
    <tr>
      <td>row1 column1</td>
      <td>
        <div class="pRelative">
          <div class="pAbsolute dropdown">
            <div class="option">Zero</div>
            <div class="option">One</div>
            <div class="option">Two</div>
            <div class="option">Three</div>
            <div class="option">Four</div>
            <div class="option">Five</div>
            <div class="option">Six</div>
          </div>
        </div>
      </td>
      <td>row1 column3</td>
    </tr>
    <tr>
      <td>row2 column1</td>
      <td>row2 column2</td>
      <td>row2 column3</td>
    </tr>
    <tr>
      <td>row3 column1</td>
      <td>row3 column2</td>
      <td>row3 column3</td>
    </tr>
    <tr>
      <td>row4 column1</td>
      <td>row4 column2</td>
      <td>row4 column3</td>
    </tr>
    <tr>
      <td>row5 column1</td>
      <td>row5 column2</td>
      <td>row5 column3</td>
    </tr>
    <tr>
      <td>row6 column1</td>
      <td>row6 column2</td>
      <td>row6 column3</td>
    </tr>
    <tr>
      <td>row7 column1</td>
      <td>row7 column2</td>
      <td>row7 column3</td>
    </tr>
    <tr>
      <td>row8 column1</td>
      <td>row8 column2</td>
      <td>row8 column3</td>
    </tr>
  </table>
</div>

Demo

Mr_Green
  • 40,727
  • 45
  • 159
  • 271
T J
  • 42,762
  • 13
  • 83
  • 138
  • If you check by giving margin-top, it is not working. [**Fiddle**](http://jsfiddle.net/n8TpR/19/). – Mr_Green Jun 23 '14 at 12:13
  • that's fixable by playing with [z-index](http://jsfiddle.net/tilwinjoy/n8TpR/21/) – T J Jun 23 '14 at 12:20
  • Strange. it's working on safari 6.1, i'll check in other browsers once i get back from office :D – T J Jun 23 '14 at 12:43
  • why you didn't say that you updated the post? it is working fine for me here. Is there any issues with this? – Mr_Green Jun 27 '14 at 06:33
  • @Mr_Green oops sry… i updated it when i got back from office that day… there isn't any as far as i know.. i checked in chrome, ff and safari... – T J Jun 27 '14 at 06:40
  • Thanks, I will give you bounty soon :) – Mr_Green Jun 27 '14 at 06:42
2

You could get the desired functionality by using a good old fashioned <select> dropdown:

Working Example

<div class="main">
    <table>
        <tr>
            <td>row1 column1</td>
            <td>
                <select class="dropdown">
                    <option class="option">Zero</option>
                    <option class="option">One</option>
                    <option class="option">Two</option>
                    <option class="option">Three</option>
                    <option class="option">Four</option>
                    <option class="option">Five</option>
                    <option class="option">Six</option>
                </select>
            </td>
            <td>row1 column3</td>
        </tr>
apaul
  • 16,092
  • 8
  • 47
  • 82
  • 1
    I have just posted the same answer... I think that simply using using `select` html tag is the best, simplest, and most semantic way, with no css/javascript overhead. +1 (and removed my duplicated answer) – falsarella Jun 26 '14 at 16:34
  • Select tag can't be designed.. :( – Mr_Green Jun 27 '14 at 05:46
  • @Mr_Green you can style the select tag, but its not easy http://stackoverflow.com/q/1895476/1947286 – apaul Jun 29 '14 at 16:17
0

As long as the drop down is a child of .main it isn't possible with CSS alone. That's because your .main has overflow-y: scroll; You can't have your cake and eat it too.

Madara's Ghost
  • 172,118
  • 50
  • 264
  • 308
  • I know `.main` has overflow property other than visible. which I think is not of concern here because if you once give remove `.pRelative` class, the dropdown is visible outside of `.main` container. but when I scroll, the dropdown is moving out of its parent `td` element. I hope my explanation is clear enough. – Mr_Green Jun 19 '14 at 08:04
0

The problem here is that you want the drop-down to "escape" its parent, while staying relative to it's parent. This is AFAIK not possible.

If you position the drop-down absolutely, you "bind" it to the nearest element with position: relative in its direct parent chain, or if no such element to the html element. There is a "trick" where if you do not provide any top/bottom/left/right-values, the element will still position itself where it would have started if it was inline.

This is why when we remove the relatively positioned wrapper the absolutely positioned drop-down "escapes" the overflow-y: hidden; value on .main (because it attaches to the html-element instead). This also means that its position will not be affected as long as the html-element is not being scrolled.

When you have a relatively positioned wrapper inside the .main the drop-down gets cut off like anything else inside it.

KnutSv
  • 748
  • 5
  • 9
  • sorry, you just explained the problem but you didn't give any solution. with all respect, I know what you explained above already. – Mr_Green Jun 19 '14 at 08:16
  • If you knew it was impossible with CSS you should have asked for a JS-solution specifically. – KnutSv Jun 19 '14 at 08:41
0

Is it what you are looking for? LINK

HTML:

<td class="hover">hh
  <ul>
    <li>0</li>
    <li>1</li>
    <li>2</li>
    <li>3</li>      
  </ul>
</td>

CSS:

td.hover {
    text-align: left;
    list-style: none;        
}
td.hover ul {
    padding: 0;
    position: absolute;
    top: 28px;
    width: 150px;       
    opacity: 0;
    visibility: hidden;       
}
td.hover ul li {
    background: #555;
    display: block;
    color: #fff;
    text-shadow: 0 -1px 0 #000;
}
td.hover ul li:hover {
    background: #666;
}
td.hover:hover ul {
    display: block;
    opacity: 1;
    visibility: visible;
}
G.L.P
  • 7,119
  • 5
  • 25
  • 41
0
try this ,


   <div class="main">
    <table>
        <tr>
            <td>row1 column1</td>
            <td>
                <div class="pRelative">
                    <div class="pAbsolute dropdown">
                        <div class="option">Zero</div>
                        <div class="option">One</div>
                        <div class="option">Two</div>
                        <div class="option">Three</div>
                        <div class="option">Four</div>
                        <div class="option">Five</div>
                        <div class="option">Six</div>
                    </div>
                </div>
            </td>
            <td>row1 column3</td>
        </tr>
        <tr>
            <td>row2 column1</td>
            <td>row2 column2</td>
            <td>row2 column3</td>
        </tr>
        <tr>
            <td>row3 column1</td>
            <td>row3 column2</td>
            <td>row3 column3</td>
        </tr>
        <tr>
            <td>row4 column1</td>
            <td>row4 column2</td>
            <td>row4 column3</td>
        </tr>
        <tr>
            <td>row5 column1</td>
            <td>row5 column2</td>
            <td>row5 column3</td>
        </tr>
        <tr>
            <td>row6 column1</td>
            <td>row6 column2</td>
            <td>row6 column3</td>
        </tr>
        <tr>
            <td>row7 column1</td>
            <td>row7 column2</td>
            <td>row7 column3</td>
        </tr>
        <tr>
            <td>row8 column1</td>
            <td>row8 column2</td>
            <td>row8 column3</td>
        </tr>
    </table>
</div>


**Css**


body{
  position:relative;
}
.main {
    height: 100px;
    overflow-y: scroll;
    overflow-x: hidden;
}

.pAbsolute {
    position: absolute;
}
.dropdown {
    width: 100px;
    background-color: cornflowerblue;
    z-index: 1000;
}
.option {
    border-top: 1px solid green;
    border-bottom: 1px solid green;
}

table td{
    border: 1px solid black;
    padding: 10px;
}
-1

This is a trick that works. but be sure to test on your own.

Chage Your Class From Position :relative To Position Fixed .

.pRelative {
    position: fixed;
}

Here Is The DEMO

Maulik Anand
  • 1,429
  • 3
  • 15
  • 19
  • Please scroll it and test. – Mr_Green Jun 19 '14 at 08:45
  • ya that dosen't work, the problem is either you can hide content by overflow:hidden , or let then overflow , you cannot choose that one element statys hidden and one can overflow inside single `overflow:hidden` container - @Mr_Green – Maulik Anand Jun 20 '14 at 16:37
-2

do you want like this,

FIDDLE

i have removed the position:relative for .pRelative

Bharath
  • 519
  • 4
  • 7