Allow element after and before content to override parent elements overflow restriction

I have a div

property overflow

set scroll

to be able to see all the contained fields without taking up too much space on the page. Each field has a range (field header) and a corresponding entry. I offer users the ability to hover over the spans and see useful information as a hint. I am using aliases after

and before

scrolling spaces to add a custom tooltip. However, the display of tooltips is limited by the parent's overflow constraint.

Here's an example of rendered HTML:

<div id="ContentPlaceHolder1_leftDiv" class="l-custom-left">     
    <div class="personalizedFields">
        <table>
            <tr>
                <td>
                    <span title="Champ associé: Prenom" class="tooltip">Prénom</span>
                </td>
            </tr>
            <tr>
                <td>
                    <input name="ctl00$ContentPlaceHolder1$ucPF$ucCustomField36$field36" type="text" id="field36" />

                </td>
            </tr>

            <tr>
                <td>
                    <span title="Champ associé: Nom" class="tooltip">Nom</span>
                </td>
            </tr>
            <tr>
                <td>
                    <input name="ctl00$ContentPlaceHolder1$ucPF$ucCustomField37$field37" type="text" id="field37" />

                </td>
            </tr>
        </table>
    </div>
</div>

      

css of the parent div and covers:

.l-custom-left
{
    overflow-x: hidden;
    width: 250px;
    height: 50vh;
}

.tooltip:hover:after{
    background: #333;
    background: rgba(0,0,0,.8);
    border-radius: 5px;
    bottom: 26px;
    color: #fff;
    content: attr(title);
    left: 20%;
    padding: 5px 10px;
    position: absolute;
    z-index: 98;
}

.tooltip:hover:before{
    border: solid;
    border-color: #333 transparent;
    border-width: 6px 6px 0 6px;
    bottom: 20px;
    content: "";
    left: 50%;
    position: absolute;
    z-index: 99;
}

      

How can I allow my gaps after and before the content to "override" the div div's overflow limit?

JSfiddle

+3


source to share


2 answers


If you really want this to work, there are two ways. First, use JavaScript (which I won't go into) to position the element outside of the container at the position of the element. This is a nasty fix, and I had to run it too many times to count before CSS3.

The second is much more elegant, but rephrases the semantics for HTML. The reason your aliases :before

and :after

do not leave the scroll container is because they are treated as children of the element .tooltip

and therefore part of the document flow for the scroll container, even though they're positioned absolutely.

So how do we deal with this? We are deceiving, simple and simple.

Add the second element after span

this:

<span class="tooltip">Prénom</span>
<span title="Champ associé: Prenom" class="tooltip-hovershim">Prénom</span>

      

We keep the same content so that the element is the same size.

Then change your CSS like this:

.tooltip, .tooltip-hovershim
{
    display: inline;
}

.tooltip:hover:after, .tooltip-hovershim:hover:after{
    background: #333;
    background: rgba(0,0,0,.8);
    border-radius: 5px;
    bottom: 26px;
    color: #fff;
    content: attr(title);
    left: 20%;
    padding: 5px 10px;
    position: absolute;
    z-index: 98;
}
.tooltip-hovershim { 
    position: absolute;
    transform: translateX(-100%);
    color: transparent;
}

.tooltip:hover:before, .tooltip-hovershim:hover:before {
    border: solid;
    border-color: #333 transparent;
    border-width: 6px 6px 0 6px;
    bottom: 20px;
    content: "";
    left: 50%;
    position: absolute;
    z-index: 99;
}

      



This voila! Vous avez votre élément flottant. It's simple.

JSFiddle example

Used only for the first two items for brevity.


Just for shits and giggles, here's the Javascript option

JSFiddle with JS option

And here's the important piece of Javascript:

var span_labels = document.querySelectorAll('.personalizedFields td span'),
    label_house = document.createElement('div');

document.body.appendChild(label_house);
label_house.setAttribute('class', 'tooltip-hoverer');

for (var i=0,l=span_labels.length;i<l;i++){
  var curr_label = span_labels[i];
    curr_label.addEventListener('mouseover', function(e) {
       e.preventDefault();
       label_house.innerHTML = e.target.getAttribute('title');
       var xy = getOffset(e.target);
       label_house.style.top = (xy.top - 26) + 'px';
       label_house.style.left = (xy.left) + 'px';
       label_house.style.display = 'block';
    });
    curr_label.addEventListener('mouseout', function() {
       label_house.style.display = 'none'; 
    });
}

function getOffset(el) {
    var elementRectangle = el.getBoundingClientRect();
    var _x = elementRectangle.left;
    var _y = elementRectangle.top + el.offsetParent.scrollTop;
    return { top: _y, left: _x };
}

      

+3


source


Since what I wanted to do is impractical with just CSS, I decided to go with a mix of JavaScript and JQuery inspired by Josh Burgess's JS solution. So if you're looking for a more jQuery-centric solution, this is it:

var tooltip;

$(document).ready(function() {
    $('span.tooltip').on({
        mouseenter: function (e) {
            tooltip = document.createElement('div');
            document.body.appendChild(tooltip);
            $(tooltip).addClass('tooltip-hoverer');
            $(tooltip).text($(this).attr('data-tooltip'));
            var x = e.clientX - (($(tooltip).outerWidth()) / 2); // "($(tooltip).outerWidth() / 2)" is required to show the tooltip down arrow next to the mouse left position
            var y = this.getBoundingClientRect().top + this.offsetParent.scrollTop;
            $(tooltip).css({
                top: y - 32,
                left: x,
                display: 'block'
            });
        },
        mouseleave: function () {
            document.body.removeChild(tooltip);
        }
    });                       
});

      



Note that unlike Josh's solution, I do not create all tooltips on load, but only once each time the range is hovered, and I delete it when the cursor leaves the range.

JSFiddle can be found here

+1


source







All Articles