Pixel-accurate text alignment - javascript

I'm using JavaScript to inflate a span of left-aligned text until it fills its container, or until it reaches variable thresholds in either height or width. This process results in a widely varying font-size.
My problem is that, with certain characters, there is a small amount of padding on the left... and while normally it's not noticeable, with very large font sizes it can reach 10 pixels or more.
I whipped up a page to demonstrate the effect on various characters:
http://jsfiddle.net/kBu7S/
The text span exists in a design where every other element going down the page is aligned pixel for pixel to the left edge, so it's very visually distracting with the larger text sizes.
Can anyone think of a way to calculate the amount of padding, so that I can bump the relative position of the span? Or maybe there's even a CSS solution? (letter-spacing and word-spacing have no effect.)
I'll admit that even a dirty solution seems pretty unlikely... thanks for your consideration though.

The padding is often called the "shoulder" of the type, and it's intrinsic to the design of the typeface. There's no simple way to counter-act it, because it's there for optical reasons, to give the type the right spacing. After all, if you type IIIIIII, you need to have some spacing between the capital I's, and that only comes from this padding. Other characters, like WWWWWW, need none.
Your best bet is to do an experiment with your typeface, and measure the actual padding on each character, then build a table mapping characters to their paddings. Then you can adjust the character's position. This is a lot of work, but I don't know what else you can do.

This worked on the fiddle:
#text:first-letter { margin-left:-3px}
You could expand that to a class...
.fontCorrection:first-letter { margin-left:-3px }
...and apply it as appropriate.

Well, you could build a script to generate an image using the same typeface with the same size (black on white background) and read the bitmap to count the distance from the left edge to the first black pixel.
It's kind of overkill, but it's the only thing I can think of.

Related

Using JavaScript to measure positions in print view, without Firefox pixel rounding of screen view?

In Firefox, the exact character width is adjusted (to nearest pixel) for on-screen viewing, but such adjustment does not occur in the print view. This means the number of lines in a paragraph (after wrapping) would differ.
I have some JavaScript that is used to add vertical margins to make two columns line up correctly, within a fixed width div. The alignment is correct on the screen, but not in the printed document.
I could make the font size and images very large and then use CSS transform: scale(0.1) to make the results small again.
I could have JavaScript separate each line in its own div (after wrapping), which would let me use white-space: nowrap.
Can you suggest something easier with less side-effects? Perhaps a CSS rule I'm not aware of?
I did notice if the user uses Ctrl+ zoom feature, then the problem goes away to some extent.

CSS 3D transform to make trapezoid of given edge lengths

I have an element of given dimensions (say, 100x300 px) living in a container of the same height and variable width that I want to transform using rotateX around -webkit-transform-origin: top center; while picking the -webkit-perspective of the container so that it appears that the bottom line of the image stays where it is but only expands to fill the entire container.
Wow, that sounds confusing. Here's a picture:
So basically, I want to create a trapezoid with a fixed upper width and a variable lower width. I can't however quite figure out the math behind the relations... Javascript welcome. Following example works IF the body is 600px wide: http://jsfiddle.net/24qrQ/
Now the task is to change the perspective and rotation continuously with the body width. Any Ideas?
Okay, after a glass of wine the maths came back to me:
First, let's look at the perspective / rotation ratio. Viewed from the side, it looks like this:
The red element is rotated around its upper edge, if we project its lower edge to the lower edge of the container, the intersection between the projection line and the line perpendicular to the container at its upper edge is the required viewpoint. We get this by simple trigonometry (notice phi here is in radians, not in degree).
If we apply this, the lower edge of the element will always appear on the lower edge of the container. Now the free parameter is rotation. This seems to have the relation
rad = pi/2 - element.width / container.width
for sufficiently large widths, however I can't quite wrap my head around the actual relationship. Here is a fiddle: http://jsfiddle.net/24qrQ/6/
Basically, you are trying to figure out how to put an object in 3D space, so it lines up with a 2D viewport. That's always a tricky thing.
I don't know what the math is, and most other probably don't either. This is hardly a common problem. But here's how I would go about figuring it out.
The only variable here is width. And the 2 values that would need to change based on the width is -webkit-perspective on the container and -webkit-transformon the inner element. So I would manually edit the values for a few different widths and record the 3D values that you had to enter to make things look right. (I'd use the web inspector to edit the values in realtime so you get immediate feedback)
One you have a few data points, plot them out on a graph and then try to figure out how they change. I have a hunch it's a parabolic curve, but it may but hyperbolic or sinusoidal too, my 3D math isn't good enough to know for sure.
Then you can try figure out an equation where when you input the widths you've sampled, you get back the manual 3D values you set previously. Then use JS to read the width of the container and set the CSS values to make it look right.
I've done that with 3 widths 300, 450, 600:
http://jsfiddle.net/24qrQ/3/
Some trends are obvious. As width increases, perspective goes up at an increasing reate, and rotation goes down at an increasing rate.
Figuring out the exact formula, is now up to you.
As a simpler alternative, if figuring out a formula becomes too difficult, you could manually curate a handful of widths and 3D values that look nice and store them in JS somewhere. Then you could just linearly interpolate between them. It wouldn't be exact, but it might be close enough.
It would also be less fun!

Is there a way good way to measure the width of a string (in pixels when rendered) in Javascript/HTML5

It seems like I could create an empty DOM element containing the string, set the opacity to zero, display it, and get then measure the width of the element, but that seems really hack-y. I'm wondering if there's a better way. Any ideas?
EDIT: I need the width in pixels when rendered to the screen, not the number of characters :)
Do you mean the pixel width? No, there's no easy way to predict that in Javascript without having the browser render it. It depends so much on what font the browser has chosen, font size (which could be affected by inheritance if set with percentage or em), letter spacing, element padding, etc ad nauseum.
Your proposed solution of rendering it in the browser, even with zero opacity or visibility:hidden (thanks commenters) is the best way I think.

hide lines of text not fully visible with javascript & css

I think this might be impossible, but is there some way using JQuery to prevent lines of text not fully visible from showing up on the screen when a user scrolls until the entire line is visible? That is, we want to prevent something like this from showing up:
Thanks!
I agree with #rahmanisback, don´t mess with the user's browsing experience.
However, what would perhaps be a nice "inbetween" solution, is using a transparency gradient so that the bottom pixels fade out. But that would apply also to "whole" lines, so perhaps that´s not a good solution for your problem.
I don't know if there is something out there to do that. But I think it will cause confusion more that it would make any visual enhancement ever. A user will not be happy when scrolling down and finds lines just "popup" suddenly, in opposite to normally easing out as a result of scrolling action.
After all, when we speak about a scrollable HTML element with scrollbars visible, a user is aware text might be partially shown and that is normal and needs to be scrolled down to read the remaining. I really would not recommend that.
But for a technical answer, I think you would need to fix the CSS line-height property of that scrolling element, say make it 8px or whatever fits your layout. Then, capture the scroll event and devide the jQuery scrollTop() by that CSS line-height, then check the results: if it have a fraction then that means there is a "partially visible" line. Don't forget aout margin and padding that can cause mistakes when calculating.
I believe I have had this problem also, in that you have a div with a specific height and overflow hidden.
Thinking about it i would resize the div based on the line-height of the text in the div.
Change the height of div so that it equals a multiple of the line height of the containing text....
ie 3 lines of text with line-height = 16 change the div height from 50 to 48px.
( i posted this at the same time as rahmanisback' answer )
Hypothetically you could measure the height of text area, measure the height of the line, find scroll position do some math and then have some way of hiding text that is not fully exposed yet (eg Using a white div of x height depending on your math). However, it seems like a lot of trouble to go to for something that is usually a non-issue. You might also be able to do something with the overflow property, but you might have some issues with that I'm not sure.
I thought of an alternate method that would be easier to implement. Capture scroll events and then change it to the closest multiple of line height.

ridonkulous large-font display issue. fontSize shatters words all over

I'm in the midst writing a Lessig-Method slideware object in javascript (so something fun, not important), and I keep encountering strange text layout anomalies, the likes of which I can't say I've ever seen. And yet, they are pervasive across my slides.
The background is straight-forward. Presentation has Slides, and Slides have Lines. A line, could be a word or a phrase, and in the images I'm linking, the slides have three Lines.
The presentation "screen" is the viewport of the browser window. The CSS line-height property of each Line is calculated by the viewport height divided by the number of lines. Each Line is a div with a font-size comfortably below the line-height (90%, but set in px).
A good looking slide looks like the first one on this page:
bbby.org/share/so_pics.html
(I can add only one link).
Here's where it gets weird:
Because everything calculates based on the viewport size, having the firebug console up, or switching to full-screen mode adjusts everything's size (upon refresh). In some cases, the first one to three letters of a word pushes all the way to the left of the screen, stacking on top of each other. The only thing different is that I went fullscreen and refreshed (and new sizes were calc'd).
Depending on the font-size modifier I set (90%, 80%, but again set in px), it could happen on a regular view (not full screen).
Has anyone ever seen anything like this before?
Funny that there are badges for trolling. I'd hate to see this site become the new youtube or failblog in our comments are issued.
That aside, the effect is controllable (though still not explained). By fine tuning the fontSize via script, I can see at what point certain letters in words fall apart.
For example, in a div with lineHeight=269 , the letters "ri" from the word "right" fly away as pictured in the original post with a fontSize >= 209 , but nothing under. The letter "l" in the word "left" has a higher number, possibly increased because "f" is also a tall letter.
For a currently consistent workaround to this very real and troubling problem (tyvm), I'm setting the fontSize attribute to be 73% of the lineHeight on the parent container.

Categories

Resources