Display a line-length guide on a non-wrapping text area - html

I'd like to display a read-only block of text as part of an HTML page - as it happens, it will be the monospaced text of the user's Git commit message - and while I want to display the text without wrapping, I would like to display a vertical line-length guide at 72 characters, so it's clear to the user when their lines have gone over the recommended length.
In some cases, the user will have entered lines of text much wider than the viewport.
Can I achieve this kind of effect with CSS?
(as an aside, I'm not drastically in favour of the text-wrapping guidelines, but my users need to be aware of them)

It's not really that practical to do it via CSS, as css doesn't give you any type of an nth-character selector. You could only draw a line at a fixed width which would be a best guess at your font character width.
However, if you're ok using a small amount of javascript, it could easily be done.
Here is a code sample I made for you showing how: http://codepen.io/beneggett/pen/GJgVrp
SO wants me to paste the code here as well as codepen, so here it is:
HTML:
<p>Example of syntax highlighting code at 72 characters w/ minimal javascript & css.</p>
<pre>
<code>
Here is my really awesome code that is nice
and it is so cool. If you are actually reading this, well I praise you for bearing with me
as you can see there is some short code
and some really, really, really, really, really, really, really, really, long boring code that is longer than 72 characters
it just goes on forever and ever and ever and ever and ever and ever and ever and ever and ever
The nice thing is we can tell our users when the code is short
or when it is getting way way way way way way way way way way way way way way way way way way way too looonggggg
oh wait, this isn't really code, it's just some gibberish text. but that's ok; the point is well made
i could go on and on and on and on and on and on and on and on and on and on and on and on and on and on and on and on and on, but you'd get tired of it
That's it for now
</code>
</pre>
<p> This is just a simple example using tools that I'm comfortable with. There may be better methods to suit your needs, but it's a good start</p>
CSS:
pre{
white-space: pre;
background: #ececec;
border: 1px solid #c3c3c3;
overflow: auto;
}
pre .long{
border-left: 1px dotted red;
color: red
}
JS (CoffeeScript):
$(document).ready ->
lines = $('pre code').text().split('\n') # First we'll find all the lines of code
$('pre code').text('') # then, remove the old code, as we're going to redraw it with syntax highlighting
$.each lines, (n, elem) -> # Loop through each line
if elem.length > 72 # If it's longer than 72 characters, we'll split the good_code and the long_code then add some html markup to differentiate
good_code = elem.substring(0,71)
long_code = elem.substring(71)
$('pre code').append "#{good_code}<span class='long'>#{long_code}</span>\n"
else # otherwise we will just keep the original code
$('pre code').append elem + '\n'
This was just a simple illustration using tools that are simple for me; but the point is to illustrate it's pretty simple code that could easily be adapted to what you're trying to do.

Use a monospaced typeface like courier new, figure out how wide 72 characters is and lay a div underneath your text with that width and dashed right border.

As said by Ben Eggett use Monospaced fonts because
"A monospaced font, also called a fixed-pitch, fixed-width, or non-proportional font, is a font whose letters and characters each occupy the same amount of horizontal space."
Even 'l' and 'm' occupy the same space. So find out how much width each char occupies based on the font size you are using and the vertical line at that place of the container.
For other fonts the widths for each characters are different and since CSS is static you cannot do with just css.
Below jsfiddle link provides example of implementation using monospaced font "Courier New"
http://jsfiddle.net/mnLzyy2x/
<div class="git-msgs-container">
<p>I want to take a moment to elaborate on what makes a well formed commit message. I think the best practices for commit message formatting is one of the little details that makes Git great. Understandably, some of the first commits to rails.git have messages of the really-long-line variety, and I want to expand on why this is a poor practice.</p>
<div class="separator"></div>
</div>
Css is
.git-msgs-container {
width: 900px;
border: 1px solid red;
font-family: 'Courier New';
font-size: 15px;
position: relative;
}
p {
margin: 0;
padding: 0;
}
.separator {
height: 100%;
border-left: 1px solid blue;
position: absolute;
top: 0;
left: 648px;
}

Enhancing Kalyan Kumar S's recipe.
Here is fiddle: http://jsfiddle.net/4mu5Lwex/
HTML:
<div class="git-msgs-container">
<p>I want to take a moment to elaborate on what makes a well formed commit message. I think the best practices for commit message formatting is one of the little details that makes Git great. Understandably, some of the first commits to rails.git have messages of the really-long-line variety, and I want to expand on why this is a poor practice.</p>
<p>_________1_________2_________3_________4_________5_________6_________7_________</p>
<p>1234567890123456789012345678901234567890123456789012345678901234567890123456789</p>
</div>
It looks that for a font-size of 10pt, the width of the each character is 6pt so the vertical line is at 72x6 = 432pt.
CSS:
.git-msgs-container {
width: 900px;
border: 1px solid red;
font-family: 'Courier New';
font-size: 10pt;
position: relative;
}
.git-msgs-container p::after {
display:block;
position: absolute;
left: 432pt;
top: 0;
margin-top: 0;
height: 100%;
border-left: 1px solid blue;
content: '';
}

Many of these suggestions will work most of the time. But positioning at absolute pixels will break if the user has set their default font size to something other than what you had intended.
Use a scalable unit like em or rem to set your font size. Then figure out how many ems or rems a single character width is, and position your vertical line marker at 72 x the character width.
example:
div#container {
position: relative;
font-size: 1rem;
}
if you haven't changed your default font size, 1rem will equal 16px. (If you have, reset you font-size to default in your browser before continuing) Now measure a single character, or a line of characters and average it out. (take a screenshot and pull it into Photoshop or Gimp to do this) Divide the single character width by 16, and you'll get the character width in rem.
eg:
character width = 9px;
9 / 16 = 0.5625rem;
multiply by 72 to figure out positing:
72 characters = 0.5625 * 72 = 40.5rem
now position your vertical line:
div#container .verticalLine {
position: absolute;
top: 0rem;
left: 40.5rem;
}
This sets up the positioning based on font size, not pixels. So it will scale with the font size accordingly.
If you want a large font-size (say 1.5rem), then multiply your calculated 72 character by the desired font size.
40.5rem * 1.5 = 60.75rem
n.b. If you don't want to measure exactly, or you don't have a graphics program, then you can just adjust the positioning by trial and error until it's positioned in the right spot.

You definitely want a monospaced font. You can include one like Paul Hunt's Source Code Pro (Google Fonts) with the following CSS:
#import url(http://fonts.googleapis.com/css?family=Source+Code+Pro);
Then, structure your commit message in a div like the one below. (Note the empty guide div):
<div class="commit-message">
Commit message goes here.
<div class="guide"> </div>
</div>
..and apply this CSS:
.commit-message {
font-family:"Source Code Pro", sans-serif;
font-size: 12px;
position: relative;
}
.commit-message .guide {
position: absolute;
top: 0;
height:100%;
width: 43em;
border-right: 2px dashed red;
}
Depending on the font-size you apply in the first rule, you may need to adjust the width in the second rule.
Here's a fiddle showing it in action: http://jsfiddle.net/yjjybtLu/4/

A pre-calculated distance for the "red line" doesn't seem reliable to me.
A background with 50 characters in exactly the same font as used in the textarea might do the trick.
This suggestion still relies on a fixed height for the background, which is not good if the height of the textarea needs to be flexible.
<style type="text/css">
* {
font-family: monospace;
}
.textarea-wrapper {
position: relative;
width: 600px;
height: 400px;
overflow: hidden;
background-color: #fff;
}
textarea {
position: absolute;
width: 600px;
height: 400px;
background-color: transparent;
border-width: 2px;
}
span {
position: absolute;
top: 2px;
left: 2px;
display: block;
width: auto;
height: 100%;
border-right: 2px dotted #fcc;
color: #fff;
}
</style>
<div class="textarea-wrapper">
<span>01234567890123456789012345678901234567890123456789</span>
<textarea readonly="readonly">01234567890123456789012345678901234567890123456789 - 50 characters and more
</textarea>
</div>

Related

Can specific text character change the line height?

I have this code:
<p style="line-height: 1;overflow: hidden;">blah_blah</p>
<p>blah_blah</p>
<p style="line-height: 1;overflow: hidden;">qypj;,</p>
<p>qypj;,</p>
which results in (notice no underscore, and cut characters):
That is, it behaves that way in Firefox (66.0.3 on Windows 10). Other browsers seem to render the underscore. The above snippet runner also seems to work (even in Firefox), unless you run it in "Full page".
This Q is similar to Text changes height after adding unicode character except there are no tricks here. "_" is just a simple ASCII character.
My question is which behavior is the correct one.
Is specific character allowed to change line height (I thought it was only supposed to be font dependent)? Shouldn't line-height: 1 imply it can fit exactly any text?
I suppose some characters are special, such as "p", "g", "j" (and possibly "_") that draw below its line. Still which behavior is the correct one. Is it considered overflow or not?
PS: Furthermore I find it funny either overflow-x: hidden;overflow-y: visible; and overflow-x: visible;overflow-y: hidden; still causes this. Which seems more like an actual bug to me.
My question is which behavior is the correct one.
All of them are correct because we don't have the same default font in all browsers and it's also different depending on the OS.
Is specific character allowed to change line height (I thought it was only supposed to be font dependent)?
Character doesn't change line-height. To be more accurate, line-height is a property that can only be changed by setting line-height but you are probably confusing with the line box that is defined by the line-height and a character alone cannot change it.
Shouldn't line-height: 1 imply it can fit exactly any text?
Not necessarely, line-height:1 means that the line box will be equal to the 1xfont-size 1 but is the font designed to include all the character inside this space? Probably most of them will do but we don't know.
Basically, you have two things to consider. The content area that is defined by the font properties and the line box that is defined by the line-height. We have no control over the first one and we can only control the second one.
Here is a basic example to illustrate:
span {
background:red;
color:#fff;
font-size:20px;
font-family:monospace;
}
body {
margin:10px 0;
border-top:1px solid;
border-bottom:1px solid;
animation:change 2s linear infinite alternate;
}
#keyframes change {
from {
line-height:0.2
}
to {
line-height:2
}
}
<span >
blah_blah
</span>
The red is our content area and its height is defined by the font properties and if you inspect the element you will see it has a height equal to 23px (not 20px like the font-size) and the borders define our line box that we control using the line-height.
So if the line-height is equal to 1 we will have a line box equal to 20px which is not enough to contain the 23px of the content area thus it will get truncated and we may probably hide some characters (or a part of them) which is logical:
span {
background: red;
color: #fff;
font-size: 20px;
font-family: monospace;
}
body {
margin: 5px;
line-height: 1;
overflow:hidden;
}
html {
overflow:auto;
}
<span>
blah_blah ÂÄ j p
</span>
a different font-size will remove the underscore in Firefox:
span {
background: red;
color: #fff;
font-size: 26px;
font-family: monospace;
}
body {
margin: 5px;
line-height: 1;
overflow:hidden;
}
html {
overflow:auto;
}
<span>
blah_blah ÂÄ j p
</span>
Another example with a Google Font where the result should be the same cross browser. The underscore is visible but not the ^/¨
span {
background: red;
color: #fff;
font-size: 26px;
font-family: 'Gugi', cursive;
}
body {
margin: 5px;
line-height: 1;
overflow:hidden;
}
html {
overflow:auto;
}
<link href="https://fonts.googleapis.com/css?family=Gugi" rel="stylesheet">
<span>
blah_blah ÂÄ j p
</span>
Another example where the underscore is not visible:
span {
background: red;
color: #fff;
font-size: 27px;
font-family: 'PT Sans', sans-serif;
}
body {
margin: 5px;
line-height: 1;
overflow:hidden;
}
html {
overflow:auto;
}
<link href="https://fonts.googleapis.com/css?family=PT+Sans" rel="stylesheet">
<span>
blah_blah ÂÄ j p
</span>
You can clearly see that we have a different overflow everytime we use a different font which confirms that this is font related. We have no control over it unless we know how the font is designed.
Related questions:
Understanding CSS2.1 specification regarding height on inline-level boxes
Why is there space between line boxes, not due to half leading?
Line height issue with inline-block elements
Here is a good article to get more accurate details and calculation: https://iamvdo.me/en/blog/css-font-metrics-line-height-and-vertical-align
A quote from this article:
It becomes obvious that setting line-height: 1 is a bad practice. I remind you that unitless values are font-size relative, not content-area relative, and dealing with a virtual-area smaller than the content-area is the origin of many of our problems.
1 : I considered a simplified explanation but in reality the calculation of the line box is not only relate to the line-height property.
The default line-height (depending on the font-family) when not otherwise specified is about 1.2 in most browsers. This includes Firefox.
This would explain why the underscore did not show in FireFox when the line-height was set to 1 - the bottom was of the line was cut off. So I don't think it's entirely to do with the font (although this does contribute), but also browser defaults.
Some font-sizes are bigger than other even at seemingly the "same" font size (as I'm sure you've seen when typing documents in e.g. Georgia vs Times new Roman/Baskerville ; so you wouldn't be guaranteed that text would always show on a specified line height of 1 (or 1.2). There are ways of measuring a font in pixels however
Hope this helps
If I use the browser tools in Firefox to inspect my snippet below, there is no height difference between the lines with and without underscore. The only difference is caused by the line-height setting: 16px with line-height: 1, 19.2 px with the browser's default line-height. So the underscore doesn't make a difference here (Firefox 66.0.3 on Mac), and it is visible in both cases.
Note that I set margins to 0 to see the "pure" line-height without distances between the lines. Also, I didn't specify a font-familiy setting, so the default font of the browser for p tags is used.
The only reason for what you describe which I can think of is a font with very particular dimensions/settings, where the descenders (i.e. the parts of letters like p q j which extend below the baseline) are not inside the line-height as defined by the font.
After a bunch of comments back and forth: I suppose it could be caused by the different default (system) fonts on Windows and Mac. Still a bug, I would say (if you are using the default font).
html,
body {
margin: 0;
padding: 0;
}
p {
background: #fb6;
margin: 0px;
}
<p style="line-height: 1;overflow: hidden;">blah_plah</p>
<p style="line-height: 1;overflow: hidden;">blah plah</p>
<p>blah_plah</p>
<p>blah plah</p>

Unexpected space on top and bottom of div

This is my problem in short: https://jsfiddle.net/b6wLwkfs/
Long story: I have a div with some text in it. It initially creates some space on top and bottom of my div (this is not padding). I would like my div to only cover the text and not create extra space. This is my only css:
div {
background-color: black;
color: white;
font-size: 50px
}
<div>This is the text</div>
What I am looking for is to narrow down the div to only contains the text without creating any space on top of bottom. I acknowledge that if you tweaking a bit with px, you will achieve that but I am looking for more generic approach since font size will be different by cases.
Your code below is missing a (;) after font-size: 50px; now to achieve the space reduction I suggest you use line-height with the same font-size refer to my correction
Your Code
div {
background-color: black;
color: white;
font-size: 50px
}
My Correction
div {
background-color: black;
color: white;
font-size: 50px;
line-height: 50px;
}
There is likely no 'generic' way to do this, as that spacing you're seeing is actually part of the font face, and whatever adjustments you make to solve the 'problem' for this font, will not necessarily work on other fonts.
For example, just take a look at how Arial displays, as it's different than the default font that is used without setting a specific font-family, and as such a fix for the default font would likely have to be adjusted for Arial.
p {
background-color: black;
color: white;
font-size: 50px;
line-height: 1;
font-family: arial;
display: inline;
}
<p>
Oh hi i'm different
</p>
In the above snippet I've added a line-height of 1 to help normalize the spacing a bit. You could try to adjust further with setting the line-height to be at, or close to the exact font-size in pixels, but this will likely result in undesired spacing if you have lots of text in the element (text should also be in an appropriately semantic element like a p, or li, not just in a div).
In the end, can you achieve the result you're looking for? Definitely. Using things like line-height, margins and/or transforms. But you are likely not going to find a silver bullet to achieve the effect you want, consistently, if swapping out font faces.
As Sebastian Brosch mentioned in the question's comments, working off from Is it possible to change inline text height, not just the line-height? is likely going to be your best path forward.

Text not aligning with large font-size

I'm building a periodic table in HTMl/CSS and I cant get the text inside the large .element-symbol to align left with the .atomic-weight, .element-name and .atomic-symbol without an arbitrary text-indent. I guess this is just to do with the width of the letters, but is there a way of having the first letter in .element-symbol start hard left? i.e against the red border
Markup:
<div class="cell">
<div class="atomic-number"><span>2</span></div>
<div class="element-symbol">
<abbr>He</abbr>
</div>
<div class="element-name"><span>Helium</span></div>
<div class="atomic-weight">4.002602</div>
</div>
CSS: (red borders to show alignment issue)
* {
padding: 0;
margin: 0;
box-sizing: border-box;
line-height: 1;
}
.cell {
border: 1px solid black;
font-family: sans-serif;
width: 280px;
height: 280px;
margin: 20px auto;
padding:10px;
background-color: #4DBCE9;
}
.element-symbol {
font-size: 173px;
border: 1px solid red;
font-weight: 400;
/*text-indent: -12px; dont want to use this*/
}
.atomic-number, .atomic-weight, .element-name {
font-size: 25px;
border: 1px solid red;
}
Example in codepen
Each glyph in a font, sits within a bounding box. The glyph is usually not hard up against any of the edges of that box, and each glyph (or letter) will have differing amounts of space around it to help space it naturally when it is combined with other glyphs to form words.
Have a look at http://www.freetype.org/freetype2/docs/glyphs/glyphs-3.html to get a feel for some of the intricacies of type design.
I'm not aware of any text or font properties in CSS that can eliminate that space, and in any case that space will be different for each glyph, and different between the same glyphs in different fonts.
You're right - it's simply because of the size of the letters.
In most fonts, each character has a small amount of whitespace to either side of it, to separate it from adjacent letters. Without this space the letters would just run in to each other. At large font sizes, this space gets to be fairly significant, and produces the effect you're seeing. The only other option would be to find (or create) a font that doesn't have that space (or perhaps only has trailing space after each letter and no leading space).

Remove white space above and below large text in an inline-block element

Say I have a single span element defined as an inline-block. It's only contents is plain text. When the font size is very large, you can clearly see how the browser adds a little padding above and below the text.
HTML:
CSS:
span {
display: inline-block;
font-size: 50px;
background-color: green;
}
​
<span>BIG TEXT</span>
Looking at the box model, it's clear the browser is adding padding inside the content edge. I need to remove this "padding", one way is to simply alter the line-height, as with:
http://jsfiddle.net/7vNpJ/1/
This works great in Chrome but in Firefox the text is shifting towards the top (FF17, Chrome 23, Mac OSX).
Any idea of a cross-browser solution? Thanks!
It appears as though you need to explicitly set a font, and change the line-height and height as needed. Assuming 'Times New Roman' is your browser's default font:
span {
display: inline-block;
font-size: 50px;
background-color: green;
/*new:*/
font-family: 'Times New Roman';
line-height: 34px;
height: 35px;
}
<span>
BIG TEXT
</span>
The browser is not adding any padding. Instead, letters (even uppercase letters) are generally considerably smaller in the vertical direction than the height of the font, not to mention the line height, which is typically by default about 1.2 times the font height (font size).
There is no general solution to this because fonts are different. Even for fixed font size, the height of a letter varies by font. And uppercase letters need not have the same height in a font.
Practical solutions can be found by experimentation, but they are unavoidably font-dependent. You will need to set the line height essentially smaller than the font size. The following seems to yield the desired result in different browsers on Windows, for the Arial font:
span.foo
{
display: inline-block;
font-size: 50px;
background-color: green;
line-height: 0.75em;
font-family: Arial;
}
span.bar
{
position: relative;
bottom: -0.02em;
}
<span class=foo><span class=bar>BIG TEXT</span></span>
The nested span elements are used to displace the text vertically. Otherwise, the text sits on the baseline, and under the baseline, there is room reserved for descenders (as in letters j and y).
If you look closely (with zooming), you will notice that there is very small space above and below most letters here. I have set things so that the letter “G” fits in. It extends vertically a bit farther than other uppercase letters because that way the letters look similar in height. There are similar issues with other letters, like “O”. And you need to tune the settings if you’ll need the letter “Q” since it has a descender that extends a bit below the baseline (in Arial). And of course, if you’ll ever need “É”, or almost any diacritic mark, you’re in trouble.
I'm a designer and our devs had this issue when dealing with Android initially, and our web devs are having the same problem. We found that the spacing between a line of text and another object (either a component like a button, or a separate line of text) that a design program spits out is incorrect. This is because the design program isn't accounting for diacritics when it is defining the "size" of a single line of text.
We ended up adding Êg to every line of text and manually creating spacers (little blue rectangles) that act as the "measurement" from the actual top of the text (ie, the top of the accent mark on the E) or from the descender (the bottom of a "g").
For example, say you have a really boring top navigation that is just a rectangle, and a headline beneath it. The design program will say that the space between the bottom of the top nav and the top of the headline textbox 24px. However, when you measure from the bottom of the nav to the top of an Ê accent mark, the spacing is actually 20px.
While I realize that this isn't a code solution, it should help explain the discrepancies between the design specs and what the build looks like.
span::before,
span::after {
content: '';
display: block;
height: 0;
width: 0;
}
span::before{
margin-top:-6px;
}
span::after{
margin-bottom:-8px;
}
Find out the margin-top and margin-bottom negative margins with this tool:
http://text-crop.eightshapes.com/
The tool also gives you SCSS, LESS and Stylus examples.
You can read more about it here:
https://medium.com/eightshapes-llc/cropping-away-negative-impacts-of-line-height-84d744e016ce
I had a similar problem. As you increase the line-height the space above the text increases. It's not padding but it will affect the vertical space between content. I found that adding a negative top margin seemed to do the trick. It had to be done for all of the different instances of line-height and it varies with font-family too.
Maybe this is something which designers need to be more aware of when passing design requirements (?)
So for a particular instance of font-family and line-height:
h1 {
font-family: 'Garamond Premier Pro Regular';
font-size: 24px;
color: #001230;
line-height: 29px;
margin-top: -5px; /* CORRECTION FOR LINE-HEIGHT */
}
This worked for me:
line-height: 80%;
If its text that has to scale proportionally to the screenwidth, you can also use the font as an svg, you can just export it from something like illustrator.
I had to do this in my case, because I wanted to align the top of left and right border with the font's top |TEXT| . Using line-height, the text will jump up and down when scaling the window.
The best way is to use display:
inline-block;
and
overflow: hidden;
I've been annoyed by this problem often. Vertical-align would only work on bottom and center, but never top! :-(
It seems I may have stumbled on a solution that works for both table elements and free paragraph elements. I hope we are at least talking similar problem here.
CSS:
p {
font-family: "Times New Roman", Times, serif;
font-size: 15px;
background: #FFFFFF;
margin: 0
margin-top: 3px;
margin-bottom: 10px;
}
For me, the margin settings sorted it out no matter where I put my "p>.../p>" code.
Hope this helps...

HTML/CSS: One element, 1 pixel high, 100% wide, 0 images, single color, all browsers

I'm looking for a way to do something which in my opinion should be super simple, but I couldn't figure it out...
I want a graphical element on my web page which is exactly 1 pixel high, 100% wide and has a certain color, let's say red. It should look exactly the same in all browser and should preferably not break the semantics too much.
I don't want to use any images for this and I don't want to use more than one HTML element. Of course, I will not use JavaScript.
I tried the old classic which probably many of you know:
<div class="hr"></div>
<style ...>
.hr {
height: 1px;
background: red;
width: 100%;
font-size: 1px; /* IE 6 */
}
</style>
The problem with the above solution is that IE6 will render this as two or three pixels high, to fit the non-existing contents of the div.
Any ideas?
just do
.hr {
height: 0px;
margin: 0px;
border-bottom: 1px solid #FF0000;
font-size: 1px;
}
I went through the same thing when I was new to CSS.
adding an overflow: hidden; style should fix it also.
I don't have IE6 handy to test, but an actual HR tag can work in modern browsers. Took me a couple of tries to realise you set the background color not the border color:
hr { width:75%; height:1px; background-color:#ebebeb; border:none; margin:1.5em auto; }
(adjust to suit)
I don't have IE6 to test this, but I remember it had to do something with the line height. Have you tried this?
line-height: 1px;