Zachiel
Zachiel

Reputation: 155

Can I dynamically hide html characters based on the line wrap?

I have several data (say a name, an address, a telephone number, an e-mail address) in a row, because they occupy the thin footer of a webpage.

They are separated by a space-dash-space construct, like this (but centered):

Name - address - phone - mail address

On small screens, the whole page is smaller and the text wraps. I'm already making use of no-breaking spaces and word wraps to ensure that everything falls in place but the result is not satisfying.

What I get is:

Name - address -
  phone - mail

What I want is:

Name - address
 phone - mail

Is there any way, with CSS or JS, to dynamically hide some characters if they happen to be located at the start or at the end of a line?

If not, feel free to suggest different solutions that don't involve changing the original formatting of the text. Shall I find no solution, I will opt for:

- Name -- address -- phone -- mail -

turning into:

- Name -- address -
 - phone -- mail -

or something like that.

Upvotes: 4

Views: 2303

Answers (5)

David Mzareulyan
David Mzareulyan

Reputation: 41

Of course it is a bit late:) but I think the pure CSS solution may exists. Please see a code snipped below.

The point is that the list items (except the first one) have a negative margin on the left and the same positive margin on the right. As a result these margins annihilate being on the same line but provide a negative indent of second and further lines. And the container's "overflow: hidden;" hides the extra separators on the left. It is important here that the dividers have a fixed width.

ul {
  list-style: none;
  padding: 0;
  
  overflow: hidden;
}

li {
  display: inline;
  white-space: nowrap;
  margin-right: 0.66em;
  margin-left: -0.66em;
}

li::before {
  display: inline-block;
  content: "-";
  width: 0.66em;
}

li:first-child {
  margin-left: 0;
}

li:first-child::before {
  content: none;
}
<ul>
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
  <li>Item 4</li>
  <li>Item 5</li>
  <li>Item 6</li>
  <li>Item 7</li>
  <li>Item 8</li>
  <li>Item 9</li>
  <li>Item 10</li>
  <li>Item 11</li>
  <li>Item 12</li>
  <li>Item 13</li>
  <li>Item 14</li>
  <li>Item 15</li>
  <li>Item 16</li>
  <li>Item 17</li>
  <li>Item 18</li>
  <li>Item 19</li>
</ul>

Upvotes: 4

JasonWoof
JasonWoof

Reputation: 4196

I don't think you can do this directly, but here's a trick that might work for you:

If your text is text-align: left you can force breaks to happen just before your - symbol and then do a visual clip (overflow: hidden) to hide the left-most character or two of every line.

Demo: https://jsfiddle.net/h4t96hav/

So that does have the "-" symbol at the beginning of each line, but you can't see it because the inner div is shifted left two characters and the outer clips.

It would take a little fudging to get it to work with a variable-width font, but I think there's a decent margin for error (since there's a space).

Note that I set the chunks to be display: inline-block so wraps wouldn't happen to the left of the numbers.

A similar trick could of course be used for text-align: right but I can't think of a way to handle centered text.

Upvotes: 1

Ava
Ava

Reputation: 2429

There is no way to do this with pure CSS, unless you want to just--at certain screen sizes--set the list to stack vertically and remove the - from the document dynamically.

With Javascript, it's possible, but the solution I came up with can be pretty expensive if used a lot on a page, or if the screen is resized a lot, as it can trigger fairly extensive repainting on complex layouts.


Javascript Solution

First off, each of those elements, like "Name", "Address", "Phone", etc., would have to be an inline-block element, and the - character next to it would have to be an ::after pseudo-element. Then, you could go through each of those inline-block elements, and when you find one that has a vertical position on the page lower than the one before it, you would set [the one before its pseudo-element] to display: none and reset on page resize.

HTML

<div>
  <ul class='tacky'>
    <li>Name</li>
    <li>Address</li>
    <li>Email</li>
    <li>Phone</li>
  </ul>
</div>

Javascript

Requires jQuery

handleList = function(c, e){
  var last;
  var lastHeight;

  $("li", e).each(function(count, listItem){
    var height = $(listItem).offset().top;

    if(typeof last !== 'undefined'){

      if(lastHeight < height){
        $(last).addClass("no-tack");
      }else{
        $(last).removeClass("no-tack");
      }
    }

    last = listItem;
    lastHeight = height;
  });
};

// jQuery event bindings for load
// and resize
$(document).ready(function(){
  $(".tacky").each(handleList);
});
$(window).resize(function(){
  $(".tacky").each(handleList);
});

CSS

The CSS is here so we can make the Javascript a little more lightweight.

.tacky
{
  margin: 0;
  padding: 0;
  list-style-type: none;
}

.tacky li
{
  display: inline-block;
}

// add tack as a psuedo element
.tacky li:after
{
  content: "-";
  margin: 0 5px;
}

.tacky li:last-of-type:after
{
  content: "";
  margin: 0;
}

.tacky li.no-tack:after
{
  content: "";
  margin: 0;
  display: none;
}

CSS Solution

For this, you'd just pick a screen size (or series of screen sizes) under which the menu doesn't have tacks anymore. This isn't quite as dynamic, but is a compromise that uses all CSS.

CSS

.tacky
{
    margin: 0;
    padding: 0;
    list-style-type: none;
}

.tacky li
{
    display: inline-block;
}

.tacky li:not(:last-of-type):after
{
    content: "-";
    padding: 0 5px;
}

// Media selector to hide tack characters.
//
// 768 is the max screen width this will
// be visible on.
@media (max-width: 768px){ 
    .tacky li:after
    {
         display: none;
    }
}

Upvotes: 1

Nutshell
Nutshell

Reputation: 8537

Maybe add a CSS class on a <span> element between dash like this :

Name - address <span class="toHideOnMobile"> - </span> phone - mail address

Then use a CSS for small devices like this :

@media (max-width: 767px){
    .toHideOnMobile { display: none; }
}

Upvotes: 2

J. Nilles
J. Nilles

Reputation: 87

If you know what you want it to split on. You can use the choose what goes to the next line by changing the CSS display property and use the CSS content property to add and remove your dashes based on the size of the display.

<style>

p > span {display: inline-block;}
p > span:after{ content: " -";}
p > span:last-of-type:after {content: "";}

@media (max-width: 500px){
  p > span.street {display: block;}
  p > span.street:after{ content: "";}
}
@media (max-width: 300px){
  p > span {display: block;}
  p > span:after{ content: "";}
}
</style>
<p>
<span class="street">1600 Pennsylvannia Ave.</span>  
<span>Washington</span>
<span>DC</span>
<span>1-555-555-5555</span> 
</p>

Here is a fiddle: https://jsfiddle.net/ae9j994j/4/

Upvotes: 1

Related Questions