I'm attempting to align a text-based list of items for an e-mail. Basically the problem I have is that it only works with fixed-width (monospaced) fonts - I'd like a script that somehow can align it based on the width of each letter in a standard Arialish font.
function sprintf_nbsp() {
$args = func_get_args();
return str_replace(' ', ' ', vsprintf(array_shift($args), array_values($args)));
}
$format = '%-6s%-\'.35.35s...%\'.10s<br>';
$str = sprintf_nbsp($format, '1', 'A list of items - this is the first', '$49.99');
$str .= sprintf_nbsp($format, '100', 'This is something else', '$4.99');
$str .= sprintf_nbsp($format, '5', 'A book', '$499.99');
$str .= sprintf_nbsp($format, '16', 'Testing the function', '$49.99');
echo '<div style="font-family:Courier">'.$str."</div>";
echo '<br><br>'.$str;
(the sprintf_nbsp() may not be necessary, I just found it on the php forums, I'm open to other solutions)
fixed-width (monospaced) fonts - I'd like a script that somehow can
align it based on the width of each letter in a standard Arialish
font.
Simply put, this is impossible.
With a fixed-width font every character has the same width, hence the name, fixed width.
With other fonts this is not the case. For example, you can plainly see that the i is much narrower than the M.
You can't know which font the user uses, even if you specify something like font-family: Arial this may not always work, different systems (OSX, X11, etc.) use different fonts, and some users also override font website's settings, etc.
And even if you knew for 100% certainty which font the user uses, it would be pretty much impossible to align everything to be pixel-perfect.
So, you have two options: either use a fixed width font ("Consolas" is a standard Windows font which looks fairly good), or use a different layout.
What you probably want is something like this:
<style>
span { display: block; width: 20em;}
</style>
<span>Some text</span>
<span>Hello, world!</span>
<span>A swallow could not carry a coconut</span>
Here, every <span> is the same width (20em) regardless of the amount of text it contains.
Using spaces to align stuff is almost always a bad idea. Using CSS is not only much cleaner, it's also a lot easier.
Related
I have a table of items which has description field. When listing out all items I would like to show exactly three rows of text followed by "..." if the text is longer.
I can do something like
<style>
.box {
overflow: hidden;
text-overflow: ellipsis;
-o-text-overflow: ellipsis;
-ms-text-overflow: ellipsis;
height: 60px;
}
</style>
...which works fine when there is a lot of text and the text is split in several lines. But if I have no new line chars in text I see only one line of text which is shortened.
Also if I have text formated like
Something
//blank-line
//blank-line
I am writing about something, because something is not nothing
I get my three lines...but it looks bad because first line is only "Something", and the two other are blank. So I figured I'd have to pre-format it before I send it from controller to view, and I tried first to approach that problem by removing empty lines and connecting whole text to one line, however this does nothing
$description = preg_replace( "/\r|\n/", "", $array[0]->description);
return $description
Which is maybe excepted since HTML formatted text enters the database
<p class="MsoNormal">Something<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">Blah blah...something else...
Does anyone have an idea how to solve this?
Naturally, text will flow to the next line when it reaches the edge of its container element in the browser. I assume your container's width is controlled by some styling (whether fixed or responsive).
So in your case I'd ditch the ellipsis styling, see (from physically looking in the browser) how many characters it takes to produce the 3 lines you desire, and then do (I also assume you don't want to keep the HTML):
$description = strip_tags($array[0]->description);
if (strlen($description) > $maximumLength) {
$description = substr($description, 0, $maximumLength) . "...";
}
return $description
Of course there are other ways to do it on the client side with CSS or JavaScript, but what I see on most sites is they settle on a fixed length for their excerpt and just say any text longer than x characters must be truncated.
How does the php echo or print effects the letter lowercase to become uppercase? or is it a css issue?
for example:
echo "Against";
// Outputs AgaInst for me
in the css there is one parent class that says: text-transform:uppercase; but the specific title overwrites that css with text-transform:capitalize; if i just write it in plain html it works fine but when i echo it with php it does turn i to I!?
Please note the AgaInst and TIed in table headers.
Found the solution as #Mathias Pointed out the font size.
Problem was the font size, it happens for for sizes smaller than font-size:12px;
It seems to be the rendering of the font in that small size.
Try increasing the font size or use a different font. When I try Open Sans in 10px or smaller in Chrome on OSX I get the same effect. Different OS and different browsers might render the text differently.
PHP has absolutely no effect what so ever, on the capitalisation of a string, unless passed through a string modification function.
The code <?php echo 'Against'; will simply output the word Against. The display of this word is entirely up to the HTML, CSS, the viewing browser and even the viewing OS and machine.
For example:
<?php
$string = 'Foo bar';
$length = strlen($string);
echo '<div style="width: '.$length.'px;">'.$string.'</div>';
The above obviously does not work, as $length is 7 and 7px is smaller than the size of the outputted text.
I also understand that font size and other factors will come into play, as well.
What I'm looking for is something like this:
<div style="width:xxx; float:left;">Label 1</div><input type="checkbox"/><br/>
<div style="width:xxx; float:left; clear:left;">Longer Label 2</div> <input type="checkbox"/><br/>
<div style="width:xxx; float:left; clear:left;">Even Longer Label 3</div> <input type="checkbox"/><br/>
If you know the font you'll be using, you want to know about imagettfbbox().
But yeah, just dont give widths and right-align the text, or use a grid-system layout like Bootstrap or 960.gs.
My understanding is that your are trying to match the length of the string to the dimensions of the corresponding . As you have already indicated this is only possible if you take Font Type and Size into consideration. Assuming you would have a mono-spaced font you would have to multiply $length with a factor.
The real messy part starts if you use not mono-spaced fonts...
Also if you set value of display property to inline-block div element behaves like a block element but it's width changes with it's containing elements
display: inline-block
I have run into this problem a few times. I have no problem limiting characters in a string to a specific number. However, some characters are longer than others so it wraps to another line or makes my DIV element wider and not uniform with the rest of my website.
For instance:
Literacy - Is it the Sa
Machu Picchu, Cuzco, Pe
are the exactly the same amount of characters (23) including spaces but the Machu Pichu one is longer in terms of the actual width on screen.
Is there any way to have a uniform size for a string that is based on the width of the actual string as opposed to the number of characters? Someone has had to have come up with a solution to this before right?
First (obvious) solution: switch to a fixed-width font such as Courier, Lucida Console, Consolas, etc.
Second solution: use the GD library to write strings to a graphic object and measure that object.
You'd probably have to play with GD and imagefontwidth(): http://ar2.php.net/manual/es/function.imagefontwidth.php
Without writing an algorithm in PHP to limit characters based on "font-widths" for the specific font you are using, you can use a monospace font.
Alternatively, I'm sure a JavaScript solution could be written as well to test the widths, but I'm not sure how off of the top of my head.
This can't be done in PHP -- the best you can do is approximate. Different browsers and different operating systems render font widths differently for the same font. So even if you manually stored an array of character font widths for the font on your browser and os, it might not match up with others.
It's usually better to work your design around the possibility of different-width fonts than to try to force it.
That being said, this can be done perfectly (without approximation) in javascript, albeit with a little bit of a hack. There are a number of possible methods, but here's one: Start by rendering the full string in a div that has width that you are looking for, then measure the div's height. If it is larger than one line could possibly be, then start a loop progressively removing the last word. Keep going until the height of the div is for one line.
Use CSS for formatting so they all have uniform widths - no jagged edges on the right side. Something like this:
p { text-align: justify; }
Had some fun workin on this CSS + JS solution. It wasn't tested intensively (Firefox + IE7/8) but it should work ok...
<script type="text/javascript" src="jquery.js"></script>
<style>
.monospaced, .not-monospaced{
font: normal normal 16px/16px Verdana; /* not monospaced font */
clear: both;
}
.monospaced span{
float: left;
display: block;
width: 16px;
text-align: center;
}
</style>
<script>
$(document).ready(function(){
$('.monospaced').each(function(){
var monospace = $(this).html(); // .trim() does not work at IE http://api.jquery.com/jQuery.trim/ (view comments)
monospace.replace(/(^[\s\xA0]+|[\s\xA0]+$)/g, '');
mono = monospace.split('');
for(i = 0; i < mono.length; i++){
if(mono[i] == ' ')
mono[i] = ' ';
mono[i] = '<span>'+mono[i]+'</span>';
}
$(this).html(mono.join(''));
});
});
</script>
</head>
<body>
<div class="not-monospaced">
This is supposed to be monospaced...
</div>
<div class="not-monospaced">
mmmm mm mmmmmmmm mm mm mmmmmmmmmm...
</div>
<div class="monospaced">
This is supposed to be monospaced...
</div>
<div class="monospaced">
mmmm mm mmmmmmmm mm mm mmmmmmmmmm...
</div>
</body>
When building websites I'm forever chopping up strings to make them display nicely as headings and paragraphs. I use the substr function to chop-off unwanted characters and then add in ellipses. For example:
if ( strlen ( $mystring ) > 22 ) {
echo substr( $mystring,0,21 ).'...';
} else {
echo $mystring;
}
This works pretty good most of the time, but it is far from perfect. Check out how the shortened headings look on one of my sites. You can clearly see a lot of inconsistency in how the shortened headings look.
Surely, there is a better PHP method/ technique?
Your problem is that normal fonts are not monospaced, i.e. the various letters have different widths. Because PHP can't tell the final width of the resulting string in the browser, it is impossible to tell what position one needs to cut the string at.
There are jQuery based solutions for this (jQuery, running in the browser, does have access to the actual width information. #Dan shows a plugin in his answer); the downside of this of course is that it won't work without JavaScript.
If you want to invest the time, it would be possible to use GD's imagettfbbox() to calculate the approximate boundary using a common font like Arial. That would be far from perfectly reliable, but should give you a rough idea where to apply the cut.
No, because PHP doesn't know anything about how the text is going to end up rendered in the browser. Other people aren't even seeing the same thing you are for the same HTML, so how can changing the HTML your PHP generates fix this?
The only way to get consistent length text is to do the adjustments on the client side.
Something like the jQUery Ellipsis plugin:
http://plugins.jquery.com/plugin-tags/ellipsis
Edit: My bad, you want ellipsis... Your ellipses looks fine on that page you showed...
If you Really want them to line up you could put the text in an inline element with max width such and such and overflow: hidden followed by a seperate element with the ellipsis.
Another way is play around with CSS. You don't cut your text (or you just shorten it a bit if it's very long) and then you place it in a fixed width container with overflow: hidden. If you want the dots you can add another element containing them above the end of the text with position: absolute.