Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoid line wrap between ::before pseudo-element and next word

The problem

I use ::before to generate a pseudo-element to display a small image left of the anchor text of links. However, when re-sizing the browser window's width, the line may become wrapped between the small image and the first word of the link anchor text, which is undesired.

Desired result

I want to keep the small image and the first word of the link anchor text together on the same line.

I keep display: inline on the a-tag because the link anchor text shall be able to wrap line, not as a whole atomic box, but so that its first word(s) fill up the current line and any remaining words continue on the next line.

Also, the text after the link shall continue on the same line as the last word of the link anchor text (provided there is space for its first word of course).

Note 1) If I would use display:inline-block on the a-tag, the entire link anchor text would wrap as a whole, which I do not want.

Note 2) I use display:inline-block on the pseudo-element because I need to set its width and height.

Note 3) I have tried with setting white-space: pre on the pseudo-element, but that did not solve the problem.

Thanks!

The code

The code is at JSFiddle and repeated below for completeness.

My HTML:

<p>
Text text <a class="pre-icon" href="#">FirstWord word2 word3</a> text after link.
</p>

My CSS:

.pre-icon::before {
    content: "";
    display: inline-block;
    width: 6px;
    height: 10px;
    background-color: transparent;
    background-image: url(data:image/gif;base64,R0lGODlhBgAKAJEAADM2Zv///////wAAACH5BAUUAAIALAAAAAAGAAoAAAINBIRimdvHFETOUWglKwA7);
    background-repeat: no-repeat;
    margin-left: .13em;
    margin-right: .25em;
    white-space: nowrap;
}
like image 797
Goran W Avatar asked Jan 26 '16 02:01

Goran W


People also ask

How do you prevent line wrapping in CSS?

If you want to prevent the text from wrapping, you can apply white-space: nowrap; Notice in HTML code example at the top of this article, there are actually two line breaks, one before the line of text and one after, which allow the text to be on its own line (in the code).

What does the pseudo-element :: Before do?

::before (:before) In CSS, ::before creates a pseudo-element that is the first child of the selected element. It is often used to add cosmetic content to an element with the content property. It is inline by default.

What are :: after and :: before?

Definition and Usage The ::before selector inserts something before the content of each selected element(s). Use the content property to specify the content to insert. Use the ::after selector to insert something after the content.

What property do you use in conjunction with the before pseudo-element to display content before an element?

The content CSS property is used in conjunction with these pseudo-elements, to insert the generated content.


2 Answers

The problem is that the line break happens between the pseudo-element and the content, so you can't avoid it by setting white-space only to the pseudo-element.

Instead, you can wrap the content of the anchor inside a span, set white-space: nowrap to the entire anchor, and restore the initial white-space: normal in the span.

.pre-icon {
  white-space: nowrap;
}
.pre-icon > span {
  white-space: normal;
}

.pre-icon::before {
  content: "";
  display: inline-block;
  width: 6px;
  height: 10px;
  background-color: transparent;
  background-image: url(data:image/gif;base64,R0lGODlhBgAKAJEAADM2Zv///////wAAACH5BAUUAAIALAAAAAAGAAoAAAINBIRimdvHFETOUWglKwA7);
  background-repeat: no-repeat;
  margin-left: .13em;
  margin-right: .25em;
}
.pre-icon {
  white-space: nowrap;
}
.pre-icon > span {
  white-space: normal;
}
Text text <a class="pre-icon" href="#"><span>FirstWord word2 word3</span></a> text after link.
like image 194
Oriol Avatar answered Sep 30 '22 14:09

Oriol


While it would be really cool if we could finally get a :first-word selector (Great post by Chris Coyier about that: https://css-tricks.com/a-call-for-nth-everything/), you probably need an extra span to do this. Here's a fork on your fiddle that looks to be doing what you described:

https://jsfiddle.net/0hrn2Lao/

HTML:

<p>Text text <a class="pre-icon" href="#">
  <span>FirstWord</span> word2 word3</a> text after link.
</p>

CSS:

.pre-icon span {
  display:inline-block;
  text-decoration:underline;}

.pre-icon span::before {
  content:"";
  display:inline-block;
  width:6px;
  height:10px;
  background-color:transparent;
  background-image:url(data:image/gif;base64,R0lGODlhBgAKAJEAADM2Zv///////wAAACH5BAUUAAIALAAAAAAGAAoAAAINBIRimdvHFETOUWglKwA7);
  background-repeat:no-repeat;
  margin-left:.13em;
  margin-right:.25em;
  white-space:nowrap;
}

Basically, put the pseudo element with the image on the span containing the first word, then let the span be inline-block, without having to put the inline-block rule on the <a> element itself.

If you wanted, you could probably use some jQuery to insert the span around the first word of <a class="pre-icon"> throughout the document - but if you're specifically adding that class, maybe it's not a lot of effort to just drop the span in manually too...depends on your pain tolerance, I guess :-)

like image 44
ryantdecker Avatar answered Sep 30 '22 13:09

ryantdecker