1

I have a fixed width menu, with flex items.

'New' items in the menu have a notification style label after the item text. When the text is short, the label positions immediately after the text (see 'News' item in the snippet).

If the text is long it forces the label to the right of the menu leaving a white-space gap between the text and the label (see 'Looooonggggg Newwwwws & Blogggggs' item in snippet).

I have tried, justify-content: flex-start, and flex: 0 1 auto - they do nothing. If I use flex: 0 1 0 the item text breaks to it's longest word - which is not what I am looking for.

Does anyone know how I always position the labels immediately after the item text?

The position I am trying to achieve:

enter image description here

body {
  background: blue;
}
.menu {
  background: white;
  width: 290px;
}
.item {
  padding: 1rem;
  display: block;
  align-items: center;
  display: flex;
  
}
.label {
  margin-left: .5rem;
  width: .5rem;
  height: .5rem;
  background: red;
  border-radius: 50%;
}
.shrunk div {
  flex: 0 1 0;
}
<div class="menu">
  <a class="item new" href=""><div>News</div><span class="label"></span></a>
  <a class="item new" href=""><div>Looooonggggg Newwwwws &amp; Blogggggs</div><span class="label"></span></a>
  <a class="item" href=""><div>Blogs</div></a>
  <a class="item new shrunk" href=""><div>If I set flex shrink and basis to 0 this happens</div><span class="label"></span></a>
</div>
matthewelsom
  • 944
  • 1
  • 10
  • 21

3 Answers3

1

You don't need flexbox here. You will need link text to be displayed as inline element. Circle can be displayed using unicode character (in pseudoelement's content). Also you can simplify your HTML and CSS:

body {
  background: blue;
}

.menu {
  background: white;
  width: 290px;
}

.item {
  padding: 1rem;
  /* for links to consume entire line */
  display: block;
}

.item.new:after {
  /* non-breakable space and circle */
  content: "\00A0\25CF";
  /* display as inline-block to avoid underlining */
  display: inline-block;
  color: red;
}
<div class="menu">
  <a class="item new" href="">News</a>
  <a class="item new" href="">Looooonggggg Newwwwws &amp; Blogggggs</a>
  <a class="item" href="">Blogs</a>
  <a class="item new" href="">If I set flex shrink and basis to 0 this happens</a>
</div>

Feedback on Update

There is no CSS way make block with multiline text to adjust to its width of text. The only way I know you can do is to wrap every word in span via JavaScript, get X coordinate (left relative to parent + outer width) of span most big X coordinate and then based on this biggest X coordinate add width or margin-right to this text block. Also you can resort to text-align: justify.

Vadim Ovchinnikov
  • 13,327
  • 5
  • 62
  • 90
1

The main problem here is that the div inside the anchor a is displayed as block (its default) hence will push the label to a new line.

By making the anchor a flex container won't solve that, it will instead create 2 columns out of the div and the span and i.e. that's why the red dot is pushed to right in the 2nd item.

The most appropriate, and simplest, solution based on the existing markup structure would be to change the div to a span (as it needs to be a non-block level element) and remove the flex properties.

body {
  background: blue;
}
.menu {
  background: white;
  width: 290px;
}
.item {
  padding: 1rem;
  display: block;  
}
.label {
  margin-left: .5rem;
  display: inline-block;       /* needed for the label to apply the height  */
  width: .5rem;
  height: .5rem;
  background: red;
  border-radius: 50%;
}
<div class="menu">
  <a class="item new" href=""><span>News</span><span class="label"></span></a>
  
  <a class="item new" href=""><span>Looooonggggg Newwwwws &amp; Blogggggs</span><span class="label"></span></a>
  
  <a class="item" href=""><span>Blogs</span></a>
  
  <a class="item new shrunk" href=""><span>If I set flex shrink and basis to 0 this happens</span><span class="label"></span></a>
  
</div>

If the purpose of the red dot is no more than being a red dot, you can optimize your code down to only this, where I used a pseudo element for it.

An even more efficient way for the red circle could be to use a dot character, as shown in one of the other answers

body {
  background: blue;
}
.menu {
  background: white;
  width: 290px;
}
.item {
  padding: 1rem;
  display: block;  
}
.item.new::after {
  content: '';
  margin-left: .5rem;
  display: inline-block;       /* needed for the pseudo to apply the height  */
  width: .5rem;
  height: .5rem;
  background: red;
  border-radius: 50%;
}
<div class="menu">
  <a class="item new" href="">News</a>
  
  <a class="item new" href="">Looooonggggg Newwwwws &amp; Blogggggs</a>
  
  <a class="item" href="">Blogs</a>
  
  <a class="item new shrunk" href="">If I set flex shrink and basis to 0 this happens</a>
  
</div>
Asons
  • 84,923
  • 12
  • 110
  • 165
  • Thanks for the response, both are possible solutions to position the dot after the text - but I need the dot to clear the text completely. Hence the reason I am using a separate element for the dot, the dot is also aligned to the center - hence the reason I am not just using inline elements. I added a picture to the original post so you can see the position I am trying to achieve. – matthewelsom Jul 20 '17 at 14:27
  • Having said that, this is probably the way I will go, as I cannot see any other solution....! – matthewelsom Jul 20 '17 at 14:28
  • @matthewelsom The white space appearing in the 2nd line you can't catch, as the `div` you use won't resize after the line break occurs. That is not how the box model works. If you really need that, you'll have to use a script. – Asons Jul 20 '17 at 15:53
  • Yeah - I just saw a comment on the OP that points me in that direction too. Appreciate the input, probably I will settle with your original `span` suggestion as a quick compromise. Thanks – matthewelsom Jul 20 '17 at 15:59
0

The gap in 'Looooonggggg Newwwwws & Blogggggs' exists because you're not allowing word 'Blogggggs' to be broken.

Add word-wrap: break-word and word-break: break-all to allow this.

body {
  background: blue;
}

.menu {
  background: white;
  width: 290px;
}

.item {
  padding: 1rem;
  display: block;
  align-items: center;
  display: flex;
}

.label {
  margin-left: .5rem;
  width: .5rem;
  height: .5rem;
  background: red;
  border-radius: 50%;
}

.item div {
  flex: 1;
  word-wrap: break-word;
  word-break: break-all;
}
<div class="menu">
  <a class="item new" href="">
    <div>News</div><span class="label"></span></a>
  <a class="item new" href="">
    <div>Looooonggggg Newwwwws &amp; Blogggggs</div><span class="label"></span></a>
  <a class="item" href="">
    <div>Blogs</div>
  </a>
  <a class="item new shrunk" href="">
    <div>If I set flex shrink and basis to 0 this happens</div><span class="label"></span></a>
</div>
fen1x
  • 5,616
  • 6
  • 28
  • 39