How to create an enumerated tabular environment in HTML/CSS? - html

I need to display some data in an HTML page in a three-column, tabular, enumerated environment, like this:
1. elephant animal a large animal that
eats leaves
2. fish animal an animal that
swims in the ocean
3. cactus plant a plant that lives
in dry places
No horizontal or vertical rules are necessary.
Each piece of data is in a left-aligned "box", so if any text needs to wrap, it still stays in its column.
Is there a clean HTML or CSS solution for presenting enumerated tabular environments?

You can make use of the CSS Counter functionality to auto-generate the numbers like shown in the below example:
table{
counter-reset: rows; /* initalize the counter variable */
}
tr{
counter-increment: rows; /* increment the counter every time a tr is encountered */
}
td{ /* just for demo */
vertical-align: top;
width: 100px;
}
td:first-child:before{ /* add the counter value before the first td in every row */
content: counter(rows) ". ";
}
Fiddle Demo
Note:
As per Can I Use, CSS Counters are supported by lower versions of IE also.
If the data is really tabular data as you have mentioned then there is nothing wrong in using the table elements itself.
We are doing a counter-reset whenever a table tag is encountered to make sure that each row in a new table always starts with 1. If the numbering has to continue into a data in another table, then we can reset the counter at the common parent's level (or if none then at body).
Tested in IE (v8 to v10), Firefox, Opera and Chrome and works exactly the same in all of them. JS Fiddle doesn't open properly in IE lower versions, so you can use this JS Bin sample for demo.

You can do this with CSS :
table {
counter-reset: rowNumber;
}
table tr {
counter-increment: rowNumber;
}
table tr td:first-child::before {
content: counter(rowNumber);
min-width: 1em;
margin-right: 0.5em;
}
Demo fiddle
But I'd suggest JS:
var table = document.getElementsByTagName('table')[0],
rows = table.getElementsByTagName('tr'),
text = 'textContent' in document ? 'textContent' : 'innerText';
console.log(text);
for (var i = 0, len = rows.length; i < len; i++){
rows[i].children[0][text] = i + ': ' + rows[i].children[0][text];
}
Demo fiddle

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

vue - inserting rows and columns into a table with scoped css

So I'm trying to insert rows and columns into a table using the code below:
add_to_table(type) {
switch (type) {
case "row":
let columns = this.$refs.table.rows[0].cells.length;
let row = this.$refs.table.insertRow(-1);
row.height = "20px";
for (let i = 0; i < columns; i++) {
let cell = row.insertCell(-1);
cell.innerHTML = " ";
}
break;
case "column":
for (let row of this.$refs.table.rows) {
let cell = row.insertCell(-1);
cell.innerHTML = " ";
}
break;
}
}
However, this doesn't seem to maintain the css (doesn't add the data-* stuff to it).
I'm currently working around this by using v-for:
<tr v-for="row in rows">
<td v-for="column in columns">
</td>
</tr>
https://codesandbox.io/s/8n728r5wr8
Your created rows and columns are not getting styled because the <style> you declared is scoped.
For the elements to get the scoped style, they must have a data-v-SOMETHING attribute. The elements you create manually, not via Vue, don't have that attribute.
WARNING: Vue is data-driven, the correct, simplest, more predictable
and maintainable way of achieving what you want is mutating a data
attribute and letting Vue's templates react to it accordingly (using
directives like v-for). Your solution is not optimal. You have been warned.
That being said, you have some options:
Declare an additional <style> (non-scoped) tag along the scoped one. The created elements will pick up these styles. Drawback: the styles will be global. Advantage: you don't depend on Vue internals, you don't have to always add the data-v attribute (see below).
Example:
<style scoped>
...
</style>
<style>
/* EXAMPLE OF GLOBAL STYLE ALONGSIDE A SCOPED ONE */
tr, td {
box-shadow:inset 0px 0px 0px 1px orange;
}
</style>
Get a hold of the data-v-SOMETHING attribute. It is available at this.$options._scopeId. Double Warning: the prefix _ means it is internal code. It may change without notice. Your app may be forever stuck with the current Vue 2.x versions. You have been warned again.
So, whenever you create elements, just add the attribute. Example:
// row example
let row = this.$refs.table.insertRow(-1);
row.setAttribute(this.$options._scopeId, ""); // <== this adds the data-v-XYZ attr
...
// cell example
let cell = row.insertCell(-1);
cell.setAttribute(this.$options._scopeId, ""); // <== this adds the data-v-XYZ attr
Here's a CodeSandbox demo containing examples for both alternatives.

How to distribute a single column of data into two columns equally distributing data?

I am displaying a table in html consisting of only a single column full name :
Full_name
Alex
Frown
Chris
Dram
Drex
Pheobe
I have used a for loop in to display the names. But i want the output to be displayed in two column distributed equally like:
Full_name Full_name
alex Frown
Chris Dram
Drex Pheobe
You can separate the names to two arrays, for example by index. If remainder of index divided by 2 is 0 push it to one array, otherwise push it to the other array.
let fullNamesArr...
let fullNamesLength = fullNamesArr.length;
let leftColumn = [];
let rightColumn = [];
for (let i = 0; i < fullNamesLength; i++) {
if (i % 2 === 0) {
leftColumnt.push(fullNamesArr[i]);
} else {
rightColumn.push(fullNamesArr[i]);
}
}
and then just display the two tables next to each other.
Or you can use styles.
Make a "header", with two divs with the same width (300px), both
containing the string Full_name.
Make container with width for example 600px. Give it a style of display: flex; flex-wrap: wrap;
In that container add the ngFor element and give it a 300px width.
(600 and 300 is an example)
It seems what i was trying to achieve could be simply done by css. Just give a css class to the tbody, in my case i named it split-table then add the following css:
<style type="text/css">
.split-table tr{
width: 50%;
float: left;
}
.split-table tr:nth-child(1n+2){
background: rgba(0,0,0,.1);
}
}
</style>

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

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.

Change last letter color

Example code:
<p class="test">string</p>
I want to change the color on the last letter, in this case "g", but I need solution with css, I don't need a javascript solution.
I display the string letter by letter and i cant use static solution.
Everyone says it can't be done. I'm here to prove otherwise.
Yes, it can be done.
Okay, so it's a horrible hack, but it can be done.
We need to use two CSS features:
Firstly, CSS provides the ability to change the direction of the flow of the text. This is typically used for scripts like Arabic or Hebrew, but it actually works for any text. If we use it for English text, the letters are displayed in reverse order to how the appear in the markup. So to get the text to show as the word "String" on a reversed element, we would have to have markup that reads "gnirtS".
Secondly, CSS has the ::first-letter pseudo-element selector, which selects the first letter in the text. (other answers already established that this is available, but there's no equivalent ::last-letter selector)
Now, if we combine the ::first-letter with the reversed text, we can select the first letter of "gnirtS", but it'll look like we're selecting the last letter of "String".
So our CSS looks like this:
div {
unicode-bidi:bidi-override;
direction:rtl;
}
div::first-letter {
color: blue;
}
and HTML:
<div>gnirtS</div>
Yes, this does work -- you can see the working fiddle here: http://jsfiddle.net/gFcA9/
But as I say, it is a bit hacky. And who wants to spend their time writing everything backwards? Not really a practical solution, but it does answer the question.
Use ::after pseudo-element combined with attr() function:
p::after {
content: attr(data-end) ;
color: red ;
}
<p data-end="g">Strin</p>
p::after {
content: attr(data-end) ;
color: red ;
}
<p data-end="g">Strin</p>
Another solution is to use ::after
.test::after{
content: "g";
color: yellow;
}
<p class="test">strin</p>
This solution allows to change the color of all characters not only letters like the answer from Spudley that uses ::first-letter. See ::first-letter specification for more information. ::first-letter applies only on letters it ignores punctuation symbols.
Moreover if you want to color more than the last character you can :
.test::after{
content: "ing";
color: yellow;
}
<p class="test">str</p>
For more information on ::after check this link.
Without using javascript, your only option is:
<p class="test">strin<span class="other-color">g</span></p>
Edit for your fiddle link:
I'm not really sure why you said you didn't need a javascript solution, since you have quite a bit of it already. Regardless, in this example, you need to make only a couple small changes. Change line 10 from
elem.text(elem.text() + contentArray[current++]);
to
if ( current == contentArray.length-1 ) {
elem.html(elem.html() + "<span style='color:red'>"+contentArray[current++]+"</span>");
} else {
elem.html(elem.html() + contentArray[current++]);
}
Note that it's important to use .html() instead of .text() now, since there's actually HTML markup being inserted.
Working fiddle: http://jsfiddle.net/QTUsb/2/
It could be achieved using only CSS and an ::after pseudo-element without any changes in HTML:
.test {
font-size: 16pt;
position: relative;
}
.test::after {
bottom: 0;
color: red;
content: 'g';
position: absolute;
transform: translate(-100%, 0);
}
<p class="test">string</p>
In what way do you "display the string letter by letter"? If you're looping through the characters in a string (variable) you can certainly tell when you're at the last letter and wrap it in a whether doing so on the server side or client side.
Looking at the fiddles attached to another of your questions ...
If this is what you're talking about, you might have to set the .innerHTML of the element instead of the element.text()
From the fiddle at http://jsfiddle.net/SLKEn/ you would change it to something like this
if(current < contentArray.length) {
elem.html(
elem.html() +
(current == contentArray.length-1 ?
'<span class="lastchar">' + contentArray[current++] + '</span>' :
contentArray[current++])
);
}
along with CSS span.lastchar { color: red; }
Update: working fiddle based on your other question.
$(document).ready(function() {
var str=$("span").text();
strArr=str.split("");
for(var key=0;key<=strArr.length-1;key++) {
if(key==strArr.length-1) {
var newEle="<span id='lastElement'>"+strArr[key]+"</div>";
strArr[key]=newEle;
}
}
var newtext=strArr.join("");
$("span").html(newtext);
});
span#lastElement {
color: red;
}
i dont have the ability to comment on an answer thread but i wanted to point out an error in an answer provided by Marc_Alx that otherwise works wonderfully. that solution worked for me only after adding a semi-colon behind the content property... so it looks like content:"ing";
.test::after{
content:"ing";
color:yellow;
}
<p class="test">str</p>