how to auto-number each line in <p> element using CSS - html

I'm trying to auto-number each line that will be generated while displaying a
<p> element.
Perhaps using counters in CSS?
I'm looking for something along the lines of p:first-line, except for every line of the <p> element
something like:
p:each-line {
counter-increment line_num;
}
p:each-line:before {
counter(line_num) " " ACTUAL-LINE;
}
Can I do this with simple CSS code? How else could I achieve this?
I have an element called message, and I don't know in advance how many lines
of actual text will be formatted using that element style. If I change the
max-width for example and that forces more/fewer lines, I'd like this to automatically
number correctly the actual lines in the element.
/* set up the speech bubbles */
p.message {
position:relative;
padding:5px 10px;
border:2px solid rgb(74,77,82);
border:2px solid rgba(74,77,82,.5);
-moz-border-radius:10px;
-webkit-border-radius:10px;
border-radius:10px;
max-width: 70%;
}

Such a task is a little much for CSS alone to handle. It isn't too hard in javascript.
It sounded like a nice little distraction so I played around a bit in jsfiddle. Perhaps this will help even though it's not pure css and uses some jquery.
http://jsfiddle.net/rSFUB/2/
Notice that I wrapped the <p> text in a div and added a line number div within that absolutely positioned. The javascript is:
$(document).ready(function () {
$(".message").each(function () {
var self = $(this);
var numbering = self.find(".lineNumbering").first();
var messageText = self.find("p").first();
var lineHeight = numbering.text("...").height();
var lines = messageText.height() / lineHeight;
var lineNumberingHtml = "";
for(var i = 1; i <= lines; i++) {
lineNumberingHtml = "" + lineNumberingHtml + i + "<br />";
}
numbering.html(lineNumberingHtml);
});
});
I tested in IE10, Chrome, and Firefox. The only difference between this code in the various versions is the padding on the .lineNumber div in order for it to line up with the text. Note this assumes that the line number div text and the paragraph is the same line-height.

Related

Manage liste separator while the screen change size (media query)

I try to manage separators (like a "-") between each element of a list.
It's relatively simple when we only have one line, but I can't do it with more than one line.
When the site is displayed on a big screen I have:
Example center aligned
Listitem1 - listitem2 - listitem3 - ... - listitemX
The last item having no separator "-"
html
<p>
<a>listitem1</a>
<a>listitem2</a>
<a>listitem3</a>
<a>listitem4</a>
<a>listitem5</a>
<a>listitem6</a>
<a>listitem7</a>
...
<a>listitemX</a>
</p>
CSS
a:nth-child(n+2)::before {
content: " - "
}
This is relatively easy in CSS using :: before from the 2nd child...
But with media queries, when my screen shrinks and this same list spans multiple lines, I would like to remove the last "-" separator from each line.
Example center aligned
Listitem1 - listitem2 - listitem3 - listitem4 (without the separator here)
Listitem5 - listitem6 - listitem6 - listitem8 (without separator here either)
Listitem9 - etc ...
Does anyone have an idea?
Thank you in advance. Sebastian
There doesn’t seem to be a pure CSS solution, but you can use a bit of JS to set or unset a class based on whether an item is the first in a line.
Here I’m setting the text color to transparent rather than the content to "" because changing the content affects width, which then jumps around as it wraps/resizes.
a.firstInLine::before {
color: transparent;
}
The Javascript goes through the nodes and checks whether it’s lower on the page than the previous node. If it is (by more than a small margin of error), it sets the class firstInLine:
function calcY() {
document.querySelectorAll("p a").forEach((n, i, nodes) => {
if(i > 0) {
const thisY = n.getClientRects()[0].y;
const prevY = nodes[i - 1].getClientRects()[0].y;
if(thisY - prevY > 4) {
n.classList.add("firstInLine");
}
else {
n.classList.remove("firstInLine");
}
}
});
}
window.addEventListener("resize", calcY);
calcY();
I should add that there are a couple of other CSS things to set. We don’t want it to wrap, and in order for getClientRects to work right, it can’t be a purely inline element, so:
a {
white-space: nowrap;
display: inline-block;
}
CodePen

Hover over a pre - how to highlight a single line with plain CSS?

I have some <pre> blocks.
Would it be possible, using just CSS, to highlight single lines when hovering over them?
== Update ==
Here is some sample code:
<pre>
#include <stdio.h>
int main()
{
printf("Hello World");
return 0;
}
</pre>
When lines become longer it would be useful to have them highlighted when hovering.
The source file can't be read via PHP, or I'd split it into separate <pre> lines, with a trivial pre:hover CSS.
pre:nth-child is not a solution, because code lines are not "children" in the CSS sense.
pre:first-line works, but of course just for the first line.
== Update 2 ==
Since CSS seems to be limited to first-line, and thanks to Zeke suggestion, I found an almost simple way to have what I want.
HTML:
<pre id="raw">
#include <stdio.h>
int main()
{
printf("Hello World");
return 0;
}
</pre>
<!-- 1×1 transparent PNG for the onload -->
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP4/x8AAwAB/2+Bq7YAAAAASUVORK5CYII=" onload="PreHover()" />
CSS:
#pre div:hover {
background: #ff0;
}
Vanilla Javascript:
function PreHover() {
var output = '';
var preBox = document.getElementById('raw');
var txt = preBox.innerHTML.split('\n');
for(var x=0;x<txt.length-1;x++) {
output = output + '<div>'+txt[x]+'</div>';
}
preBox.innerHTML = output;
}
JSFiddle here
This will help you wrap div for each line
var txt = $('pre').html().split("\n");
var output = "";
for(var x=0;x<txt.length-1;x++)
output = output + "<div>"+txt[x]+"</div>";
}
$('pre').html(output);
You can write one line css then for highlighting:
pre div:hover { background-color: rgba(0,0,0,0.2); }
Demo here
Note: This requires jQuery
Optional: Add white-space:nowrap to prevent wrapping each line
Why do this?
Because if just have <pre>, it will be a DOM element containing just text inside it, on which you can make changes as a whole, and not line by line.
To have much better control over every line, build a new DOM element by manipulating the text contained in <pre> with pre containing many div each of which contains one line of text. And now you can master each and every div

HTML table scale to fit

I have a KPI dashboard with a lot of small charts. One type of chart is in fact a HTML table. It is displayed in a DIV.
<div style="width:400px; height:250px;overflow:hidden">
<table>
<tr><th>Col1</th><th>Col2</th></tr>
<tr><td>Row1</td><td>Row2</td></tr>
</table>
<div>
Currently, I hide the overflow. I would like to make the table 'fit' the div.
How can I make this table to fit/scale down to the DIV if it would become too big to diplay? Ideally, the text would also shrink.
This CSS will make your table have the same height/width as the container you are using. Borders/background are only added for visualising what happens.
Shrinking the text will however be far more challenging. There is probably no way without using javascript to achieve that. And even if you did, content might end up being unreadable because of a too small font-size.
I managed to come up with some javascript/jquery code to change the font-size until the table fits the div or the font-size reaches 5px (= unreadable). Of coarse you will need to edit some of it yourself (because it would apply on all tables if you don't change the selectors to id's)
[JSFiddle]
table{
width: 100%;
background-color: red;
}
th, td{
width: 50%;
border: blue solid 1px;
}
Jquery / Javascript
$(document).ready(function () {
var HeightDiv = $("div").height();
var HeightTable = $("table").height();
if (HeightTable > HeightDiv) {
var FontSizeTable = parseInt($("table").css("font-size"), 10);
while (HeightTable > HeightDiv && FontSizeTable > 5) {
FontSizeTable--;
$("table").css("font-size", FontSizeTable);
HeightTable = $("table").height();
}
}
});
Here is what I use currently, it is embedded in a project (see for example the classes), but feel free to use it as inspiration.
scaleTable = function (markupId) {
//This hacky stuff is used because the table is invisible in IE.
function realWidth(obj){
var clone = obj.clone();
clone.css("visibility","hidden");
$('body').append(clone);
var width = clone.outerWidth();
clone.remove();
return width;
}
function realHeight(obj){
var clone = obj.clone();
clone.css("visibility","hidden");
$('body').append(clone);
var height = clone.outerHeight();
clone.remove();
return height;
}
var table = $("#"+markupId+" table:first-of-type");
var tablecontainer = $("#"+markupId).parents( ".scalabletablecontainer" );
var scalex = tablecontainer.innerWidth() / realWidth(table);
var scaley = tablecontainer.innerHeight() / realHeight(table);
var scale = Math.min(scalex, scaley);
if (scale<1.0) {
var fontsize = 12.0 * scale;
var padding = 5.0 * scale;
$("#"+markupId+" table tbody").css("font-size", fontsize + "px");
$("#"+markupId+" table tbody TD").css("padding",padding + "px");
$("#"+markupId+" table TH").css("padding",padding + "px");
}
};
Get table and div dimensions as shown in the previous comments. Then apply css
transfrom:scale(factorX, factorY)
to the table.

Add a border only to the bottom of wrapped text

I'm trying to achieve an underline on some wrapped text that fits to the width of the bottom row of text whilst only appearing underneath that bottom line. Figure 1 illustrates the desired effect
Figure 1
Using this HTML:
<h2><span class="inline-block">optatur, volendit inum simolor</span></h2>
and setting the span to display:inline; I can get the underline to fit perfectly with the width of the text but it underlines all of the text.
Or, setting the span to display:inline-block; I can get the underline to only appear under the bottom line but it then fills the whole width of the parent.
See this JSfiddle for the above examples: http://jsfiddle.net/PWDV7/1/
Is there any way to achieve the result of figure 1?
With a good leg up from this answer to a questions about finding line wraps, I managed to come up with this solution (in short, it involves using JS to find where a line wrap has occurred and wraps a span around all the text that sits on the last line):
function underLineText () {
$underlined_text.each(function(){
var $this = $(this);
var text = $this.text();
var originalText = text;
var breakWords = new Array();
//split the words into individual strings
var words = text.split(' ');
//find the height of the first word
$this.text(words[0]);
var height = $this.height();
//if there is more than one word
if (words.length > 1) {
//loop through all the words
for(var i = 1; i < words.length; i++){
$this.text($this.text() + ' ' + words[i]);
//check if the current word has a different height from the previous word
//if this is true, we have witnessed a word wrap!
if($this.height() > height){
height = $this.height();
//add the first word after the wrap to a predefined array
breakWords.push(words[i]);
}
//on the last iteration on the loop...
if (i === words.length - 1) {
if (breakWords.length > 0) {
//select the last word of the breakWords array
//(this is to handle cases where there there are more than one line or word wraps)
var breakStartAt = breakWords[breakWords.length - 1];
//add a span before the last word
var withSpan = '<span>'+breakStartAt;
//replace the last occurrence of this word with the span wrapped version
//(this is to handle cases where there are more than one occurrences of the last word)
originalText = originalText.replaceLast(breakStartAt,withSpan);
//close the last line with a span
originalText += "</span>";
}
}
}
}
//if there are no word wraps, wrap the whole text in spans
else {
originalText = '<span>'+originalText+'</span>';
}
//replace the original text with the span-wrapped mod
$(this).html(originalText);
});
}
You can see it working here: http://jsfiddle.net/PWDV7/5/
Change the code like so:
HTML
<h2>optatur, volendit <span>inum simolor</span></h2>
CSS
h2 {
width:200px;
text-align:center;
}
h2 span {
border-bottom:3px solid black;
width:100%;
}
All I changed was the position of the <span> to wrap the text that you want the border on.
JsFiddle

Placing words directly under or above other words

I wish to do the following within div tags:
The words will be coloured differently using spans.
I will be given some text in a text box and via JavaScript I will need to dynamically update to div to show something like the above.
What is the best way to do this?
Will it involve a monospaced font?
Will it involve writing "hidden" text?
I wish to do entire paragraphs in this manner.
This might seem weird but the research I'm doing requires me present certain words from a given text with multiple colours and I think this might be a nice way of conveying this information.
Updating the text in the text box will update the following variables, and in turn I will need to convert these two variables into something like the image above.
text = "I am under the text above me and there is lots more text to come./n I am even moving onto a new line since I have more text"
color_per_word_position = {0:green, 1: red, 2: cyan, 4: yellow, 5: red, ...}
You will have to use a monospaced font for this.*
I basically see two options: 1. use whitespace 2. margins.
Option 1
Your text will look like
I•am•under•the•text•above
••am•under•••••text•above
where • denotes a space character. Pretty straight-forward in terms of CSS, since you don't have to worry about the spacing. The browser does it all for you. Example: http://jsfiddle.net/PYXdr/
*well, it may be possible with any font, using a lot of JS, but I guess it's not worth it.
Option 2
Since you probably don't want whitespace in between your spans, you may prefer this:
I•am•under•the•text•above
am•under text•above
Now, the spacing needs to be taken care of manually. Each span should get a margin-left that pushes it to the desired position. But before we can do that, we need to know the width of one character (using JS, since CSS does not provide that). Okay, pretty easy:
var el = document.createElement('pre');
el.style.display = 'inline-block';
el.innerHTML = ' ';
document.body.appendChild(el);
var width = parseFloat(getComputedStyle(el).width);
document.body.removeChild(el);
Now let's go ahead and move the spans:
span1.style.marginLeft = (2 * width) + 'px';
span2.style.marginLeft = (5 * width) + 'px';
Example: http://jsfiddle.net/JC3Sc/
Putting it all together
Now here's a basic example of how this might work:
var text = "I am under the text above me and there is lots more text to come.\nI am even moving onto a new line since I have more text"
var highlightBorders = [[2, 3, 4, 6], [6, 7]]; // YOUR TASK: implement the logic to display the following lines
var color_per_word_position = {0:'lime', 1: 'red', 2: 'cyan', 3:'orange', 4: 'yellow', 5: 'red'}
/* generate CSS */
var style = document.createElement('style');
for (var i in color_per_word_position) {
style.innerHTML += '.hl' + i + '{background:' + color_per_word_position[i] + '}';
}
document.head.appendChild(style);
/* generating the text */
text = text.split('\n');
var pre = document.createElement('pre');
text.forEach(function (line, i) {
var div = document.createElement('div');
var words = line.split(' ');
var result = [];
highlightBorders[i].forEach(function (len, j) {
var span = document.createElement('span');
span.innerHTML = words.splice(0, len).join(' ');
span.className = 'hl' + j;
if (j) {
span.style.marginLeft = width + 'px' // YOUR TASK: implement the logic
}
div.appendChild(span);
});
pre.appendChild(div);
});
document.body.appendChild(pre);
This is not a complete solution, since a) I don't really see which parts exactly you want to highlight and b) I don't want to spoil all the fun. But you get the idea.
Example: http://jsfiddle.net/tNyqL/
Using padding this is possible but also have absolute control by assigning text to a selector such as "p" for the class: fiddle http://jsfiddle.net/3NDs3/1/
.one {
width:200px;
}
.one p {
font: normal 14px Futura, sans-serif;
text-align:left;
padding-left:130px;
}
.two {
width:200px;
}
.two p {
text-align:center;
font: normal 14px Futura, sans-serif;
}
.three {
width:200px
}
.three p {
text-align:left;
font: normal 14px Futura, sans-serif;
padding-left:35px;
}
<div class="one">
<p>above me</p>
</div>
<div class="two">
<p>i am under the text above me</p>
</div>
<div class="three">
<p>under</p>
</div>