简体   繁体   中英

How to make position absolute respect vertically viewport limits

I have a table with some rows and each row has a "more options" button that when clicked, opens a dropdown with the options. But in the last row, the options dropdown persists to overflow the viewport vertically. I saw a similar question here , but i'm not using bootstrap. The Bootstrap solution used JS to calculate and position the element using transform. But there is any way to do that with just CSS?

Here its my table structure:

    <table>
      <tbody>
        <tr>
            <td>
                ...
            </td>
            <td>
                ...
            </td>
            <td>
                ...
            </td>
            <td>
                ...
            </td>
            <td>
                ...
            </td>
            <td>
                ...
            </td>
            <td>
                <svg class="ICON HERE..."></svg>
                <ul class="options">
                    <li><span>Salvar a biblioteca</span></li>
                    <li><span>Adicionar a fila</span></li>
                    <li><span>Adicionar a playlist</span></li>
                    <li><span>Remover dessa playlist</span></li>
                    <li><span>Desabilitar nessa playlist</span></li>
                </ul>
            </td>
        </tr>
      </tbody>
    </table>
    
<style>
table{
    width: 100%;
    table-layout: fixed;
}

table tbody tr td:nth-child(7) {
    width: 50px;
}

tr td:last-child {
    overflow: visible;
    position: relative;
}

table tbody tr td {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

table tbody tr td {
    font-size: 16px;
    text-align: left;
    vertical-align: middle;
    padding: 10px 15px;
    color: #bbb;
}

.options{
    border: 1px solid #3D4466;
    border-radius: 14px;
    margin: 10px 0 0 0;
    box-shadow: 0 6px 12px 0px rgba(0,0,0,0.16);
    transition: .5s opacity;
    position: absolute;
    z-index: 2;
    min-width: 175px;
    background: #252A41;
    top: 0;
    left: inherit;
    right: 100%;
    bottom: inherit;
 }
</style>

打印屏幕

You can use

.options:not(:nth-last-child(-n+2)) {
    //style here
}

And set for them different styles with proper vertical align

You can try this CSS:

tr:nth-last-child(-n+2){/*This will select last two rows*/
    /*creates a context*/
    position: relative;
}
tr:nth-last-child(-n+2) td:last-child .option{/*this will select the drop down of last two rows*/
    /*positioned within tr*/
    position: absolute;
    bottom: 0;
}

Here you can replace 2 with 3 to grab last 3 elements.

Whats going on?

Actually these selectors work like a loop which runs through all the elements. Here n specifies that I want all the elements. The formula -n+2 will work like this:

suppose we have 10 elements

n = {0,1,2,3...,9}

-n+2 = 2,1,0,-1,-2,...

for each value of n.

Negative values are disregarded. 2 is the second last and 1 is the last element, 0 is also disregarded.

Answering my own question, I got a solution that worked for me using JS, and maybe is gonna be useful for someone in the future... So basically I checked if the element is overflowing his parent by getting the top and height of the element and of his parent. I sum his height with his top, and I get the axis Y of the bottom of this element. If the axis Y of this element is greater than the axis Y of his parent, the element its overflowing. To solve that just position the parent as relative and add a bottom: 0 on the child element.

const ulBottom = ul.getBoundingClientRect().top + ul.offsetHeight
const sectionBottom = section.getBoundingClientRect().top + section.offsetHeight
if(ulBottom > sectionBottom) ul.style.bottom = '0px'

(Sorry for any writing mistake, english isn't my first language)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM