Nakib
Nakib

Reputation: 4703

Showing truncated text on hover using CSS ellipsis overlaps text below it

I have a name tag in the sidebar which should display single line and truncate if long text follow by triple dots (lorem ipsum...) and should show full text on hover.

I am able to achieve this using css but my problem is when full text is displayed it overlaps the text below it. (Images attached)

HTML

<p class="name">
    Lorem ipsum lorem ipsum lorem ipsum
</p>

CSS

.name{
    color: #0079c1;
    height: 2em; 
    line-height: 1em; 
    font-size: 20px;
    font-weight: 400;
    text-overflow: ellipsis;
    margin-bottom: 12px;
    cursor: pointer;
    word-break: break-all;
    overflow:hidden;
    white-space: nowrap;
}

.name:hover{
    overflow: visible; 
    white-space: normal; 
}

Here is a JSFiddle

Text overlapping on hover. Expected behaviour is it should push the content below it. enter image description here

Upvotes: 38

Views: 108602

Answers (4)

Timo Grossenbacher
Timo Grossenbacher

Reputation: 31

I wrote this snippet to reveal truncated text in buttons. Full snippet with scss here

document.querySelectorAll('.truncate-scroll').forEach(function(button) {
        // get with of span, when outside of container and on single line
    var span = button.querySelector('span');
    var spanClone = span.cloneNode(true);
    spanClone.style.position = 'absolute';
    spanClone.style.visibility = 'hidden';
    spanClone.style.whiteSpace = 'nowrap';
    spanClone.style.width = 'auto';
    spanClone.style.left = '-9999px';
    document.body.appendChild(spanClone);
    var width = spanClone.offsetWidth;
    document.body.removeChild(spanClone);

    // get difference of 'width' and 'span.offsetWidth' in percentage of 'width'
    var diff = ((width - span.offsetWidth) / width * 100).toFixed(2);

    // add diff as data attribute to span
    span.dataset.diff = diff;

    // add class truncate if span wider than its container
    if (width > button.offsetWidth) {
        button.classList.add('truncate');
        span.style.width = width + 'px';
    }

    // on mouseenter, span of button with class 'truncate', should transform to the left 'diff' percentage (+ 5px)
    button.addEventListener('mouseenter', function() {
        if (button.classList.contains('truncate')) {
            span.style.transform = 'translateX(calc(-1 * (' + diff + '% + 5px)))';
                        button.classList.add('hover');
        }
    });

    // on leave, span of button with class 'truncate', should transform to the left '0'
    button.addEventListener('mouseleave', function() {
        if (button.classList.contains('truncate')) {
            span.style.transform = 'translateX(0)';
                        button.classList.remove('hover');
        }
    });
});
@charset "UTF-8";
.wrapper {
  border: 1px solid #D5D5D5;
  border-radius: 3px;
  height: 500px;
  padding: 20px;
  margin: 60px;
}

.nav {
  gap: 10px;
}
.nav li {
  max-width: 100%;
}
.nav button {
  background: none;
  border: 1px solid #D5D5D5;
  border-radius: 3px;
  display: block;
  color: black;
  padding: 10px 15px;
  width: 100%;
  overflow: hidden;
  position: relative;
}
.nav button.truncate::after {
  position: absolute;
  right: 0;
  bottom: 0;
  content: "…";
  background: white;
  width: 20px;
  padding-bottom: inherit;
  transition: opacity 0.5s;
}
.nav button.truncate.hover::after {
  opacity: 0;
}
.nav button span {
  white-space: nowrap;
  position: relative;
  overflow: hidden;
  display: block;
  transition: transform 2s;
  text-align: start;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.0.2/css/bootstrap.min.css" rel="stylesheet"/>
<!-- https://codepen.io/tgrossenbacher/pen/zYVNVqO -->
<div class="container">
    <div class="wrapper">
        <div class="row">
            <div class="col-3">
                <ul class="nav flex-column">
                    <li>
                        <button type="button" class="truncate-scroll"><span>This text is way to long for its container. Donec mollis hendrerit risus</span></button>
                    </li>
                    <li>
                        <button type="button" class="truncate-scroll"><span>This text fits right in</span></button>
                    </li>
                </ul>
            </div>
        </div>
    </div>
</div>

Upvotes: 3

Juanma Menendez
Juanma Menendez

Reputation: 20099

This code would work and also thanks to the title HTML prop the text will be shown on-hover by default

.truncated {
  white-space: nowrap; 
  overflow: hidden;
  text-overflow: ellipsis; 
  /* Optional: set a fixed max-width or width to the element if needed */
  max-width: 200px; /* max-width: 100%; also works */
}
<div class="truncated" title="This is a long text that will be truncated, but showed on hover">
  This is a long text that will be truncated, but shown on hover
</div>

Upvotes: 15

Natalia
Natalia

Reputation: 386

Facing similar problem with some long email addresses in a form I created this solution where the full content is displayed on hover in a tooltip-style pseudo element.

body{
  background:#eee;
}
.box{
  background:#fff;
  box-shadow: 0 25px 30px 0 rgba(0,0,0,0.15);
  border:rgba(0,0,0,0.3);
  width:10rem;
  margin:2rem auto;
  padding:2rem;
}
.ellipsis {
    display: block;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    transition: all .2s linear;
    white-space: nowrap;
    padding:.5rem 1rem;
}
.ellipsis:focus, .ellipsis:hover {
  color:transparent;
}
.ellipsis:focus:after,.ellipsis:hover:after{
    content:attr(data-text);
    overflow: visible;
    text-overflow: inherit;
    background: #fff;
    position: absolute;
    left:auto;
    top:auto;
    width: auto;
    max-width: 20rem;
    border: 1px solid #eaebec;
    padding: 0 .5rem;
    box-shadow: 0 2px 4px 0 rgba(0,0,0,.28);
    white-space: normal;
    word-wrap: break-word;
    display:block;
    color:black;
    margin-top:-1.25rem;
  }
<div class="box">
  <p class='ellipsis' data-text='f6cd8edc-60c2-11e7-9919-ef706e78474f'>f6cd8edc-60c2-11e7-9919-ef706e78474f</p>      
  <p class='ellipsis' data-text='Mauris ac eros odio. Etiam imperdiet vitae dolor eu feugiat. Pellentesque at ante dignissim, tincidunt ipsum quis, rutrum ante. Donec ac lorem nisl. Cras fringilla ex ut rutrum imperdiet. Fusce accumsan id est vel lacinia. Cras nec ligula eu velit mattis mollis. Nunc venenatis neque nibh, id dapibus orci aliquet id. Ut dictum mollis eros sed imperdiet. Phasellus quis enim nec felis sagittis varius. Ut et rutrum quam. Morbi id interdum felis. Mauris id dignissim odio.'>Mauris ac eros odio. Etiam imperdiet vitae dolor eu feugiat. Pellentesque at ante dignissim, tincidunt ipsum quis, rutrum ante. Donec ac lorem nisl. Cras fringilla ex ut rutrum imperdiet. Fusce accumsan id est vel lacinia. Cras nec ligula eu velit mattis mollis. Nunc venenatis neque nibh, id dapibus orci aliquet id. Ut dictum mollis eros sed imperdiet. Phasellus quis enim nec felis sagittis varius. Ut et rutrum quam. Morbi id interdum felis. Mauris id dignissim odio.</p>
</div>

https://codepen.io/natalitique/pen/gRdmre

Requires using data attribute with the full content.

Upvotes: 33

Mi-Creativity
Mi-Creativity

Reputation: 9654

You can just add height:auto to the hover state and it'll work just fine:

JS Fiddle

.name{
    width:120px;
    color: #0079c1;
    height: 2em; 
    line-height: 1em; 
    font-size: 20px;
    font-weight: 400;
    text-overflow: ellipsis;
    margin-bottom: 12px;
    cursor: pointer;
    word-break: break-all;
    overflow:hidden;
    white-space: nowrap;
}
.name:hover{
    overflow: visible; 
    white-space: normal;
    height:auto;  /* just added this line */
}
<p class="name">
Lorem ipsum lorem ipsum lorem ipsum ipsum lorem ipsum
</p>
<span>
  Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quidem voluptate deserunt consequatur velit, alias ullam fuga aspernatur, ut doloremque eos fugiat quo a accusamus minus distinctio quasi, recusandae excepturi molestiae.
</span>

Upvotes: 48

Related Questions