I'm currently developing a website and my client wants the text of various articles to overflow into two columns. Kind of like in a newspaper? So it would look like:
Today in Wales, someone actually Nobody was harmed in
did something interesting. the incident, although one
Authorities are baffled by this elderly victim is receiving
development and have arrested the counselling.
perpetrator.
Is there a way I can do this with just CSS alone? I'd prefer not to have to use multiple divs. I'm open to using JavaScript too, but I'm really bad at that, so help would be appreciated. I was thinking maybe JavaScript could count how many <p>'s there are in the content div, and then move the second half of them to be floated right based on that?
The good news is that there is a CSS-only solution. If it was implemented, it would look like this:
div.multi {
column-count: 3
column-gap: 10px;
column-rule: 1px solid black;
}
I'd probably handle it in your backend, whatever that happens to be. An example in PHP might look like:
$content = "Today in Wales, someone actually did something...";
// Find the literal halfway point, should be close to the textual halfway point
$pos = int(strlen($content) / 2);
// Find the end of the nearest word
while ($content[$pos] != " ") { $pos++; }
// Split into columns based on the word ending.
$column1 = substr($content, 0, $pos);
$column2 = substr($content, $pos+1);
It should probably be possible to do something similar in JavaScript with InnerHTML, but personally I'd avoid that whole situation because more and more people are using plugins like NoScript that disables JavaScript till it's explicitly allowed for x site, and above anything else, div's and CSS were designed to degrade nicely. A JavaScript solution would degrade horribly in this case.
Here's a JQuery plugin which does columns automatically, and can even vary number of columns based on screen size.
I haven't used this myself, but check it out.
If you are using Mootools, you can check out MooColumns.
First off, i don't think just css can do that, but i would love to be proven wrong.
Second, just counting paragraphs won't help you at all, you need at least all the heights and calculate the middle of the text height based on that, but you'd have to account for window resizing etc. I don't think there is a reasonably simple off the shelf solution. Unfortunately i'm pessimistic about finding a perfect solution to this problem, But it is an interesting one.
This is difficult to achieve in HTML/CSS/JS for a reason (although I'm sure it's possible).
Newspapers use multiple columns to reduce the line width make text more readable. This is fine on paper because when you finish one column you flip your eye up to the beginning of the next.
On the web we use scrolling to allow text to continue past the bounds of the screen therefore don't need columns.
This is supported in a Mozilla only CSS extension: -moz-column-count. See : https://developer.mozilla.org/en/CSS3_Columns
Related
I need to add line breaks in the positions that the browser naturally adds a newline in a paragraph of text.
For example:
<p>This is some very long text \n that spans a number of lines in the paragraph.</p>
This is a paragraph that the browser chose to break at the position of the \n
I need to find this position and insert a <br />
Does anyone know of any JS libraries or functions that are able to do this?
The only solutuion that I have found so far is to remove tokens from the paragraph and observe the clientHeight property to detect a change in element height. I don't have time to finish this and would like to find something that's already tested.
Edit:
The reason I need to do this is that I need to accurately convert HTML to PDF. Acrobat renders text narrower than the browser does. This results in text that breaks in different positions. I need an identical ragged edge and the same number of lines in the converted PDF.
Edit:
#dtsazza: Thanks for your considered answer. It's not impossible to produce a layout editor that almost exactly replciates HTML I've written 99% of one ;)
The app I'm working on allows a user to create a product catalogue by dragging on 'tiles' The tiles are fixed width, absolutely positioned divs that contain images and text. All elemets are styled so font size is fixed. My solution for finding \n in paragraph is ok 80% of the time and when it works with a given paragrah the resulting PDF is so close to the on-screen version that the differences do not matter. Paragraphs are the same height (to the pixel), images are replaced with high res versions and all bitmap artwork is replaced with SVGs generated server side.
The only slight difference between my HTML and PDF is that Acrobat renderes text slightly more narrowly which results in line slightly shorter line length.
Diodeus's solution of adding span's and finding their coords is a very good one and should give me the location of the BRs. Please remember that the user will never see the HTML with the inserted BRs - these are added so that the PDF conversion produces a paragraph that is exactly the same size.
There are lots of people that seem to think this is impossible. I already have a working app that created extremely accurate HTML->PDF conversion of our docs - I just need a better solution of adding BRs because my solution sometimes misses a BR. BTW when it does work my paragraphs are the same height as the HTML equivalents which is the result we are after.
If anyone is interested in the type of doc i'm converting then you can check ou this screen cast:
http://www.localsa.com.au/brochure/brochure.html
Edit: Many thanks to Diodeus - your suggestion was spot on.
Solution:
for my situation it made more sense to wrap the words in spans instead of the spaces.
var text = paragraphElement.innerHTML.replace(/ /g, '</span> <span>');
text = "<span>"+text+"</span>"; //wrap first and last words.
This wraps each word in a span. I can now query the document to get all the words, iterate and compare y position. When y pos changes add a br.
This works flawlessly and gives me the results I need - Thank you!
I would suggest wrapping all spaces in a span tag and finding the coordinates of each tag. When the Y-value changes, you're on a new line.
I don't think there's going to be a very clean solution to this one, if any at all. The browser will flow a paragraph to fit the available space, linebreaking where needed. Consider that if a user resizes the browser window, all the paragraphs will be rerendered and almost certainly will change their break positions. If the user changes the size of the text on the page, the paragraphs will be rerendered with different line break points. If you (or some script on your page) changes the size of another element on the page, this will change the amount of space available to a floating paragraph and again - different line break points.
Besides, changing the actual markup of your page to mimic something that the browser does for you (and does very well) seems like the wrong approach to whatever you're doing. What's the actual problem you're trying to solve here? There's probably a better way to achieve it.
Edit: OK, so you want to render to PDF the same as "the screen version". Do you have a specific definitive screen version nominated - in terms of browser window dimensions, user stylesheets, font preferences and adjusted font size? The critical thing about HTML is that it deliberately does not specify a specific layout. It simply describes what is on the page, what they are and where they are in relation to one another.
I've seen several misguided attempts before to produce some HTML that will exactly replicate a printed creative, designed in something like a DTP application where a definitive absolute layout is essential. Those efforts were doomed to failure because of the nature of HTML, and doing it the other way round (as you're trying to) will be even worse because you don't even have a definitive starting point to work from.
On the assumption that this is all out of your hands and you'll have to do it anyway, my suggestion would be to give up on the idea of mangling the HTML. Look at the PDF conversion software - if it's any good it should give you some options for font kerning and similar settings. Playing around with the details here should get you something that approximates the font rendering in the browser and thus breaks lines at the same places.
Failing that, all I can suggest is taking screenshots of the browser and parsing these with OCR to work out where the lines break (it shouldn't require a very accurate OCR since you know what the raw text is anyway, it essentially just has to count spaces). Or perhaps just embed the screenshot in the PDF if text search/selection isn't a big deal.
Finally doing it by hand is likely the only way to make this work definitively and reliably.
But really, this is still just wrong and any attempts to revise the requirements would be better. Keep going up one step in the chain - why does the PDF have to have the exact same ragged edge as some arbitrary browser rendering? Can you achieve that purpose in another (better) way?
Sounds like a bad idea when you account for user set font sizes, MS Windows accessibility mode, and the hundreds of different mobile devices. Let the browser do it's thing - trying to have exact control over the rendering will only cause you hours of frustration.
I don't think you'll be able to do this with any kind of accuracy without embedding Gecko/WebKit/Trident or essentially recreating them.
Maybe an alternative: do all line-breaks yourself, instead of relying on the browser. Place all text in pre tags, and add your own linebreaks. Now at least you don't have to figure out where the browser put them.
I have a bit of a strange question. My apologies if this has already been asked and answered...I think part of my problem is that I don't really know what exactly I should be searching for since I don't even remotely know what the right approach is!
I have a website that has HTML pages containing product reviews. Each review has about 15 standard text fields, such as Strengths, Weaknesses, Summary, etc. Each of these text fields is generally approximately the same number of words from one review to the next, but they do vary in length by +/- 20% or so. Right now, when I print them, some of them take one page and some of them take two pages.
I'm trying to come up with a decent way to print each of these product reviews such that each one always fits on one sheet of paper. I'm OK with making some assumptions, such as assuming a certain paper size and orientation. What I'm imagining is that each of my review's text fields (Strengths, for example) will have a certain "box" on the printed page that it can occupy and I'll have some code that programmatically resizes the font or adjusts the vertical line spacing (or perhaps just truncates the text and adds "..." at the end) until it fits into the "box".
I'm just looking for some pointers on what the most sensible approaches might be for this sort of thing. For example, here are some of the random thoughts that come to my mind:
1) Is there anything that can be done with CSS in a print style sheet to do this kind of dynamic resizing and/or truncating automatically?
2) I'm up for having a button on each page that says "Print" that when clicked generates a new page with completely different markup that is optimized for what I'm trying to do. All of the data in these pages is stored in a database, so this would be an acceptable solution. If I do end up opting for this option, would it be most sensible to try to lay this out using HTML tables, divs, or something else?
4) I'm wondering if I can do the programmatic resizing using JavaScript. Is there some kind of function or library that is used for this sort of thing (calculating how much space a block of text needs)? If so, is this a fairly reliable way of achieving what I'm shooting for?
5) Is it better to do what I'm trying to do on the server side somehow? I'm using PHP, of that helps.
6) If all else fails, is there a way to programmatically generate PDF pages server side that I can layout per my one-page requirement? Is there a good PHP library out there for that sort of thing?
Thanks in advance for any suggestions and pointers! As you can tell, I'm pretty lost on what path I should start down!
Without using CSS3 you could:
1) Store the original font sizes in variables using javascript
2) Get the Document Height through Javascript
var body = document.body,
html = document.documentElement;
var height = Math.max( body.scrollHeight, body.offsetHeight,
html.clientHeight, html.scrollHeight, html.offsetHeight );
3) Check to make sure your height is small enough to be printed on one page
4) If not start loop where you:
a) decrease each font-size by 1
b) Check height again
c) if good, then do window.print()
d) If still too much height continue in loop
5) Set all your font-sizes back to the original values.
Hope this helps.
:) David
css3 intruduces the vw and vh units which should suit your needs.
Downside is support is ie9+ only
I'm trying to find a way to control how lines break in a menu listing, so that we don't wind up with a single word in the second line.
For example, I have a navigation menu that is 200px wide. One of the items is "City Development Reources & Plan." Natively, the line breaks like this:
City Development Resources & Plan
What I want is a minimum number of words or characters to break, so that it looks more like this:
City Development Resources & Plan
I'm not finding anything in pure CSS to manage that, and before I go down the javascript rabbit-hole, I was wondering if anyone had something already handy.
Thanks for any help,
ty
Unfortunately there is no way to do this with css only. You can either add the line break manually or write a javascript function to manage this.
Since you have the fixed 200 width on the container, you can trick the browser using left-right padding, just measure it with the web inspector and add padding until breaks on a nice way.
I have a ul>li structure with a list of file paths. It's in a container about 200px wide, so it wraps longer paths down a line which works fine but isn't desireable.
I can use text-overflow: ellipses which works well except my main concern is being able to see the file name, so it would be better to have it cut off the beginning and show the end.
I'm pretty sure this isn't possible with CSS, so I'm assuming I'll need to use JS, the only issue is I need it to be as unobtrusive as possible - the text in the li is referenced when the object is clicked on.
Any ideas on a good way to approach this?
I know people always want code, so here's what I'm doing: http://jsfiddle.net/qbvcn/
A simple solution would be something like this (assuming you'd be willing to use jQuery):
$('li').each(function() {
var $this = $(this);
if ($this.text().length > 20) {
$this.html($this.text().replace(/^(.*)(.{17})$/, '<span style="display:none">\$1</span><span class="ellipsis">...</span>\$2'));
}
});
This is really only going to work if you know the number of characters your element can hold. Although you can overcome this by adding some javascript to calculate this value you for you, see this question.
text-overflow is a nice CSS feature to have, but it is somewhat limited to the features it offers. All it does is truncate and add an ellipsis to the end of the text; it doesn't have the options or flexibility to do what you're asking for here.
Many people (including myself) kicked up a fuss when Mozilla refused to support it in Firefox until FF7, but the reasons given by Mozilla for not supporting it sooner, because of its lack of flexibility, were right.
The simple fact is that if you want anything more than a simple trailing ellipsis, you'll need to do it in Javascript. The ThreeDots jQuery plugin pointed out by #GolezTrol in the comments may be useful. There are other options, though.
Hi
To make convenient some animation, my strategy for a client-side script involves grouping list items into DIVs. It seems that having anything other than LIs as the children of OL or UL elements does validate. However, I'd be doing this in script, so no validation issue (for what that's worth!).
But might this cause a problem with screen readers and so on?
Thanks for any thoughts
One way to find out! I don't think there would be too much trouble, but the only way to know is to test it. Javascript's interaction with screen readers is a complex subject, so I'm hesitant to make any firm judgments. NVDA seems like a good place to start. :D
I'd normally steer clear of invalid markup, but I can't think of a better way to group things in the way you want to. Perhaps consider whether a single list is the best markup to use rather than multiple lists or some other set of constructs. Since you are needing to group list items in this way, it seems likely that there's a semantic reason for grouping them in markup as well.
As it goes, if browsers cope with the invalid markup in question, it is likely to work in screen readers and the like as well. As CrazyJugglerDrummer says, it's best to test it. However, you never know when that invalid markup is going to start causing problems in future software releases.
First off, screen readers and JavaScript do not have the best track record of compatibility. (Correct me if I'm wrong, I am no expert on usability) From what I have come to understand, screen readers typically read a static version of your page, and refresh it at seemingly random times irregardless of what dynamic changes have occured through JavaScript. This was my last experience with screen readers, but that was 3 years ago so things may have changed for the better.
To give an example, if your dynamic list is in fact an accordion that expands and contracts, you cannot with any degree of certainty know if a screen reader will display the text being shown (even if the JavaScript made the text visible to the screen).
Before I would start worrying about problems your script might cause for screen readers, I would instead focus on your overall accessibility of the site structure (HTML+CSS). Are you making integral elements to your page keyboard focusable? Are you following WAI-ARIA guidelines? Are you using the correct technique to hide content (situation dependent) display:none, left:-9999px, or visibility:hidden?