kakaja
kakaja

Reputation: 734

CSS: element should get max-width before breaking words

There are CSS tooltips (codepen is given below). They have min-width and max-width. They contain sometimes short phrases, sometimes very long words without breaks. This is what happens if there is white-space: nowrap => Short tooltips are rendered perfectly, but long ones, obviously, are not wrapped and are not fully visible:

description

This is what happens when I add white-space: normal and word-break: break-word => Now short ones and long ones get wrapped long before getting to the max-width:

enter image description here

What I would like to achieve is: Tooltips don't wrap before getting to the max-width. And start wrapping only if they don't get into the max-width. Like here:

enter image description here

Is it possible to get this behaviour just with CSS (no javascript)?

Here is the codepen: https://codepen.io/anon/pen/bWXobM (Uncomment lines 58-59 to change the behaviour.)

I didn't manage to achieve this with any of the found solutions. If you know how to apply them in this case, please share!

Update: apparently some kind of solution to this problem has just been added to the wg draft: https://github.com/w3c/csswg-drafts/issues/1171. It is still interesting if someone found a workaround for now.

Upvotes: 4

Views: 3380

Answers (4)

ncode
ncode

Reputation: 71

The other answers are too verbose or insufficient. What I added was width:max-content; which works rather intuitively since its trying to maximise the width, but will stop at the max-width and then breaks the overflow through either word-break:break-all;, word-wrap:break-word; or overflow-wrap:break-word;

Here is the CSS (SCSS) to answer OP, you can test it via the codepen in OP's question, just paste it.

@keyframes show-vert {
  to {
    transform: translate(-50%, 0);
    opacity: .9;
  }
}
@keyframes show-diag {
  to {
    transform: translate(0, 0);
    opacity: .9;
  }
}
body {
  background: #eaeaea;
  font-family: Verdana;
}
span {
  display: block;
  padding: 16px 8px;
  border: 1px solid;
}

[data-tooltip] {
  position: relative;
  z-index: auto !important;
  &::before, &::after {
    content: '';
    display: none;
    box-sizing: border-box;
    position: absolute;
    opacity: 0;
    font-size: 14px;
    line-height: 1;
    user-select: none;
    pointer-events: none;
  }
  &::before {
    z-index: 1001;
    border: 6px solid transparent;
  }
  &::after {
    content: attr(data-tooltip);
    z-index: 1000;
    min-width: 50px;
    max-width: 280px;
    height: auto;
    //changes - removed
    //width: 100%;
    border-radius: 2px;
    padding: 8px 16px;
    background: hsla(0, 0%, 38%, 1);
    box-shadow: 0 1em 2em -.5em rgba(0, 0, 0, 0.35);
    color: white;
    text-align: center;
    //changes - added
    word-break: break-all;
    width: max-content;
  }
  &:hover {
    &::before, &::after {
      display: block;
    }
    &::after {
      //changes - removed
      // width: auto;
    }
  }
}

[data-tooltip] {
  &.tooltip-down {
    &::before {
      top: 100%;
      left: 50%;
      transform: translate(-50%, .5em);
      border-top-width: 0;
      border-bottom-color: hsla(0, 0%, 38%, 1);
    }
    &::after {
      left: 50%;
      top: calc(100% + 5px);
      transform: translate(-50%, .5em);
    }
    &:hover {
      &::before, &::after {
        animation: show-vert 500ms linear 1ms forwards;
      }
    }
  }
  &.tooltip-down-left {
    &::before {
      left: 1em;
    }
    &::after {
      left: 0;
    }
    &::before, &::after {
      transform: translate(-1em, -.5em);
    }
    &:hover{
      &::before, &::after {
        animation: show-diag 500ms linear 1ms forwards;
      }
    }
  }
}

Upvotes: 2

SnailCoil
SnailCoil

Reputation: 808

I had a similar problem, and was able to use a wrapping element to style it the way I wanted. I forked a previous answer's codepen and got it to work based on what I am assuming you wanted: https://codepen.io/anon/pen/BONWGG

the key changes were creating a new element for the [data-tooltip], giving it column flex, and letting the ::after element scale as big as it needs to

<span class="tooltip-container">
  Tooltip 1 should be on 1 line
  <span data-tooltip="Short"></span>
</span>

[data-tooltip] {
  position: absolute;
  left: 0;
  right: 0;
  height: 0;
  flex-direction: column;
  align-items: center;
  &::after {
    ...
    flex-shrink: 0;
  }
}
.tooltip-container {
  ...
  &:hover {
    [data-tooltip] {
      display: flex;
      ...
    }
  }
}

Upvotes: 2

Aman
Aman

Reputation: 640

Don't use word-break: break-word as it is breaking every word to new line, instead use overflow-wrap: break-word; and white-space: normal.

Upvotes: 1

jagpreet
jagpreet

Reputation: 84

I made some changed in the css code.I have commented on the lines which i have changed.(eg. //changed).Actually you already made the half solution by using

word-break: break-word;

The only thing i changed is min-width and max-width to achieve the required results.

Here is the updated link

https://codepen.io/anon/pen/ZyGpaL

Upvotes: 0

Related Questions